2018-06-19 21:52:01 +00:00
//
//---------------------------------------------------------------------------
//
// Copyright(C) 2000-2018 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_drawinfo . cpp
* * Basic scene draw info management class
* *
*/
# include "a_sharedglobal.h"
# include "r_utility.h"
# include "r_sky.h"
# include "d_player.h"
# include "g_levellocals.h"
# include "hw_fakeflat.h"
2018-06-23 21:02:56 +00:00
# include "hw_portal.h"
2018-10-25 20:45:55 +00:00
# include "hw_renderstate.h"
2018-10-28 17:49:29 +00:00
# include "hw_drawinfo.h"
2018-06-19 21:52:01 +00:00
# include "hwrenderer/utility/hw_clock.h"
# include "hwrenderer/utility/hw_cvars.h"
2018-10-28 17:49:29 +00:00
# include "hwrenderer/data/hw_viewpointbuffer.h"
2018-10-28 21:58:35 +00:00
# include "hwrenderer/dynlights/hw_lightbuffer.h"
2018-10-28 18:19:46 +00:00
# include "hw_clipper.h"
2018-06-19 21:52:01 +00:00
2018-06-22 19:32:38 +00:00
EXTERN_CVAR ( Float , r_visibility )
CVAR ( Bool , gl_bandedswlight , false , CVAR_ARCHIVE )
2018-10-28 21:58:35 +00:00
CVAR ( Bool , gl_sort_textures , false , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
2018-06-22 19:32:38 +00:00
2018-06-19 21:52:01 +00:00
sector_t * hw_FakeFlat ( sector_t * sec , sector_t * dest , area_t in_area , bool back ) ;
//==========================================================================
//
//
//
//==========================================================================
2018-08-15 18:20:27 +00:00
template < class T >
inline void DeleteLinkedList ( T * node )
2018-06-19 21:52:01 +00:00
{
2018-08-15 18:20:27 +00:00
while ( node )
2018-06-19 21:52:01 +00:00
{
2018-08-15 18:20:27 +00:00
auto n = node ;
node = node - > next ;
delete n ;
2018-06-19 21:52:01 +00:00
}
2018-08-15 18:20:27 +00:00
}
2018-10-28 18:39:31 +00:00
class FDrawInfoList
{
public :
TDeletingArray < HWDrawInfo * > mList ;
HWDrawInfo * GetNew ( ) ;
void Release ( HWDrawInfo * ) ;
} ;
FDrawInfoList di_list ;
//==========================================================================
//
// Try to reuse the lists as often as possible as they contain resources that
// are expensive to create and delete.
//
// Note: If multithreading gets used, this class needs synchronization.
//
//==========================================================================
HWDrawInfo * FDrawInfoList : : GetNew ( )
{
if ( mList . Size ( ) > 0 )
{
HWDrawInfo * di ;
mList . Pop ( di ) ;
return di ;
}
return screen - > CreateDrawInfo ( ) ;
}
void FDrawInfoList : : Release ( HWDrawInfo * di )
{
di - > ClearBuffers ( ) ;
mList . Push ( di ) ;
}
//==========================================================================
//
// Sets up a new drawinfo struct
//
//==========================================================================
HWDrawInfo * HWDrawInfo : : StartDrawInfo ( FRenderViewpoint & parentvp , HWViewpointUniforms * uniforms )
{
HWDrawInfo * di = di_list . GetNew ( ) ;
di - > StartScene ( parentvp , uniforms ) ;
return di ;
}
//==========================================================================
//
//
//
//==========================================================================
static Clipper staticClipper ; // Since all scenes are processed sequentially we only need one clipper.
static HWDrawInfo * gl_drawinfo ; // This is a linked list of all active DrawInfos and needed to free the memory arena after the last one goes out of scope.
2018-10-28 18:19:46 +00:00
void HWDrawInfo : : StartScene ( FRenderViewpoint & parentvp , HWViewpointUniforms * uniforms )
{
2018-10-28 18:39:31 +00:00
staticClipper . Clear ( ) ;
mClipper = & staticClipper ;
2018-10-28 18:19:46 +00:00
Viewpoint = parentvp ;
if ( uniforms )
{
VPUniforms = * uniforms ;
// The clip planes will never be inherited from the parent drawinfo.
VPUniforms . mClipLine . X = - 1000001.f ;
VPUniforms . mClipHeight = 0 ;
}
else VPUniforms . SetDefaults ( ) ;
mClipper - > SetViewpoint ( Viewpoint ) ;
ClearBuffers ( ) ;
for ( int i = 0 ; i < GLDL_TYPES ; i + + ) drawlists [ i ] . Reset ( ) ;
hudsprites . Clear ( ) ;
vpIndex = 0 ;
// Fullbright information needs to be propagated from the main view.
if ( outer ! = nullptr ) FullbrightFlags = outer - > FullbrightFlags ;
else FullbrightFlags = 0 ;
2018-10-28 18:39:31 +00:00
outer = gl_drawinfo ;
gl_drawinfo = this ;
2018-10-28 18:19:46 +00:00
}
2018-10-28 18:39:31 +00:00
//==========================================================================
//
//
//
//==========================================================================
HWDrawInfo * HWDrawInfo : : EndDrawInfo ( )
{
assert ( this = = gl_drawinfo ) ;
for ( int i = 0 ; i < GLDL_TYPES ; i + + ) drawlists [ i ] . Reset ( ) ;
gl_drawinfo = outer ;
di_list . Release ( this ) ;
if ( gl_drawinfo = = nullptr )
ResetRenderDataAllocator ( ) ;
return gl_drawinfo ;
}
//==========================================================================
//
//
//
//==========================================================================
2018-08-15 18:20:27 +00:00
void HWDrawInfo : : ClearBuffers ( )
{
for ( auto node : otherfloorplanes ) DeleteLinkedList ( node ) ;
2018-06-19 21:52:01 +00:00
otherfloorplanes . Clear ( ) ;
2018-08-15 18:20:27 +00:00
for ( auto node : otherceilingplanes ) DeleteLinkedList ( node ) ;
2018-06-19 21:52:01 +00:00
otherceilingplanes . Clear ( ) ;
2018-08-15 18:20:27 +00:00
for ( auto node : floodfloorsegs ) DeleteLinkedList ( node ) ;
floodfloorsegs . Clear ( ) ;
for ( auto node : floodceilingsegs ) DeleteLinkedList ( node ) ;
floodceilingsegs . Clear ( ) ;
2018-06-19 21:52:01 +00:00
// clear all the lists that might not have been cleared already
MissingUpperTextures . Clear ( ) ;
MissingLowerTextures . Clear ( ) ;
MissingUpperSegs . Clear ( ) ;
MissingLowerSegs . Clear ( ) ;
SubsectorHacks . Clear ( ) ;
CeilingStacks . Clear ( ) ;
FloorStacks . Clear ( ) ;
HandledSubsectors . Clear ( ) ;
spriteindex = 0 ;
CurrentMapSections . Resize ( level . NumMapSections ) ;
CurrentMapSections . Zero ( ) ;
sectorrenderflags . Resize ( level . sectors . Size ( ) ) ;
ss_renderflags . Resize ( level . subsectors . Size ( ) ) ;
no_renderflags . Resize ( level . subsectors . Size ( ) ) ;
memset ( & sectorrenderflags [ 0 ] , 0 , level . sectors . Size ( ) * sizeof ( sectorrenderflags [ 0 ] ) ) ;
memset ( & ss_renderflags [ 0 ] , 0 , level . subsectors . Size ( ) * sizeof ( ss_renderflags [ 0 ] ) ) ;
memset ( & no_renderflags [ 0 ] , 0 , level . nodes . Size ( ) * sizeof ( no_renderflags [ 0 ] ) ) ;
2018-10-21 11:53:50 +00:00
Decals [ 0 ] . Clear ( ) ;
Decals [ 1 ] . Clear ( ) ;
2018-06-19 21:52:01 +00:00
mClipPortal = nullptr ;
2018-06-23 11:51:19 +00:00
mCurrentPortal = nullptr ;
2018-06-19 21:52:01 +00:00
}
//==========================================================================
//
//
//
//==========================================================================
void HWDrawInfo : : UpdateCurrentMapSection ( )
{
const int mapsection = R_PointInSubsector ( Viewpoint . Pos ) - > mapsection ;
CurrentMapSections . Set ( mapsection ) ;
}
//-----------------------------------------------------------------------------
//
// Sets the area the camera is in
//
//-----------------------------------------------------------------------------
void HWDrawInfo : : SetViewArea ( )
{
auto & vp = Viewpoint ;
// The render_sector is better suited to represent the current position in GL
vp . sector = R_PointInSubsector ( vp . Pos ) - > render_sector ;
// Get the heightsec state from the render sector, not the current one!
if ( vp . sector - > GetHeightSec ( ) )
{
in_area = vp . Pos . Z < = vp . sector - > heightsec - > floorplane . ZatPoint ( vp . Pos ) ? area_below :
( vp . Pos . Z > vp . sector - > heightsec - > ceilingplane . ZatPoint ( vp . Pos ) & &
! ( vp . sector - > heightsec - > MoreFlags & SECMF_FAKEFLOORONLY ) ) ? area_above : area_normal ;
}
else
{
in_area = level . HasHeightSecs ? area_default : area_normal ; // depends on exposed lower sectors, if map contains heightsecs.
}
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
int HWDrawInfo : : SetFullbrightFlags ( player_t * player )
{
FullbrightFlags = 0 ;
// check for special colormaps
player_t * cplayer = player ? player - > camera - > player : nullptr ;
if ( cplayer )
{
int cm = CM_DEFAULT ;
if ( cplayer - > extralight = = INT_MIN )
{
cm = CM_FIRSTSPECIALCOLORMAP + INVERSECOLORMAP ;
Viewpoint . extralight = 0 ;
FullbrightFlags = Fullbright ;
// This does never set stealth vision.
}
else if ( cplayer - > fixedcolormap ! = NOFIXEDCOLORMAP )
{
cm = CM_FIRSTSPECIALCOLORMAP + cplayer - > fixedcolormap ;
FullbrightFlags = Fullbright ;
if ( gl_enhanced_nv_stealth > 2 ) FullbrightFlags | = StealthVision ;
}
else if ( cplayer - > fixedlightlevel ! = - 1 )
{
auto torchtype = PClass : : FindActor ( NAME_PowerTorch ) ;
auto litetype = PClass : : FindActor ( NAME_PowerLightAmp ) ;
for ( AInventory * in = cplayer - > mo - > Inventory ; in ; in = in - > Inventory )
{
//PalEntry color = in->CallGetBlend();
// Need special handling for light amplifiers
if ( in - > IsKindOf ( torchtype ) )
{
FullbrightFlags = Fullbright ;
if ( gl_enhanced_nv_stealth > 1 ) FullbrightFlags | = StealthVision ;
}
else if ( in - > IsKindOf ( litetype ) )
{
FullbrightFlags = Fullbright ;
if ( gl_enhanced_nightvision ) FullbrightFlags | = Nightvision ;
if ( gl_enhanced_nv_stealth > 0 ) FullbrightFlags | = StealthVision ;
}
}
}
return cm ;
}
else
{
return CM_DEFAULT ;
}
}
//-----------------------------------------------------------------------------
//
// R_FrustumAngle
//
//-----------------------------------------------------------------------------
angle_t HWDrawInfo : : FrustumAngle ( )
{
float tilt = fabs ( Viewpoint . HWAngles . Pitch . Degrees ) ;
// If the pitch is larger than this you can look all around at a FOV of 90°
if ( tilt > 46.0f ) return 0xffffffff ;
// ok, this is a gross hack that barely works...
// but at least it doesn't overestimate too much...
double floatangle = 2.0 + ( 45.0 + ( ( tilt / 1.9 ) ) ) * Viewpoint . FieldOfView . Degrees * 48.0 / AspectMultiplier ( r_viewwindow . WidescreenRatio ) / 90.0 ;
angle_t a1 = DAngle ( floatangle ) . BAMs ( ) ;
if ( a1 > = ANGLE_180 ) return 0xffffffff ;
return a1 ;
}
2018-06-23 11:25:23 +00:00
//-----------------------------------------------------------------------------
//
// Setup the modelview matrix
//
//-----------------------------------------------------------------------------
void HWDrawInfo : : SetViewMatrix ( const FRotator & angles , float vx , float vy , float vz , bool mirror , bool planemirror )
{
2018-06-23 18:57:02 +00:00
float mult = mirror ? - 1.f : 1.f ;
2018-06-23 11:25:23 +00:00
float planemult = planemirror ? - level . info - > pixelstretch : level . info - > pixelstretch ;
VPUniforms . mViewMatrix . loadIdentity ( ) ;
VPUniforms . mViewMatrix . rotate ( angles . Roll . Degrees , 0.0f , 0.0f , 1.0f ) ;
VPUniforms . mViewMatrix . rotate ( angles . Pitch . Degrees , 1.0f , 0.0f , 0.0f ) ;
VPUniforms . mViewMatrix . rotate ( angles . Yaw . Degrees , 0.0f , mult , 0.0f ) ;
VPUniforms . mViewMatrix . translate ( vx * mult , - vz * planemult , - vy ) ;
VPUniforms . mViewMatrix . scale ( - mult , planemult , 1 ) ;
}
//-----------------------------------------------------------------------------
//
// SetupView
// Setup the view rotation matrix for the given viewpoint
//
//-----------------------------------------------------------------------------
2018-10-28 21:20:51 +00:00
void HWDrawInfo : : SetupView ( FRenderState & state , float vx , float vy , float vz , bool mirror , bool planemirror )
2018-06-23 11:25:23 +00:00
{
auto & vp = Viewpoint ;
vp . SetViewAngle ( r_viewwindow ) ;
SetViewMatrix ( vp . HWAngles , vx , vy , vz , mirror , planemirror ) ;
SetCameraPos ( vp . Pos ) ;
2018-10-28 17:49:29 +00:00
VPUniforms . CalcDependencies ( ) ;
2018-10-28 21:20:51 +00:00
vpIndex = screen - > mViewpoints - > SetViewpoint ( state , & VPUniforms ) ;
2018-06-23 11:25:23 +00:00
}
2018-06-22 19:32:38 +00:00
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
2018-10-24 05:35:22 +00:00
HWPortal * HWDrawInfo : : FindPortal ( const void * src )
2018-06-23 21:02:56 +00:00
{
int i = Portals . Size ( ) - 1 ;
while ( i > = 0 & & Portals [ i ] & & Portals [ i ] - > GetSource ( ) ! = src ) i - - ;
return i > = 0 ? Portals [ i ] : nullptr ;
}
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
2018-06-22 19:32:38 +00:00
void HWViewpointUniforms : : SetDefaults ( )
{
mProjectionMatrix . loadIdentity ( ) ;
mViewMatrix . loadIdentity ( ) ;
mNormalViewMatrix . loadIdentity ( ) ;
mViewHeight = viewheight ;
2018-06-22 21:49:39 +00:00
mGlobVis = ( float ) R_GetGlobVis ( r_viewwindow , r_visibility ) / 32.f ;
2018-06-22 19:32:38 +00:00
mPalLightLevels = static_cast < int > ( gl_bandedswlight ) | ( static_cast < int > ( gl_fogmode ) < < 8 ) ;
2018-06-22 21:49:39 +00:00
mClipLine . X = - 10000000.0f ;
2018-09-29 11:23:40 +00:00
mShadowmapFilter = gl_shadowmap_filter ;
2018-06-22 19:32:38 +00:00
}
2018-10-21 11:53:50 +00:00
//-----------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------
GLDecal * HWDrawInfo : : AddDecal ( bool onmirror )
{
auto decal = ( GLDecal * ) RenderDataAllocator . Alloc ( sizeof ( GLDecal ) ) ;
Decals [ onmirror ? 1 : 0 ] . Push ( decal ) ;
return decal ;
}
2018-10-28 21:58:35 +00:00
//-----------------------------------------------------------------------------
//
// RenderScene
//
// Draws the current draw lists for the non GLSL renderer
//
//-----------------------------------------------------------------------------
void HWDrawInfo : : RenderScene ( FRenderState & state )
{
const auto & vp = Viewpoint ;
RenderAll . Clock ( ) ;
state . SetDepthMask ( true ) ;
screen - > mLights - > BindBase ( state ) ; // not needed for OpenGL but necessary for Vulkan command buffers to do it here!
state . EnableFog ( true ) ;
state . SetRenderStyle ( STYLE_Source ) ;
if ( gl_sort_textures )
{
drawlists [ GLDL_PLAINWALLS ] . SortWalls ( ) ;
drawlists [ GLDL_PLAINFLATS ] . SortFlats ( ) ;
drawlists [ GLDL_MASKEDWALLS ] . SortWalls ( ) ;
drawlists [ GLDL_MASKEDFLATS ] . SortFlats ( ) ;
drawlists [ GLDL_MASKEDWALLSOFS ] . SortWalls ( ) ;
}
// Part 1: solid geometry. This is set up so that there are no transparent parts
state . SetDepthFunc ( DF_Less ) ;
state . AlphaFunc ( Alpha_GEqual , 0.f ) ;
state . ClearDepthBias ( ) ;
state . EnableTexture ( gl_texture ) ;
state . EnableBrightmap ( true ) ;
drawlists [ GLDL_PLAINWALLS ] . DrawWalls ( this , state , false ) ;
drawlists [ GLDL_PLAINFLATS ] . DrawFlats ( this , state , false ) ;
// Part 2: masked geometry. This is set up so that only pixels with alpha>gl_mask_threshold will show
state . AlphaFunc ( Alpha_GEqual , gl_mask_threshold ) ;
drawlists [ GLDL_MASKEDWALLS ] . DrawWalls ( this , state , false ) ;
drawlists [ GLDL_MASKEDFLATS ] . DrawFlats ( this , state , false ) ;
// Part 3: masked geometry with polygon offset. This list is empty most of the time so only waste time on it when in use.
if ( drawlists [ GLDL_MASKEDWALLSOFS ] . Size ( ) > 0 )
{
state . SetDepthBias ( - 1 , - 128 ) ;
drawlists [ GLDL_MASKEDWALLSOFS ] . DrawWalls ( this , state , false ) ;
state . ClearDepthBias ( ) ;
}
drawlists [ GLDL_MODELS ] . Draw ( this , state , false ) ;
state . SetRenderStyle ( STYLE_Translucent ) ;
// Part 4: Draw decals (not a real pass)
state . SetDepthFunc ( DF_LEqual ) ;
DrawDecals ( state , Decals [ 0 ] ) ;
RenderAll . Unclock ( ) ;
}
//-----------------------------------------------------------------------------
//
// RenderTranslucent
//
//-----------------------------------------------------------------------------
void HWDrawInfo : : RenderTranslucent ( FRenderState & state )
{
RenderAll . Clock ( ) ;
// final pass: translucent stuff
state . AlphaFunc ( Alpha_GEqual , gl_mask_sprite_threshold ) ;
state . SetRenderStyle ( STYLE_Translucent ) ;
state . EnableBrightmap ( true ) ;
drawlists [ GLDL_TRANSLUCENTBORDER ] . Draw ( this , state , true ) ;
state . SetDepthMask ( false ) ;
drawlists [ GLDL_TRANSLUCENT ] . DrawSorted ( this , state ) ;
state . EnableBrightmap ( false ) ;
state . AlphaFunc ( Alpha_GEqual , 0.5f ) ;
state . SetDepthMask ( true ) ;
RenderAll . Unclock ( ) ;
}