mirror of
https://github.com/ZDoom/qzdoom.git
synced 2025-01-05 17:21:00 +00:00
d72623b9b5
Removing this made me realize that calling the renderers' FakeFlat functions from the automap is inherently unsafe with the recent refactorings because there is absolutely no guarantee that the data may actually still be defined when the automap is being drawn. So the best approach here is to give the automap its own FakeFlat function that runs independently of render data and assumptions of data preservation. This one can also be a lot simpler because it only needs the floor, not the ceiling info.
484 lines
No EOL
12 KiB
C++
484 lines
No EOL
12 KiB
C++
//
|
|
//---------------------------------------------------------------------------
|
|
//
|
|
// Copyright(C) 2000-2016 Christoph Oelckers
|
|
// All rights reserved.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with this program. If not, see http://www.gnu.org/licenses/
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
//
|
|
/*
|
|
** gl_weapon.cpp
|
|
** Weapon sprite drawing
|
|
**
|
|
*/
|
|
|
|
#include "gl/system/gl_system.h"
|
|
#include "sbar.h"
|
|
#include "r_utility.h"
|
|
#include "v_video.h"
|
|
#include "doomstat.h"
|
|
#include "d_player.h"
|
|
#include "g_level.h"
|
|
#include "g_levellocals.h"
|
|
|
|
#include "gl/system/gl_interface.h"
|
|
#include "gl/system/gl_cvars.h"
|
|
#include "gl/renderer/gl_renderer.h"
|
|
#include "gl/renderer/gl_lightdata.h"
|
|
#include "gl/renderer/gl_renderstate.h"
|
|
#include "gl/data/gl_data.h"
|
|
#include "gl/data/gl_vertexbuffer.h"
|
|
#include "gl/dynlights/gl_glow.h"
|
|
#include "gl/scene/gl_drawinfo.h"
|
|
#include "gl/scene/gl_scenedrawer.h"
|
|
#include "gl/models/gl_models.h"
|
|
#include "gl/shaders/gl_shader.h"
|
|
#include "gl/textures/gl_material.h"
|
|
#include "gl/renderer/gl_quaddrawer.h"
|
|
#include "gl/stereo3d/gl_stereo3d.h"
|
|
|
|
EXTERN_CVAR (Bool, r_drawplayersprites)
|
|
EXTERN_CVAR(Float, transsouls)
|
|
EXTERN_CVAR (Bool, st_scale)
|
|
EXTERN_CVAR(Int, gl_fuzztype)
|
|
EXTERN_CVAR (Bool, r_deathcamera)
|
|
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_DrawPSprite
|
|
//
|
|
//==========================================================================
|
|
|
|
void GLSceneDrawer::DrawPSprite (player_t * player,DPSprite *psp, float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture)
|
|
{
|
|
float fU1,fV1;
|
|
float fU2,fV2;
|
|
float tx;
|
|
float x1,y1,x2,y2;
|
|
float scale;
|
|
float scalex;
|
|
float ftexturemid;
|
|
|
|
// [BB] In the HUD model step we just render the model and break out.
|
|
if ( hudModelStep )
|
|
{
|
|
gl_RenderHUDModel(psp, sx, sy);
|
|
return;
|
|
}
|
|
|
|
// decide which patch to use
|
|
bool mirror;
|
|
FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, &mirror);
|
|
if (!lump.isValid()) return;
|
|
|
|
FMaterial * tex = FMaterial::ValidateTexture(lump, true, false);
|
|
if (!tex) return;
|
|
|
|
gl_RenderState.SetMaterial(tex, CLAMP_XY_NOMIP, 0, OverrideShader, alphatexture);
|
|
|
|
float vw = (float)viewwidth;
|
|
float vh = (float)viewheight;
|
|
|
|
FloatRect r;
|
|
tex->GetSpriteRect(&r);
|
|
|
|
// calculate edges of the shape
|
|
scalex = (320.0f / (240.0f * r_viewwindow.WidescreenRatio)) * vw / 320;
|
|
|
|
tx = sx - (160 - r.left);
|
|
x1 = tx * scalex + vw/2;
|
|
if (x1 > vw) return; // off the right side
|
|
x1 += viewwindowx;
|
|
|
|
tx += r.width;
|
|
x2 = tx * scalex + vw / 2;
|
|
if (x2 < 0) return; // off the left side
|
|
x2 += viewwindowx;
|
|
|
|
|
|
// killough 12/98: fix psprite positioning problem
|
|
ftexturemid = 100.f - sy - r.top;
|
|
|
|
AWeapon * wi=player->ReadyWeapon;
|
|
if (wi && wi->YAdjust != 0)
|
|
{
|
|
float fYAd = wi->YAdjust;
|
|
if (screenblocks >= 11)
|
|
{
|
|
ftexturemid -= fYAd;
|
|
}
|
|
else if (!st_scale)
|
|
{
|
|
ftexturemid -= StatusBar->GetDisplacement () * fYAd;
|
|
}
|
|
}
|
|
|
|
scale = (SCREENHEIGHT*vw) / (SCREENWIDTH * 200.0f);
|
|
y1 = viewwindowy + vh / 2 - (ftexturemid * scale);
|
|
y2 = y1 + (r.height * scale) + 1;
|
|
|
|
if (!(mirror) != !(psp->Flags & PSPF_FLIP))
|
|
{
|
|
fU2 = tex->GetSpriteUL();
|
|
fV1 = tex->GetSpriteVT();
|
|
fU1 = tex->GetSpriteUR();
|
|
fV2 = tex->GetSpriteVB();
|
|
}
|
|
else
|
|
{
|
|
fU1 = tex->GetSpriteUL();
|
|
fV1 = tex->GetSpriteVT();
|
|
fU2 = tex->GetSpriteUR();
|
|
fV2 = tex->GetSpriteVB();
|
|
|
|
}
|
|
|
|
if (tex->GetTransparent() || OverrideShader != -1)
|
|
{
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f);
|
|
}
|
|
gl_RenderState.Apply();
|
|
FQuadDrawer qd;
|
|
qd.Set(0, x1, y1, 0, fU1, fV1);
|
|
qd.Set(1, x1, y2, 0, fU1, fV2);
|
|
qd.Set(2, x2, y1, 0, fU2, fV1);
|
|
qd.Set(3, x2, y2, 0, fU2, fV2);
|
|
qd.Render(GL_TRIANGLE_STRIP);
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f);
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
//
|
|
//
|
|
//==========================================================================
|
|
|
|
static bool isBright(DPSprite *psp)
|
|
{
|
|
if (psp != nullptr && psp->GetState() != nullptr)
|
|
{
|
|
bool disablefullbright = false;
|
|
FTextureID lump = gl_GetSpriteFrame(psp->GetSprite(), psp->GetFrame(), 0, 0, NULL);
|
|
if (lump.isValid())
|
|
{
|
|
FMaterial * tex = FMaterial::ValidateTexture(lump, false, false);
|
|
if (tex)
|
|
disablefullbright = tex->tex->gl_info.bDisableFullbright;
|
|
}
|
|
return psp->GetState()->GetFullbright() && !disablefullbright;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_DrawPlayerSprites
|
|
//
|
|
//==========================================================================
|
|
|
|
void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep)
|
|
{
|
|
bool brightflash = false;
|
|
unsigned int i;
|
|
int lightlevel=0;
|
|
FColormap cm;
|
|
sector_t * fakesec, fs;
|
|
AActor * playermo=players[consoleplayer].camera;
|
|
player_t * player=playermo->player;
|
|
|
|
s3d::Stereo3DMode::getCurrentMode().AdjustPlayerSprites();
|
|
|
|
AActor *camera = r_viewpoint.camera;
|
|
|
|
// this is the same as the software renderer
|
|
if (!player ||
|
|
!r_drawplayersprites ||
|
|
!camera->player ||
|
|
(player->cheats & CF_CHASECAM) ||
|
|
(r_deathcamera && camera->health <= 0))
|
|
return;
|
|
|
|
float bobx, boby, wx, wy;
|
|
DPSprite *weapon;
|
|
|
|
P_BobWeapon(camera->player, &bobx, &boby, r_viewpoint.TicFrac);
|
|
|
|
// Interpolate the main weapon layer once so as to be able to add it to other layers.
|
|
if ((weapon = camera->player->FindPSprite(PSP_WEAPON)) != nullptr)
|
|
{
|
|
if (weapon->firstTic)
|
|
{
|
|
wx = weapon->x;
|
|
wy = weapon->y;
|
|
}
|
|
else
|
|
{
|
|
wx = weapon->oldx + (weapon->x - weapon->oldx) * r_viewpoint.TicFrac;
|
|
wy = weapon->oldy + (weapon->y - weapon->oldy) * r_viewpoint.TicFrac;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
wx = 0;
|
|
wy = 0;
|
|
}
|
|
|
|
if (FixedColormap)
|
|
{
|
|
lightlevel=255;
|
|
cm.Clear();
|
|
fakesec = viewsector;
|
|
}
|
|
else
|
|
{
|
|
fakesec = gl_FakeFlat(viewsector, &fs, in_area, false);
|
|
|
|
// calculate light level for weapon sprites
|
|
lightlevel = gl_ClampLight(fakesec->lightlevel);
|
|
|
|
// calculate colormap for weapon sprites
|
|
if (viewsector->e->XFloor.ffloors.Size() && !glset.nocoloredspritelighting)
|
|
{
|
|
TArray<lightlist_t> & lightlist = viewsector->e->XFloor.lightlist;
|
|
for(i=0;i<lightlist.Size();i++)
|
|
{
|
|
double lightbottom;
|
|
|
|
if (i<lightlist.Size()-1)
|
|
{
|
|
lightbottom=lightlist[i+1].plane.ZatPoint(r_viewpoint.Pos);
|
|
}
|
|
else
|
|
{
|
|
lightbottom=viewsector->floorplane.ZatPoint(r_viewpoint.Pos);
|
|
}
|
|
|
|
if (lightbottom<player->viewz)
|
|
{
|
|
cm = lightlist[i].extra_colormap;
|
|
lightlevel = gl_ClampLight(*lightlist[i].p_lightlevel);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cm=fakesec->ColorMap;
|
|
if (glset.nocoloredspritelighting) cm.ClearColor();
|
|
}
|
|
|
|
lightlevel = gl_CalcLightLevel(lightlevel, getExtraLight(), true);
|
|
|
|
if (glset.lightmode == 8)
|
|
{
|
|
// Korshun: the way based on max possible light level for sector like in software renderer.
|
|
float min_L = 36.0 / 31.0 - ((lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63
|
|
if (min_L < 0)
|
|
min_L = 0;
|
|
else if (min_L > 1.0)
|
|
min_L = 1.0;
|
|
|
|
lightlevel = (1.0 - min_L) * 255;
|
|
}
|
|
else
|
|
{
|
|
lightlevel = (2 * lightlevel + 255) / 3;
|
|
}
|
|
lightlevel = gl_CheckSpriteGlow(viewsector, lightlevel, playermo->Pos());
|
|
|
|
}
|
|
|
|
// Korshun: fullbright fog in opengl, render weapon sprites fullbright (but don't cancel out the light color!)
|
|
if (glset.brightfog && ((level.flags&LEVEL_HASFADETABLE) || cm.FadeColor != 0))
|
|
{
|
|
lightlevel = 255;
|
|
}
|
|
|
|
PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff;
|
|
ThingColor.a = 255;
|
|
|
|
visstyle_t vis;
|
|
|
|
vis.RenderStyle = STYLE_Count;
|
|
vis.Alpha = playermo->Alpha;
|
|
vis.Invert = false;
|
|
playermo->AlterWeaponSprite(&vis);
|
|
|
|
FRenderStyle RenderStyle;
|
|
if (vis.RenderStyle == STYLE_Count) RenderStyle = playermo->RenderStyle;
|
|
else RenderStyle = vis.RenderStyle;
|
|
|
|
if (vis.Invert)
|
|
{
|
|
// this only happens for Strife's inverted weapon sprite
|
|
RenderStyle.Flags |= STYLEF_InvertSource;
|
|
}
|
|
if (RenderStyle.AsDWORD == 0)
|
|
{
|
|
// This is RenderStyle None.
|
|
return;
|
|
}
|
|
|
|
// Set the render parameters
|
|
|
|
int OverrideShader = -1;
|
|
float trans = 0.f;
|
|
if (RenderStyle.BlendOp >= STYLEOP_Fuzz && RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub)
|
|
{
|
|
RenderStyle.CheckFuzz();
|
|
if (RenderStyle.BlendOp == STYLEOP_Fuzz)
|
|
{
|
|
if (gl_fuzztype != 0)
|
|
{
|
|
// Todo: implement shader selection here
|
|
RenderStyle = LegacyRenderStyles[STYLE_Translucent];
|
|
OverrideShader = gl_fuzztype + 4;
|
|
trans = 0.99f; // trans may not be 1 here
|
|
}
|
|
else
|
|
{
|
|
RenderStyle.BlendOp = STYLEOP_Shadow;
|
|
}
|
|
}
|
|
}
|
|
|
|
gl_SetRenderStyle(RenderStyle, false, false);
|
|
|
|
if (RenderStyle.Flags & STYLEF_TransSoulsAlpha)
|
|
{
|
|
trans = transsouls;
|
|
}
|
|
else if (RenderStyle.Flags & STYLEF_Alpha1)
|
|
{
|
|
trans = 1.f;
|
|
}
|
|
else if (trans == 0.f)
|
|
{
|
|
trans = vis.Alpha;
|
|
}
|
|
|
|
// now draw the different layers of the weapon
|
|
gl_RenderState.EnableBrightmap(true);
|
|
PalEntry finalcol(ThingColor.a,
|
|
ThingColor.r * viewsector->SpecialColors[sector_t::sprites].r / 255,
|
|
ThingColor.g * viewsector->SpecialColors[sector_t::sprites].g / 255,
|
|
ThingColor.b * viewsector->SpecialColors[sector_t::sprites].b / 255);
|
|
|
|
gl_RenderState.SetObjectColor(finalcol);
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold);
|
|
|
|
// hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change
|
|
// light mode here to draw the weapon sprite.
|
|
int oldlightmode = glset.lightmode;
|
|
if (glset.lightmode == 8) glset.lightmode = 2;
|
|
|
|
for(DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext())
|
|
{
|
|
if (psp->GetState() != nullptr)
|
|
{
|
|
FColormap cmc = cm;
|
|
int ll = lightlevel;
|
|
if (isBright(psp))
|
|
{
|
|
if (fakesec == viewsector || in_area != area_below)
|
|
{
|
|
cmc.LightColor.r=
|
|
cmc.LightColor.g=
|
|
cmc.LightColor.b=0xff;
|
|
}
|
|
else
|
|
{
|
|
// under water areas keep most of their color for fullbright objects
|
|
cmc.LightColor.r = (3 * cmc.LightColor.r + 0xff) / 4;
|
|
cmc.LightColor.g = (3*cmc.LightColor.g + 0xff)/4;
|
|
cmc.LightColor.b = (3*cmc.LightColor.b + 0xff)/4;
|
|
}
|
|
ll = 255;
|
|
}
|
|
// set the lighting parameters
|
|
if (RenderStyle.BlendOp == STYLEOP_Shadow)
|
|
{
|
|
gl_RenderState.SetColor(0.2f, 0.2f, 0.2f, 0.33f, cmc.desaturation);
|
|
}
|
|
else
|
|
{
|
|
if (gl_lights && GLRenderer->mLightCount && FixedColormap == CM_DEFAULT && gl_light_sprites)
|
|
{
|
|
gl_SetDynSpriteLight(playermo, NULL);
|
|
}
|
|
SetColor(ll, 0, cmc, trans, true);
|
|
}
|
|
|
|
if (psp->firstTic)
|
|
{ // Can't interpolate the first tic.
|
|
psp->firstTic = false;
|
|
psp->oldx = psp->x;
|
|
psp->oldy = psp->y;
|
|
}
|
|
|
|
float sx = psp->oldx + (psp->x - psp->oldx) * r_viewpoint.TicFrac;
|
|
float sy = psp->oldy + (psp->y - psp->oldy) * r_viewpoint.TicFrac;
|
|
|
|
if (psp->Flags & PSPF_ADDBOB)
|
|
{
|
|
sx += bobx;
|
|
sy += boby;
|
|
}
|
|
|
|
if (psp->Flags & PSPF_ADDWEAPON && psp->GetID() != PSP_WEAPON)
|
|
{
|
|
sx += wx;
|
|
sy += wy;
|
|
}
|
|
|
|
|
|
DrawPSprite(player, psp, sx, sy, hudModelStep, OverrideShader, !!(RenderStyle.Flags & STYLEF_RedIsAlpha));
|
|
}
|
|
}
|
|
gl_RenderState.SetObjectColor(0xffffffff);
|
|
gl_RenderState.SetDynLight(0, 0, 0);
|
|
gl_RenderState.EnableBrightmap(false);
|
|
glset.lightmode = oldlightmode;
|
|
}
|
|
|
|
//==========================================================================
|
|
//
|
|
// R_DrawPlayerSprites
|
|
//
|
|
//==========================================================================
|
|
|
|
void GLSceneDrawer::DrawTargeterSprites()
|
|
{
|
|
AActor * playermo=players[consoleplayer].camera;
|
|
player_t * player=playermo->player;
|
|
|
|
if(!player || playermo->renderflags&RF_INVISIBLE || !r_drawplayersprites ||
|
|
GLRenderer->mViewActor!=playermo) return;
|
|
|
|
gl_RenderState.EnableBrightmap(false);
|
|
gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
gl_RenderState.AlphaFunc(GL_GEQUAL,gl_mask_sprite_threshold);
|
|
gl_RenderState.BlendEquation(GL_FUNC_ADD);
|
|
gl_RenderState.ResetColor();
|
|
gl_RenderState.SetTextureMode(TM_MODULATE);
|
|
|
|
// The Targeter's sprites are always drawn normally.
|
|
for (DPSprite *psp = player->FindPSprite(PSP_TARGETCENTER); psp != nullptr; psp = psp->GetNext())
|
|
{
|
|
if (psp->GetState() != nullptr) DrawPSprite(player, psp, psp->x, psp->y, false, 0, false);
|
|
}
|
|
} |