2016-03-01 15:47:10 +00:00
//-----------------------------------------------------------------------------
//
2017-04-17 11:33:19 +00:00
// Copyright 1993-1996 id Software
// Copyright 1994-1996 Raven Software
// Copyright 1999-2016 Randy Heit
// Copyright 2002-2016 Christoph Oelckers
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
// This program is distributed in the hope that it will be useful,
2016-03-01 15:47:10 +00:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2017-04-17 11:33:19 +00:00
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see http://www.gnu.org/licenses/
2016-03-01 15:47:10 +00:00
//
2017-04-17 11:33:19 +00:00
//-----------------------------------------------------------------------------
2016-03-01 15:47:10 +00:00
//
// DESCRIPTION:
// Rendering main loop and setup functions,
// utility functions (BSP, geometry, trigonometry).
// See tables.c, too.
//
//-----------------------------------------------------------------------------
// HEADER FILES ------------------------------------------------------------
# include <stdlib.h>
# include <math.h>
# include "templates.h"
# include "doomdef.h"
# include "d_net.h"
# include "doomstat.h"
# include "m_random.h"
# include "m_bbox.h"
# include "r_sky.h"
# include "st_stuff.h"
# include "c_dispatch.h"
# include "v_video.h"
# include "stats.h"
# include "i_video.h"
# include "a_sharedglobal.h"
# include "p_3dmidtex.h"
# include "r_data/r_interpolate.h"
# include "po_man.h"
# include "p_effect.h"
# include "st_start.h"
# include "v_font.h"
# include "r_renderer.h"
2016-09-20 21:13:12 +00:00
# include "serializer.h"
2016-03-01 15:47:10 +00:00
# include "r_utility.h"
# include "d_player.h"
# include "p_local.h"
2017-01-14 15:41:56 +00:00
# include "g_levellocals.h"
2016-03-31 14:52:25 +00:00
# include "p_maputl.h"
2017-03-29 17:23:40 +00:00
# include "sbar.h"
2017-04-19 09:01:56 +00:00
# include "vm.h"
2017-11-12 08:06:40 +00:00
# include "i_time.h"
2016-03-01 15:47:10 +00:00
// EXTERNAL DATA DECLARATIONS ----------------------------------------------
extern bool DrawFSHUD ; // [RH] Defined in d_main.cpp
EXTERN_CVAR ( Bool , cl_capfps )
// TYPES -------------------------------------------------------------------
struct InterpolationViewer
{
2016-04-01 10:22:16 +00:00
struct instance
{
DVector3 Pos ;
DRotator Angles ;
} ;
2016-03-01 15:47:10 +00:00
AActor * ViewActor ;
int otic ;
2016-04-01 10:22:16 +00:00
instance Old , New ;
2016-03-01 15:47:10 +00:00
} ;
// PRIVATE DATA DECLARATIONS -----------------------------------------------
static TArray < InterpolationViewer > PastViewers ;
static FRandom pr_torchflicker ( " TorchFlicker " ) ;
static FRandom pr_hom ;
2016-04-07 17:35:01 +00:00
bool NoInterpolateView ; // GL needs access to this.
2016-03-27 11:29:58 +00:00
static TArray < DVector3a > InterpolationPath ;
2016-03-01 15:47:10 +00:00
// PUBLIC DATA DEFINITIONS -------------------------------------------------
CVAR ( Bool , r_deathcamera , false , CVAR_ARCHIVE )
CVAR ( Int , r_clearbuffer , 0 , 0 )
CVAR ( Bool , r_drawvoxels , true , 0 )
CVAR ( Bool , r_drawplayersprites , true , 0 ) // [RH] Draw player sprites?
CUSTOM_CVAR ( Float , r_quakeintensity , 1.0f , CVAR_ARCHIVE | CVAR_GLOBALCONFIG )
{
if ( self < 0.f ) self = 0.f ;
else if ( self > 1.f ) self = 1.f ;
}
int viewwindowx ;
int viewwindowy ;
2017-03-11 10:31:09 +00:00
int viewwidth ;
int viewheight ;
2016-03-01 15:47:10 +00:00
2017-03-11 22:28:07 +00:00
FRenderViewpoint : : FRenderViewpoint ( )
{
player = nullptr ;
Pos = { 0.0 , 0.0 , 0.0 } ;
ActorPos = { 0.0 , 0.0 , 0.0 } ;
Angles = { 0.0 , 0.0 , 0.0 } ;
Path [ 0 ] = { 0.0 , 0.0 , 0.0 } ;
Path [ 1 ] = { 0.0 , 0.0 , 0.0 } ;
Cos = 0.0 ;
Sin = 0.0 ;
TanCos = 0.0 ;
TanSin = 0.0 ;
camera = nullptr ;
sector = nullptr ;
FieldOfView = 90. ; // Angles in the SCREENWIDTH wide window
TicFrac = 0.0 ;
FrameTime = 0 ;
extralight = 0 ;
showviewer = false ;
}
2017-03-11 10:31:09 +00:00
2017-03-11 22:28:07 +00:00
FRenderViewpoint r_viewpoint ;
FViewWindow r_viewwindow ;
2016-03-01 15:47:10 +00:00
bool r_NoInterpolate ;
angle_t LocalViewAngle ;
int LocalViewPitch ;
bool LocalKeyboardTurner ;
int setblocks ;
bool setsizeneeded ;
unsigned int R_OldBlend = ~ 0 ;
int validcount = 1 ; // increment every time a check is made
FCanvasTextureInfo * FCanvasTextureInfo : : List ;
2016-04-14 17:40:14 +00:00
DVector3a view ;
DAngle viewpitch ;
2016-04-02 18:07:02 +00:00
2017-04-30 22:25:21 +00:00
DEFINE_GLOBAL ( LocalViewPitch ) ;
2016-03-01 15:47:10 +00:00
// CODE --------------------------------------------------------------------
static void R_Shutdown ( ) ;
//==========================================================================
//
// R_SetFOV
//
// Changes the field of view in degrees
//
//==========================================================================
2017-03-11 22:28:07 +00:00
void R_SetFOV ( FRenderViewpoint & viewpoint , DAngle fov )
2016-03-01 15:47:10 +00:00
{
2016-04-28 11:59:06 +00:00
if ( fov < 5. ) fov = 5. ;
else if ( fov > 170. ) fov = 170. ;
2017-03-11 22:28:07 +00:00
if ( fov ! = viewpoint . FieldOfView )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . FieldOfView = fov ;
2016-03-01 15:47:10 +00:00
setsizeneeded = true ;
}
}
//==========================================================================
//
// R_SetViewSize
//
// Do not really change anything here, because it might be in the middle
// of a refresh. The change will take effect next refresh.
//
//==========================================================================
void R_SetViewSize ( int blocks )
{
setsizeneeded = true ;
setblocks = blocks ;
}
//==========================================================================
//
// R_SetWindow
//
//==========================================================================
2017-03-11 22:28:07 +00:00
void R_SetWindow ( FRenderViewpoint & viewpoint , FViewWindow & viewwindow , int windowSize , int fullWidth , int fullHeight , int stHeight , bool renderingToCanvas )
2016-03-01 15:47:10 +00:00
{
if ( windowSize > = 11 )
{
viewwidth = fullWidth ;
freelookviewheight = viewheight = fullHeight ;
}
else if ( windowSize = = 10 )
{
viewwidth = fullWidth ;
viewheight = stHeight ;
freelookviewheight = fullHeight ;
}
else
{
viewwidth = ( ( setblocks * fullWidth ) / 10 ) & ( ~ 15 ) ;
viewheight = ( ( setblocks * stHeight ) / 10 ) & ~ 7 ;
freelookviewheight = ( ( setblocks * fullHeight ) / 10 ) & ~ 7 ;
}
2016-09-13 21:26:30 +00:00
if ( renderingToCanvas )
{
2017-03-11 22:28:07 +00:00
viewwindow . WidescreenRatio = fullWidth / ( float ) fullHeight ;
2016-09-13 21:26:30 +00:00
}
else
{
2017-03-11 22:28:07 +00:00
viewwindow . WidescreenRatio = ActiveRatio ( fullWidth , fullHeight ) ;
2016-09-13 21:26:30 +00:00
}
2016-03-01 15:47:10 +00:00
DrawFSHUD = ( windowSize = = 11 ) ;
// [RH] Sky height fix for screens not 200 (or 240) pixels tall
R_InitSkyMap ( ) ;
2017-03-11 22:28:07 +00:00
viewwindow . centery = viewheight / 2 ;
viewwindow . centerx = viewwidth / 2 ;
if ( AspectTallerThanWide ( viewwindow . WidescreenRatio ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewwindow . centerxwide = viewwindow . centerx ;
2016-03-01 15:47:10 +00:00
}
else
{
2017-03-11 22:28:07 +00:00
viewwindow . centerxwide = viewwindow . centerx * AspectMultiplier ( viewwindow . WidescreenRatio ) / 48 ;
2016-03-01 15:47:10 +00:00
}
2017-03-11 22:28:07 +00:00
DAngle fov = viewpoint . FieldOfView ;
2016-03-01 15:47:10 +00:00
// For widescreen displays, increase the FOV so that the middle part of the
// screen that would be visible on a 4:3 display has the requested FOV.
2017-03-11 22:28:07 +00:00
if ( viewwindow . centerxwide ! = viewwindow . centerx )
2016-03-01 15:47:10 +00:00
{ // centerxwide is what centerx would be if the display was not widescreen
2017-03-11 22:28:07 +00:00
fov = DAngle : : ToDegrees ( 2 * atan ( viewwindow . centerx * tan ( fov . Radians ( ) / 2 ) / double ( viewwindow . centerxwide ) ) ) ;
2016-04-28 11:59:06 +00:00
if ( fov > 170. ) fov = 170. ;
2016-03-01 15:47:10 +00:00
}
2017-03-11 22:28:07 +00:00
viewwindow . FocalTangent = tan ( fov . Radians ( ) / 2 ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// R_ExecuteSetViewSize
//
//==========================================================================
2017-03-11 22:28:07 +00:00
void R_ExecuteSetViewSize ( FRenderViewpoint & viewpoint , FViewWindow & viewwindow )
2016-03-01 15:47:10 +00:00
{
setsizeneeded = false ;
2017-03-29 17:23:40 +00:00
R_SetWindow ( viewpoint , viewwindow , setblocks , SCREENWIDTH , SCREENHEIGHT , StatusBar - > GetTopOfStatusbar ( ) ) ;
2016-03-01 15:47:10 +00:00
// Handle resize, e.g. smaller view windows with border and/or status bar.
viewwindowx = ( screen - > GetWidth ( ) - viewwidth ) > > 1 ;
// Same with base row offset.
2017-03-29 17:23:40 +00:00
viewwindowy = ( viewwidth = = screen - > GetWidth ( ) ) ? 0 : ( StatusBar - > GetTopOfStatusbar ( ) - viewheight ) > > 1 ;
2016-03-01 15:47:10 +00:00
}
2017-07-09 17:01:34 +00:00
//==========================================================================
//
// r_visibility
//
// Controls how quickly light ramps across a 1/z range.
//
//==========================================================================
double R_ClampVisibility ( double vis )
{
// Allow negative visibilities, just for novelty's sake
return clamp ( vis , - 204.7 , 204.7 ) ; // (205 and larger do not work in 5:4 aspect ratio)
}
CUSTOM_CVAR ( Float , r_visibility , 8.0f , CVAR_NOINITCALL )
{
if ( netgame & & self ! = 8.0f )
{
Printf ( " Visibility cannot be changed in net games. \n " ) ;
self = 8.0f ;
}
else
{
float clampValue = ( float ) R_ClampVisibility ( self ) ;
if ( self ! = clampValue )
self = clampValue ;
}
}
//==========================================================================
//
// R_GetGlobVis
//
// Calculates the global visibility constant used by the software renderer
//
//==========================================================================
double R_GetGlobVis ( const FViewWindow & viewwindow , double vis )
{
vis = R_ClampVisibility ( vis ) ;
double virtwidth = screen - > GetWidth ( ) ;
double virtheight = screen - > GetHeight ( ) ;
if ( AspectTallerThanWide ( viewwindow . WidescreenRatio ) )
{
virtheight = ( virtheight * AspectMultiplier ( viewwindow . WidescreenRatio ) ) / 48 ;
}
else
{
virtwidth = ( virtwidth * AspectMultiplier ( viewwindow . WidescreenRatio ) ) / 48 ;
}
double YaspectMul = 320.0 * virtheight / ( 200.0 * virtwidth ) ;
double InvZtoScale = YaspectMul * viewwindow . centerx ;
double wallVisibility = vis ;
// Prevent overflow on walls
double maxVisForWall = ( InvZtoScale * ( screen - > GetWidth ( ) * r_Yaspect ) / ( viewwidth * screen - > GetHeight ( ) * viewwindow . FocalTangent ) ) ;
maxVisForWall = 32767.0 / maxVisForWall ;
if ( vis < 0 & & vis < - maxVisForWall )
wallVisibility = - maxVisForWall ;
else if ( vis > 0 & & vis > maxVisForWall )
wallVisibility = maxVisForWall ;
wallVisibility = InvZtoScale * screen - > GetWidth ( ) * AspectBaseHeight ( viewwindow . WidescreenRatio ) / ( viewwidth * screen - > GetHeight ( ) * 3 ) * ( wallVisibility * viewwindow . FocalTangent ) ;
return wallVisibility / viewwindow . FocalTangent ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// CVAR screenblocks
//
// Selects the size of the visible window
//
//==========================================================================
CUSTOM_CVAR ( Int , screenblocks , 10 , CVAR_ARCHIVE )
{
if ( self > 12 )
self = 12 ;
else if ( self < 3 )
self = 3 ;
else
R_SetViewSize ( self ) ;
}
//==========================================================================
//
// R_PointInSubsector
//
//==========================================================================
subsector_t * R_PointInSubsector ( fixed_t x , fixed_t y )
{
node_t * node ;
int side ;
// single subsector is a special case
2017-03-17 00:42:37 +00:00
if ( level . nodes . Size ( ) = = 0 )
2017-03-16 23:22:52 +00:00
return & level . subsectors [ 0 ] ;
2016-03-01 15:47:10 +00:00
2017-03-17 00:42:37 +00:00
node = level . HeadNode ( ) ;
2016-03-01 15:47:10 +00:00
do
{
side = R_PointOnSide ( x , y , node ) ;
node = ( node_t * ) node - > children [ side ] ;
}
while ( ! ( ( size_t ) node & 1 ) ) ;
2017-03-08 17:47:52 +00:00
return ( subsector_t * ) ( ( uint8_t * ) node - 1 ) ;
2016-03-01 15:47:10 +00:00
}
2018-04-03 22:21:25 +00:00
//==========================================================================
//
//
//
//==========================================================================
FRenderer * CreateSWRenderer ( ) ;
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// R_Init
//
//==========================================================================
void R_Init ( )
{
atterm ( R_Shutdown ) ;
StartScreen - > Progress ( ) ;
R_InitTranslationTables ( ) ;
R_SetViewSize ( screenblocks ) ;
2018-04-03 22:21:25 +00:00
if ( SWRenderer = = NULL )
{
SWRenderer = CreateSWRenderer ( ) ;
}
SWRenderer - > Init ( ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// R_Shutdown
//
//==========================================================================
static void R_Shutdown ( )
{
2018-04-03 22:21:25 +00:00
if ( SWRenderer ! = nullptr ) delete SWRenderer ;
SWRenderer = nullptr ;
2016-03-01 15:47:10 +00:00
R_DeinitTranslationTables ( ) ;
R_DeinitColormaps ( ) ;
FCanvasTextureInfo : : EmptyList ( ) ;
}
//==========================================================================
//
// R_InterpolateView
//
//==========================================================================
//CVAR (Int, tf, 0, 0)
EXTERN_CVAR ( Bool , cl_noprediction )
2017-03-11 22:28:07 +00:00
void R_InterpolateView ( FRenderViewpoint & viewpoint , player_t * player , double Frac , InterpolationViewer * iview )
2016-03-01 15:47:10 +00:00
{
if ( NoInterpolateView )
{
InterpolationPath . Clear ( ) ;
NoInterpolateView = false ;
2016-04-01 10:22:16 +00:00
iview - > Old = iview - > New ;
2016-03-01 15:47:10 +00:00
}
2016-04-01 10:22:16 +00:00
int oldgroup = R_PointInSubsector ( iview - > Old . Pos ) - > sector - > PortalGroup ;
int newgroup = R_PointInSubsector ( iview - > New . Pos ) - > sector - > PortalGroup ;
2016-03-01 15:47:10 +00:00
2016-04-01 10:22:16 +00:00
DAngle oviewangle = iview - > Old . Angles . Yaw ;
DAngle nviewangle = iview - > New . Angles . Yaw ;
2016-04-07 17:35:01 +00:00
if ( ! cl_capfps )
2016-03-01 15:47:10 +00:00
{
2016-04-07 17:35:01 +00:00
if ( ( iview - > Old . Pos . X ! = iview - > New . Pos . X | | iview - > Old . Pos . Y ! = iview - > New . Pos . Y ) & & InterpolationPath . Size ( ) > 0 )
2016-03-01 15:47:10 +00:00
{
2016-04-07 17:35:01 +00:00
DVector3 view = iview - > New . Pos ;
2016-03-01 15:47:10 +00:00
2016-04-07 17:35:01 +00:00
// Interpolating through line portals is a messy affair.
// What needs be done is to store the portal transitions of the camera actor as waypoints
// and then find out on which part of the path the current view lies.
// Needless to say, this doesn't work for chasecam mode.
2017-03-11 22:28:07 +00:00
if ( ! viewpoint . showviewer )
2016-03-01 15:47:10 +00:00
{
2016-04-07 17:35:01 +00:00
double pathlen = 0 ;
double zdiff = 0 ;
double totalzdiff = 0 ;
DAngle adiff = 0. ;
DAngle totaladiff = 0. ;
double oviewz = iview - > Old . Pos . Z ;
double nviewz = iview - > New . Pos . Z ;
DVector3a oldpos = { { iview - > Old . Pos . X , iview - > Old . Pos . Y , 0 } , 0. } ;
DVector3a newpos = { { iview - > New . Pos . X , iview - > New . Pos . Y , 0 } , 0. } ;
InterpolationPath . Push ( newpos ) ; // add this to the array to simplify the loops below
for ( unsigned i = 0 ; i < InterpolationPath . Size ( ) ; i + = 2 )
2016-03-01 15:47:10 +00:00
{
2016-04-07 17:35:01 +00:00
DVector3a & start = i = = 0 ? oldpos : InterpolationPath [ i - 1 ] ;
DVector3a & end = InterpolationPath [ i ] ;
pathlen + = ( end . pos - start . pos ) . Length ( ) ;
totalzdiff + = start . pos . Z ;
totaladiff + = start . angle ;
2016-03-01 15:47:10 +00:00
}
2016-04-07 17:35:01 +00:00
double interpolatedlen = Frac * pathlen ;
for ( unsigned i = 0 ; i < InterpolationPath . Size ( ) ; i + = 2 )
2016-03-01 15:47:10 +00:00
{
2016-04-07 17:35:01 +00:00
DVector3a & start = i = = 0 ? oldpos : InterpolationPath [ i - 1 ] ;
DVector3a & end = InterpolationPath [ i ] ;
double fraglen = ( end . pos - start . pos ) . Length ( ) ;
zdiff + = start . pos . Z ;
adiff + = start . angle ;
if ( fraglen < = interpolatedlen )
{
interpolatedlen - = fraglen ;
}
else
{
double fragfrac = interpolatedlen / fraglen ;
oviewz + = zdiff ;
nviewz - = totalzdiff - zdiff ;
oviewangle + = adiff ;
nviewangle - = totaladiff - adiff ;
DVector2 viewpos = start . pos + ( fragfrac * ( end . pos - start . pos ) ) ;
2017-03-11 22:28:07 +00:00
viewpoint . Pos = { viewpos , oviewz + Frac * ( nviewz - oviewz ) } ;
2016-04-07 17:35:01 +00:00
break ;
}
2016-03-01 15:47:10 +00:00
}
2016-04-07 17:35:01 +00:00
InterpolationPath . Pop ( ) ;
2017-03-11 22:28:07 +00:00
viewpoint . Path [ 0 ] = iview - > Old . Pos ;
viewpoint . Path [ 1 ] = viewpoint . Path [ 0 ] + ( InterpolationPath [ 0 ] . pos - viewpoint . Path [ 0 ] ) . XY ( ) . MakeResize ( pathlen ) ;
2016-03-01 15:47:10 +00:00
}
2016-04-07 17:35:01 +00:00
}
else
{
2018-04-01 18:17:39 +00:00
DVector2 disp = level . Displacements . getOffset ( oldgroup , newgroup ) ;
2017-03-11 22:28:07 +00:00
viewpoint . Pos = iview - > Old . Pos + ( iview - > New . Pos - iview - > Old . Pos - disp ) * Frac ;
viewpoint . Path [ 0 ] = viewpoint . Path [ 1 ] = iview - > New . Pos ;
2016-03-01 15:47:10 +00:00
}
}
else
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos = iview - > New . Pos ;
viewpoint . Path [ 0 ] = viewpoint . Path [ 1 ] = iview - > New . Pos ;
2016-03-01 15:47:10 +00:00
}
if ( player ! = NULL & &
! ( player - > cheats & CF_INTERPVIEW ) & &
player - players = = consoleplayer & &
2017-03-11 22:28:07 +00:00
viewpoint . camera = = player - > mo & &
2016-03-01 15:47:10 +00:00
! demoplayback & &
2017-03-11 22:28:07 +00:00
iview - > New . Pos . X = = viewpoint . camera - > X ( ) & &
iview - > New . Pos . Y = = viewpoint . camera - > Y ( ) & &
2016-03-01 15:47:10 +00:00
! ( player - > cheats & ( CF_TOTALLYFROZEN | CF_FROZEN ) ) & &
player - > playerstate = = PST_LIVE & &
player - > mo - > reactiontime = = 0 & &
! NoInterpolateView & &
! paused & &
( ! netgame | | ! cl_noprediction ) & &
! LocalKeyboardTurner )
{
2017-03-11 22:28:07 +00:00
viewpoint . Angles . Yaw = ( nviewangle + AngleToFloat ( LocalViewAngle & 0xFFFF0000 ) ) . Normalized180 ( ) ;
2016-04-01 10:22:16 +00:00
DAngle delta = player - > centering ? DAngle ( 0. ) : AngleToFloat ( int ( LocalViewPitch & 0xFFFF0000 ) ) ;
2017-03-11 22:28:07 +00:00
viewpoint . Angles . Pitch = clamp < DAngle > ( ( iview - > New . Angles . Pitch - delta ) . Normalized180 ( ) , player - > MinPitch , player - > MaxPitch ) ;
viewpoint . Angles . Roll = iview - > New . Angles . Roll . Normalized180 ( ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2017-03-11 22:28:07 +00:00
viewpoint . Angles . Pitch = ( iview - > Old . Angles . Pitch + deltaangle ( iview - > Old . Angles . Pitch , iview - > New . Angles . Pitch ) * Frac ) . Normalized180 ( ) ;
viewpoint . Angles . Yaw = ( oviewangle + deltaangle ( oviewangle , nviewangle ) * Frac ) . Normalized180 ( ) ;
viewpoint . Angles . Roll = ( iview - > Old . Angles . Roll + deltaangle ( iview - > Old . Angles . Roll , iview - > New . Angles . Roll ) * Frac ) . Normalized180 ( ) ;
2016-03-01 15:47:10 +00:00
}
// Due to interpolation this is not necessarily the same as the sector the camera is in.
2017-03-11 22:28:07 +00:00
viewpoint . sector = R_PointInSubsector ( viewpoint . Pos ) - > sector ;
2016-03-01 15:47:10 +00:00
bool moved = false ;
2017-03-11 22:28:07 +00:00
while ( ! viewpoint . sector - > PortalBlocksMovement ( sector_t : : ceiling ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
if ( viewpoint . Pos . Z > viewpoint . sector - > GetPortalPlaneZ ( sector_t : : ceiling ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos + = viewpoint . sector - > GetPortalDisplacement ( sector_t : : ceiling ) ;
viewpoint . ActorPos + = viewpoint . sector - > GetPortalDisplacement ( sector_t : : ceiling ) ;
viewpoint . sector = R_PointInSubsector ( viewpoint . Pos ) - > sector ;
2016-03-01 15:47:10 +00:00
moved = true ;
}
else break ;
}
if ( ! moved )
{
2017-03-11 22:28:07 +00:00
while ( ! viewpoint . sector - > PortalBlocksMovement ( sector_t : : floor ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
if ( viewpoint . Pos . Z < viewpoint . sector - > GetPortalPlaneZ ( sector_t : : floor ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos + = viewpoint . sector - > GetPortalDisplacement ( sector_t : : floor ) ;
viewpoint . ActorPos + = viewpoint . sector - > GetPortalDisplacement ( sector_t : : floor ) ;
viewpoint . sector = R_PointInSubsector ( viewpoint . Pos ) - > sector ;
2016-03-01 15:47:10 +00:00
moved = true ;
}
else break ;
}
}
}
//==========================================================================
//
// R_ResetViewInterpolation
//
//==========================================================================
void R_ResetViewInterpolation ( )
{
InterpolationPath . Clear ( ) ;
NoInterpolateView = true ;
}
//==========================================================================
//
2018-06-19 21:16:22 +00:00
// R_SetViewAngle
// sets all values derived from the view angle.
2016-03-01 15:47:10 +00:00
//
//==========================================================================
2018-06-19 15:44:11 +00:00
void FRenderViewpoint : : SetViewAngle ( const FViewWindow & viewwindow )
2016-03-01 15:47:10 +00:00
{
2018-06-19 15:44:11 +00:00
Sin = Angles . Yaw . Sin ( ) ;
Cos = Angles . Yaw . Cos ( ) ;
2016-03-01 15:47:10 +00:00
2018-06-19 15:44:11 +00:00
TanSin = viewwindow . FocalTangent * Sin ;
TanCos = viewwindow . FocalTangent * Cos ;
2018-06-19 21:16:22 +00:00
DVector2 v = Angles . Yaw . ToVector ( ) ;
ViewVector . X = v . X ;
ViewVector . Y = v . Y ;
HWAngles . Yaw = float ( 270.0 - Angles . Yaw . Degrees ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// FindPastViewer
//
//==========================================================================
static InterpolationViewer * FindPastViewer ( AActor * actor )
{
for ( unsigned int i = 0 ; i < PastViewers . Size ( ) ; + + i )
{
if ( PastViewers [ i ] . ViewActor = = actor )
{
return & PastViewers [ i ] ;
}
}
// Not found, so make a new one
2016-04-01 10:22:16 +00:00
InterpolationViewer iview ;
memset ( & iview , 0 , sizeof ( iview ) ) ;
2016-03-01 15:47:10 +00:00
iview . ViewActor = actor ;
iview . otic = - 1 ;
InterpolationPath . Clear ( ) ;
return & PastViewers [ PastViewers . Push ( iview ) ] ;
}
//==========================================================================
//
// R_FreePastViewers
//
//==========================================================================
void R_FreePastViewers ( )
{
InterpolationPath . Clear ( ) ;
PastViewers . Clear ( ) ;
}
//==========================================================================
//
// R_ClearPastViewer
//
// If the actor changed in a non-interpolatable way, remove it.
//
//==========================================================================
void R_ClearPastViewer ( AActor * actor )
{
InterpolationPath . Clear ( ) ;
for ( unsigned int i = 0 ; i < PastViewers . Size ( ) ; + + i )
{
if ( PastViewers [ i ] . ViewActor = = actor )
{
// Found it, so remove it.
if ( i = = PastViewers . Size ( ) )
{
PastViewers . Delete ( i ) ;
}
else
{
PastViewers . Pop ( PastViewers [ i ] ) ;
}
}
}
}
//==========================================================================
//
// R_RebuildViewInterpolation
//
//==========================================================================
void R_RebuildViewInterpolation ( player_t * player )
{
if ( player = = NULL | | player - > camera = = NULL )
return ;
if ( ! NoInterpolateView )
return ;
NoInterpolateView = false ;
InterpolationViewer * iview = FindPastViewer ( player - > camera ) ;
2016-04-01 10:22:16 +00:00
iview - > Old = iview - > New ;
2016-03-01 15:47:10 +00:00
InterpolationPath . Clear ( ) ;
}
//==========================================================================
//
// R_GetViewInterpolationStatus
//
//==========================================================================
bool R_GetViewInterpolationStatus ( )
{
return NoInterpolateView ;
}
//==========================================================================
//
// R_ClearInterpolationPath
//
//==========================================================================
void R_ClearInterpolationPath ( )
{
InterpolationPath . Clear ( ) ;
}
//==========================================================================
//
// R_AddInterpolationPoint
//
//==========================================================================
2016-03-27 11:29:58 +00:00
void R_AddInterpolationPoint ( const DVector3a & vec )
2016-03-01 15:47:10 +00:00
{
InterpolationPath . Push ( vec ) ;
}
//==========================================================================
//
// QuakePower
//
//==========================================================================
2016-09-04 21:49:57 +00:00
static double QuakePower ( double factor , double intensity , double offset )
2016-03-01 15:47:10 +00:00
{
2016-03-23 19:45:48 +00:00
double randumb ;
2016-03-01 15:47:10 +00:00
if ( intensity = = 0 )
{
randumb = 0 ;
}
else
{
2016-03-23 19:45:48 +00:00
randumb = pr_torchflicker . GenRand_Real2 ( ) * ( intensity * 2 ) - intensity ;
2016-03-01 15:47:10 +00:00
}
2016-09-04 21:49:57 +00:00
return factor * ( offset + randumb ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// R_SetupFrame
//
//==========================================================================
2017-11-12 23:28:43 +00:00
void R_SetupFrame ( FRenderViewpoint & viewpoint , FViewWindow & viewwindow , AActor * actor )
2016-03-01 15:47:10 +00:00
{
if ( actor = = NULL )
{
I_Error ( " Tried to render from a NULL actor. " ) ;
}
player_t * player = actor - > player ;
unsigned int newblend ;
InterpolationViewer * iview ;
2016-03-06 12:10:42 +00:00
bool unlinked = false ;
2016-03-01 15:47:10 +00:00
if ( player ! = NULL & & player - > mo = = actor )
{ // [RH] Use camera instead of viewplayer
2017-03-11 22:28:07 +00:00
viewpoint . camera = player - > camera ;
if ( viewpoint . camera = = NULL )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . camera = player - > camera = player - > mo ;
2016-03-01 15:47:10 +00:00
}
}
else
{
2017-03-11 22:28:07 +00:00
viewpoint . camera = actor ;
2016-03-01 15:47:10 +00:00
}
2017-03-11 22:28:07 +00:00
if ( viewpoint . camera = = NULL )
2016-03-01 15:47:10 +00:00
{
I_Error ( " You lost your body. Bad dehacked work is likely to blame. " ) ;
}
2017-03-11 22:28:07 +00:00
iview = FindPastViewer ( viewpoint . camera ) ;
2016-03-01 15:47:10 +00:00
2017-11-12 02:12:22 +00:00
int nowtic = I_GetTime ( ) ;
2016-03-01 15:47:10 +00:00
if ( iview - > otic ! = - 1 & & nowtic > iview - > otic )
{
iview - > otic = nowtic ;
2016-04-01 10:22:16 +00:00
iview - > Old = iview - > New ;
2016-03-01 15:47:10 +00:00
}
if ( player ! = NULL & & gamestate ! = GS_TITLELEVEL & &
2017-03-11 22:28:07 +00:00
( ( player - > cheats & CF_CHASECAM ) | | ( r_deathcamera & & viewpoint . camera - > health < = 0 ) ) )
2016-03-01 15:47:10 +00:00
{
2016-04-01 10:22:16 +00:00
sector_t * oldsector = R_PointInSubsector ( iview - > Old . Pos ) - > sector ;
2016-03-01 15:47:10 +00:00
// [RH] Use chasecam view
2016-03-23 17:07:04 +00:00
DVector3 campos ;
2016-04-16 20:54:47 +00:00
DAngle camangle ;
2017-03-11 22:28:07 +00:00
P_AimCamera ( viewpoint . camera , campos , camangle , viewpoint . sector , unlinked ) ; // fixme: This needs to translate the angle, too.
2016-04-01 10:22:16 +00:00
iview - > New . Pos = campos ;
2016-04-16 20:54:47 +00:00
iview - > New . Angles . Yaw = camangle ;
2016-04-25 14:56:01 +00:00
2017-03-11 22:28:07 +00:00
viewpoint . showviewer = true ;
2016-03-06 12:10:42 +00:00
// Interpolating this is a very complicated thing because nothing keeps track of the aim camera's movement, so whenever we detect a portal transition
// it's probably best to just reset the interpolation for this move.
// Note that this can still cause problems with unusually linked portals
2017-03-11 22:28:07 +00:00
if ( viewpoint . sector - > PortalGroup ! = oldsector - > PortalGroup | | ( unlinked & & ( ( iview - > New . Pos . XY ( ) - iview - > Old . Pos . XY ( ) ) . LengthSquared ( ) ) > 256 * 256 ) )
2016-03-06 12:10:42 +00:00
{
iview - > otic = nowtic ;
2016-04-01 10:22:16 +00:00
iview - > Old = iview - > New ;
2016-04-17 16:42:54 +00:00
r_NoInterpolate = true ;
2016-03-06 12:10:42 +00:00
}
2017-03-11 22:28:07 +00:00
viewpoint . ActorPos = campos ;
2016-03-01 15:47:10 +00:00
}
else
{
2017-03-11 22:28:07 +00:00
viewpoint . ActorPos = iview - > New . Pos = { viewpoint . camera - > Pos ( ) . XY ( ) , viewpoint . camera - > player ? viewpoint . camera - > player - > viewz : viewpoint . camera - > Z ( ) + viewpoint . camera - > GetCameraHeight ( ) } ;
viewpoint . sector = viewpoint . camera - > Sector ;
viewpoint . showviewer = false ;
2016-03-01 15:47:10 +00:00
}
2017-03-11 22:28:07 +00:00
iview - > New . Angles = viewpoint . camera - > Angles ;
if ( viewpoint . camera - > player ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
player = viewpoint . camera - > player ;
2016-03-01 15:47:10 +00:00
}
if ( iview - > otic = = - 1 | | r_NoInterpolate )
{
R_ResetViewInterpolation ( ) ;
iview - > otic = nowtic ;
}
2017-11-12 23:54:32 +00:00
viewpoint . TicFrac = I_GetTimeFrac ( ) ;
2016-03-01 15:47:10 +00:00
if ( cl_capfps | | r_NoInterpolate )
{
2017-03-11 22:28:07 +00:00
viewpoint . TicFrac = 1. ;
2016-03-01 15:47:10 +00:00
}
2017-03-11 22:28:07 +00:00
R_InterpolateView ( viewpoint , player , viewpoint . TicFrac , iview ) ;
2016-03-01 15:47:10 +00:00
2018-06-19 15:44:11 +00:00
viewpoint . SetViewAngle ( viewwindow ) ;
2016-03-01 15:47:10 +00:00
2017-03-11 22:28:07 +00:00
interpolator . DoInterpolations ( viewpoint . TicFrac ) ;
2016-03-01 15:47:10 +00:00
// Keep the view within the sector's floor and ceiling
2017-03-11 22:28:07 +00:00
if ( viewpoint . sector - > PortalBlocksMovement ( sector_t : : ceiling ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
double theZ = viewpoint . sector - > ceilingplane . ZatPoint ( viewpoint . Pos ) - 4 ;
if ( viewpoint . Pos . Z > theZ )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos . Z = theZ ;
2016-03-01 15:47:10 +00:00
}
}
2017-03-11 22:28:07 +00:00
if ( viewpoint . sector - > PortalBlocksMovement ( sector_t : : floor ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
double theZ = viewpoint . sector - > floorplane . ZatPoint ( viewpoint . Pos ) + 4 ;
if ( viewpoint . Pos . Z < theZ )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos . Z = theZ ;
2016-03-01 15:47:10 +00:00
}
}
if ( ! paused )
{
2016-03-23 19:45:48 +00:00
FQuakeJiggers jiggers ;
2016-03-01 15:47:10 +00:00
2016-03-23 19:45:48 +00:00
memset ( & jiggers , 0 , sizeof ( jiggers ) ) ;
2018-06-19 06:32:25 +00:00
if ( DEarthquake : : StaticGetQuakeIntensities ( viewpoint . TicFrac , viewpoint . camera , jiggers ) > 0 )
2016-03-01 15:47:10 +00:00
{
2016-03-23 19:45:48 +00:00
double quakefactor = r_quakeintensity ;
DAngle an ;
2016-03-01 15:47:10 +00:00
2016-04-27 15:26:06 +00:00
if ( jiggers . RollIntensity ! = 0 | | jiggers . RollWave ! = 0 )
2016-04-25 14:56:01 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Angles . Roll + = QuakePower ( quakefactor , jiggers . RollIntensity , jiggers . RollWave ) ;
2016-04-25 14:56:01 +00:00
}
2016-03-23 19:45:48 +00:00
if ( jiggers . RelIntensity . X ! = 0 | | jiggers . RelOffset . X ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
an = viewpoint . camera - > Angles . Yaw ;
2016-09-04 21:49:57 +00:00
double power = QuakePower ( quakefactor , jiggers . RelIntensity . X , jiggers . RelOffset . X ) ;
2017-03-11 22:28:07 +00:00
viewpoint . Pos + = an . ToVector ( power ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-23 19:45:48 +00:00
if ( jiggers . RelIntensity . Y ! = 0 | | jiggers . RelOffset . Y ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
an = viewpoint . camera - > Angles . Yaw + 90 ;
2016-09-04 21:49:57 +00:00
double power = QuakePower ( quakefactor , jiggers . RelIntensity . Y , jiggers . RelOffset . Y ) ;
2017-03-11 22:28:07 +00:00
viewpoint . Pos + = an . ToVector ( power ) ;
2016-03-01 15:47:10 +00:00
}
// FIXME: Relative Z is not relative
2016-03-23 19:45:48 +00:00
if ( jiggers . RelIntensity . Z ! = 0 | | jiggers . RelOffset . Z ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos . Z + = QuakePower ( quakefactor , jiggers . RelIntensity . Z , jiggers . RelOffset . Z ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-23 19:45:48 +00:00
if ( jiggers . Intensity . X ! = 0 | | jiggers . Offset . X ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos . X + = QuakePower ( quakefactor , jiggers . Intensity . X , jiggers . Offset . X ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-23 19:45:48 +00:00
if ( jiggers . Intensity . Y ! = 0 | | jiggers . Offset . Y ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos . Y + = QuakePower ( quakefactor , jiggers . Intensity . Y , jiggers . Offset . Y ) ;
2016-03-01 15:47:10 +00:00
}
2016-03-23 19:45:48 +00:00
if ( jiggers . Intensity . Z ! = 0 | | jiggers . Offset . Z ! = 0 )
2016-03-01 15:47:10 +00:00
{
2017-03-11 22:28:07 +00:00
viewpoint . Pos . Z + = QuakePower ( quakefactor , jiggers . Intensity . Z , jiggers . Offset . Z ) ;
2016-03-01 15:47:10 +00:00
}
}
}
2017-03-11 22:28:07 +00:00
viewpoint . extralight = viewpoint . camera - > player ? viewpoint . camera - > player - > extralight : 0 ;
2016-03-01 15:47:10 +00:00
// killough 3/20/98, 4/4/98: select colormap based on player status
// [RH] Can also select a blend
newblend = 0 ;
2017-03-11 22:28:07 +00:00
TArray < lightlist_t > & lightlist = viewpoint . sector - > e - > XFloor . lightlist ;
2016-03-01 15:47:10 +00:00
if ( lightlist . Size ( ) > 0 )
{
for ( unsigned int i = 0 ; i < lightlist . Size ( ) ; i + + )
{
secplane_t * plane ;
int viewside ;
2017-03-11 22:28:07 +00:00
plane = ( i < lightlist . Size ( ) - 1 ) ? & lightlist [ i + 1 ] . plane : & viewpoint . sector - > floorplane ;
viewside = plane - > PointOnSide ( viewpoint . Pos ) ;
2016-03-01 15:47:10 +00:00
// Reverse the direction of the test if the plane was downward facing.
// We want to know if the view is above it, whatever its orientation may be.
2016-03-29 10:40:41 +00:00
if ( plane - > fC ( ) < 0 )
2016-03-01 15:47:10 +00:00
viewside = - viewside ;
if ( viewside > 0 )
{
// 3d floor 'fog' is rendered as a blending value
PalEntry blendv = lightlist [ i ] . blend ;
// If no alpha is set, use 50%
if ( blendv . a = = 0 & & blendv ! = 0 ) blendv . a = 128 ;
newblend = blendv . d ;
break ;
}
}
}
else
{
2017-03-11 22:28:07 +00:00
const sector_t * s = viewpoint . sector - > GetHeightSec ( ) ;
2016-03-01 15:47:10 +00:00
if ( s ! = NULL )
{
2017-03-11 22:28:07 +00:00
newblend = s - > floorplane . PointOnSide ( viewpoint . Pos ) < 0
2016-03-01 15:47:10 +00:00
? s - > bottommap
2017-03-11 22:28:07 +00:00
: s - > ceilingplane . PointOnSide ( viewpoint . Pos ) < 0
2016-03-01 15:47:10 +00:00
? s - > topmap
: s - > midmap ;
2017-03-15 21:04:23 +00:00
if ( APART ( newblend ) = = 0 & & newblend > = fakecmaps . Size ( ) )
2016-03-01 15:47:10 +00:00
newblend = 0 ;
}
}
// [RH] Don't override testblend unless entering a sector with a
// blend different from the previous sector's. Same goes with
// NormalLight's maps pointer.
if ( R_OldBlend ! = newblend )
{
R_OldBlend = newblend ;
if ( APART ( newblend ) )
{
BaseBlendR = RPART ( newblend ) ;
BaseBlendG = GPART ( newblend ) ;
BaseBlendB = BPART ( newblend ) ;
BaseBlendA = APART ( newblend ) / 255.f ;
}
else
{
BaseBlendR = BaseBlendG = BaseBlendB = 0 ;
BaseBlendA = 0.f ;
}
}
validcount + + ;
2017-01-15 02:19:03 +00:00
if ( r_clearbuffer ! = 0 )
2016-03-01 15:47:10 +00:00
{
int color ;
int hom = r_clearbuffer ;
if ( hom = = 3 )
{
2017-11-12 23:28:43 +00:00
hom = ( ( screen - > FrameTime / 128 ) & 1 ) + 1 ;
2016-03-01 15:47:10 +00:00
}
if ( hom = = 1 )
{
color = GPalette . BlackIndex ;
}
else if ( hom = = 2 )
{
color = GPalette . WhiteIndex ;
}
else if ( hom = = 4 )
{
2017-11-12 23:28:43 +00:00
color = ( screen - > FrameTime / 32 ) & 255 ;
2016-03-01 15:47:10 +00:00
}
else
{
color = pr_hom ( ) ;
}
2018-04-03 20:50:47 +00:00
screen - > SetClearColor ( color ) ;
SWRenderer - > SetClearColor ( color ) ;
2016-03-01 15:47:10 +00:00
}
2018-06-20 09:17:38 +00:00
else
{
screen - > SetClearColor ( GPalette . BlackIndex ) ;
}
2018-06-20 08:47:03 +00:00
// And finally some info that is needed for the hardware renderer
// Scale the pitch to account for the pixel stretching, because the playsim doesn't know about this and treats it as 1:1.
// However, to set up a projection matrix this needs to be adjusted.
double radPitch = viewpoint . Angles . Pitch . Normalized180 ( ) . Radians ( ) ;
double angx = cos ( radPitch ) ;
double angy = sin ( radPitch ) * level . info - > pixelstretch ;
double alen = sqrt ( angx * angx + angy * angy ) ;
viewpoint . HWAngles . Pitch = ( float ) RAD2DEG ( asin ( angy / alen ) ) ;
viewpoint . HWAngles . Roll . Degrees = viewpoint . Angles . Roll . Degrees ; // copied for convenience.
// ViewActor only gets set, if the camera actor should not be rendered
if ( actor - > player & & actor - > player - players = = consoleplayer & &
( ( actor - > player - > cheats & CF_CHASECAM ) | | ( r_deathcamera & & actor - > health < = 0 ) ) & & actor = = actor - > player - > mo )
{
viewpoint . ViewActor = nullptr ;
}
else
{
viewpoint . ViewActor = actor ;
}
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// FCanvasTextureInfo :: Add
//
// Assigns a camera to a canvas texture.
//
//==========================================================================
2017-08-31 20:37:29 +00:00
void FCanvasTextureInfo : : Add ( AActor * viewpoint , FTextureID picnum , double fov )
2016-03-01 15:47:10 +00:00
{
FCanvasTextureInfo * probe ;
FCanvasTexture * texture ;
if ( ! picnum . isValid ( ) )
{
return ;
}
texture = static_cast < FCanvasTexture * > ( TexMan [ picnum ] ) ;
if ( ! texture - > bHasCanvas )
{
Printf ( " %s is not a valid target for a camera \n " , texture - > Name . GetChars ( ) ) ;
return ;
}
// Is this texture already assigned to a camera?
for ( probe = List ; probe ! = NULL ; probe = probe - > Next )
{
if ( probe - > Texture = = texture )
{
// Yes, change its assignment to this new camera
if ( probe - > Viewpoint ! = viewpoint | | probe - > FOV ! = fov )
{
texture - > bFirstUpdate = true ;
}
probe - > Viewpoint = viewpoint ;
probe - > FOV = fov ;
return ;
}
}
// No, create a new assignment
probe = new FCanvasTextureInfo ;
probe - > Viewpoint = viewpoint ;
probe - > Texture = texture ;
probe - > PicNum = picnum ;
probe - > FOV = fov ;
probe - > Next = List ;
texture - > bFirstUpdate = true ;
List = probe ;
}
2017-04-19 09:01:56 +00:00
// [ZZ] expose this to ZScript
DEFINE_ACTION_FUNCTION ( _TexMan , SetCameraToTexture )
{
PARAM_PROLOGUE ;
PARAM_OBJECT ( viewpoint , AActor ) ;
PARAM_STRING ( texturename ) ; // [ZZ] there is no point in having this as FTextureID because it's easier to refer to a cameratexture by name and it isn't executed too often to cache it.
2017-08-31 20:37:29 +00:00
PARAM_FLOAT ( fov ) ;
2018-03-25 18:26:16 +00:00
FTextureID textureid = TexMan . CheckForTexture ( texturename , ETextureType : : Wall , FTextureManager : : TEXMAN_Overridable ) ;
2018-04-03 21:01:15 +00:00
if ( textureid . isValid ( ) )
FCanvasTextureInfo : : Add ( viewpoint , textureid , fov ) ;
2017-04-19 09:01:56 +00:00
return 0 ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// FCanvasTextureInfo :: UpdateAll
//
// Updates all canvas textures that were visible in the last frame.
//
//==========================================================================
void FCanvasTextureInfo : : UpdateAll ( )
{
FCanvasTextureInfo * probe ;
for ( probe = List ; probe ! = NULL ; probe = probe - > Next )
{
if ( probe - > Viewpoint ! = NULL & & probe - > Texture - > bNeedsUpdate )
{
2018-04-03 22:21:25 +00:00
screen - > RenderTextureView ( probe - > Texture , probe - > Viewpoint , probe - > FOV ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//==========================================================================
//
// FCanvasTextureInfo :: EmptyList
//
// Removes all camera->texture assignments.
//
//==========================================================================
void FCanvasTextureInfo : : EmptyList ( )
{
FCanvasTextureInfo * probe , * next ;
for ( probe = List ; probe ! = NULL ; probe = next )
{
next = probe - > Next ;
probe - > Texture - > Unload ( ) ;
delete probe ;
}
List = NULL ;
}
//==========================================================================
//
// FCanvasTextureInfo :: Serialize
//
// Reads or writes the current set of mappings in an archive.
//
//==========================================================================
2016-09-20 21:13:12 +00:00
void FCanvasTextureInfo : : Serialize ( FSerializer & arc )
2016-03-01 15:47:10 +00:00
{
2016-09-20 21:13:12 +00:00
if ( arc . isWriting ( ) )
2016-03-01 15:47:10 +00:00
{
2016-09-20 21:13:12 +00:00
if ( List ! = nullptr )
2016-03-01 15:47:10 +00:00
{
2016-09-20 21:13:12 +00:00
if ( arc . BeginArray ( " canvastextures " ) )
2016-03-01 15:47:10 +00:00
{
2016-09-20 21:13:12 +00:00
FCanvasTextureInfo * probe ;
for ( probe = List ; probe ! = nullptr ; probe = probe - > Next )
{
if ( probe - > Texture ! = nullptr & & probe - > Viewpoint ! = nullptr )
{
if ( arc . BeginObject ( nullptr ) )
{
arc ( " viewpoint " , probe - > Viewpoint )
( " fov " , probe - > FOV )
( " texture " , probe - > PicNum )
. EndObject ( ) ;
}
}
}
2016-09-23 06:27:31 +00:00
arc . EndArray ( ) ;
2016-03-01 15:47:10 +00:00
}
}
}
else
{
2016-09-20 21:13:12 +00:00
if ( arc . BeginArray ( " canvastextures " ) )
2016-03-01 15:47:10 +00:00
{
2017-03-11 18:02:00 +00:00
AActor * viewpoint = nullptr ;
2017-08-31 20:37:29 +00:00
double fov ;
2016-09-20 21:13:12 +00:00
FTextureID picnum ;
while ( arc . BeginObject ( nullptr ) )
{
arc ( " viewpoint " , viewpoint )
( " fov " , fov )
( " texture " , picnum )
. EndObject ( ) ;
Add ( viewpoint , picnum , fov ) ;
}
2016-09-23 06:27:31 +00:00
arc . EndArray ( ) ;
2016-03-01 15:47:10 +00:00
}
}
}
//==========================================================================
//
// FCanvasTextureInfo :: Mark
//
// Marks all viewpoints in the list for the collector.
//
//==========================================================================
void FCanvasTextureInfo : : Mark ( )
{
for ( FCanvasTextureInfo * probe = List ; probe ! = NULL ; probe = probe - > Next )
{
GC : : Mark ( probe - > Viewpoint ) ;
}
}
2016-11-06 10:36:12 +00:00
//==========================================================================
//
// CVAR transsouls
//
// How translucent things drawn with STYLE_SoulTrans are. Normally, only
// Lost Souls have this render style.
// Values less than 0.25 will automatically be set to
// 0.25 to ensure some degree of visibility. Likewise, values above 1.0 will
// be set to 1.0, because anything higher doesn't make sense.
//
//==========================================================================
CUSTOM_CVAR ( Float , transsouls , 0.75f , CVAR_ARCHIVE )
{
if ( self < 0.25f )
{
self = 0.25f ;
}
else if ( self > 1.f )
{
self = 1.f ;
}
}
2017-03-16 17:51:54 +00:00
CUSTOM_CVAR ( Float , maxviewpitch , 90.f , CVAR_ARCHIVE | CVAR_SERVERINFO )
{
if ( self > 90.f ) self = 90.f ;
else if ( self < - 90.f ) self = - 90.f ;
if ( usergame )
{
// [SP] Update pitch limits to the netgame/gamesim.
players [ consoleplayer ] . SendPitchLimits ( ) ;
}
}