2017-01-03 06:17:54 +00:00
|
|
|
//
|
|
|
|
// 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.
|
|
|
|
//
|
2016-12-30 07:11:06 +00:00
|
|
|
|
|
|
|
#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"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/things/r_wallsprite.h"
|
2016-12-30 07:11:06 +00:00
|
|
|
#include "c_console.h"
|
|
|
|
#include "c_cvars.h"
|
|
|
|
#include "c_dispatch.h"
|
|
|
|
#include "doomstat.h"
|
|
|
|
#include "v_video.h"
|
|
|
|
#include "sc_man.h"
|
|
|
|
#include "s_sound.h"
|
|
|
|
#include "sbar.h"
|
|
|
|
#include "gi.h"
|
|
|
|
#include "r_sky.h"
|
|
|
|
#include "cmdlib.h"
|
|
|
|
#include "g_level.h"
|
|
|
|
#include "d_net.h"
|
|
|
|
#include "colormatcher.h"
|
|
|
|
#include "d_netinf.h"
|
|
|
|
#include "p_effect.h"
|
2017-01-11 19:42:39 +00:00
|
|
|
#include "swrenderer/scene/r_opaque_pass.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/scene/r_3dfloors.h"
|
2017-01-11 19:42:39 +00:00
|
|
|
#include "swrenderer/scene/r_translucent_pass.h"
|
2016-12-30 07:11:06 +00:00
|
|
|
#include "swrenderer/drawers/r_draw_rgba.h"
|
|
|
|
#include "swrenderer/drawers/r_draw_pal.h"
|
|
|
|
#include "v_palette.h"
|
|
|
|
#include "r_data/r_translate.h"
|
|
|
|
#include "r_data/colormaps.h"
|
|
|
|
#include "r_data/voxels.h"
|
|
|
|
#include "p_local.h"
|
|
|
|
#include "p_maputl.h"
|
|
|
|
#include "r_voxel.h"
|
2016-12-31 11:45:07 +00:00
|
|
|
#include "swrenderer/segments/r_drawsegment.h"
|
|
|
|
#include "swrenderer/scene/r_portal.h"
|
2017-01-12 15:21:46 +00:00
|
|
|
#include "swrenderer/scene/r_scene.h"
|
|
|
|
#include "swrenderer/scene/r_viewport.h"
|
|
|
|
#include "swrenderer/scene/r_light.h"
|
2017-01-01 09:28:35 +00:00
|
|
|
#include "swrenderer/line/r_wallsetup.h"
|
|
|
|
#include "swrenderer/line/r_walldraw.h"
|
2016-12-30 07:11:06 +00:00
|
|
|
#include "swrenderer/r_memory.h"
|
|
|
|
|
2017-01-11 14:41:42 +00:00
|
|
|
EXTERN_CVAR(Bool, r_fullbrightignoresectorcolor);
|
|
|
|
|
2016-12-30 07:11:06 +00:00
|
|
|
namespace swrenderer
|
|
|
|
{
|
2017-01-12 20:29:19 +00:00
|
|
|
void RenderWallSprite::Project(AActor *thing, const DVector3 &pos, FTextureID picnum, const DVector2 &scale, int renderflags, int spriteshade, bool foggy, FDynamicColormap *basecolormap)
|
2016-12-30 07:11:06 +00:00
|
|
|
{
|
|
|
|
FWallCoords wallc;
|
|
|
|
double x1, x2;
|
|
|
|
DVector2 left, right;
|
|
|
|
double gzb, gzt, tz;
|
|
|
|
FTexture *pic = TexMan(picnum, true);
|
|
|
|
DAngle ang = thing->Angles.Yaw + 90;
|
|
|
|
double angcos = ang.Cos();
|
|
|
|
double angsin = ang.Sin();
|
|
|
|
|
|
|
|
// Determine left and right edges of sprite. The sprite's angle is its normal,
|
|
|
|
// so the edges are 90 degrees each side of it.
|
|
|
|
x2 = pic->GetScaledWidth();
|
|
|
|
x1 = pic->GetScaledLeftOffset();
|
|
|
|
|
|
|
|
x1 *= scale.X;
|
|
|
|
x2 *= scale.X;
|
|
|
|
|
|
|
|
left.X = pos.X - x1 * angcos - ViewPos.X;
|
|
|
|
left.Y = pos.Y - x1 * angsin - ViewPos.Y;
|
|
|
|
right.X = left.X + x2 * angcos;
|
|
|
|
right.Y = right.Y + x2 * angsin;
|
|
|
|
|
|
|
|
// Is it off-screen?
|
|
|
|
if (wallc.Init(left, right, TOO_CLOSE_Z))
|
|
|
|
return;
|
2017-01-05 03:55:26 +00:00
|
|
|
|
|
|
|
RenderPortal *renderportal = RenderPortal::Instance();
|
2016-12-30 07:11:06 +00:00
|
|
|
|
2017-01-05 03:55:26 +00:00
|
|
|
if (wallc.sx1 >= renderportal->WindowRight || wallc.sx2 <= renderportal->WindowLeft)
|
2016-12-30 07:11:06 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
// Sprite sorting should probably treat these as walls, not sprites,
|
|
|
|
// but right now, I just want to get them drawing.
|
|
|
|
tz = (pos.X - ViewPos.X) * ViewTanCos + (pos.Y - ViewPos.Y) * ViewTanSin;
|
|
|
|
|
|
|
|
int scaled_to = pic->GetScaledTopOffset();
|
|
|
|
int scaled_bo = scaled_to - pic->GetScaledHeight();
|
|
|
|
gzt = pos.Z + scale.Y * scaled_to;
|
|
|
|
gzb = pos.Z + scale.Y * scaled_bo;
|
|
|
|
|
2017-01-16 04:26:22 +00:00
|
|
|
RenderWallSprite *vis = RenderMemory::NewObject<RenderWallSprite>();
|
2017-01-05 03:55:26 +00:00
|
|
|
vis->CurrentPortalUniq = renderportal->CurrentPortalUniq;
|
|
|
|
vis->x1 = wallc.sx1 < renderportal->WindowLeft ? renderportal->WindowLeft : wallc.sx1;
|
|
|
|
vis->x2 = wallc.sx2 >= renderportal->WindowRight ? renderportal->WindowRight : wallc.sx2;
|
2016-12-30 07:11:06 +00:00
|
|
|
vis->yscale = (float)scale.Y;
|
|
|
|
vis->idepth = float(1 / tz);
|
|
|
|
vis->depth = (float)tz;
|
|
|
|
vis->sector = thing->Sector;
|
|
|
|
vis->heightsec = NULL;
|
|
|
|
vis->gpos = { (float)pos.X, (float)pos.Y, (float)pos.Z };
|
|
|
|
vis->gzb = (float)gzb;
|
|
|
|
vis->gzt = (float)gzt;
|
|
|
|
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
|
2017-01-16 15:23:02 +00:00
|
|
|
vis->RenderStyle = thing->RenderStyle;
|
2016-12-30 07:11:06 +00:00
|
|
|
vis->FillColor = thing->fillcolor;
|
|
|
|
vis->Translation = thing->Translation;
|
2017-01-04 18:03:33 +00:00
|
|
|
vis->FakeFlatStat = WaterFakeSide::Center;
|
2017-01-16 15:23:02 +00:00
|
|
|
vis->Alpha = float(thing->Alpha);
|
2016-12-30 07:11:06 +00:00
|
|
|
vis->fakefloor = NULL;
|
|
|
|
vis->fakeceiling = NULL;
|
2017-01-16 04:26:22 +00:00
|
|
|
//vis->bInMirror = renderportal->MirrorFlags & RF_XFLIP;
|
2016-12-30 07:11:06 +00:00
|
|
|
vis->pic = pic;
|
|
|
|
vis->wallc = wallc;
|
2017-01-12 19:13:21 +00:00
|
|
|
vis->foggy = foggy;
|
2017-01-16 02:46:05 +00:00
|
|
|
|
2017-01-24 03:15:54 +00:00
|
|
|
vis->Light.SetColormap(r_SpriteVisibility / MAX(tz, MINZ), spriteshade, basecolormap, false, false, false);
|
2017-01-17 00:30:12 +00:00
|
|
|
|
2017-01-16 02:46:05 +00:00
|
|
|
VisibleSpriteList::Instance()->Push(vis);
|
2016-12-30 07:11:06 +00:00
|
|
|
}
|
|
|
|
|
2017-01-16 04:26:22 +00:00
|
|
|
void RenderWallSprite::Render(short *mfloorclip, short *mceilingclip, int, int)
|
2016-12-30 07:11:06 +00:00
|
|
|
{
|
2017-01-16 04:26:22 +00:00
|
|
|
auto spr = this;
|
|
|
|
|
2016-12-30 07:11:06 +00:00
|
|
|
int x1, x2;
|
|
|
|
double iyscale;
|
2017-01-09 12:53:02 +00:00
|
|
|
bool sprflipvert;
|
2016-12-30 07:11:06 +00:00
|
|
|
|
|
|
|
x1 = MAX<int>(spr->x1, spr->wallc.sx1);
|
|
|
|
x2 = MIN<int>(spr->x2, spr->wallc.sx2);
|
|
|
|
if (x1 >= x2)
|
|
|
|
return;
|
2017-01-03 17:57:48 +00:00
|
|
|
FWallTmapVals WallT;
|
2016-12-30 07:11:06 +00:00
|
|
|
WallT.InitFromWallCoords(&spr->wallc);
|
2017-01-03 17:57:48 +00:00
|
|
|
PrepWall(swall, lwall, spr->pic->GetWidth() << FRACBITS, x1, x2, WallT);
|
2016-12-30 07:11:06 +00:00
|
|
|
iyscale = 1 / spr->yscale;
|
2017-01-12 21:52:17 +00:00
|
|
|
double texturemid = (spr->gzt - ViewPos.Z) * iyscale;
|
2016-12-30 07:11:06 +00:00
|
|
|
if (spr->renderflags & RF_XFLIP)
|
|
|
|
{
|
|
|
|
int right = (spr->pic->GetWidth() << FRACBITS) - 1;
|
|
|
|
|
|
|
|
for (int i = x1; i < x2; i++)
|
|
|
|
{
|
|
|
|
lwall[i] = right - lwall[i];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Prepare lighting
|
|
|
|
bool calclighting = false;
|
2017-01-24 03:15:54 +00:00
|
|
|
FSWColormap *usecolormap = spr->Light.BaseColormap;
|
2016-12-30 07:11:06 +00:00
|
|
|
bool rereadcolormap = true;
|
|
|
|
|
|
|
|
// Decals that are added to the scene must fade to black.
|
2017-01-16 15:23:02 +00:00
|
|
|
if (spr->RenderStyle == LegacyRenderStyles[STYLE_Add] && usecolormap->Fade != 0)
|
2016-12-30 07:11:06 +00:00
|
|
|
{
|
|
|
|
usecolormap = GetSpecialLights(usecolormap->Color, 0, usecolormap->Desaturate);
|
|
|
|
rereadcolormap = false;
|
|
|
|
}
|
|
|
|
|
2017-01-12 19:13:21 +00:00
|
|
|
int shade = LIGHT2SHADE(spr->sector->lightlevel + R_ActualExtraLight(spr->foggy));
|
2017-01-12 17:38:27 +00:00
|
|
|
double GlobVis = r_WallVisibility;
|
2017-01-03 17:57:48 +00:00
|
|
|
float lightleft = float(GlobVis / spr->wallc.sz1);
|
|
|
|
float lightstep = float((GlobVis / spr->wallc.sz2 - lightleft) / (spr->wallc.sx2 - spr->wallc.sx1));
|
|
|
|
float light = lightleft + (x1 - spr->wallc.sx1) * lightstep;
|
2016-12-30 07:11:06 +00:00
|
|
|
if (fixedlightlev >= 0)
|
|
|
|
R_SetColorMapLight(usecolormap, 0, FIXEDLIGHT2SHADE(fixedlightlev));
|
|
|
|
else if (fixedcolormap != NULL)
|
|
|
|
R_SetColorMapLight(fixedcolormap, 0, 0);
|
2017-01-12 19:13:21 +00:00
|
|
|
else if (!spr->foggy && (spr->renderflags & RF_FULLBRIGHT))
|
2016-12-30 07:11:06 +00:00
|
|
|
R_SetColorMapLight((r_fullbrightignoresectorcolor) ? &FullNormalLight : usecolormap, 0, 0);
|
|
|
|
else
|
|
|
|
calclighting = true;
|
|
|
|
|
|
|
|
// Draw it
|
2017-01-09 13:51:34 +00:00
|
|
|
FTexture *WallSpriteTile = spr->pic;
|
2016-12-30 07:11:06 +00:00
|
|
|
if (spr->renderflags & RF_YFLIP)
|
|
|
|
{
|
|
|
|
sprflipvert = true;
|
|
|
|
iyscale = -iyscale;
|
2017-01-12 21:52:17 +00:00
|
|
|
texturemid -= spr->pic->GetHeight();
|
2016-12-30 07:11:06 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sprflipvert = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
float maskedScaleY = (float)iyscale;
|
|
|
|
|
|
|
|
int x = x1;
|
|
|
|
|
2017-01-24 03:15:54 +00:00
|
|
|
FDynamicColormap *basecolormap = static_cast<FDynamicColormap*>(spr->Light.BaseColormap);
|
2017-01-12 20:29:19 +00:00
|
|
|
|
2017-01-16 15:23:02 +00:00
|
|
|
bool visible = R_SetPatchStyle(spr->RenderStyle, spr->Alpha, spr->Translation, spr->FillColor, basecolormap);
|
2016-12-30 07:11:06 +00:00
|
|
|
|
|
|
|
// R_SetPatchStyle can modify basecolormap.
|
|
|
|
if (rereadcolormap)
|
|
|
|
{
|
2017-01-24 03:15:54 +00:00
|
|
|
usecolormap = spr->Light.BaseColormap;
|
2016-12-30 07:11:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!visible)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (x < x2)
|
|
|
|
{
|
|
|
|
if (calclighting)
|
|
|
|
{ // calculate lighting
|
2017-01-03 17:57:48 +00:00
|
|
|
R_SetColorMapLight(usecolormap, light, shade);
|
2016-12-30 07:11:06 +00:00
|
|
|
}
|
2017-01-11 19:42:39 +00:00
|
|
|
if (!RenderTranslucentPass::ClipSpriteColumnWithPortals(x, spr))
|
2017-01-12 21:52:17 +00:00
|
|
|
DrawColumn(x, WallSpriteTile, texturemid, maskedScaleY, sprflipvert, mfloorclip, mceilingclip);
|
2017-01-03 17:57:48 +00:00
|
|
|
light += lightstep;
|
2016-12-30 07:11:06 +00:00
|
|
|
x++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-01-12 21:52:17 +00:00
|
|
|
void RenderWallSprite::DrawColumn(int x, FTexture *WallSpriteTile, double texturemid, float maskedScaleY, bool sprflipvert, const short *mfloorclip, const short *mceilingclip)
|
2016-12-30 07:11:06 +00:00
|
|
|
{
|
2017-01-09 12:53:02 +00:00
|
|
|
float iscale = swall[x] * maskedScaleY;
|
|
|
|
double spryscale = 1 / iscale;
|
|
|
|
double sprtopscreen;
|
2016-12-30 07:11:06 +00:00
|
|
|
if (sprflipvert)
|
2017-01-12 21:52:17 +00:00
|
|
|
sprtopscreen = CenterY + texturemid * spryscale;
|
2016-12-30 07:11:06 +00:00
|
|
|
else
|
2017-01-12 21:52:17 +00:00
|
|
|
sprtopscreen = CenterY - texturemid * spryscale;
|
2016-12-30 07:11:06 +00:00
|
|
|
|
2017-01-09 12:53:02 +00:00
|
|
|
R_DrawMaskedColumn(x, FLOAT2FIXED(iscale), WallSpriteTile, lwall[x], spryscale, sprtopscreen, sprflipvert, mfloorclip, mceilingclip);
|
2016-12-30 07:11:06 +00:00
|
|
|
}
|
|
|
|
}
|