2017-04-17 10:27:19 +00:00
//-----------------------------------------------------------------------------
2017-01-03 06:17:54 +00:00
//
2017-04-17 10:27:19 +00:00
// Copyright 1993-1996 id Software
// Copyright 1999-2016 Randy Heit
// Copyright 2016 Magnus Norddahl
2017-01-03 06:17:54 +00:00
//
2017-04-17 10:27: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.
2017-01-03 06:17:54 +00:00
//
2017-04-17 10:27:19 +00:00
// This program is distributed in the hope that it will be useful,
2017-01-03 06:17:54 +00:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
2017-04-17 10:27: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/
//
//-----------------------------------------------------------------------------
2017-01-03 06:17:54 +00:00
//
2016-12-31 09:19:31 +00:00
# include <stdlib.h>
# include <float.h>
# include "templates.h"
# include "i_system.h"
# include "w_wad.h"
# include "doomdef.h"
# include "doomstat.h"
# include "r_sky.h"
# include "stats.h"
# include "v_video.h"
# include "a_sharedglobal.h"
# include "c_console.h"
# include "cmdlib.h"
# include "d_net.h"
# include "g_level.h"
2017-01-11 19:42:39 +00:00
# include "swrenderer/scene/r_opaque_pass.h"
2016-12-31 09:19:31 +00:00
# include "r_skyplane.h"
2016-12-31 11:45:07 +00:00
# include "swrenderer/scene/r_3dfloors.h"
2016-12-31 09:19:31 +00:00
# include "v_palette.h"
# include "r_data/colormaps.h"
# include "swrenderer/drawers/r_draw_rgba.h"
2017-03-16 12:49:34 +00:00
# include "a_dynlight.h"
2016-12-31 11:45:07 +00:00
# include "swrenderer/segments/r_clipsegment.h"
# include "swrenderer/segments/r_drawsegment.h"
2017-01-01 09:28:35 +00:00
# include "swrenderer/line/r_wallsetup.h"
# include "swrenderer/line/r_walldraw.h"
2016-12-31 11:45:07 +00:00
# include "swrenderer/scene/r_portal.h"
2017-01-12 15:21:46 +00:00
# include "swrenderer/scene/r_scene.h"
# include "swrenderer/scene/r_light.h"
2017-02-02 14:10:06 +00:00
# include "swrenderer/viewport/r_viewport.h"
2016-12-31 09:19:31 +00:00
# include "swrenderer/r_memory.h"
2017-02-03 23:25:37 +00:00
# include "swrenderer/r_renderthread.h"
2017-01-09 15:16:24 +00:00
# include "g_levellocals.h"
2016-12-31 09:19:31 +00:00
CVAR ( Bool , r_linearsky , false , CVAR_ARCHIVE | CVAR_GLOBALCONFIG ) ;
EXTERN_CVAR ( Int , r_skymode )
2018-12-06 19:52:03 +00:00
double skytexturemid ;
double skyscale ;
float skyiscale ;
fixed_t sky1cyl , sky2cyl ;
void InitSoftwareSky ( )
{
2018-12-07 01:53:18 +00:00
auto skytex1 = TexMan . GetPalettedTexture ( sky1texture , true ) ;
auto skytex2 = TexMan . GetPalettedTexture ( sky2texture , true ) ;
2018-12-06 19:52:03 +00:00
if ( skytex1 = = nullptr )
return ;
// Note: I don't think it is good that this stuff gets cached globally.
// For something that only needs to be once per frame it is rather pointless and makes it hard to swap out the underlying textures based on user settings.
FSoftwareTexture * sskytex1 = skytex1 - > GetSoftwareTexture ( ) ;
FSoftwareTexture * sskytex2 = skytex2 - > GetSoftwareTexture ( ) ;
skytexturemid = 0 ;
int skyheight = skytex1 - > GetDisplayHeight ( ) ;
if ( skyheight > = 128 & & skyheight < 200 )
{
skytexturemid = - 28 ;
}
else if ( skyheight > 200 )
{
skytexturemid = ( 200 - skyheight ) * sskytex1 - > GetScale ( ) . Y + ( ( r_skymode = = 2 & & ! ( level . flags & LEVEL_FORCETILEDSKY ) ) ? skytex1 - > GetSkyOffset ( ) : 0 ) ;
}
if ( viewwidth ! = 0 & & viewheight ! = 0 )
{
skyiscale = float ( r_Yaspect / freelookviewheight ) ;
skyscale = freelookviewheight / r_Yaspect ;
skyiscale * = float ( r_viewpoint . FieldOfView . Degrees / 90. ) ;
skyscale * = float ( 90. / r_viewpoint . FieldOfView . Degrees ) ;
}
if ( skystretch )
{
skyscale * = ( double ) SKYSTRETCH_HEIGHT / skyheight ;
skyiscale * = skyheight / ( float ) SKYSTRETCH_HEIGHT ;
skytexturemid * = skyheight / ( double ) SKYSTRETCH_HEIGHT ;
}
// The standard Doom sky texture is 256 pixels wide, repeated 4 times over 360 degrees,
// giving a total sky width of 1024 pixels. So if the sky texture is no wider than 1024,
// we map it to a cylinder with circumfrence 1024. For larger ones, we use the width of
// the texture as the cylinder's circumfrence.
sky1cyl = MAX ( sskytex1 - > GetWidth ( ) , fixed_t ( sskytex1 - > GetScale ( ) . X * 1024 ) ) ;
sky2cyl = MAX ( sskytex2 - > GetWidth ( ) , fixed_t ( sskytex2 - > GetScale ( ) . Y * 1024 ) ) ;
}
2016-12-31 09:19:31 +00:00
namespace swrenderer
{
2018-12-06 19:52:03 +00:00
2018-12-06 19:12:15 +00:00
static FSoftwareTexture * GetSWTex ( FTextureID texid , bool allownull = true )
{
2018-12-07 01:53:18 +00:00
auto tex = TexMan . GetPalettedTexture ( texid , true ) ;
2018-12-06 19:12:15 +00:00
if ( tex = = nullptr ) return nullptr ;
if ( ! allownull & & ! tex - > isValid ( ) ) return nullptr ;
return tex - > GetSoftwareTexture ( ) ;
}
2017-02-03 23:25:37 +00:00
RenderSkyPlane : : RenderSkyPlane ( RenderThread * thread )
{
Thread = thread ;
}
2017-01-19 02:11:49 +00:00
void RenderSkyPlane : : Render ( VisiblePlane * pl )
2016-12-31 09:19:31 +00:00
{
FTextureID sky1tex , sky2tex ;
double frontdpos = 0 , backdpos = 0 ;
if ( ( level . flags & LEVEL_SWAPSKIES ) & & ! ( level . flags & LEVEL_DOUBLESKY ) )
{
sky1tex = sky2texture ;
}
else
{
sky1tex = sky1texture ;
}
sky2tex = sky2texture ;
skymid = skytexturemid ;
2017-03-12 17:54:39 +00:00
skyangle = Thread - > Viewport - > viewpoint . Angles . Yaw . BAMs ( ) ;
2016-12-31 09:19:31 +00:00
if ( pl - > picnum = = skyflatnum )
{
if ( ! ( pl - > sky & PL_SKYFLAT ) )
{ // use sky1
sky1 :
2018-12-06 19:12:15 +00:00
frontskytex = GetSWTex ( sky1tex ) ;
2016-12-31 09:19:31 +00:00
if ( level . flags & LEVEL_DOUBLESKY )
2018-12-06 19:12:15 +00:00
backskytex = GetSWTex ( sky2tex ) ;
2016-12-31 09:19:31 +00:00
else
backskytex = NULL ;
skyflip = 0 ;
frontdpos = sky1pos ;
backdpos = sky2pos ;
frontcyl = sky1cyl ;
backcyl = sky2cyl ;
}
else if ( pl - > sky = = PL_SKYFLAT )
{ // use sky2
2018-12-06 19:12:15 +00:00
frontskytex = GetSWTex ( sky2tex ) ;
2016-12-31 09:19:31 +00:00
backskytex = NULL ;
frontcyl = sky2cyl ;
skyflip = 0 ;
frontdpos = sky2pos ;
}
else
{ // MBF's linedef-controlled skies
// Sky Linedef
2017-01-09 15:16:24 +00:00
const line_t * l = & level . lines [ ( pl - > sky & ~ PL_SKYFLAT ) - 1 ] ;
2016-12-31 09:19:31 +00:00
// Sky transferred from first sidedef
const side_t * s = l - > sidedef [ 0 ] ;
int pos ;
// Texture comes from upper texture of reference sidedef
// [RH] If swapping skies, then use the lower sidedef
if ( level . flags & LEVEL_SWAPSKIES & & s - > GetTexture ( side_t : : bottom ) . isValid ( ) )
{
pos = side_t : : bottom ;
}
else
{
pos = side_t : : top ;
}
2018-12-06 19:12:15 +00:00
frontskytex = GetSWTex ( s - > GetTexture ( pos ) ) ;
if ( frontskytex = = nullptr )
2016-12-31 09:19:31 +00:00
{ // [RH] The blank texture: Use normal sky instead.
goto sky1 ;
}
backskytex = NULL ;
// Horizontal offset is turned into an angle offset,
// to allow sky rotation as well as careful positioning.
// However, the offset is scaled very small, so that it
// allows a long-period of sky rotation.
skyangle + = FLOAT2FIXED ( s - > GetTextureXOffset ( pos ) ) ;
// Vertical offset allows careful sky positioning.
2017-07-11 09:53:21 +00:00
skymid = s - > GetTextureYOffset ( pos ) - 28.0 ;
2016-12-31 09:19:31 +00:00
// We sometimes flip the picture horizontally.
//
// Doom always flipped the picture, so we make it optional,
// to make it easier to use the new feature, while to still
// allow old sky textures to be used.
skyflip = l - > args [ 2 ] ? 0u : ~ 0u ;
2018-12-06 19:12:15 +00:00
int frontxscale = int ( frontskytex - > GetScale ( ) . X * 1024 ) ;
2016-12-31 09:19:31 +00:00
frontcyl = MAX ( frontskytex - > GetWidth ( ) , frontxscale ) ;
if ( skystretch )
{
skymid = skymid * frontskytex - > GetScaledHeightDouble ( ) / SKYSTRETCH_HEIGHT ;
}
}
}
frontpos = int ( fmod ( frontdpos , sky1cyl * 65536.0 ) ) ;
if ( backskytex ! = NULL )
{
backpos = int ( fmod ( backdpos , sky2cyl * 65536.0 ) ) ;
}
2018-12-17 23:37:50 +00:00
drawerargs . SetStyle ( ) ;
2016-12-31 09:19:31 +00:00
2018-03-18 20:33:44 +00:00
Thread - > PrepareTexture ( frontskytex , DefaultRenderStyle ( ) ) ;
Thread - > PrepareTexture ( backskytex , DefaultRenderStyle ( ) ) ;
2017-03-15 01:59:33 +00:00
2017-01-11 21:09:06 +00:00
DrawSky ( pl ) ;
2016-12-31 09:19:31 +00:00
}
2017-01-29 09:25:32 +00:00
void RenderSkyPlane : : DrawSkyColumnStripe ( int start_x , int y1 , int y2 , double scale , double texturemid , double yrepeat )
2016-12-31 09:19:31 +00:00
{
2017-02-03 23:25:37 +00:00
RenderPortal * renderportal = Thread - > Portal . get ( ) ;
2017-03-12 17:54:39 +00:00
auto viewport = Thread - > Viewport . get ( ) ;
2016-12-31 09:19:31 +00:00
2017-01-29 09:25:32 +00:00
double uv_stepd = skyiscale * yrepeat ;
2018-12-16 13:34:44 +00:00
double v = ( texturemid + uv_stepd * ( y1 - viewport - > CenterY + 0.5 ) ) / frontskytex - > GetHeight ( ) ;
double v_step = uv_stepd / frontskytex - > GetHeight ( ) ;
2016-12-31 09:19:31 +00:00
2017-03-22 09:51:12 +00:00
uint32_t uv_pos = ( uint32_t ) ( int32_t ) ( v * 0x01000000 ) ;
uint32_t uv_step = ( uint32_t ) ( int32_t ) ( v_step * 0x01000000 ) ;
2016-12-31 09:19:31 +00:00
2017-01-29 09:25:32 +00:00
int x = start_x ;
if ( renderportal - > MirrorFlags & RF_XFLIP )
x = ( viewwidth - x ) ;
2016-12-31 09:19:31 +00:00
2017-01-29 09:25:32 +00:00
uint32_t ang , angle1 , angle2 ;
2016-12-31 09:19:31 +00:00
2017-01-29 09:25:32 +00:00
if ( r_linearsky )
{
2017-03-12 17:54:39 +00:00
angle_t xangle = ( angle_t ) ( ( 0.5 - x / ( double ) viewwidth ) * viewport - > viewwindow . FocalTangent * ANGLE_90 ) ;
2017-01-29 09:25:32 +00:00
ang = ( skyangle + xangle ) ^ skyflip ;
}
else
{
2017-02-01 15:02:21 +00:00
ang = ( skyangle + viewport - > xtoviewangle [ x ] ) ^ skyflip ;
2017-01-29 09:25:32 +00:00
}
2018-12-16 13:34:44 +00:00
angle1 = UMulScale16 ( ang , frontcyl ) + frontpos ;
angle2 = UMulScale16 ( ang , backcyl ) + backpos ;
2016-12-31 09:19:31 +00:00
2017-03-12 21:53:20 +00:00
drawerargs . SetFrontTexture ( Thread , frontskytex , angle1 ) ;
drawerargs . SetBackTexture ( Thread , backskytex , angle2 ) ;
2017-01-30 19:21:18 +00:00
drawerargs . SetTextureVStep ( uv_step ) ;
drawerargs . SetTextureVPos ( uv_pos ) ;
2017-03-12 17:54:39 +00:00
drawerargs . SetDest ( viewport , start_x , y1 ) ;
2017-01-30 19:21:18 +00:00
drawerargs . SetCount ( y2 - y1 ) ;
drawerargs . SetFadeSky ( r_skymode = = 2 & & ! ( level . flags & LEVEL_FORCETILEDSKY ) ) ;
drawerargs . SetSolidTop ( frontskytex - > GetSkyCapColor ( false ) ) ;
drawerargs . SetSolidBottom ( frontskytex - > GetSkyCapColor ( true ) ) ;
2017-01-18 23:02:51 +00:00
2016-12-31 09:19:31 +00:00
if ( ! backskytex )
2017-02-04 11:38:05 +00:00
drawerargs . DrawSingleSkyColumn ( Thread ) ;
2016-12-31 09:19:31 +00:00
else
2017-02-04 11:38:05 +00:00
drawerargs . DrawDoubleSkyColumn ( Thread ) ;
2017-11-27 22:47:26 +00:00
2018-06-09 10:29:33 +00:00
if ( r_modelscene )
2017-11-29 21:18:21 +00:00
drawerargs . DrawDepthSkyColumn ( Thread , 1.0f / 65536.0f ) ;
2016-12-31 09:19:31 +00:00
}
2017-01-29 09:25:32 +00:00
void RenderSkyPlane : : DrawSkyColumn ( int start_x , int y1 , int y2 )
2016-12-31 09:19:31 +00:00
{
2018-12-16 13:34:44 +00:00
if ( 1 < < frontskytex - > GetHeightBits ( ) = = frontskytex - > GetPhysicalHeight ( ) )
2016-12-31 09:19:31 +00:00
{
2018-12-06 19:12:15 +00:00
double texturemid = skymid * frontskytex - > GetScale ( ) . Y + frontskytex - > GetHeight ( ) ;
DrawSkyColumnStripe ( start_x , y1 , y2 , frontskytex - > GetScale ( ) . Y , texturemid , frontskytex - > GetScale ( ) . Y ) ;
2016-12-31 09:19:31 +00:00
}
else
{
2017-03-12 17:54:39 +00:00
auto viewport = Thread - > Viewport . get ( ) ;
2018-12-06 19:12:15 +00:00
double yrepeat = frontskytex - > GetScale ( ) . Y ;
double scale = frontskytex - > GetScale ( ) . Y * skyscale ;
2016-12-31 09:19:31 +00:00
double iscale = 1 / scale ;
short drawheight = short ( frontskytex - > GetHeight ( ) * scale ) ;
2017-02-01 15:02:21 +00:00
double topfrac = fmod ( skymid + iscale * ( 1 - viewport - > CenterY ) , frontskytex - > GetHeight ( ) ) ;
2016-12-31 09:19:31 +00:00
if ( topfrac < 0 ) topfrac + = frontskytex - > GetHeight ( ) ;
2017-02-01 15:02:21 +00:00
double texturemid = topfrac - iscale * ( 1 - viewport - > CenterY ) ;
2017-01-29 09:25:32 +00:00
DrawSkyColumnStripe ( start_x , y1 , y2 , scale , texturemid , yrepeat ) ;
2016-12-31 09:19:31 +00:00
}
}
2017-01-19 02:11:49 +00:00
void RenderSkyPlane : : DrawSky ( VisiblePlane * pl )
2016-12-31 09:19:31 +00:00
{
int x1 = pl - > left ;
int x2 = pl - > right ;
short * uwal = ( short * ) pl - > top ;
short * dwal = ( short * ) pl - > bottom ;
for ( int x = x1 ; x < x2 ; x + + )
{
int y1 = uwal [ x ] ;
int y2 = dwal [ x ] ;
if ( y2 < = y1 )
continue ;
2017-01-29 09:25:32 +00:00
DrawSkyColumn ( x , y1 , y2 ) ;
2016-12-31 09:19:31 +00:00
}
}
}