2016-03-01 15:47:10 +00:00
/*
* * v_draw . cpp
* * Draw patches and blocks to a canvas
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* * Copyright 1998 - 2008 Randy Heit
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
# include <stdio.h>
# include <stdarg.h>
# include "doomtype.h"
# include "v_video.h"
# include "r_defs.h"
# include "r_utility.h"
2017-02-13 16:32:52 +00:00
# include "r_renderer.h"
2016-03-01 15:47:10 +00:00
# include "doomstat.h"
# include "gi.h"
# include "g_level.h"
# include "sbar.h"
2018-05-05 09:20:37 +00:00
# include "d_player.h"
2016-03-01 15:47:10 +00:00
# include "i_video.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-04-12 23:12:04 +00:00
# include "vm.h"
2018-06-16 11:47:24 +00:00
# include "hwrenderer/utility/hw_cvars.h"
2016-03-01 15:47:10 +00:00
2018-05-05 09:20:37 +00:00
CVAR ( Float , underwater_fade_scalar , 1.0f , CVAR_ARCHIVE ) // [Nash] user-settable underwater blend intensity
2017-03-30 09:30:09 +00:00
CUSTOM_CVAR ( Int , uiscale , 0 , CVAR_ARCHIVE | CVAR_NOINITCALL )
2016-09-06 17:48:14 +00:00
{
2017-03-29 17:23:40 +00:00
if ( self < 0 )
{
self = 0 ;
return ;
}
2016-09-06 17:48:14 +00:00
if ( StatusBar ! = NULL )
{
2017-03-21 19:09:09 +00:00
StatusBar - > CallScreenSizeChanged ( ) ;
2016-09-06 17:48:14 +00:00
}
2017-08-19 10:02:56 +00:00
setsizeneeded = true ;
2016-09-06 17:48:14 +00:00
}
2017-03-30 00:16:23 +00:00
int GetUIScale ( int altval )
{
int scaleval ;
if ( altval > 0 ) scaleval = altval ;
else if ( uiscale = = 0 )
{
2017-03-30 09:30:09 +00:00
// Default should try to scale to 640x400
int vscale = screen - > GetHeight ( ) / 400 ;
int hscale = screen - > GetWidth ( ) / 640 ;
2017-03-30 00:16:23 +00:00
scaleval = clamp ( vscale , 1 , hscale ) ;
}
else scaleval = uiscale ;
// block scales that result in something larger than the current screen.
int vmax = screen - > GetHeight ( ) / 200 ;
int hmax = screen - > GetWidth ( ) / 320 ;
int max = MAX ( vmax , hmax ) ;
2017-06-20 03:46:07 +00:00
return MAX ( 1 , MIN ( scaleval , max ) ) ;
2017-03-30 00:16:23 +00:00
}
2016-03-01 15:47:10 +00:00
// [RH] Stretch values to make a 320x200 image best fit the screen
// without using fractional steppings
int CleanXfac , CleanYfac ;
// [RH] Effective screen sizes that the above scale values give you
int CleanWidth , CleanHeight ;
// Above minus 1 (or 1, if they are already 1)
int CleanXfac_1 , CleanYfac_1 , CleanWidth_1 , CleanHeight_1 ;
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// ZScript wrappers for inlines
//
//==========================================================================
2017-02-03 23:46:22 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , GetWidth )
{
PARAM_PROLOGUE ;
ACTION_RETURN_INT ( screen - > GetWidth ( ) ) ;
}
DEFINE_ACTION_FUNCTION ( _Screen , GetHeight )
{
PARAM_PROLOGUE ;
ACTION_RETURN_INT ( screen - > GetHeight ( ) ) ;
}
2016-03-01 15:47:10 +00:00
2017-02-09 23:25:50 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , PaletteColor )
{
PARAM_PROLOGUE ;
PARAM_INT ( index ) ;
if ( index < 0 | | index > 255 ) index = 0 ;
else index = GPalette . BaseColors [ index ] ;
ACTION_RETURN_INT ( index ) ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// Internal texture drawing function
//
//==========================================================================
void DFrameBuffer : : DrawTexture ( FTexture * img , double x , double y , int tags_first , . . . )
2016-03-01 15:47:10 +00:00
{
2017-02-05 20:54:09 +00:00
Va_List tags ;
va_start ( tags . list , tags_first ) ;
2016-04-09 10:55:12 +00:00
DrawParms parms ;
2016-04-09 18:47:54 +00:00
bool res = ParseDrawTextureTags ( img , x , y , tags_first , tags , & parms , false ) ;
2017-02-05 20:54:09 +00:00
va_end ( tags . list ) ;
2016-04-09 18:47:54 +00:00
if ( ! res )
2016-04-09 10:55:12 +00:00
{
return ;
}
2016-04-09 10:59:50 +00:00
DrawTextureParms ( img , parms ) ;
2016-03-01 15:47:10 +00:00
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// ZScript texture drawing function
//
//==========================================================================
2017-02-05 15:47:33 +00:00
int ListGetInt ( VMVa_List & tags ) ;
2017-02-04 21:09:49 +00:00
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : DrawTexture ( FTexture * img , double x , double y , VMVa_List & args )
2017-02-04 21:09:49 +00:00
{
DrawParms parms ;
uint32_t tag = ListGetInt ( args ) ;
bool res = ParseDrawTextureTags ( img , x , y , tag , args , & parms , false ) ;
if ( ! res ) return ;
DrawTextureParms ( img , parms ) ;
}
DEFINE_ACTION_FUNCTION ( _Screen , DrawTexture )
{
PARAM_PROLOGUE ;
PARAM_INT ( texid ) ;
PARAM_BOOL ( animate ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2017-03-28 11:25:17 +00:00
2017-02-04 21:09:49 +00:00
FTexture * tex = animate ? TexMan ( FSetTextureID ( texid ) ) : TexMan [ FSetTextureID ( texid ) ] ;
VMVa_List args = { param + 4 , 0 , numparam - 4 } ;
screen - > DrawTexture ( tex , x , y , args ) ;
return 0 ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// common drawing function
//
//==========================================================================
2016-03-01 15:47:10 +00:00
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : DrawTextureParms ( FTexture * img , DrawParms & parms )
{
2018-03-28 21:42:06 +00:00
m2DDrawer . AddTexture ( img , parms ) ;
2016-03-01 15:47:10 +00:00
}
2018-06-07 18:58:31 +00:00
//==========================================================================
//
// ZScript arbitrary textured shape drawing functions
//
//==========================================================================
void DFrameBuffer : : DrawShape ( FTexture * img , DShape2D * shape , int tags_first , . . . )
{
Va_List tags ;
va_start ( tags . list , tags_first ) ;
DrawParms parms ;
bool res = ParseDrawTextureTags ( img , 0 , 0 , tags_first , tags , & parms , false ) ;
va_end ( tags . list ) ;
if ( ! res ) return ;
m2DDrawer . AddShape ( img , shape , parms ) ;
}
void DFrameBuffer : : DrawShape ( FTexture * img , DShape2D * shape , VMVa_List & args )
{
DrawParms parms ;
uint32_t tag = ListGetInt ( args ) ;
bool res = ParseDrawTextureTags ( img , 0 , 0 , tag , args , & parms , false ) ;
if ( ! res ) return ;
m2DDrawer . AddShape ( img , shape , parms ) ;
}
DEFINE_ACTION_FUNCTION ( _Screen , DrawShape )
{
PARAM_PROLOGUE ;
PARAM_INT ( texid ) ;
PARAM_BOOL ( animate ) ;
PARAM_POINTER ( shape , DShape2D ) ;
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
FTexture * tex = animate ? TexMan ( FSetTextureID ( texid ) ) : TexMan [ FSetTextureID ( texid ) ] ;
VMVa_List args = { param + 3 , 0 , numparam - 3 } ;
screen - > DrawShape ( tex , shape , args ) ;
return 0 ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// Clipping rect
//
//==========================================================================
void DFrameBuffer : : SetClipRect ( int x , int y , int w , int h )
2017-03-28 11:06:24 +00:00
{
clipleft = clamp ( x , 0 , GetWidth ( ) ) ;
2017-04-14 13:41:36 +00:00
clipwidth = clamp ( w , - 1 , GetWidth ( ) - x ) ;
2017-03-28 11:06:24 +00:00
cliptop = clamp ( y , 0 , GetHeight ( ) ) ;
2017-04-14 13:41:36 +00:00
clipheight = clamp ( h , - 1 , GetHeight ( ) - y ) ;
2017-03-28 11:06:24 +00:00
}
2017-03-30 10:13:28 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , SetClipRect )
{
PARAM_PROLOGUE ;
PARAM_INT ( x ) ;
PARAM_INT ( y ) ;
PARAM_INT ( w ) ;
PARAM_INT ( h ) ;
screen - > SetClipRect ( x , y , w , h ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( _Screen , ClearClipRect )
{
PARAM_PROLOGUE ;
screen - > ClearClipRect ( ) ;
return 0 ;
}
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : GetClipRect ( int * x , int * y , int * w , int * h )
2017-03-28 11:06:24 +00:00
{
if ( x ) * x = clipleft ;
if ( y ) * y = cliptop ;
if ( w ) * w = clipwidth ;
if ( h ) * h = clipheight ;
}
2017-03-30 10:13:28 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , GetClipRect )
{
PARAM_PROLOGUE ;
int x , y , w , h ;
screen - > GetClipRect ( & x , & y , & w , & h ) ;
if ( numret > 0 ) ret [ 0 ] . SetInt ( x ) ;
2017-03-30 19:12:39 +00:00
if ( numret > 1 ) ret [ 1 ] . SetInt ( y ) ;
if ( numret > 2 ) ret [ 2 ] . SetInt ( w ) ;
if ( numret > 3 ) ret [ 3 ] . SetInt ( h ) ;
2017-03-30 10:13:28 +00:00
return MIN ( numret , 4 ) ;
}
2018-01-20 20:02:36 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , GetViewWindow )
{
PARAM_PROLOGUE ;
if ( numret > 0 ) ret [ 0 ] . SetInt ( viewwindowx ) ;
if ( numret > 1 ) ret [ 1 ] . SetInt ( viewwindowy ) ;
if ( numret > 2 ) ret [ 2 ] . SetInt ( viewwidth ) ;
if ( numret > 3 ) ret [ 3 ] . SetInt ( viewheight ) ;
return MIN ( numret , 4 ) ;
}
2017-03-30 10:13:28 +00:00
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// Draw parameter parsing
//
//==========================================================================
bool DFrameBuffer : : SetTextureParms ( DrawParms * parms , FTexture * img , double xx , double yy ) const
2016-04-09 18:47:54 +00:00
{
if ( img ! = NULL )
{
parms - > x = xx ;
parms - > y = yy ;
parms - > texwidth = img - > GetScaledWidthDouble ( ) ;
parms - > texheight = img - > GetScaledHeightDouble ( ) ;
if ( parms - > top = = INT_MAX | | parms - > fortext )
{
2018-03-31 08:37:46 +00:00
parms - > top = img - > GetScaledTopOffset ( 0 ) ;
2016-04-09 18:47:54 +00:00
}
if ( parms - > left = = INT_MAX | | parms - > fortext )
{
2018-03-31 08:37:46 +00:00
parms - > left = img - > GetScaledLeftOffset ( 0 ) ;
2016-04-09 18:47:54 +00:00
}
if ( parms - > destwidth = = INT_MAX | | parms - > fortext )
{
parms - > destwidth = img - > GetScaledWidthDouble ( ) ;
}
if ( parms - > destheight = = INT_MAX | | parms - > fortext )
{
parms - > destheight = img - > GetScaledHeightDouble ( ) ;
}
switch ( parms - > cleanmode )
{
default :
break ;
case DTA_Clean :
parms - > x = ( parms - > x - 160.0 ) * CleanXfac + ( Width * 0.5 ) ;
parms - > y = ( parms - > y - 100.0 ) * CleanYfac + ( Height * 0.5 ) ;
parms - > destwidth = parms - > texwidth * CleanXfac ;
parms - > destheight = parms - > texheight * CleanYfac ;
break ;
case DTA_CleanNoMove :
parms - > destwidth = parms - > texwidth * CleanXfac ;
parms - > destheight = parms - > texheight * CleanYfac ;
break ;
case DTA_CleanNoMove_1 :
parms - > destwidth = parms - > texwidth * CleanXfac_1 ;
parms - > destheight = parms - > texheight * CleanYfac_1 ;
break ;
case DTA_Fullscreen :
parms - > x = parms - > y = 0 ;
break ;
case DTA_HUDRules :
case DTA_HUDRulesC :
{
2017-03-25 17:31:53 +00:00
// Note that this has been deprecated because the HUD should be drawn by the status bar.
2016-04-09 18:47:54 +00:00
bool xright = parms - > x < 0 ;
bool ybot = parms - > y < 0 ;
2017-03-25 17:31:53 +00:00
DVector2 scale = StatusBar - > GetHUDScale ( ) ;
parms - > x * = scale . X ;
if ( parms - > cleanmode = = DTA_HUDRulesC )
parms - > x + = Width * 0.5 ;
else if ( xright )
parms - > x = Width + parms - > x ;
parms - > y * = scale . Y ;
if ( ybot )
parms - > y = Height + parms - > y ;
parms - > destwidth = parms - > texwidth * scale . X ;
parms - > destheight = parms - > texheight * scale . Y ;
2016-04-09 18:47:54 +00:00
break ;
}
}
if ( parms - > virtWidth ! = Width | | parms - > virtHeight ! = Height )
{
VirtualToRealCoords ( parms - > x , parms - > y , parms - > destwidth , parms - > destheight ,
parms - > virtWidth , parms - > virtHeight , parms - > virtBottom , ! parms - > keepratio ) ;
}
}
2016-04-09 20:56:12 +00:00
2016-04-09 18:47:54 +00:00
return false ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// template helpers
//
//==========================================================================
2017-02-05 20:54:09 +00:00
static void ListEnd ( Va_List & tags )
2017-02-04 12:11:12 +00:00
{
2017-02-05 20:54:09 +00:00
va_end ( tags . list ) ;
2017-02-04 12:11:12 +00:00
}
2017-02-05 20:54:09 +00:00
static int ListGetInt ( Va_List & tags )
2017-02-04 12:11:12 +00:00
{
2017-02-05 20:54:09 +00:00
return va_arg ( tags . list , int ) ;
2017-02-04 12:11:12 +00:00
}
2017-02-05 20:54:09 +00:00
static inline double ListGetDouble ( Va_List & tags )
2017-02-04 12:11:12 +00:00
{
2017-02-05 20:54:09 +00:00
return va_arg ( tags . list , double ) ;
2017-02-04 12:11:12 +00:00
}
2017-02-05 20:54:09 +00:00
static inline FSpecialColormap * ListGetSpecialColormap ( Va_List & tags )
2017-02-04 12:11:12 +00:00
{
2017-02-05 20:54:09 +00:00
return va_arg ( tags . list , FSpecialColormap * ) ;
2017-02-04 12:11:12 +00:00
}
2017-02-04 21:09:49 +00:00
static void ListEnd ( VMVa_List & tags )
{
}
2017-02-05 15:47:33 +00:00
int ListGetInt ( VMVa_List & tags )
2017-02-04 21:09:49 +00:00
{
2017-02-10 12:20:19 +00:00
if ( tags . curindex < tags . numargs )
2017-02-04 21:09:49 +00:00
{
2017-02-10 12:20:19 +00:00
if ( tags . args [ tags . curindex ] . Type = = REGT_INT )
{
return tags . args [ tags . curindex + + ] . i ;
}
ThrowAbortException ( X_OTHER , " Invalid parameter in draw function, int expected " ) ;
2017-02-04 21:09:49 +00:00
}
2017-02-10 12:20:19 +00:00
return TAG_DONE ;
2017-02-04 21:09:49 +00:00
}
static inline double ListGetDouble ( VMVa_List & tags )
{
if ( tags . curindex < tags . numargs & & tags . args [ tags . curindex ] . Type = = REGT_FLOAT )
{
return tags . args [ tags . curindex + + ] . f ;
}
ThrowAbortException ( X_OTHER , " Invalid parameter in draw function, float expected " ) ;
return 0 ;
}
static inline FSpecialColormap * ListGetSpecialColormap ( VMVa_List & tags )
{
ThrowAbortException ( X_OTHER , " Invalid tag in draw function " ) ;
return nullptr ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// Main taglist parsing
//
//==========================================================================
2017-02-04 21:09:49 +00:00
template < class T >
2018-03-26 21:16:27 +00:00
bool DFrameBuffer : : ParseDrawTextureTags ( FTexture * img , double x , double y , uint32_t tag , T & tags , DrawParms * parms , bool fortext ) const
2016-03-01 15:47:10 +00:00
{
INTBOOL boolval ;
int intval ;
bool translationset = false ;
bool fillcolorset = false ;
2016-04-09 18:47:54 +00:00
if ( ! fortext )
2016-03-01 15:47:10 +00:00
{
2018-03-25 18:26:16 +00:00
if ( img = = NULL | | img - > UseType = = ETextureType : : Null )
2016-04-09 18:47:54 +00:00
{
2017-02-04 12:11:12 +00:00
ListEnd ( tags ) ;
2016-04-09 18:47:54 +00:00
return false ;
}
2016-03-01 15:47:10 +00:00
}
// Do some sanity checks on the coordinates.
if ( x < - 16383 | | x > 16383 | | y < - 16383 | | y > 16383 )
{
2017-02-04 12:11:12 +00:00
ListEnd ( tags ) ;
2016-03-01 15:47:10 +00:00
return false ;
}
2016-04-09 18:47:54 +00:00
parms - > fortext = fortext ;
2016-03-01 15:47:10 +00:00
parms - > windowleft = 0 ;
2016-04-09 18:47:54 +00:00
parms - > windowright = INT_MAX ;
2016-03-01 15:47:10 +00:00
parms - > dclip = this - > GetHeight ( ) ;
parms - > uclip = 0 ;
parms - > lclip = 0 ;
parms - > rclip = this - > GetWidth ( ) ;
2016-04-09 18:47:54 +00:00
parms - > left = INT_MAX ;
parms - > top = INT_MAX ;
parms - > destwidth = INT_MAX ;
parms - > destheight = INT_MAX ;
2016-03-22 12:35:16 +00:00
parms - > Alpha = 1.f ;
2016-03-01 15:47:10 +00:00
parms - > fillcolor = - 1 ;
parms - > remap = NULL ;
parms - > colorOverlay = 0 ;
parms - > alphaChannel = false ;
parms - > flipX = false ;
2018-03-28 14:40:09 +00:00
parms - > flipY = false ;
2017-03-29 19:22:05 +00:00
parms - > color = 0xffffffff ;
2017-02-25 18:10:49 +00:00
//parms->shadowAlpha = 0;
2016-03-01 15:47:10 +00:00
parms - > shadowColor = 0 ;
parms - > virtWidth = this - > GetWidth ( ) ;
parms - > virtHeight = this - > GetHeight ( ) ;
parms - > keepratio = false ;
parms - > style . BlendOp = 255 ; // Dummy "not set" value
parms - > masked = true ;
parms - > bilinear = false ;
parms - > specialcolormap = NULL ;
2018-03-29 14:21:21 +00:00
parms - > desaturate = 0 ;
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
parms - > scalex = parms - > scaley = 1 ;
parms - > cellx = parms - > celly = 0 ;
parms - > maxstrlen = INT_MAX ;
parms - > virtBottom = false ;
2018-03-28 14:40:09 +00:00
parms - > srcx = 0. ;
parms - > srcy = 0. ;
parms - > srcwidth = 1. ;
parms - > srcheight = 1. ;
2018-08-28 13:11:35 +00:00
parms - > burn = false ;
2016-03-01 15:47:10 +00:00
// Parse the tag list for attributes. (For floating point attributes,
// consider that the C ABI dictates that all floats be promoted to
// doubles when passed as function arguments.)
while ( tag ! = TAG_DONE )
{
switch ( tag )
{
default :
2017-02-04 12:11:12 +00:00
ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_DestWidth :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > destwidth = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_DestWidthF :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > destwidth = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_DestHeight :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > destheight = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_DestHeightF :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > destheight = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_Clean :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2016-04-09 18:47:54 +00:00
parms - > scalex = 1 ;
parms - > scaley = 1 ;
parms - > cleanmode = tag ;
2016-03-01 15:47:10 +00:00
}
break ;
case DTA_CleanNoMove :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2016-04-09 18:47:54 +00:00
parms - > scalex = CleanXfac ;
parms - > scaley = CleanYfac ;
parms - > cleanmode = tag ;
2016-03-01 15:47:10 +00:00
}
break ;
case DTA_CleanNoMove_1 :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2016-04-09 18:47:54 +00:00
parms - > scalex = CleanXfac_1 ;
parms - > scaley = CleanYfac_1 ;
parms - > cleanmode = tag ;
2016-03-01 15:47:10 +00:00
}
break ;
case DTA_320x200 :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
parms - > scalex = 1 ;
parms - > scaley = 1 ;
2016-03-01 15:47:10 +00:00
parms - > virtWidth = 320 ;
parms - > virtHeight = 200 ;
}
break ;
case DTA_Bottom320x200 :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
parms - > scalex = 1 ;
parms - > scaley = 1 ;
2016-03-01 15:47:10 +00:00
parms - > virtWidth = 320 ;
parms - > virtHeight = 200 ;
}
2016-04-09 18:47:54 +00:00
parms - > virtBottom = true ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_HUDRules :
2017-02-04 12:11:12 +00:00
intval = ListGetInt ( tags ) ;
2016-04-09 18:47:54 +00:00
parms - > cleanmode = intval = = HUD_HorizCenter ? DTA_HUDRulesC : DTA_HUDRules ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_VirtualWidth :
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > virtWidth = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_VirtualWidthF :
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > virtWidth = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
2017-02-04 21:09:49 +00:00
2016-03-01 15:47:10 +00:00
case DTA_VirtualHeight :
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > virtHeight = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_VirtualHeightF :
2016-04-09 18:47:54 +00:00
parms - > cleanmode = DTA_Base ;
2017-02-04 12:11:12 +00:00
parms - > virtHeight = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_Fullscreen :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( img = = NULL ) return false ;
parms - > cleanmode = DTA_Fullscreen ;
2016-03-01 15:47:10 +00:00
parms - > virtWidth = img - > GetScaledWidthDouble ( ) ;
parms - > virtHeight = img - > GetScaledHeightDouble ( ) ;
}
break ;
case DTA_Alpha :
2017-02-04 12:11:12 +00:00
parms - > Alpha = ( float ) ( MIN < double > ( 1. , ListGetDouble ( tags ) ) ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_AlphaChannel :
2017-02-04 12:11:12 +00:00
parms - > alphaChannel = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_FillColor :
2017-02-04 12:11:12 +00:00
parms - > fillcolor = ListGetInt ( tags ) ;
2017-03-26 19:04:04 +00:00
if ( parms - > fillcolor ! = ~ 0u )
2017-03-23 14:18:09 +00:00
{
fillcolorset = true ;
}
else if ( parms - > fillcolor ! = 0 )
{
// The crosshair is the only thing which uses a non-black fill color.
parms - > fillcolor = PalEntry ( ColorMatcher . Pick ( parms - > fillcolor ) , RPART ( parms - > fillcolor ) , GPART ( parms - > fillcolor ) , BPART ( parms - > fillcolor ) ) ;
}
2016-03-01 15:47:10 +00:00
break ;
2017-02-04 22:26:28 +00:00
case DTA_TranslationIndex :
parms - > remap = TranslationToTable ( ListGetInt ( tags ) ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_ColorOverlay :
2017-02-04 12:11:12 +00:00
parms - > colorOverlay = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
2017-03-29 19:22:05 +00:00
case DTA_Color :
parms - > color = ListGetInt ( tags ) ;
break ;
2016-03-01 15:47:10 +00:00
case DTA_FlipX :
2017-02-04 12:11:12 +00:00
parms - > flipX = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
2018-03-28 14:40:09 +00:00
case DTA_FlipY :
parms - > flipY = ListGetInt ( tags ) ;
break ;
case DTA_SrcX :
parms - > srcx = ListGetDouble ( tags ) / img - > GetScaledWidthDouble ( ) ;
break ;
case DTA_SrcY :
parms - > srcy = ListGetDouble ( tags ) / img - > GetScaledHeightDouble ( ) ;
break ;
case DTA_SrcWidth :
parms - > srcwidth = ListGetDouble ( tags ) / img - > GetScaledWidthDouble ( ) ;
break ;
case DTA_SrcHeight :
parms - > srcheight = ListGetDouble ( tags ) / img - > GetScaledHeightDouble ( ) ;
break ;
2016-03-01 15:47:10 +00:00
case DTA_TopOffset :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > top = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_TopOffsetF :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > top = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_LeftOffset :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > left = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_LeftOffsetF :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > left = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_CenterOffset :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
if ( ListGetInt ( tags ) )
2016-03-01 15:47:10 +00:00
{
2016-04-09 18:47:54 +00:00
parms - > left = img - > GetScaledWidthDouble ( ) * 0.5 ;
parms - > top = img - > GetScaledHeightDouble ( ) * 0.5 ;
2016-03-01 15:47:10 +00:00
}
break ;
case DTA_CenterBottomOffset :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
if ( ListGetInt ( tags ) )
2016-03-01 15:47:10 +00:00
{
2016-04-09 18:47:54 +00:00
parms - > left = img - > GetScaledWidthDouble ( ) * 0.5 ;
parms - > top = img - > GetScaledHeightDouble ( ) ;
2016-03-01 15:47:10 +00:00
}
break ;
case DTA_WindowLeft :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > windowleft = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_WindowLeftF :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > windowleft = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_WindowRight :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > windowright = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_WindowRightF :
2016-04-09 18:47:54 +00:00
assert ( fortext = = false ) ;
if ( fortext ) return false ;
2017-02-04 12:11:12 +00:00
parms - > windowright = ListGetDouble ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_ClipTop :
2017-02-04 12:11:12 +00:00
parms - > uclip = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( parms - > uclip < 0 )
{
parms - > uclip = 0 ;
}
break ;
case DTA_ClipBottom :
2017-02-04 12:11:12 +00:00
parms - > dclip = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( parms - > dclip > this - > GetHeight ( ) )
{
parms - > dclip = this - > GetHeight ( ) ;
}
break ;
case DTA_ClipLeft :
2017-02-04 12:11:12 +00:00
parms - > lclip = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( parms - > lclip < 0 )
{
parms - > lclip = 0 ;
}
break ;
case DTA_ClipRight :
2017-02-04 12:11:12 +00:00
parms - > rclip = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( parms - > rclip > this - > GetWidth ( ) )
{
parms - > rclip = this - > GetWidth ( ) ;
}
break ;
case DTA_ShadowAlpha :
2017-02-25 18:10:49 +00:00
//parms->shadowAlpha = (float)MIN(1., ListGetDouble(tags));
2016-03-01 15:47:10 +00:00
break ;
case DTA_ShadowColor :
2017-02-04 12:11:12 +00:00
parms - > shadowColor = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_Shadow :
2017-02-04 12:11:12 +00:00
boolval = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
if ( boolval )
{
2017-02-25 18:10:49 +00:00
//parms->shadowAlpha = 0.5;
2016-03-01 15:47:10 +00:00
parms - > shadowColor = 0 ;
}
else
{
2017-02-25 18:10:49 +00:00
//parms->shadowAlpha = 0;
2016-03-01 15:47:10 +00:00
}
break ;
case DTA_Masked :
2017-02-04 12:11:12 +00:00
parms - > masked = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_BilinearFilter :
2017-02-04 12:11:12 +00:00
parms - > bilinear = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_KeepRatio :
// I think this is a terribly misleading name, since it actually turns
// *off* aspect ratio correction.
2017-02-04 12:11:12 +00:00
parms - > keepratio = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
case DTA_RenderStyle :
2017-02-04 12:11:12 +00:00
parms - > style . AsDWORD = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
2018-07-14 20:58:24 +00:00
case DTA_LegacyRenderStyle : // mainly for ZScript which does not handle FRenderStyle that well.
parms - > style = ( ERenderStyle ) ListGetInt ( tags ) ;
break ;
2016-03-01 15:47:10 +00:00
case DTA_SpecialColormap :
2017-02-04 12:11:12 +00:00
parms - > specialcolormap = ListGetSpecialColormap ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
2018-03-29 14:21:21 +00:00
case DTA_Desaturate :
parms - > desaturate = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
break ;
2016-04-09 18:47:54 +00:00
case DTA_TextLen :
2017-02-04 12:11:12 +00:00
parms - > maxstrlen = ListGetInt ( tags ) ;
2016-04-09 18:47:54 +00:00
break ;
case DTA_CellX :
2017-02-04 12:11:12 +00:00
parms - > cellx = ListGetInt ( tags ) ;
2016-04-09 18:47:54 +00:00
break ;
case DTA_CellY :
2017-02-04 12:11:12 +00:00
parms - > celly = ListGetInt ( tags ) ;
2016-04-09 18:47:54 +00:00
break ;
2018-08-28 13:11:35 +00:00
case DTA_Burn :
parms - > burn = true ;
break ;
2016-04-09 18:47:54 +00:00
2016-03-01 15:47:10 +00:00
}
2017-02-04 12:11:12 +00:00
tag = ListGetInt ( tags ) ;
2016-03-01 15:47:10 +00:00
}
2017-02-04 21:09:49 +00:00
ListEnd ( tags ) ;
2016-03-01 15:47:10 +00:00
2017-02-04 21:50:23 +00:00
if ( parms - > remap ! = nullptr & & parms - > remap - > Inactive )
{ // If it's inactive, pretend we were passed NULL instead.
parms - > remap = nullptr ;
2016-03-01 15:47:10 +00:00
}
2017-03-28 11:06:24 +00:00
// intersect with the canvas's clipping rectangle.
if ( clipwidth > = 0 & & clipheight > = 0 )
{
if ( parms - > lclip < clipleft ) parms - > lclip = clipleft ;
if ( parms - > rclip > clipleft + clipwidth ) parms - > rclip = clipleft + clipwidth ;
if ( parms - > uclip < cliptop ) parms - > uclip = cliptop ;
2017-04-23 10:58:40 +00:00
if ( parms - > dclip > cliptop + clipheight ) parms - > dclip = cliptop + clipheight ;
2017-03-28 11:06:24 +00:00
}
2016-03-01 15:47:10 +00:00
if ( parms - > uclip > = parms - > dclip | | parms - > lclip > = parms - > rclip )
{
return false ;
}
2016-04-09 18:47:54 +00:00
if ( img ! = NULL )
2016-03-01 15:47:10 +00:00
{
2016-04-09 18:47:54 +00:00
SetTextureParms ( parms , img , x , y ) ;
2016-03-01 15:47:10 +00:00
2016-04-09 18:47:54 +00:00
if ( parms - > destwidth < = 0 | | parms - > destheight < = 0 )
{
return false ;
}
2016-03-01 15:47:10 +00:00
}
if ( parms - > style . BlendOp = = 255 )
{
if ( fillcolorset )
{
if ( parms - > alphaChannel )
{
parms - > style = STYLE_Shaded ;
}
2016-03-22 12:35:16 +00:00
else if ( parms - > Alpha < 1.f )
2016-03-01 15:47:10 +00:00
{
parms - > style = STYLE_TranslucentStencil ;
}
else
{
parms - > style = STYLE_Stencil ;
}
}
2016-03-22 12:35:16 +00:00
else if ( parms - > Alpha < 1.f )
2016-03-01 15:47:10 +00:00
{
parms - > style = STYLE_Translucent ;
}
else
{
parms - > style = STYLE_Normal ;
}
}
return true ;
}
2017-02-04 21:09:49 +00:00
// explicitly instantiate both versions for v_text.cpp.
2018-03-26 21:16:27 +00:00
template bool DFrameBuffer : : ParseDrawTextureTags < Va_List > ( FTexture * img , double x , double y , uint32_t tag , Va_List & tags , DrawParms * parms , bool fortext ) const ;
template bool DFrameBuffer : : ParseDrawTextureTags < VMVa_List > ( FTexture * img , double x , double y , uint32_t tag , VMVa_List & tags , DrawParms * parms , bool fortext ) const ;
//==========================================================================
//
// Coordinate conversion
//
//==========================================================================
2016-03-01 15:47:10 +00:00
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : VirtualToRealCoords ( double & x , double & y , double & w , double & h ,
2016-03-01 15:47:10 +00:00
double vwidth , double vheight , bool vbottom , bool handleaspect ) const
{
2016-09-12 13:51:50 +00:00
float myratio = handleaspect ? ActiveRatio ( Width , Height ) : ( 4.0f / 3.0f ) ;
2016-03-02 20:07:11 +00:00
// if 21:9 AR, map to 16:9 for all callers.
// this allows for black bars and stops the stretching of fullscreen images
2016-09-12 13:51:50 +00:00
if ( myratio > 1.7f ) {
myratio = 16.0f / 9.0f ;
2016-03-02 20:07:11 +00:00
}
2016-03-01 15:47:10 +00:00
double right = x + w ;
double bottom = y + h ;
2016-09-13 21:26:30 +00:00
if ( myratio > 1.334f )
2016-03-01 15:47:10 +00:00
{ // The target surface is either 16:9 or 16:10, so expand the
// specified virtual size to avoid undesired stretching of the
// image. Does not handle non-4:3 virtual sizes. I'll worry about
// those if somebody expresses a desire to use them.
2016-09-12 13:51:50 +00:00
x = ( x - vwidth * 0.5 ) * Width * 960 / ( vwidth * AspectBaseWidth ( myratio ) ) + Width * 0.5 ;
w = ( right - vwidth * 0.5 ) * Width * 960 / ( vwidth * AspectBaseWidth ( myratio ) ) + Width * 0.5 - x ;
2016-03-01 15:47:10 +00:00
}
else
{
x = x * Width / vwidth ;
w = right * Width / vwidth - x ;
}
2016-09-13 21:26:30 +00:00
if ( AspectTallerThanWide ( myratio ) )
2016-03-01 15:47:10 +00:00
{ // The target surface is 5:4
2016-09-12 13:51:50 +00:00
y = ( y - vheight * 0.5 ) * Height * 600 / ( vheight * AspectBaseHeight ( myratio ) ) + Height * 0.5 ;
h = ( bottom - vheight * 0.5 ) * Height * 600 / ( vheight * AspectBaseHeight ( myratio ) ) + Height * 0.5 - y ;
2016-03-01 15:47:10 +00:00
if ( vbottom )
{
2016-09-12 13:51:50 +00:00
y + = ( Height - Height * AspectMultiplier ( myratio ) / 48.0 ) * 0.5 ;
2016-03-01 15:47:10 +00:00
}
}
else
{
y = y * Height / vheight ;
h = bottom * Height / vheight - y ;
}
}
2017-03-22 13:59:12 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , VirtualToRealCoords )
{
PARAM_PROLOGUE ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
PARAM_FLOAT ( w ) ;
PARAM_FLOAT ( h ) ;
PARAM_FLOAT ( vw ) ;
PARAM_FLOAT ( vh ) ;
PARAM_BOOL_DEF ( vbottom ) ;
PARAM_BOOL_DEF ( handleaspect ) ;
screen - > VirtualToRealCoords ( x , y , w , h , vw , vh , vbottom , handleaspect ) ;
if ( numret > = 1 ) ret [ 0 ] . SetVector2 ( DVector2 ( x , y ) ) ;
if ( numret > = 2 ) ret [ 1 ] . SetVector2 ( DVector2 ( w , h ) ) ;
return MIN ( numret , 2 ) ;
}
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : VirtualToRealCoordsInt ( int & x , int & y , int & w , int & h ,
2016-03-01 15:47:10 +00:00
int vwidth , int vheight , bool vbottom , bool handleaspect ) const
{
double dx , dy , dw , dh ;
dx = x ;
dy = y ;
dw = w ;
dh = h ;
VirtualToRealCoords ( dx , dy , dw , dh , vwidth , vheight , vbottom , handleaspect ) ;
x = int ( dx + 0.5 ) ;
y = int ( dy + 0.5 ) ;
w = int ( dx + dw + 0.5 ) - x ;
h = int ( dy + dh + 0.5 ) - y ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
//
//
//==========================================================================
void DFrameBuffer : : FillBorder ( FTexture * img )
2016-03-01 15:47:10 +00:00
{
2016-09-12 13:51:50 +00:00
float myratio = ActiveRatio ( Width , Height ) ;
2016-03-02 20:33:06 +00:00
// if 21:9 AR, fill borders akin to 16:9, since all fullscreen
// images are being drawn to that scale.
2016-09-12 13:51:50 +00:00
if ( myratio > 1.7f ) {
myratio = 16 / 9.0f ;
2016-03-02 20:33:06 +00:00
}
2016-09-12 13:51:50 +00:00
if ( myratio > = 1.3f & & myratio < = 1.4f )
2016-03-01 15:47:10 +00:00
{ // This is a 4:3 display, so no border to show
return ;
}
int bordtop , bordbottom , bordleft , bordright , bord ;
2016-09-13 21:26:30 +00:00
if ( AspectTallerThanWide ( myratio ) )
2016-03-01 15:47:10 +00:00
{ // Screen is taller than it is wide
bordleft = bordright = 0 ;
2016-09-12 13:51:50 +00:00
bord = Height - Height * AspectMultiplier ( myratio ) / 48 ;
2016-03-01 15:47:10 +00:00
bordtop = bord / 2 ;
bordbottom = bord - bordtop ;
}
else
{ // Screen is wider than it is tall
bordtop = bordbottom = 0 ;
2016-09-12 13:51:50 +00:00
bord = Width - Width * AspectMultiplier ( myratio ) / 48 ;
2016-03-01 15:47:10 +00:00
bordleft = bord / 2 ;
bordright = bord - bordleft ;
}
if ( img ! = NULL )
{
FlatFill ( 0 , 0 , Width , bordtop , img ) ; // Top
FlatFill ( 0 , bordtop , bordleft , Height - bordbottom , img ) ; // Left
FlatFill ( Width - bordright , bordtop , Width , Height - bordbottom , img ) ; // Right
FlatFill ( 0 , Height - bordbottom , Width , Height , img ) ; // Bottom
}
else
{
Clear ( 0 , 0 , Width , bordtop , GPalette . BlackIndex , 0 ) ; // Top
Clear ( 0 , bordtop , bordleft , Height - bordbottom , GPalette . BlackIndex , 0 ) ; // Left
Clear ( Width - bordright , bordtop , Width , Height - bordbottom , GPalette . BlackIndex , 0 ) ; // Right
Clear ( 0 , Height - bordbottom , Width , Height , GPalette . BlackIndex , 0 ) ; // Bottom
}
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// Draw a line
//
//==========================================================================
2018-09-26 16:59:22 +00:00
void DFrameBuffer : : DrawLine ( int x0 , int y0 , int x1 , int y1 , int palColor , uint32_t realcolor , uint8_t alpha )
2016-03-01 15:47:10 +00:00
{
2018-09-26 16:59:22 +00:00
m2DDrawer . AddLine ( x0 , y0 , x1 , y1 , palColor , realcolor , alpha ) ;
2016-03-01 15:47:10 +00:00
}
2017-08-03 00:20:55 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , DrawLine )
{
PARAM_PROLOGUE ;
PARAM_INT ( x0 ) ;
PARAM_INT ( y0 ) ;
PARAM_INT ( x1 ) ;
PARAM_INT ( y1 ) ;
PARAM_INT ( color ) ;
2018-09-26 16:59:22 +00:00
PARAM_INT_DEF ( alpha ) ;
2017-08-03 00:20:55 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2018-09-26 16:59:22 +00:00
screen - > DrawLine ( x0 , y0 , x1 , y1 , - 1 , color , alpha ) ;
2017-08-03 00:20:55 +00:00
return 0 ;
}
2018-09-26 16:59:22 +00:00
void DFrameBuffer : : DrawThickLine ( int x0 , int y0 , int x1 , int y1 , double thickness , uint32_t realcolor , uint8_t alpha ) {
m2DDrawer . AddThickLine ( x0 , y0 , x1 , y1 , thickness , realcolor , alpha ) ;
2018-08-30 15:49:10 +00:00
}
DEFINE_ACTION_FUNCTION ( _Screen , DrawThickLine )
{
PARAM_PROLOGUE ;
PARAM_INT ( x0 ) ;
PARAM_INT ( y0 ) ;
PARAM_INT ( x1 ) ;
PARAM_INT ( y1 ) ;
PARAM_FLOAT ( thickness ) ;
PARAM_INT ( color ) ;
2018-09-26 16:59:22 +00:00
PARAM_INT_DEF ( alpha ) ;
2018-08-30 15:49:10 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2018-09-26 16:59:22 +00:00
screen - > DrawThickLine ( x0 , y0 , x1 , y1 , thickness , color , alpha ) ;
2018-08-30 15:49:10 +00:00
return 0 ;
}
2018-03-26 21:16:27 +00:00
//==========================================================================
//
// Draw a single pixel
//
//==========================================================================
void DFrameBuffer : : DrawPixel ( int x , int y , int palColor , uint32_t realcolor )
2016-03-01 15:47:10 +00:00
{
2018-03-28 14:40:09 +00:00
m2DDrawer . AddPixel ( x , y , palColor , realcolor ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// DCanvas :: Clear
//
// Set an area to a specified color.
//
//==========================================================================
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : Clear ( int left , int top , int right , int bottom , int palcolor , uint32_t color )
2017-03-28 11:06:24 +00:00
{
if ( clipwidth > = 0 & & clipheight > = 0 )
{
int w = right - left ;
int h = bottom - top ;
if ( left < clipleft )
{
w - = ( clipleft - left ) ;
left = clipleft ;
}
if ( w > clipwidth ) w = clipwidth ;
if ( w < = 0 ) return ;
if ( top < cliptop )
{
h - = ( cliptop - top ) ;
top = cliptop ;
}
if ( h > clipheight ) w = clipheight ;
if ( h < = 0 ) return ;
right = left + w ;
bottom = top + h ;
}
2018-03-28 14:40:09 +00:00
if ( palcolor > = 0 & & color = = 0 )
{
color = GPalette . BaseColors [ palcolor ] | 0xff000000 ;
}
2018-04-07 08:53:20 +00:00
m2DDrawer . AddColorOnlyQuad ( left , top , right - left , bottom - top , color | 0xFF000000 , nullptr ) ;
2017-03-28 11:06:24 +00:00
}
2017-02-10 12:20:19 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , Clear )
{
PARAM_PROLOGUE ;
PARAM_INT ( x1 ) ;
PARAM_INT ( y1 ) ;
PARAM_INT ( x2 ) ;
PARAM_INT ( y2 ) ;
PARAM_INT ( color ) ;
PARAM_INT_DEF ( palcol ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2017-02-10 12:20:19 +00:00
screen - > Clear ( x1 , y1 , x2 , y2 , palcol , color ) ;
return 0 ;
}
2016-08-06 17:20:41 +00:00
2017-02-13 16:32:52 +00:00
//==========================================================================
//
// DCanvas :: Dim
//
// Applies a colored overlay to an area of the screen.
//
//==========================================================================
2018-04-07 08:53:20 +00:00
void DFrameBuffer : : DoDim ( PalEntry color , float amount , int x1 , int y1 , int w , int h , FRenderStyle * style )
2017-02-13 16:32:52 +00:00
{
2018-03-28 14:40:09 +00:00
if ( amount < = 0 )
{
return ;
}
if ( amount > 1 )
{
amount = 1 ;
}
2018-04-08 09:53:41 +00:00
m2DDrawer . AddColorOnlyQuad ( x1 , y1 , w , h , ( color . d & 0xffffff ) | ( int ( amount * 255 ) < < 24 ) , style ) ;
2017-02-13 16:32:52 +00:00
}
2018-04-07 08:53:20 +00:00
void DFrameBuffer : : Dim ( PalEntry color , float damount , int x1 , int y1 , int w , int h , FRenderStyle * style )
2017-03-28 11:06:24 +00:00
{
if ( clipwidth > = 0 & & clipheight > = 0 )
{
if ( x1 < clipleft )
{
w - = ( clipleft - x1 ) ;
x1 = clipleft ;
}
if ( w > clipwidth ) w = clipwidth ;
if ( w < = 0 ) return ;
if ( y1 < cliptop )
{
h - = ( cliptop - y1 ) ;
y1 = cliptop ;
}
2017-06-05 06:48:09 +00:00
if ( h > clipheight ) h = clipheight ;
2017-03-28 11:06:24 +00:00
if ( h < = 0 ) return ;
}
2018-04-07 08:53:20 +00:00
DoDim ( color , damount , x1 , y1 , w , h , style ) ;
2017-03-28 11:06:24 +00:00
}
DEFINE_ACTION_FUNCTION ( _Screen , Dim )
{
PARAM_PROLOGUE ;
PARAM_INT ( color ) ;
PARAM_FLOAT ( amount ) ;
PARAM_INT ( x1 ) ;
PARAM_INT ( y1 ) ;
PARAM_INT ( w ) ;
PARAM_INT ( h ) ;
2017-03-28 22:45:53 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2017-03-28 11:06:24 +00:00
screen - > Dim ( color , float ( amount ) , x1 , y1 , w , h ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// DCanvas :: FillSimplePoly
//
// Fills a simple polygon with a texture. Here, "simple" means that a
// horizontal scanline at any vertical position within the polygon will
// not cross it more than twice.
//
// The originx, originy, scale, and rotation parameters specify
// transformation of the filling texture, not of the points.
//
// The points must be specified in clockwise order.
//
//==========================================================================
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : FillSimplePoly ( FTexture * tex , FVector2 * points , int npoints ,
2016-03-24 15:36:43 +00:00
double originx , double originy , double scalex , double scaley , DAngle rotation ,
2018-11-10 07:04:03 +00:00
const FColormap & colormap , PalEntry flatcolor , int lightlevel , int bottomclip , uint32_t * indices , size_t indexcount )
2016-03-01 15:47:10 +00:00
{
2018-11-10 07:04:03 +00:00
m2DDrawer . AddPoly ( tex , points , npoints , originx , originy , scalex , scaley , rotation , colormap , flatcolor , lightlevel , indices , indexcount ) ;
2016-03-01 15:47:10 +00:00
}
2018-03-26 21:16:27 +00:00
//==========================================================================
2016-03-01 15:47:10 +00:00
//
2018-03-26 21:16:27 +00:00
// DCanvas :: FlatFill
2016-03-01 15:47:10 +00:00
//
2018-03-26 21:16:27 +00:00
// Fill an area with a texture. If local_origin is false, then the origin
// used for the wrapping is (0,0). Otherwise, (left,right) is used.
//
//==========================================================================
2016-05-31 03:31:32 +00:00
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : FlatFill ( int left , int top , int right , int bottom , FTexture * src , bool local_origin )
{
2018-03-28 14:40:09 +00:00
m2DDrawer . AddFlatFill ( left , top , right , bottom , src , local_origin ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// V_DrawFrame
//
// Draw a frame around the specified area using the view border
// frame graphics. The border is drawn outside the area, not in it.
//
//==========================================================================
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : DrawFrame ( int left , int top , int width , int height )
2016-03-01 15:47:10 +00:00
{
FTexture * p ;
const gameborder_t * border = & gameinfo . Border ;
// Sanity check for incomplete gameinfo
if ( border = = NULL )
return ;
int offset = border - > offset ;
int right = left + width ;
int bottom = top + height ;
// Draw top and bottom sides.
p = TexMan [ border - > t ] ;
2018-03-26 21:16:27 +00:00
FlatFill ( left , top - p - > GetHeight ( ) , right , top , p , true ) ;
2016-03-01 15:47:10 +00:00
p = TexMan [ border - > b ] ;
2018-03-26 21:16:27 +00:00
FlatFill ( left , bottom , right , bottom + p - > GetHeight ( ) , p , true ) ;
2016-03-01 15:47:10 +00:00
// Draw left and right sides.
p = TexMan [ border - > l ] ;
2018-03-26 21:16:27 +00:00
FlatFill ( left - p - > GetWidth ( ) , top , left , bottom , p , true ) ;
2016-03-01 15:47:10 +00:00
p = TexMan [ border - > r ] ;
2018-03-26 21:16:27 +00:00
FlatFill ( right , top , right + p - > GetWidth ( ) , bottom , p , true ) ;
2016-03-01 15:47:10 +00:00
// Draw beveled corners.
2018-03-26 21:16:27 +00:00
DrawTexture ( TexMan [ border - > tl ] , left - offset , top - offset , TAG_DONE ) ;
DrawTexture ( TexMan [ border - > tr ] , left + width , top - offset , TAG_DONE ) ;
DrawTexture ( TexMan [ border - > bl ] , left - offset , top + height , TAG_DONE ) ;
DrawTexture ( TexMan [ border - > br ] , left + width , top + height , TAG_DONE ) ;
2016-03-01 15:47:10 +00:00
}
2017-02-11 15:11:48 +00:00
DEFINE_ACTION_FUNCTION ( _Screen , DrawFrame )
{
PARAM_PROLOGUE ;
PARAM_INT ( x ) ;
PARAM_INT ( y ) ;
PARAM_INT ( w ) ;
PARAM_INT ( h ) ;
2018-03-26 21:16:27 +00:00
screen - > DrawFrame ( x , y , w , h ) ;
2017-02-11 15:11:48 +00:00
return 0 ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
2018-03-26 21:16:27 +00:00
// screen->DrawBorder
2016-03-01 15:47:10 +00:00
//
//==========================================================================
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : DrawBorder ( int x1 , int y1 , int x2 , int y2 )
2016-03-01 15:47:10 +00:00
{
FTextureID picnum ;
if ( level . info ! = NULL & & level . info - > BorderTexture . Len ( ) ! = 0 )
{
2018-03-25 18:26:16 +00:00
picnum = TexMan . CheckForTexture ( level . info - > BorderTexture , ETextureType : : Flat ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2018-03-25 18:26:16 +00:00
picnum = TexMan . CheckForTexture ( gameinfo . BorderFlat , ETextureType : : Flat ) ;
2016-03-01 15:47:10 +00:00
}
if ( picnum . isValid ( ) )
{
2018-03-26 21:16:27 +00:00
FlatFill ( x1 , y1 , x2 , y2 , TexMan ( picnum ) ) ;
2016-03-01 15:47:10 +00:00
}
else
{
2018-03-26 21:16:27 +00:00
Clear ( x1 , y1 , x2 , y2 , 0 , 0 ) ;
2016-03-01 15:47:10 +00:00
}
}
//==========================================================================
//
// R_DrawViewBorder
//
// Draws the border around the view for different size windows
//
//==========================================================================
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : DrawViewBorder ( void )
2016-03-01 15:47:10 +00:00
{
2018-03-26 21:16:27 +00:00
if ( viewwidth = = Width )
2016-03-01 15:47:10 +00:00
{
return ;
}
2018-03-26 21:16:27 +00:00
DrawBorder ( 0 , 0 , Width , viewwindowy ) ;
DrawBorder ( 0 , viewwindowy , viewwindowx , viewheight + viewwindowy ) ;
DrawBorder ( viewwindowx + viewwidth , viewwindowy , Width , viewheight + viewwindowy ) ;
DrawBorder ( 0 , viewwindowy + viewheight , Width , StatusBar - > GetTopOfStatusbar ( ) ) ;
2016-03-01 15:47:10 +00:00
2018-03-26 21:16:27 +00:00
DrawFrame ( viewwindowx , viewwindowy , viewwidth , viewheight ) ;
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// R_RefreshViewBorder
//
// Draws the border around the player view, if needed.
//
//==========================================================================
2018-03-26 21:16:27 +00:00
void DFrameBuffer : : RefreshViewBorder ( )
2016-03-01 15:47:10 +00:00
{
if ( setblocks < 10 )
{
2018-04-02 22:50:40 +00:00
DrawViewBorder ( ) ;
2016-03-01 15:47:10 +00:00
}
}
2018-05-05 09:20:37 +00:00
//==========================================================================
//
// Draws a blend over the entire view
//
//==========================================================================
void DFrameBuffer : : DrawBlend ( sector_t * viewsector )
{
float blend [ 4 ] = { 0 , 0 , 0 , 0 } ;
PalEntry blendv = 0 ;
float extra_red ;
float extra_green ;
float extra_blue ;
player_t * player = nullptr ;
bool fullbright = false ;
if ( players [ consoleplayer ] . camera ! = nullptr )
{
player = players [ consoleplayer ] . camera - > player ;
2018-05-06 00:31:58 +00:00
if ( player )
fullbright = ( player - > fixedcolormap ! = NOFIXEDCOLORMAP | | player - > extralight = = INT_MIN | | player - > fixedlightlevel ! = - 1 ) ;
2018-05-05 09:20:37 +00:00
}
// don't draw sector based blends when any fullbright screen effect is active.
if ( ! fullbright )
{
2018-06-19 09:20:36 +00:00
const auto & vpp = r_viewpoint . Pos ;
2018-05-05 09:20:37 +00:00
if ( ! viewsector - > e - > XFloor . ffloors . Size ( ) )
{
if ( viewsector - > GetHeightSec ( ) )
{
auto s = viewsector - > heightsec ;
2018-06-19 09:20:36 +00:00
blendv = s - > floorplane . PointOnSide ( vpp ) < 0 ? s - > bottommap : s - > ceilingplane . PointOnSide ( vpp ) < 0 ? s - > topmap : s - > midmap ;
2018-05-05 09:20:37 +00:00
}
}
else
{
TArray < lightlist_t > & lightlist = viewsector - > e - > XFloor . lightlist ;
for ( unsigned int i = 0 ; i < lightlist . Size ( ) ; i + + )
{
double lightbottom ;
if ( i < lightlist . Size ( ) - 1 )
2018-06-19 09:20:36 +00:00
lightbottom = lightlist [ i + 1 ] . plane . ZatPoint ( vpp ) ;
2018-05-05 09:20:37 +00:00
else
2018-06-19 09:20:36 +00:00
lightbottom = viewsector - > floorplane . ZatPoint ( vpp ) ;
2018-05-05 09:20:37 +00:00
2018-06-19 09:20:36 +00:00
if ( lightbottom < vpp . Z & & ( ! lightlist [ i ] . caster | | ! ( lightlist [ i ] . caster - > flags & FF_FADEWALLS ) ) )
2018-05-05 09:20:37 +00:00
{
// 3d floor 'fog' is rendered as a blending value
blendv = lightlist [ i ] . blend ;
// If this is the same as the sector's it doesn't apply!
if ( blendv = = viewsector - > Colormap . FadeColor ) blendv = 0 ;
// a little hack to make this work for Legacy maps.
if ( blendv . a = = 0 & & blendv ! = 0 ) blendv . a = 128 ;
break ;
}
}
}
if ( blendv . a = = 0 & & V_IsTrueColor ( ) ) // The paletted software renderer uses the original colormap as this frame's palette, but in true color that isn't doable.
{
blendv = R_BlendForColormap ( blendv ) ;
}
if ( blendv . a = = 255 )
{
extra_red = blendv . r / 255.0f ;
extra_green = blendv . g / 255.0f ;
extra_blue = blendv . b / 255.0f ;
// If this is a multiplicative blend do it separately and add the additive ones on top of it.
// black multiplicative blends are ignored
if ( extra_red | | extra_green | | extra_blue )
{
screen - > Dim ( blendv , 1 , 0 , 0 , screen - > GetWidth ( ) , screen - > GetHeight ( ) , & LegacyRenderStyles [ STYLE_Multiply ] ) ;
}
blendv = 0 ;
}
else if ( blendv . a )
{
// [Nash] allow user to set blend intensity
int cnt = blendv . a ;
cnt = ( int ) ( cnt * underwater_fade_scalar ) ;
V_AddBlend ( blendv . r / 255.f , blendv . g / 255.f , blendv . b / 255.f , cnt / 255.0f , blend ) ;
}
}
2018-06-17 05:57:29 +00:00
else if ( player & & player - > fixedlightlevel ! = - 1 & & player - > fixedcolormap = = NOFIXEDCOLORMAP )
2018-06-16 11:47:24 +00:00
{
// Draw fixedlightlevel effects as a 2D overlay. The hardware renderer just processes such a scene fullbright without any lighting.
auto torchtype = PClass : : FindActor ( NAME_PowerTorch ) ;
auto litetype = PClass : : FindActor ( NAME_PowerLightAmp ) ;
PalEntry color = 0xffffffff ;
for ( AInventory * in = player - > mo - > Inventory ; in ; in = in - > Inventory )
{
// Need special handling for light amplifiers
if ( in - > IsKindOf ( torchtype ) )
{
// The software renderer already bakes the torch flickering into its output, so this must be omitted here.
float r = vid_rendermode < 4 ? 1.f : ( 0.8f + ( 7 - player - > fixedlightlevel ) / 70.0f ) ;
if ( r > 1.0f ) r = 1.0f ;
int rr = ( int ) ( r * 255 ) ;
int b = rr ;
if ( gl_enhanced_nightvision ) b = b * 3 / 4 ;
color = PalEntry ( 255 , rr , rr , b ) ;
}
else if ( in - > IsKindOf ( litetype ) )
{
if ( gl_enhanced_nightvision )
{
color = PalEntry ( 255 , 104 , 255 , 104 ) ;
}
}
}
if ( color ! = 0xffffffff )
{
screen - > Dim ( color , 1 , 0 , 0 , screen - > GetWidth ( ) , screen - > GetHeight ( ) , & LegacyRenderStyles [ STYLE_Multiply ] ) ;
}
}
2018-05-05 09:20:37 +00:00
if ( player )
{
V_AddPlayerBlend ( player , blend , 0.5 , 175 ) ;
}
if ( players [ consoleplayer ] . camera ! = NULL )
{
// except for fadeto effects
player_t * player = ( players [ consoleplayer ] . camera - > player ! = NULL ) ? players [ consoleplayer ] . camera - > player : & players [ consoleplayer ] ;
V_AddBlend ( player - > BlendR , player - > BlendG , player - > BlendB , player - > BlendA , blend ) ;
}
2018-06-30 17:27:04 +00:00
const float br = clamp ( blend [ 0 ] * 255.f , 0.f , 255.f ) ;
const float bg = clamp ( blend [ 1 ] * 255.f , 0.f , 255.f ) ;
const float bb = clamp ( blend [ 2 ] * 255.f , 0.f , 255.f ) ;
const PalEntry bcolor ( 255 , uint8_t ( br ) , uint8_t ( bg ) , uint8_t ( bb ) ) ;
screen - > Dim ( bcolor , blend [ 3 ] , 0 , 0 , screen - > GetWidth ( ) , screen - > GetHeight ( ) ) ;
2018-05-05 09:20:37 +00:00
}