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 .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
*/
2017-02-13 16:32:52 +00:00
// #define NO_SWRENDER // set this if you want to exclude the software renderer. Without the software renderer software canvas drawing does nothing.
2016-03-01 15:47:10 +00:00
# include <stdio.h>
# include <stdarg.h>
# include "doomtype.h"
# include "v_video.h"
# include "m_swap.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
# ifndef NO_SWRENDER
2017-02-13 16:32:52 +00:00
# include "swrenderer/r_swcanvas.h"
2016-03-01 15:47:10 +00:00
# endif
# include "r_data/r_translate.h"
# include "doomstat.h"
# include "v_palette.h"
# include "gi.h"
# include "g_level.h"
# include "st_stuff.h"
# include "sbar.h"
# include "i_system.h"
# include "i_video.h"
# include "templates.h"
# include "d_net.h"
# include "colormatcher.h"
# include "r_data/colormaps.h"
2017-01-08 17:45:30 +00:00
# include "g_levellocals.h"
2017-03-10 01:22:42 +00:00
# include "textures.h"
2017-04-12 23:12:04 +00:00
# include "vm.h"
2016-03-01 15:47:10 +00:00
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 ;
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-07-15 09:22:26 +00:00
// Dummy ZScript arbitrary textured shape drawing
2019-06-10 18:07:47 +00:00
IMPLEMENT_CLASS ( DShape2DTransform , false , false )
DEFINE_ACTION_FUNCTION ( DShape2DTransform , Clear )
{
PARAM_SELF_PROLOGUE ( DShape2DTransform ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DShape2DTransform , Rotate )
{
PARAM_SELF_PROLOGUE ( DShape2DTransform ) ;
PARAM_FLOAT ( angle ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DShape2DTransform , Scale )
{
PARAM_SELF_PROLOGUE ( DShape2DTransform ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DShape2DTransform , Translate )
{
PARAM_SELF_PROLOGUE ( DShape2DTransform ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
return 0 ;
}
2018-07-15 09:22:26 +00:00
IMPLEMENT_CLASS ( DShape2D , false , false )
2019-06-10 18:07:47 +00:00
DEFINE_ACTION_FUNCTION ( DShape2D , SetTransform )
{
PARAM_SELF_PROLOGUE ( DShape2D ) ;
PARAM_OBJECT ( transform , DShape2DTransform ) ;
return 0 ;
}
2018-07-15 09:22:26 +00:00
DEFINE_ACTION_FUNCTION ( DShape2D , Clear )
{
PARAM_SELF_PROLOGUE ( DShape2D ) ;
2018-11-17 09:03:40 +00:00
PARAM_INT ( which ) ;
2018-07-15 09:22:26 +00:00
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DShape2D , PushVertex )
{
PARAM_SELF_PROLOGUE ( DShape2D ) ;
PARAM_FLOAT ( x ) ;
PARAM_FLOAT ( y ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DShape2D , PushCoord )
{
PARAM_SELF_PROLOGUE ( DShape2D ) ;
PARAM_FLOAT ( u ) ;
PARAM_FLOAT ( v ) ;
return 0 ;
}
DEFINE_ACTION_FUNCTION ( DShape2D , PushTriangle )
{
PARAM_SELF_PROLOGUE ( DShape2D ) ;
PARAM_INT ( a ) ;
PARAM_INT ( b ) ;
PARAM_INT ( c ) ;
return 0 ;
}
2016-04-11 08:46:30 +00:00
void DCanvas : : 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
}
2017-02-05 15:47:33 +00:00
int ListGetInt ( VMVa_List & tags ) ;
2017-02-04 21:09:49 +00:00
void DCanvas : : DrawTexture ( FTexture * img , double x , double y , VMVa_List & args )
{
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 ) ;
2018-11-18 18:31:13 +00:00
PARAM_VA_POINTER ( va_reginfo ) // Get the hidden type information array
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 ) ] ;
2018-11-18 20:18:15 +00:00
VMVa_List args = { param + 4 , 0 , numparam - 5 , va_reginfo + 4 } ;
2017-02-04 21:09:49 +00:00
screen - > DrawTexture ( tex , x , y , args ) ;
return 0 ;
}
2016-04-09 10:59:50 +00:00
void DCanvas : : DrawTextureParms ( FTexture * img , DrawParms & parms )
2016-03-01 15:47:10 +00:00
{
# ifndef NO_SWRENDER
2017-02-13 16:32:52 +00:00
SWCanvas : : DrawTexture ( this , img , parms ) ;
# endif
2016-03-01 15:47:10 +00:00
if ( ticdup ! = 0 & & menuactive = = MENU_Off )
{
NetUpdate ( ) ;
}
}
2018-07-15 09:22:26 +00:00
//==========================================================================
//
// Dummy ZScript arbitrary textured shape drawing functions
//
//==========================================================================
void DCanvas : : DrawShape ( FTexture * img , DShape2D * shape , int tags_first , . . . )
{
}
void DCanvas : : DrawShape ( FTexture * img , DShape2D * shape , VMVa_List & args )
{
}
DEFINE_ACTION_FUNCTION ( _Screen , DrawShape )
{
PARAM_PROLOGUE ;
PARAM_INT ( texid ) ;
PARAM_BOOL ( animate ) ;
PARAM_POINTER ( shape , DShape2D ) ;
2018-11-18 18:31:13 +00:00
PARAM_VA_POINTER ( va_reginfo ) // Get the hidden type information array
2018-07-15 09:22:26 +00:00
return 0 ;
}
//==========================================================================
//
// Clipping rect
//
//==========================================================================
2017-03-28 11:06:24 +00:00
void DCanvas : : SetClipRect ( int x , int y , int w , int h )
{
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 ;
}
2017-03-28 11:06:24 +00:00
void DCanvas : : GetClipRect ( int * x , int * y , int * w , int * h )
{
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
2016-04-09 18:47:54 +00:00
bool DCanvas : : SetTextureParms ( DrawParms * parms , FTexture * img , double xx , double yy ) const
{
if ( img ! = NULL )
{
parms - > x = xx ;
parms - > y = yy ;
parms - > texwidth = img - > GetScaledWidthDouble ( ) ;
parms - > texheight = img - > GetScaledHeightDouble ( ) ;
if ( parms - > top = = INT_MAX | | parms - > fortext )
{
parms - > top = img - > GetScaledTopOffset ( ) ;
}
if ( parms - > left = = INT_MAX | | parms - > fortext )
{
parms - > left = img - > GetScaledLeftOffset ( ) ;
}
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 :
2020-03-15 08:27:02 +00:00
case DTA_FullscreenEx :
{
double aspect ;
double srcwidth = img - > GetScaledWidthDouble ( ) ;
double srcheight = img - > GetScaledHeightDouble ( ) ;
int autoaspect = parms - > fsscalemode ;
2020-04-19 11:49:10 +00:00
if ( srcheight = = 200 ) aspect = srcwidth / 240. ;
else if ( srcheight = = 400 ) aspect = srcwidth / 480 ;
else aspect = srcwidth / srcheight ;
2016-04-09 18:47:54 +00:00
parms - > x = parms - > y = 0 ;
2020-03-15 08:27:02 +00:00
parms - > keepratio = true ;
auto screenratio = ActiveRatio ( GetWidth ( ) , GetHeight ( ) ) ;
if ( autoaspect = = 3 )
{
2020-06-06 08:19:02 +00:00
if ( screenratio > = aspect | | aspect < 1.4 ) autoaspect = 1 ; // screen is wider than the image -> pillarbox it. 4:3 images must also be pillarboxed if the screen is taller than the image
2020-03-15 08:27:02 +00:00
else if ( screenratio > 1.32 ) autoaspect = 2 ; // on anything 4:3 and wider crop the sides of the image.
else
{
// special case: Crop image to 4:3 and then letterbox this. This avoids too much cropping on narrow windows.
double width4_3 = srcheight * ( 4. / 3. ) ;
parms - > destwidth = ( double ) GetWidth ( ) * srcwidth / width4_3 ;
parms - > destheight = GetHeight ( ) * screenratio * ( 3. / 4. ) ; // use 4:3 for the image
parms - > y = ( GetHeight ( ) - parms - > destheight ) / 2 ;
parms - > x = - ( srcwidth - width4_3 ) / 2 ;
return false ; // Do not call VirtualToRealCoords for this!
}
}
if ( ( screenratio > aspect ) ^ ( autoaspect = = 2 ) )
{
// pillarboxed or vertically cropped (i.e. scale to height)
parms - > destheight = GetHeight ( ) ;
parms - > destwidth = GetWidth ( ) * aspect / screenratio ;
parms - > x = ( GetWidth ( ) - parms - > destwidth ) / 2 ;
}
else
{
// letterboxed or horizontally cropped (i.e. scale to width)
parms - > destwidth = GetWidth ( ) ;
parms - > destheight = GetHeight ( ) * screenratio / aspect ;
parms - > y = ( GetHeight ( ) - parms - > destheight ) / 2 ;
}
return false ; // Do not call VirtualToRealCoords for this!
}
2016-04-09 18:47:54 +00:00
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 ;
}
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
}
// These two options are only being used by the D3D version of the HUD weapon drawer, they serve no purpose anywhere else.
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-05 20:54:09 +00:00
static inline FColormapStyle * ListGetColormapStyle ( Va_List & tags )
2017-02-04 12:11:12 +00:00
{
2017-02-05 20:54:09 +00:00
return va_arg ( tags . list , FColormapStyle * ) ;
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
{
2018-11-18 18:31:13 +00:00
if ( tags . reginfo [ tags . curindex ] = = REGT_INT )
2017-02-10 12:20:19 +00:00
{
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 )
{
2018-11-18 18:31:13 +00:00
if ( tags . curindex < tags . numargs )
2017-02-04 21:09:49 +00:00
{
2018-11-18 18:31:13 +00:00
if ( tags . reginfo [ tags . curindex ] = = REGT_FLOAT )
{
return tags . args [ tags . curindex + + ] . f ;
}
if ( tags . reginfo [ tags . curindex ] = = REGT_INT )
{
return tags . args [ tags . curindex + + ] . i ;
}
ThrowAbortException ( X_OTHER , " Invalid parameter in draw function, float expected " ) ;
2017-02-04 21:09:49 +00:00
}
return 0 ;
}
static inline FSpecialColormap * ListGetSpecialColormap ( VMVa_List & tags )
{
ThrowAbortException ( X_OTHER , " Invalid tag in draw function " ) ;
return nullptr ;
}
static inline FColormapStyle * ListGetColormapStyle ( VMVa_List & tags )
{
ThrowAbortException ( X_OTHER , " Invalid tag in draw function " ) ;
return nullptr ;
}
template < class T >
2017-03-09 19:19:55 +00:00
bool DCanvas : : 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 ;
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 ;
parms - > colormapstyle = NULL ;
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 ;
2019-04-13 10:17:38 +00:00
parms - > monospace = EMonospacing : : MOff ;
parms - > spacing = 0 ;
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 :
2020-03-15 08:27:02 +00:00
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 ;
2020-03-15 08:27:02 +00:00
parms - > fsscalemode = ( uint8_t ) gameinfo . fullscreenautoaspect ;
parms - > virtWidth = img - > GetScaledWidthDouble ( ) ;
parms - > virtHeight = img - > GetScaledHeightDouble ( ) ;
}
break ;
case DTA_FullscreenEx :
intval = ListGetInt ( tags ) ;
if ( intval > = 0 & & intval < = 3 )
{
assert ( fortext = = false ) ;
if ( img = = NULL ) return false ;
parms - > cleanmode = DTA_Fullscreen ;
parms - > fsscalemode = ( uint8_t ) intval ;
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 ;
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 ;
case DTA_ColormapStyle :
2017-02-04 12:11:12 +00:00
parms - > colormapstyle = ListGetColormapStyle ( 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 ;
2019-04-13 10:17:38 +00:00
case DTA_Monospace :
parms - > monospace = ListGetInt ( tags ) ;
break ;
case DTA_Spacing :
parms - > spacing = ListGetInt ( tags ) ;
break ;
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.
2017-03-09 19:19:55 +00:00
template bool DCanvas : : ParseDrawTextureTags < Va_List > ( FTexture * img , double x , double y , uint32_t tag , Va_List & tags , DrawParms * parms , bool fortext ) const ;
template bool DCanvas : : ParseDrawTextureTags < VMVa_List > ( FTexture * img , double x , double y , uint32_t tag , VMVa_List & tags , DrawParms * parms , bool fortext ) const ;
2016-03-01 15:47:10 +00:00
void DCanvas : : VirtualToRealCoords ( double & x , double & y , double & w , double & h ,
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 ) ;
2018-11-17 09:03:40 +00:00
PARAM_BOOL ( vbottom ) ;
PARAM_BOOL ( handleaspect ) ;
2017-03-22 13:59:12 +00:00
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 ) ;
}
2016-03-01 15:47:10 +00:00
void DCanvas : : VirtualToRealCoordsInt ( int & x , int & y , int & w , int & h ,
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 ;
}
void DCanvas : : FillBorder ( FTexture * img )
{
2016-09-12 13:51:50 +00:00
float myratio = ActiveRatio ( Width , Height ) ;
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-11-02 12:04:37 +00:00
void DCanvas : : 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
{
2017-02-13 16:32:52 +00:00
# ifndef NO_SWRENDER
2018-11-02 12:04:37 +00:00
SWCanvas : : DrawLine ( this , x0 , y0 , x1 , y1 , palColor , realcolor , alpha ) ;
2017-02-13 16:32:52 +00:00
# endif
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-11-17 09:03:40 +00:00
PARAM_INT ( alpha ) ;
2017-08-03 00:20:55 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2019-10-26 16:42:24 +00:00
screen - > DrawLine ( x0 , y0 , x1 , y1 , - 1 , color | MAKEARGB ( 255 , 0 , 0 , 0 ) , alpha ) ;
2017-08-03 00:20:55 +00:00
return 0 ;
}
2018-11-02 12:04:37 +00:00
void DCanvas : : DrawThickLine ( int x0 , int y0 , int x1 , int y1 , double thickness , uint32_t realcolor , uint8_t alpha ) {
2018-09-01 22:29:11 +00:00
# ifndef NO_SWRENDER
2018-11-02 12:04:37 +00:00
SWCanvas : : DrawLine ( this , x0 , y0 , x1 , y1 , - 1 , realcolor , alpha ) ;
2018-09-01 22:29:11 +00:00
# endif
}
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-11-17 09:03:40 +00:00
PARAM_INT ( alpha ) ;
2018-09-01 22:29:11 +00:00
if ( ! screen - > HasBegun2D ( ) ) ThrowAbortException ( X_OTHER , " Attempt to draw to screen outside a draw function " ) ;
2018-11-02 12:04:37 +00:00
screen - > DrawLine ( x0 , y0 , x1 , y1 , - 1 , color , alpha ) ;
2018-09-01 22:29:11 +00:00
return 0 ;
}
2017-03-09 18:31:45 +00:00
void DCanvas : : DrawPixel ( int x , int y , int palColor , uint32_t realcolor )
2016-03-01 15:47:10 +00:00
{
2017-02-13 16:32:52 +00:00
# ifndef NO_SWRENDER
SWCanvas : : DrawPixel ( this , x , y , palColor , realcolor ) ;
# endif
2016-03-01 15:47:10 +00:00
}
//==========================================================================
//
// DCanvas :: Clear
//
// Set an area to a specified color.
//
//==========================================================================
2017-03-28 11:06:24 +00:00
void DCanvas : : DoClear ( int left , int top , int right , int bottom , int palcolor , uint32_t color )
2016-03-01 15:47:10 +00:00
{
2017-02-13 16:32:52 +00:00
# ifndef NO_SWRENDER
if ( palcolor < 0 & & APART ( color ) ! = 255 )
2016-03-01 15:47:10 +00:00
{
2017-02-13 16:32:52 +00:00
Dim ( color , APART ( color ) / 255.f , left , top , right - left , bottom - top ) ;
2016-05-31 03:31:32 +00:00
}
else
{
2017-02-13 16:32:52 +00:00
SWCanvas : : Clear ( this , left , top , right , bottom , palcolor , color ) ;
2016-03-01 15:47:10 +00:00
}
2017-02-13 16:32:52 +00:00
# endif
2016-03-01 15:47:10 +00:00
}
2017-03-28 11:06:24 +00:00
void DCanvas : : Clear ( int left , int top , int right , int bottom , int palcolor , uint32_t color )
{
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 ;
}
DoClear ( left , top , right , bottom , palcolor , color ) ;
}
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 ) ;
2018-11-17 09:03:40 +00:00
PARAM_INT ( 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.
//
//==========================================================================
2017-03-28 11:06:24 +00:00
void DCanvas : : DoDim ( PalEntry color , float damount , int x1 , int y1 , int w , int h )
2017-02-13 16:32:52 +00:00
{
# ifndef NO_SWRENDER
SWCanvas : : Dim ( this , color , damount , x1 , y1 , w , h ) ;
# endif
}
2017-03-28 11:06:24 +00:00
void DCanvas : : Dim ( PalEntry color , float damount , int x1 , int y1 , int w , int h )
{
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 ;
}
DoDim ( color , damount , x1 , y1 , w , h ) ;
}
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.
//
//==========================================================================
void DCanvas : : 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 ,
2017-03-15 15:47:42 +00:00
const FColormap & colormap , PalEntry flatcolor , int lightlevel , int bottomclip )
2016-03-01 15:47:10 +00:00
{
# ifndef NO_SWRENDER
2017-02-13 16:32:52 +00:00
SWCanvas : : FillSimplePoly ( this , tex , points , npoints , originx , originy , scalex , scaley , rotation , colormap , flatcolor , lightlevel , bottomclip ) ;
2016-03-01 15:47:10 +00:00
# endif
}
/********************************/
/* */
/* Other miscellaneous routines */
/* */
/********************************/
//
// V_DrawBlock
// Draw a linear block of pixels into the view buffer.
//
2017-03-09 18:54:41 +00:00
void DCanvas : : DrawBlock ( int x , int y , int _width , int _height , const uint8_t * src ) const
2016-03-01 15:47:10 +00:00
{
2016-05-31 07:36:18 +00:00
if ( IsBgra ( ) )
2016-05-31 03:31:32 +00:00
return ;
2016-03-01 15:47:10 +00:00
int srcpitch = _width ;
int destpitch ;
2017-03-09 18:54:41 +00:00
uint8_t * dest ;
2016-03-01 15:47:10 +00:00
if ( ClipBox ( x , y , _width , _height , src , srcpitch ) )
{
return ; // Nothing to draw
}
destpitch = Pitch ;
dest = Buffer + y * Pitch + x ;
do
{
memcpy ( dest , src , _width ) ;
src + = srcpitch ;
dest + = destpitch ;
} while ( - - _height ) ;
}
//
// V_GetBlock
// Gets a linear block of pixels from the view buffer.
//
2017-03-09 18:54:41 +00:00
void DCanvas : : GetBlock ( int x , int y , int _width , int _height , uint8_t * dest ) const
2016-03-01 15:47:10 +00:00
{
2016-05-31 07:36:18 +00:00
if ( IsBgra ( ) )
2016-05-31 03:31:32 +00:00
return ;
2017-03-09 18:54:41 +00:00
const uint8_t * src ;
2016-03-01 15:47:10 +00:00
# ifdef RANGECHECK
if ( x < 0
| | x + _width > Width
| | y < 0
| | y + _height > Height )
{
I_Error ( " Bad V_GetBlock " ) ;
}
# endif
src = Buffer + y * Pitch + x ;
while ( _height - - )
{
memcpy ( dest , src , _width ) ;
src + = Pitch ;
dest + = _width ;
}
}
// Returns true if the box was completely clipped. False otherwise.
2017-03-09 18:54:41 +00:00
bool DCanvas : : ClipBox ( int & x , int & y , int & w , int & h , const uint8_t * & src , const int srcpitch ) const
2016-03-01 15:47:10 +00:00
{
if ( x > = Width | | y > = Height | | x + w < = 0 | | y + h < = 0 )
{ // Completely clipped off screen
return true ;
}
if ( x < 0 ) // clip left edge
{
src - = x ;
w + = x ;
x = 0 ;
}
if ( x + w > Width ) // clip right edge
{
w = Width - x ;
}
if ( y < 0 ) // clip top edge
{
src - = y * srcpitch ;
h + = y ;
y = 0 ;
}
if ( y + h > Height ) // clip bottom edge
{
h = Height - y ;
}
return false ;
}
//==========================================================================
//
// V_SetBorderNeedRefresh
//
// Flag the border as in need of updating. (Probably because something that
// was on top of it has changed.
//
//==========================================================================
void V_SetBorderNeedRefresh ( )
{
if ( screen ! = NULL )
{
BorderNeedRefresh = screen - > GetPageCount ( ) ;
}
}
//==========================================================================
//
// 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.
//
//==========================================================================
void V_DrawFrame ( int left , int top , int width , int height )
{
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 ] ;
screen - > FlatFill ( left , top - p - > GetHeight ( ) , right , top , p , true ) ;
p = TexMan [ border - > b ] ;
screen - > FlatFill ( left , bottom , right , bottom + p - > GetHeight ( ) , p , true ) ;
// Draw left and right sides.
p = TexMan [ border - > l ] ;
screen - > FlatFill ( left - p - > GetWidth ( ) , top , left , bottom , p , true ) ;
p = TexMan [ border - > r ] ;
screen - > FlatFill ( right , top , right + p - > GetWidth ( ) , bottom , p , true ) ;
// Draw beveled corners.
screen - > DrawTexture ( TexMan [ border - > tl ] , left - offset , top - offset , TAG_DONE ) ;
screen - > DrawTexture ( TexMan [ border - > tr ] , left + width , top - offset , TAG_DONE ) ;
screen - > DrawTexture ( TexMan [ border - > bl ] , left - offset , top + height , TAG_DONE ) ;
screen - > DrawTexture ( TexMan [ border - > br ] , left + width , top + height , TAG_DONE ) ;
}
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 ) ;
V_DrawFrame ( x , y , w , h ) ;
return 0 ;
}
2016-03-01 15:47:10 +00:00
//==========================================================================
//
// V_DrawBorder
//
//==========================================================================
void V_DrawBorder ( int x1 , int y1 , int x2 , int y2 )
{
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 ( ) )
{
screen - > FlatFill ( x1 , y1 , x2 , y2 , TexMan ( picnum ) ) ;
}
else
{
screen - > Clear ( x1 , y1 , x2 , y2 , 0 , 0 ) ;
}
}
//==========================================================================
//
// R_DrawViewBorder
//
// Draws the border around the view for different size windows
//
//==========================================================================
int BorderNeedRefresh ;
static void V_DrawViewBorder ( void )
{
if ( viewwidth = = SCREENWIDTH )
{
return ;
}
V_DrawBorder ( 0 , 0 , SCREENWIDTH , viewwindowy ) ;
V_DrawBorder ( 0 , viewwindowy , viewwindowx , viewheight + viewwindowy ) ;
V_DrawBorder ( viewwindowx + viewwidth , viewwindowy , SCREENWIDTH , viewheight + viewwindowy ) ;
2017-03-29 17:23:40 +00:00
V_DrawBorder ( 0 , viewwindowy + viewheight , SCREENWIDTH , StatusBar - > GetTopOfStatusbar ( ) ) ;
2016-03-01 15:47:10 +00:00
V_DrawFrame ( viewwindowx , viewwindowy , viewwidth , viewheight ) ;
}
//==========================================================================
//
// R_DrawTopBorder
//
// Draws the top border around the view for different size windows
//
//==========================================================================
static void V_DrawTopBorder ( )
{
FTexture * p ;
int offset ;
if ( viewwidth = = SCREENWIDTH )
return ;
offset = gameinfo . Border . offset ;
if ( viewwindowy < 34 )
{
V_DrawBorder ( 0 , 0 , viewwindowx , 34 ) ;
V_DrawBorder ( viewwindowx , 0 , viewwindowx + viewwidth , viewwindowy ) ;
V_DrawBorder ( viewwindowx + viewwidth , 0 , SCREENWIDTH , 34 ) ;
p = TexMan ( gameinfo . Border . t ) ;
screen - > FlatFill ( viewwindowx , viewwindowy - p - > GetHeight ( ) ,
viewwindowx + viewwidth , viewwindowy , p , true ) ;
p = TexMan ( gameinfo . Border . l ) ;
screen - > FlatFill ( viewwindowx - p - > GetWidth ( ) , viewwindowy ,
viewwindowx , 35 , p , true ) ;
p = TexMan ( gameinfo . Border . r ) ;
screen - > FlatFill ( viewwindowx + viewwidth , viewwindowy ,
viewwindowx + viewwidth + p - > GetWidth ( ) , 35 , p , true ) ;
p = TexMan ( gameinfo . Border . tl ) ;
screen - > DrawTexture ( p , viewwindowx - offset , viewwindowy - offset , TAG_DONE ) ;
p = TexMan ( gameinfo . Border . tr ) ;
screen - > DrawTexture ( p , viewwindowx + viewwidth , viewwindowy - offset , TAG_DONE ) ;
}
else
{
V_DrawBorder ( 0 , 0 , SCREENWIDTH , 34 ) ;
}
}
//==========================================================================
//
// R_RefreshViewBorder
//
// Draws the border around the player view, if needed.
//
//==========================================================================
void V_RefreshViewBorder ( )
{
if ( setblocks < 10 )
{
if ( BorderNeedRefresh )
{
BorderNeedRefresh - - ;
if ( BorderTopRefresh )
{
BorderTopRefresh - - ;
}
V_DrawViewBorder ( ) ;
}
else if ( BorderTopRefresh )
{
BorderTopRefresh - - ;
V_DrawTopBorder ( ) ;
}
}
}