2018-04-29 21:38:26 +00:00
//
//---------------------------------------------------------------------------
//
// 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/
//
//--------------------------------------------------------------------------
//
/*
* * hw_weapon . cpp
* * Weapon sprite utilities
* *
*/
# include "sbar.h"
# include "r_utility.h"
# include "v_video.h"
# include "doomstat.h"
# include "d_player.h"
# include "g_levellocals.h"
2018-05-04 21:11:37 +00:00
# include "r_data/models/models.h"
2018-04-29 21:38:26 +00:00
# include "hw_weapon.h"
# include "hw_fakeflat.h"
2018-05-04 21:11:37 +00:00
# include "hwrenderer/dynlights/hw_dynlightdata.h"
2018-04-29 22:09:42 +00:00
# include "hwrenderer/textures/hw_material.h"
2018-04-29 21:38:26 +00:00
# include "hwrenderer/utility/hw_lighting.h"
# include "hwrenderer/utility/hw_cvars.h"
2018-05-04 21:11:37 +00:00
# include "hwrenderer/scene/hw_drawinfo.h"
# include "hwrenderer/scene/hw_drawstructs.h"
# include "hwrenderer/data/flatvertices.h"
2018-04-29 21:38:26 +00:00
EXTERN_CVAR ( Float , transsouls )
EXTERN_CVAR ( Int , gl_fuzztype )
2018-05-04 21:11:37 +00:00
EXTERN_CVAR ( Bool , r_drawplayersprites )
EXTERN_CVAR ( Bool , r_deathcamera )
2018-04-29 21:38:26 +00:00
//==========================================================================
//
//
//
//==========================================================================
2018-05-03 21:49:16 +00:00
static bool isBright ( DPSprite * psp )
2018-04-29 21:38:26 +00:00
{
if ( psp ! = nullptr & & psp - > GetState ( ) ! = nullptr )
{
bool disablefullbright = false ;
FTextureID lump = sprites [ psp - > GetSprite ( ) ] . GetSpriteFrame ( psp - > GetFrame ( ) , 0 , 0. , nullptr ) ;
if ( lump . isValid ( ) )
{
FTexture * tex = TexMan ( lump ) ;
if ( tex ) disablefullbright = tex - > bDisableFullbright ;
}
return psp - > GetState ( ) - > GetFullbright ( ) & & ! disablefullbright ;
}
return false ;
}
//==========================================================================
//
// Weapon position
//
//==========================================================================
2018-05-04 21:11:37 +00:00
static WeaponPosition GetWeaponPosition ( player_t * player )
2018-04-29 21:38:26 +00:00
{
WeaponPosition w ;
P_BobWeapon ( player , & w . bobx , & w . boby , r_viewpoint . TicFrac ) ;
// Interpolate the main weapon layer once so as to be able to add it to other layers.
if ( ( w . weapon = player - > FindPSprite ( PSP_WEAPON ) ) ! = nullptr )
{
if ( w . weapon - > firstTic )
{
w . wx = ( float ) w . weapon - > x ;
w . wy = ( float ) w . weapon - > y ;
}
else
{
w . wx = ( float ) ( w . weapon - > oldx + ( w . weapon - > x - w . weapon - > oldx ) * r_viewpoint . TicFrac ) ;
w . wy = ( float ) ( w . weapon - > oldy + ( w . weapon - > y - w . weapon - > oldy ) * r_viewpoint . TicFrac ) ;
}
}
else
{
w . wx = 0 ;
w . wy = 0 ;
}
return w ;
}
//==========================================================================
//
// Bobbing
//
//==========================================================================
2018-05-04 21:11:37 +00:00
static FVector2 BobWeapon ( WeaponPosition & weap , DPSprite * psp )
2018-04-29 21:38:26 +00:00
{
if ( psp - > firstTic )
{ // Can't interpolate the first tic.
psp - > firstTic = false ;
psp - > oldx = psp - > x ;
psp - > oldy = psp - > y ;
}
float sx = float ( psp - > oldx + ( psp - > x - psp - > oldx ) * r_viewpoint . TicFrac ) ;
float sy = float ( psp - > oldy + ( psp - > y - psp - > oldy ) * r_viewpoint . TicFrac ) ;
if ( psp - > Flags & PSPF_ADDBOB )
{
sx + = ( psp - > Flags & PSPF_MIRROR ) ? - weap . bobx : weap . bobx ;
sy + = weap . boby ;
}
if ( psp - > Flags & PSPF_ADDWEAPON & & psp - > GetID ( ) ! = PSP_WEAPON )
{
sx + = weap . wx ;
sy + = weap . wy ;
}
return { sx , sy } ;
}
//==========================================================================
//
// Lighting
//
//==========================================================================
2018-05-04 21:11:37 +00:00
static WeaponLighting GetWeaponLighting ( sector_t * viewsector , const DVector3 & pos , int FixedColormap , area_t in_area , const DVector3 & playerpos )
2018-04-29 21:38:26 +00:00
{
WeaponLighting l ;
if ( FixedColormap )
{
l . lightlevel = 255 ;
l . cm . Clear ( ) ;
l . isbelow = false ;
}
else
{
sector_t fs ;
auto fakesec = hw_FakeFlat ( viewsector , & fs , in_area , false ) ;
// calculate light level for weapon sprites
l . lightlevel = hw_ClampLight ( fakesec - > lightlevel ) ;
// calculate colormap for weapon sprites
if ( viewsector - > e - > XFloor . ffloors . Size ( ) & & ! ( level . flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING ) )
{
TArray < lightlist_t > & lightlist = viewsector - > e - > XFloor . lightlist ;
for ( unsigned 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 < r_viewpoint . Pos . Z )
{
l . cm = lightlist [ i ] . extra_colormap ;
l . lightlevel = hw_ClampLight ( * lightlist [ i ] . p_lightlevel ) ;
break ;
}
}
}
else
{
l . cm = fakesec - > Colormap ;
if ( level . flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING ) l . cm . ClearColor ( ) ;
}
l . lightlevel = hw_CalcLightLevel ( l . lightlevel , getExtraLight ( ) , true ) ;
if ( level . lightmode = = 8 | | l . lightlevel < 92 )
{
// Korshun: the way based on max possible light level for sector like in software renderer.
double min_L = 36.0 / 31.0 - ( ( l . 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 ;
l . lightlevel = int ( ( 1.0 - min_L ) * 255 ) ;
}
else
{
l . lightlevel = ( 2 * l . lightlevel + 255 ) / 3 ;
}
l . lightlevel = viewsector - > CheckSpriteGlow ( l . lightlevel , playerpos ) ;
l . isbelow = fakesec ! = viewsector & & in_area = = area_below ;
}
// Korshun: fullbright fog in opengl, render weapon sprites fullbright (but don't cancel out the light color!)
if ( level . brightfog & & ( ( level . flags & LEVEL_HASFADETABLE ) | | l . cm . FadeColor ! = 0 ) )
{
l . lightlevel = 255 ;
}
return l ;
}
2018-05-03 21:49:16 +00:00
//==========================================================================
//
//
//
//==========================================================================
void HUDSprite : : SetBright ( bool isbelow )
2018-04-30 19:28:06 +00:00
{
if ( ! isbelow )
{
cm . MakeWhite ( ) ;
}
else
{
// under water areas keep most of their color for fullbright objects
cm . LightColor . r = ( 3 * cm . LightColor . r + 0xff ) / 4 ;
cm . LightColor . g = ( 3 * cm . LightColor . g + 0xff ) / 4 ;
cm . LightColor . b = ( 3 * cm . LightColor . b + 0xff ) / 4 ;
}
lightlevel = 255 ;
}
2018-04-29 21:38:26 +00:00
//==========================================================================
//
// Render Style
//
//==========================================================================
2018-05-03 21:49:16 +00:00
bool HUDSprite : : GetWeaponRenderStyle ( DPSprite * psp , AActor * playermo , sector_t * viewsector , WeaponLighting & lighting )
2018-04-29 21:38:26 +00:00
{
auto rs = psp - > GetRenderStyle ( playermo - > RenderStyle , playermo - > Alpha ) ;
visstyle_t vis ;
float trans = 0.f ;
vis . RenderStyle = STYLE_Count ;
vis . Alpha = rs . second ;
vis . Invert = false ;
playermo - > AlterWeaponSprite ( & vis ) ;
if ( ! ( psp - > Flags & PSPF_FORCEALPHA ) ) trans = vis . Alpha ;
if ( vis . RenderStyle ! = STYLE_Count & & ! ( psp - > Flags & PSPF_FORCESTYLE ) )
{
2018-05-03 21:49:16 +00:00
RenderStyle = vis . RenderStyle ;
2018-04-29 21:38:26 +00:00
}
else
{
2018-05-03 21:49:16 +00:00
RenderStyle = rs . first ;
2018-04-29 21:38:26 +00:00
}
2018-05-03 21:49:16 +00:00
if ( RenderStyle . BlendOp = = STYLEOP_None ) return false ;
2018-04-29 21:38:26 +00:00
if ( vis . Invert )
{
// this only happens for Strife's inverted weapon sprite
2018-05-03 21:49:16 +00:00
RenderStyle . Flags | = STYLEF_InvertSource ;
2018-04-29 21:38:26 +00:00
}
// Set the render parameters
2018-05-03 21:49:16 +00:00
OverrideShader = - 1 ;
if ( RenderStyle . BlendOp = = STYLEOP_Fuzz )
2018-04-29 21:38:26 +00:00
{
if ( gl_fuzztype ! = 0 )
{
// Todo: implement shader selection here
2018-05-03 21:49:16 +00:00
RenderStyle = LegacyRenderStyles [ STYLE_Translucent ] ;
OverrideShader = SHADER_NoTexture + gl_fuzztype ;
alpha = 0.99f ; // trans may not be 1 here
2018-04-29 21:38:26 +00:00
}
else
{
2018-05-03 21:49:16 +00:00
RenderStyle . BlendOp = STYLEOP_Shadow ;
2018-04-29 21:38:26 +00:00
}
}
2018-05-03 21:49:16 +00:00
if ( RenderStyle . Flags & STYLEF_TransSoulsAlpha )
2018-04-29 21:38:26 +00:00
{
2018-05-03 21:49:16 +00:00
alpha = transsouls ;
2018-04-29 21:38:26 +00:00
}
2018-05-03 21:49:16 +00:00
else if ( RenderStyle . Flags & STYLEF_Alpha1 )
2018-04-29 21:38:26 +00:00
{
2018-05-03 21:49:16 +00:00
alpha = 1.f ;
2018-04-29 21:38:26 +00:00
}
else if ( trans = = 0.f )
{
2018-05-03 21:49:16 +00:00
alpha = vis . Alpha ;
2018-04-29 21:38:26 +00:00
}
2018-05-03 21:49:16 +00:00
if ( ! RenderStyle . IsVisible ( alpha ) ) return false ; // if it isn't visible skip the rest.
PalEntry ThingColor = ( playermo - > RenderStyle . Flags & STYLEF_ColorIsFixed ) ? playermo - > fillcolor : 0xffffff ;
ThingColor . a = 255 ;
const bool bright = isBright ( psp ) ;
ObjectColor = bright ? ThingColor : ThingColor . Modulate ( viewsector - > SpecialColors [ sector_t : : sprites ] ) ;
lightlevel = lighting . lightlevel ;
cm = lighting . cm ;
if ( bright ) SetBright ( lighting . isbelow ) ;
return true ;
2018-04-29 21:38:26 +00:00
}
2018-04-29 22:09:42 +00:00
//==========================================================================
//
// Coordinates
//
//==========================================================================
2018-05-04 21:11:37 +00:00
bool HUDSprite : : GetWeaponRect ( HWDrawInfo * di , DPSprite * psp , float sx , float sy , player_t * player )
2018-04-29 22:09:42 +00:00
{
float tx ;
float scale ;
float scalex ;
float ftexturemid ;
// decide which patch to use
bool mirror ;
FTextureID lump = sprites [ psp - > GetSprite ( ) ] . GetSpriteFrame ( psp - > GetFrame ( ) , 0 , 0. , & mirror ) ;
if ( ! lump . isValid ( ) ) return false ;
FMaterial * tex = FMaterial : : ValidateTexture ( lump , true , false ) ;
if ( ! tex ) return false ;
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 ;
2018-05-04 21:11:37 +00:00
float x1 , y1 , x2 , y2 , u1 , v1 , u2 , v2 ;
2018-04-29 22:09:42 +00:00
tx = ( psp - > Flags & PSPF_MIRROR ) ? ( ( 160 - r . width ) - ( sx + r . left ) ) : ( sx - ( 160 - r . left ) ) ;
x1 = tx * scalex + vw / 2 ;
if ( x1 > vw ) return false ; // off the right side
2018-05-03 21:49:16 +00:00
x1 + = viewwindowx ;
2018-04-29 22:09:42 +00:00
tx + = r . width ;
x2 = tx * scalex + vw / 2 ;
if ( x2 < 0 ) return false ; // off the left side
2018-05-03 21:49:16 +00:00
x2 + = viewwindowx ;
2018-04-29 22:09:42 +00:00
// 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
{
ftexturemid - = float ( StatusBar - > GetDisplacement ( ) ) * fYAd ;
}
}
scale = ( SCREENHEIGHT * vw ) / ( SCREENWIDTH * 200.0f ) ;
2018-05-03 21:49:16 +00:00
y1 = viewwindowy + vh / 2 - ( ftexturemid * scale ) ;
y2 = y1 + ( r . height * scale ) + 1 ;
2018-04-29 22:09:42 +00:00
if ( ! ( mirror ) ! = ! ( psp - > Flags & ( PSPF_FLIP ) ) )
{
2018-05-03 21:49:16 +00:00
u2 = tex - > GetSpriteUL ( ) ;
v1 = tex - > GetSpriteVT ( ) ;
u1 = tex - > GetSpriteUR ( ) ;
v2 = tex - > GetSpriteVB ( ) ;
2018-04-29 22:09:42 +00:00
}
else
{
2018-05-03 21:49:16 +00:00
u1 = tex - > GetSpriteUL ( ) ;
v1 = tex - > GetSpriteVT ( ) ;
u2 = tex - > GetSpriteUR ( ) ;
v2 = tex - > GetSpriteVB ( ) ;
2018-04-29 22:09:42 +00:00
}
2018-05-04 21:11:37 +00:00
auto verts = di - > AllocVertices ( 4 ) ;
mx = verts . second ;
verts . first [ 0 ] . Set ( x1 , y1 , 0 , u1 , v1 ) ;
verts . first [ 1 ] . Set ( x1 , y2 , 0 , u1 , v2 ) ;
verts . first [ 2 ] . Set ( x2 , y1 , 0 , u2 , v1 ) ;
verts . first [ 3 ] . Set ( x2 , y2 , 0 , u2 , v2 ) ;
2018-05-03 21:49:16 +00:00
this - > tex = tex ;
2018-04-29 22:09:42 +00:00
return true ;
}
2018-05-04 21:11:37 +00:00
//==========================================================================
//
// R_DrawPlayerSprites
//
//==========================================================================
void HWDrawInfo : : PreparePlayerSprites ( sector_t * viewsector , area_t in_area )
{
bool brightflash = false ;
AActor * playermo = players [ consoleplayer ] . camera ;
player_t * player = playermo - > player ;
const bool hudModelStep = gl_IsHUDModelForPlayerAvailable ( player ) ;
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 ;
WeaponPosition weap = GetWeaponPosition ( camera - > player ) ;
WeaponLighting light = GetWeaponLighting ( viewsector , r_viewpoint . Pos , FixedColormap , in_area , camera - > Pos ( ) ) ;
// 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 = level . lightmode ;
if ( level . lightmode = = 8 ) level . lightmode = 2 ;
for ( DPSprite * psp = player - > psprites ; psp ! = nullptr & & psp - > GetID ( ) < PSP_TARGETCENTER ; psp = psp - > GetNext ( ) )
{
if ( ! psp - > GetState ( ) ) continue ;
FSpriteModelFrame * smf = playermo - > player - > ReadyWeapon ? gl_FindModelFrame ( playermo - > player - > ReadyWeapon - > GetClass ( ) , psp - > GetState ( ) - > sprite , psp - > GetState ( ) - > GetFrame ( ) , false ) : nullptr ;
// This is an 'either-or' proposition. This maybe needs some work to allow overlays with weapon models but as originally implemented this just won't work.
if ( smf & & ! hudModelStep ) continue ;
if ( ! smf & & hudModelStep ) continue ;
HUDSprite hudsprite ;
hudsprite . owner = playermo ;
hudsprite . mframe = smf ;
hudsprite . weapon = psp ;
if ( ! hudsprite . GetWeaponRenderStyle ( psp , camera , viewsector , light ) ) continue ;
FVector2 spos = BobWeapon ( weap , psp ) ;
hudsprite . dynrgb [ 0 ] = hudsprite . dynrgb [ 1 ] = hudsprite . dynrgb [ 2 ] = 0 ;
hudsprite . lightindex = - 1 ;
// set the lighting parameters
if ( hudsprite . RenderStyle . BlendOp ! = STYLEOP_Shadow & & level . HasDynamicLights & & FixedColormap = = CM_DEFAULT & & gl_light_sprites )
{
if ( ! hudModelStep | | ( screen - > hwcaps & RFL_NO_SHADERS ) )
{
GetDynSpriteLight ( playermo , nullptr , hudsprite . dynrgb ) ;
}
else
{
hw_GetDynModelLight ( playermo , lightdata ) ;
hudsprite . lightindex = UploadLights ( lightdata ) ;
}
}
// [BB] In the HUD model step we just render the model and break out.
if ( hudModelStep )
{
hudsprite . mx = spos . X ;
hudsprite . my = spos . Y ;
}
else
{
if ( ! hudsprite . GetWeaponRect ( this , psp , spos . X , spos . Y , player ) ) continue ;
}
AddHUDSprite ( & hudsprite ) ;
}
level . lightmode = oldlightmode ;
PrepareTargeterSprites ( ) ;
}
//==========================================================================
//
// R_DrawPlayerSprites
//
//==========================================================================
void HWDrawInfo : : PrepareTargeterSprites ( )
{
AActor * playermo = players [ consoleplayer ] . camera ;
player_t * player = playermo - > player ;
AActor * camera = r_viewpoint . camera ;
// this is the same as above
if ( ! player | |
! r_drawplayersprites | |
! camera - > player | |
( player - > cheats & CF_CHASECAM ) | |
( r_deathcamera & & camera - > health < = 0 ) )
return ;
HUDSprite hudsprite ;
hudsprite . owner = playermo ;
hudsprite . mframe = nullptr ;
hudsprite . cm . Clear ( ) ;
hudsprite . lightlevel = 255 ;
hudsprite . ObjectColor = 0xffffffff ;
hudsprite . alpha = 1 ;
hudsprite . RenderStyle = DefaultRenderStyle ( ) ;
hudsprite . OverrideShader = - 1 ;
hudsprite . dynrgb [ 0 ] = hudsprite . dynrgb [ 1 ] = hudsprite . dynrgb [ 2 ] = 0 ;
// The Targeter's sprites are always drawn normally.
for ( DPSprite * psp = player - > FindPSprite ( PSP_TARGETCENTER ) ; psp ! = nullptr ; psp = psp - > GetNext ( ) )
{
if ( psp - > GetState ( ) ! = nullptr & & ( psp - > GetID ( ) ! = PSP_TARGETCENTER | | CrosshairImage = = nullptr ) )
{
hudsprite . weapon = psp ;
2018-05-10 07:09:24 +00:00
if ( hudsprite . GetWeaponRect ( this , psp , psp - > x , psp - > y , player ) )
{
AddHUDSprite ( & hudsprite ) ;
}
2018-05-04 21:11:37 +00:00
}
}
}