2020-09-06 10:44:58 +00:00
//-------------------------------------------------------------------------
/*
Copyright ( C ) 1996 , 2003 - 3 D Realms Entertainment
Copyright ( C ) 2020 - Christoph Oelckers
This file is part of Duke Nukem 3 D version 1.5 - Atomic Edition
Duke Nukem 3 D is free software ; you can redistribute it and / or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation ; either version 2
of the License , or ( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE .
See the GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 59 Temple Place - Suite 330 , Boston , MA 02111 - 1307 , USA .
Original Source : 1996 - Todd Replogle
Prepared for public release : 03 / 21 / 2003 - Charlie Wiederhold , 3 D Realms
Modifications for JonoF ' s port by Jonathon Fowler ( jf @ jonof . id . au )
*/
//-------------------------------------------------------------------------
# include "automap.h"
# include "c_dispatch.h"
# include "c_cvars.h"
# include "gstrings.h"
# include "printf.h"
2020-09-06 11:39:57 +00:00
# include "serializer.h"
2020-09-06 18:49:43 +00:00
# include "v_2ddrawer.h"
# include "earcut.hpp"
# include "buildtiles.h"
# include "d_event.h"
# include "c_bind.h"
# include "gamestate.h"
# include "gamecontrol.h"
# include "quotemgr.h"
# include "v_video.h"
# include "gamestruct.h"
2020-10-13 19:38:24 +00:00
# include "v_draw.h"
2021-03-20 11:47:51 +00:00
# include "sectorgeometry.h"
# include "gamefuncs.h"
2021-12-16 05:10:59 +00:00
# include "hw_sections.h"
2021-11-27 20:19:15 +00:00
# include "coreactor.h"
2020-09-06 18:49:43 +00:00
CVAR ( Bool , am_followplayer , true , CVAR_ARCHIVE )
CVAR ( Bool , am_rotate , true , CVAR_ARCHIVE )
2021-07-09 22:18:59 +00:00
CVAR ( Float , am_linealpha , 1.0f , CVAR_ARCHIVE )
CVAR ( Int , am_linethickness , 1 , CVAR_ARCHIVE )
2020-09-06 18:49:43 +00:00
CVAR ( Bool , am_textfont , false , CVAR_ARCHIVE )
CVAR ( Bool , am_showlabel , false , CVAR_ARCHIVE )
CVAR ( Bool , am_nameontop , false , CVAR_ARCHIVE )
2020-09-06 10:44:58 +00:00
2022-09-20 00:20:40 +00:00
static DVector2 min_bounds = { INT_MAX , 0 } ; ;
static DVector2 max_bounds = { 0 , 0 } ;
static DVector2 follow = { INT_MAX , INT_MAX } ;
static DAngle follow_a = DAngle : : fromDeg ( INT_MAX ) ;
2022-08-31 11:22:14 +00:00
static double gZoom = 0.75 ;
2022-09-20 00:20:40 +00:00
static float am_zoomdir ;
int automapMode ;
2020-09-06 10:44:58 +00:00
bool automapping ;
bool gFullMap ;
2021-11-20 23:03:56 +00:00
BitArray show2dsector ;
BitArray show2dwall ;
2020-09-06 18:49:43 +00:00
CVAR ( Color , am_twosidedcolor , 0xaaaaaa , CVAR_ARCHIVE )
CVAR ( Color , am_onesidedcolor , 0xaaaaaa , CVAR_ARCHIVE )
CVAR ( Color , am_playercolor , 0xaaaaaa , CVAR_ARCHIVE )
CVAR ( Color , am_ovtwosidedcolor , 0xaaaaaa , CVAR_ARCHIVE )
CVAR ( Color , am_ovonesidedcolor , 0xaaaaaa , CVAR_ARCHIVE )
CVAR ( Color , am_ovplayercolor , 0xaaaaaa , CVAR_ARCHIVE )
2020-09-06 10:44:58 +00:00
2020-09-06 11:39:57 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2020-09-06 18:49:43 +00:00
CCMD ( allmap )
{
if ( ! CheckCheatmode ( true , false ) )
{
gFullMap = ! gFullMap ;
Printf ( " %s \n " , GStrings ( gFullMap ? " SHOW MAP: ON " : " SHOW MAP: OFF " ) ) ;
}
}
CCMD ( togglemap )
{
if ( gamestate = = GS_LEVEL )
{
automapMode + + ;
if ( automapMode = = am_count ) automapMode = am_off ;
2021-01-02 03:46:58 +00:00
if ( isBlood ( ) & & automapMode = = am_overlay ) automapMode = am_full ; // todo: investigate if this can be re-enabled
2020-09-06 18:49:43 +00:00
}
}
CCMD ( togglefollow )
{
am_followplayer = ! am_followplayer ;
auto msg = quoteMgr . GetQuote ( am_followplayer ? 84 : 83 ) ;
if ( ! msg | | ! * msg ) msg = am_followplayer ? GStrings ( " FOLLOW MODE ON " ) : GStrings ( " FOLLOW MODE Off " ) ;
2020-09-06 21:12:47 +00:00
Printf ( PRINT_NOTIFY , " %s \n " , msg ) ;
2022-09-20 00:20:40 +00:00
if ( am_followplayer ) follow . X = INT_MAX ;
2020-09-06 18:49:43 +00:00
}
2020-09-06 21:12:47 +00:00
CCMD ( togglerotate )
{
am_rotate = ! am_rotate ;
2020-09-07 17:56:28 +00:00
auto msg = am_rotate ? GStrings ( " TXT_ROTATE_ON " ) : GStrings ( " TXT_ROTATE_OFF " ) ;
2020-09-06 21:12:47 +00:00
Printf ( PRINT_NOTIFY , " %s \n " , msg ) ;
}
2020-09-06 18:49:43 +00:00
CCMD ( am_zoom )
2020-09-06 11:39:57 +00:00
{
2020-09-06 18:49:43 +00:00
if ( argv . argc ( ) > = 2 )
{
am_zoomdir = ( float ) atof ( argv [ 1 ] ) ;
}
2020-09-06 11:39:57 +00:00
}
2020-09-06 18:49:43 +00:00
//==========================================================================
//
// AM_Responder
// Handle automap exclusive bindings.
//
//==========================================================================
bool AM_Responder ( event_t * ev , bool last )
{
if ( ev - > type = = EV_KeyDown | | ev - > type = = EV_KeyUp )
{
if ( am_followplayer )
{
// check for am_pan* and ignore in follow mode
const char * defbind = AutomapBindings . GetBind ( ev - > data1 ) ;
if ( defbind & & ! strnicmp ( defbind , " +am_pan " , 7 ) ) return false ;
}
bool res = C_DoKey ( ev , & AutomapBindings , nullptr ) ;
if ( res & & ev - > type = = EV_KeyUp & & ! last )
{
// If this is a release event we also need to check if it released a button in the main Bindings
// so that that button does not get stuck.
const char * defbind = Bindings . GetBind ( ev - > data1 ) ;
return ( ! defbind | | defbind [ 0 ] ! = ' + ' ) ; // Let G_Responder handle button releases
}
return res ;
}
return false ;
}
2020-09-06 11:39:57 +00:00
2020-09-06 10:44:58 +00:00
//---------------------------------------------------------------------------
//
2020-09-06 18:49:43 +00:00
//
2020-09-06 10:44:58 +00:00
//
2020-09-06 18:49:43 +00:00
//---------------------------------------------------------------------------
static void CalcMapBounds ( )
{
2022-09-20 00:20:40 +00:00
min_bounds = { INT_MAX , INT_MAX } ;
max_bounds = { INT_MIN , INT_MIN } ;
2020-09-06 18:49:43 +00:00
2021-12-21 08:23:39 +00:00
for ( auto & wal : wall )
2020-09-06 18:49:43 +00:00
{
// get map min and max coordinates
2022-09-20 00:20:40 +00:00
if ( wal . pos . X < min_bounds . X ) min_bounds . X = wal . pos . X ;
if ( wal . pos . Y < min_bounds . Y ) min_bounds . Y = wal . pos . Y ;
if ( wal . pos . X > max_bounds . X ) max_bounds . X = wal . pos . X ;
if ( wal . pos . Y > max_bounds . Y ) max_bounds . Y = wal . pos . Y ;
2020-09-06 18:49:43 +00:00
}
}
//---------------------------------------------------------------------------
//
//
2020-09-06 10:44:58 +00:00
//
//---------------------------------------------------------------------------
2022-09-20 00:07:15 +00:00
static void AutomapControl ( const DVector2 & cangvect )
2020-09-06 10:44:58 +00:00
{
2022-08-29 13:05:10 +00:00
static double nonsharedtimer ;
2022-10-12 17:00:29 +00:00
double ms = ( double ) screen - > FrameTime ;
2022-08-29 13:05:10 +00:00
double interval ;
2020-09-06 18:49:43 +00:00
if ( nonsharedtimer > 0 | | ms < nonsharedtimer )
2020-09-06 10:44:58 +00:00
{
2020-09-06 18:49:43 +00:00
interval = ms - nonsharedtimer ;
}
else
{
interval = 0 ;
}
2021-05-11 23:50:41 +00:00
nonsharedtimer = ms ;
2020-09-06 18:49:43 +00:00
if ( System_WantGuiCapture ( ) )
return ;
if ( automapMode ! = am_off )
{
if ( am_zoomdir > 0 )
{
2022-08-29 13:05:10 +00:00
gZoom = gZoom * am_zoomdir ;
2020-09-06 18:49:43 +00:00
}
else if ( am_zoomdir < 0 )
{
2022-08-29 13:05:10 +00:00
gZoom = gZoom / - am_zoomdir ;
2020-09-06 18:49:43 +00:00
}
am_zoomdir = 0 ;
2022-09-20 00:20:40 +00:00
double j = interval * ( 35. / 65536. ) / gZoom ;
gZoom + = ( buttonMap . ButtonDown ( gamefunc_Enlarge_Screen ) - buttonMap . ButtonDown ( gamefunc_Shrink_Screen ) ) * j * max ( gZoom , 0.25 ) ;
2022-08-31 11:22:14 +00:00
gZoom = clamp ( gZoom , 0.05 , 2. ) ;
2020-09-06 21:12:47 +00:00
if ( ! am_followplayer )
{
2022-09-20 00:20:40 +00:00
const double zoomspeed = j * 512. ;
const auto panhorz = buttonMap . ButtonDown ( gamefunc_AM_PanRight ) - buttonMap . ButtonDown ( gamefunc_AM_PanLeft ) ;
const auto panvert = buttonMap . ButtonDown ( gamefunc_AM_PanUp ) - buttonMap . ButtonDown ( gamefunc_AM_PanDown ) ;
2020-09-06 18:49:43 +00:00
2022-09-20 00:20:40 +00:00
if ( min_bounds . X = = INT_MAX ) CalcMapBounds ( ) ;
2020-09-06 18:49:43 +00:00
2022-09-20 00:07:15 +00:00
follow = clamp ( follow + DVector2 ( panvert , panhorz ) . Rotated ( cangvect . X , cangvect . Y ) * zoomspeed , min_bounds , max_bounds ) ;
2020-09-06 21:12:47 +00:00
}
2020-09-06 10:44:58 +00:00
}
}
2020-09-06 18:49:43 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void SerializeAutomap ( FSerializer & arc )
{
if ( arc . BeginObject ( " automap " ) )
{
arc ( " automapping " , automapping )
( " fullmap " , gFullMap )
2021-11-20 23:24:47 +00:00
( " mappedsectors " , show2dsector )
( " mappedwalls " , show2dwall )
2020-09-06 18:49:43 +00:00
. EndObject ( ) ;
}
}
2020-09-06 10:44:58 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
void ClearAutomap ( )
{
2020-09-06 18:49:43 +00:00
show2dsector . Zero ( ) ;
show2dwall . Zero ( ) ;
2022-09-20 00:20:40 +00:00
min_bounds . X = INT_MAX ;
2020-09-06 10:44:58 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2021-12-02 00:05:07 +00:00
void MarkSectorSeen ( sectortype * sec )
2020-09-06 10:44:58 +00:00
{
2021-12-02 00:05:07 +00:00
if ( sec )
2020-09-06 10:44:58 +00:00
{
2022-11-15 11:03:44 +00:00
show2dsector . Set ( sectindex ( sec ) ) ;
2022-11-15 14:24:17 +00:00
for ( auto & wal : sec - > walls )
2020-09-06 10:44:58 +00:00
{
2021-12-02 00:05:07 +00:00
if ( ! wal . twoSided ( ) ) continue ;
2021-12-18 14:16:31 +00:00
const auto bits = ( CSTAT_WALL_BLOCK | CSTAT_WALL_MASKED | CSTAT_WALL_1WAY | CSTAT_WALL_BLOCK_HITSCAN ) ;
if ( wal . cstat & bits ) continue ;
if ( wal . nextWall ( ) - > cstat & bits ) continue ;
2021-12-02 00:05:07 +00:00
auto osec = wal . nextSector ( ) ;
if ( osec - > lotag = = 32767 ) continue ;
2022-08-20 17:35:24 +00:00
if ( osec - > ceilingz > = osec - > floorz ) continue ;
2022-11-15 11:03:44 +00:00
show2dsector . Set ( sectindex ( osec ) ) ;
2020-09-06 10:44:58 +00:00
}
}
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-02 08:39:01 +00:00
void drawlinergb ( const DVector2 & v1 , const DVector2 & v2 , PalEntry p )
2020-09-06 18:49:43 +00:00
{
2022-09-02 06:05:03 +00:00
if ( am_linethickness < = 1 )
{
2022-09-02 08:39:01 +00:00
twod - > AddLine ( v1 , v2 , & viewport3d , p , uint8_t ( am_linealpha * 255 ) ) ;
2021-07-09 22:18:59 +00:00
}
2022-09-02 06:05:03 +00:00
else
{
2022-09-02 08:39:01 +00:00
twod - > AddThickLine ( v1 , v2 , am_linethickness , p , uint8_t ( am_linealpha * 255 ) ) ;
2022-09-02 06:05:03 +00:00
}
2020-09-06 18:49:43 +00:00
}
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-20 00:31:01 +00:00
static inline PalEntry RedLineColor ( )
2020-09-06 18:49:43 +00:00
{
// todo:
// Blood uses palette index 12 (99,99,99)
// Exhumed uses palette index 111 (roughly 170,170,170) but darkens the line in overlay mode the farther it is away from the player in vertical direction.
// Shadow Warrior uses palette index 152 in overlay mode and index 12 in full map mode. (152: 84, 88, 40)
return automapMode = = am_overlay ? * am_ovtwosidedcolor : * am_twosidedcolor ;
}
2022-09-20 00:31:01 +00:00
static inline PalEntry WhiteLineColor ( )
2020-09-06 18:49:43 +00:00
{
// todo:
// Blood uses palette index 24
// Exhumed uses palette index 111 (roughly 170,170,170) but darkens the line in overlay mode the farther it is away from the player in vertical direction.
// Shadow Warrior uses palette index 24 (60,60,60)
return automapMode = = am_overlay ? * am_ovonesidedcolor : * am_onesidedcolor ;
}
2022-09-20 00:31:01 +00:00
static inline PalEntry PlayerLineColor ( )
2020-09-06 18:49:43 +00:00
{
return automapMode = = am_overlay ? * am_ovplayercolor : * am_playercolor ;
}
CCMD ( printpalcol )
{
if ( argv . argc ( ) < 2 ) return ;
int i = atoi ( argv [ 1 ] ) ;
Printf ( " %d, %d, %d \n " , GPalette . BaseColors [ i ] . r , GPalette . BaseColors [ i ] . g , GPalette . BaseColors [ i ] . b ) ;
}
2022-09-20 00:31:01 +00:00
2020-09-06 18:49:43 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
bool ShowRedLine ( int j , int i )
{
auto wal = & wall [ j ] ;
2021-07-11 02:39:54 +00:00
if ( ! isSWALL ( ) )
2020-09-06 18:49:43 +00:00
{
return ! gFullMap & & ! show2dsector [ wal - > nextsector ] ;
}
else
{
if ( ! gFullMap )
{
if ( ! show2dwall [ j ] ) return false ;
int k = wal - > nextwall ;
if ( k > j & & ! show2dwall [ k ] ) return false ; //???
}
if ( automapMode = = am_full )
{
2022-02-03 18:15:46 +00:00
if ( sector [ i ] . floorz ! = sector [ i ] . ceilingz )
if ( wal - > nextSector ( ) - > floorz ! = wal - > nextSector ( ) - > ceilingz )
2021-12-18 14:16:31 +00:00
if ( ( ( wal - > cstat | wal - > nextWall ( ) - > cstat ) & ( CSTAT_WALL_MASKED | CSTAT_WALL_1WAY ) ) = = 0 )
2022-02-03 18:15:46 +00:00
if ( sector [ i ] . floorz = = wal - > nextSector ( ) - > floorz )
2020-09-06 18:49:43 +00:00
return false ;
2021-11-26 19:55:13 +00:00
if ( sector [ i ] . floorpicnum ! = wal - > nextSector ( ) - > floorpicnum )
2020-09-06 18:49:43 +00:00
return false ;
2021-11-26 19:55:13 +00:00
if ( sector [ i ] . floorshade ! = wal - > nextSector ( ) - > floorshade )
2020-09-06 18:49:43 +00:00
return false ;
}
return true ;
}
}
//---------------------------------------------------------------------------
//
// two sided lines
//
//---------------------------------------------------------------------------
2022-09-20 00:07:15 +00:00
static void drawredlines ( const DVector2 & cpos , const DVector2 & cangvect , const DVector2 & xydim )
2020-09-06 18:49:43 +00:00
{
2021-12-21 09:51:41 +00:00
for ( unsigned i = 0 ; i < sector . Size ( ) ; i + + )
2020-09-06 18:49:43 +00:00
{
if ( ! gFullMap & & ! show2dsector [ i ] ) continue ;
2022-08-20 17:35:24 +00:00
double z1 = sector [ i ] . ceilingz ;
double z2 = sector [ i ] . floorz ;
2020-09-06 18:49:43 +00:00
2022-11-15 14:24:17 +00:00
for ( auto & wal : sector [ i ] . walls )
2020-09-06 18:49:43 +00:00
{
2021-12-05 20:18:55 +00:00
if ( ! wal . twoSided ( ) ) continue ;
2020-09-06 18:49:43 +00:00
2021-12-05 20:18:55 +00:00
auto osec = wal . nextSector ( ) ;
2021-04-12 18:54:12 +00:00
2022-08-20 17:35:24 +00:00
if ( osec - > ceilingz = = z1 & & osec - > floorz = = z2 )
2021-12-18 14:16:31 +00:00
if ( ( ( wal . cstat | wal . nextWall ( ) - > cstat ) & ( CSTAT_WALL_MASKED | CSTAT_WALL_1WAY ) ) = = 0 ) continue ;
2020-09-06 18:49:43 +00:00
2022-11-15 11:03:44 +00:00
if ( ShowRedLine ( wallindex ( & wal ) , i ) )
2020-09-06 18:49:43 +00:00
{
2022-09-20 00:07:15 +00:00
auto v1 = OutAutomapVector ( wal . pos - cpos , cangvect , gZoom , xydim ) ;
auto v2 = OutAutomapVector ( wal . point2Wall ( ) - > pos - cpos , cangvect , gZoom , xydim ) ;
2022-09-02 08:39:01 +00:00
drawlinergb ( v1 , v2 , RedLineColor ( ) ) ;
2020-09-06 18:49:43 +00:00
}
}
}
}
//---------------------------------------------------------------------------
//
// one sided lines
//
//---------------------------------------------------------------------------
2022-09-20 00:07:15 +00:00
static void drawwhitelines ( const DVector2 & cpos , const DVector2 & cangvect , const DVector2 & xydim )
2020-09-06 18:49:43 +00:00
{
2021-12-21 09:51:41 +00:00
for ( int i = ( int ) sector . Size ( ) - 1 ; i > = 0 ; i - - )
2020-09-06 18:49:43 +00:00
{
2021-07-11 02:39:54 +00:00
if ( ! gFullMap & & ! show2dsector [ i ] & & ! isSWALL ( ) ) continue ;
2020-09-06 18:49:43 +00:00
2022-11-15 14:24:17 +00:00
for ( auto & wal : sector [ i ] . walls )
2020-09-06 18:49:43 +00:00
{
2021-12-05 20:18:55 +00:00
if ( wal . nextwall > = 0 ) continue ;
2022-12-05 19:42:12 +00:00
if ( ! gFullMap & & ! tileGetTexture ( wal . wallpicnum ) - > isValid ( ) ) continue ;
2020-09-06 18:49:43 +00:00
2022-11-15 11:03:44 +00:00
if ( isSWALL ( ) & & ! gFullMap & & ! show2dwall [ wallindex ( & wal ) ] )
2020-09-06 18:49:43 +00:00
continue ;
2022-09-20 00:07:15 +00:00
auto v1 = OutAutomapVector ( wal . pos - cpos , cangvect , gZoom , xydim ) ;
auto v2 = OutAutomapVector ( wal . point2Wall ( ) - > pos - cpos , cangvect , gZoom , xydim ) ;
2022-09-02 08:39:01 +00:00
drawlinergb ( v1 , v2 , WhiteLineColor ( ) ) ;
2020-09-06 18:49:43 +00:00
}
}
}
2021-03-20 11:47:51 +00:00
//---------------------------------------------------------------------------
//
// player sprite fallback
//
//---------------------------------------------------------------------------
2020-09-06 18:49:43 +00:00
2022-08-29 14:17:51 +00:00
static void DrawPlayerArrow ( const DVector2 & cpos , const DAngle cang , const double czoom , const DAngle pl_angle )
2020-09-06 18:49:43 +00:00
{
2022-09-02 08:39:01 +00:00
#if 0
2022-08-29 14:17:51 +00:00
static constexpr int arrow [ ] =
2020-09-06 18:49:43 +00:00
{
0 , 65536 , 0 , - 65536 ,
0 , 65536 , - 32768 , 32878 ,
0 , 65536 , 32768 , 32878 ,
} ;
2022-08-31 11:22:14 +00:00
double xvect = - cang . Sin ( ) * czoom ;
double yvect = - cang . Cos ( ) * czoom ;
2020-09-06 18:49:43 +00:00
2022-08-29 14:17:51 +00:00
double pxvect = - pl_angle . Sin ( ) ;
double pyvect = - pl_angle . Cos ( ) ;
2020-09-06 18:49:43 +00:00
2021-02-27 11:30:20 +00:00
int width = screen - > GetWidth ( ) ;
int height = screen - > GetHeight ( ) ;
2020-09-06 18:49:43 +00:00
for ( int i = 0 ; i < 12 ; i + = 4 )
{
2022-08-31 13:10:40 +00:00
// FIXME: This has been broken since before the floatification refactor.
// Needs repair and changing out to backended vector function.
2022-08-29 14:17:51 +00:00
double px1 = ( arrow [ i ] * pxvect ) - ( arrow [ i + 1 ] * pyvect ) ;
double py1 = ( arrow [ i + 1 ] * pxvect ) + ( arrow [ i ] * pyvect ) + ( height * 0.5 ) ;
double px2 = ( arrow [ i + 2 ] * pxvect ) - ( arrow [ i + 3 ] * pyvect ) ;
double py2 = ( arrow [ i + 3 ] * pxvect ) + ( arrow [ i + 2 ] * pyvect ) + ( height * 0.5 ) ;
2020-09-06 18:49:43 +00:00
2022-08-29 14:17:51 +00:00
auto oxy1 = DVector2 ( px1 , py1 ) - cpos ;
auto oxy2 = DVector2 ( px2 , py2 ) - cpos ;
2020-09-06 18:49:43 +00:00
2022-08-29 14:17:51 +00:00
double sx1 = ( oxy1 . X * xvect ) - ( oxy1 . Y * yvect ) + ( width * 0.5 ) ;
double sy1 = ( oxy1 . Y * xvect ) + ( oxy1 . X * yvect ) + ( height * 0.5 ) ;
double sx2 = ( oxy2 . X * xvect ) - ( oxy2 . Y * yvect ) + ( width * 0.5 ) ;
double sy2 = ( oxy2 . Y * xvect ) + ( oxy2 . X * yvect ) + ( height * 0.5 ) ;
2020-09-06 18:49:43 +00:00
drawlinergb ( sx1 , sy1 , sx2 , sy2 , WhiteLineColor ( ) ) ;
}
2022-09-02 08:39:01 +00:00
# endif
2020-09-06 18:49:43 +00:00
}
2021-03-20 11:47:51 +00:00
//---------------------------------------------------------------------------
//
// floor textures
//
//---------------------------------------------------------------------------
2022-09-20 00:07:15 +00:00
static void renderDrawMapView ( const DVector2 & cpos , const DVector2 & cangvect , const DVector2 & xydim )
2021-03-20 11:47:51 +00:00
{
TArray < FVector4 > vertices ;
2021-12-30 11:21:51 +00:00
TArray < DCoreActor * > floorsprites ;
2021-03-20 11:47:51 +00:00
2021-12-21 09:51:41 +00:00
for ( int i = ( int ) sector . Size ( ) - 1 ; i > = 0 ; i - - )
2021-03-20 11:47:51 +00:00
{
2021-11-27 20:19:15 +00:00
auto sect = & sector [ i ] ;
2021-04-01 18:47:05 +00:00
if ( ! gFullMap & & ! show2dsector [ i ] ) continue ;
2021-03-20 11:47:51 +00:00
//Collect floor sprites to draw
2021-11-27 20:19:15 +00:00
TSectIterator < DCoreActor > it ( sect ) ;
while ( auto act = it . Next ( ) )
2021-03-20 11:47:51 +00:00
{
2021-12-22 22:14:16 +00:00
if ( act - > spr . cstat & CSTAT_SPRITE_INVISIBLE )
2021-03-20 11:47:51 +00:00
continue ;
2021-12-22 22:14:16 +00:00
if ( act - > spr . cstat & CSTAT_SPRITE_ALIGNMENT_FLOOR ) // floor and slope sprites
2021-03-20 11:47:51 +00:00
{
2021-12-22 22:14:16 +00:00
if ( ( act - > spr . cstat & ( CSTAT_SPRITE_ONE_SIDE | CSTAT_SPRITE_YFLIP ) ) = = ( CSTAT_SPRITE_ONE_SIDE | CSTAT_SPRITE_YFLIP ) )
2021-03-20 11:47:51 +00:00
continue ; // upside down
2021-12-30 11:21:51 +00:00
floorsprites . Push ( act ) ;
2021-03-20 11:47:51 +00:00
}
}
2021-11-27 20:19:15 +00:00
if ( sect - > floorstat & CSTAT_SECTOR_SKY ) continue ;
2021-03-20 11:47:51 +00:00
2021-11-27 20:19:15 +00:00
int picnum = sect - > floorpicnum ;
2021-04-01 18:47:05 +00:00
if ( ( unsigned ) picnum > = ( unsigned ) MAXTILES ) continue ;
2021-12-14 16:40:03 +00:00
int translation = TRANSLATION ( Translation_Remap + curbasepal , sector [ i ] . floorpal ) ;
PalEntry light = shadeToLight ( sector [ i ] . floorshade ) ;
2021-12-24 08:19:43 +00:00
for ( auto section : sectionsPerSector [ i ] )
2021-03-20 11:47:51 +00:00
{
2021-12-14 08:03:19 +00:00
TArray < int > * indices ;
2022-02-20 12:14:39 +00:00
auto mesh = sectionGeometry . get ( & sections [ section ] , 0 , { 0.f , 0.f } , & indices ) ;
2021-12-14 16:40:03 +00:00
vertices . Resize ( mesh - > vertices . Size ( ) ) ;
for ( unsigned j = 0 ; j < mesh - > vertices . Size ( ) ; j + + )
2021-05-02 22:15:09 +00:00
{
2022-09-20 00:07:15 +00:00
auto v = OutAutomapVector ( DVector2 ( mesh - > vertices [ j ] . X - cpos . X , - mesh - > vertices [ j ] . Y - cpos . Y ) , cangvect , gZoom , xydim ) ;
2022-08-31 13:10:40 +00:00
vertices [ j ] = { float ( v . X ) , float ( v . Y ) , mesh - > texcoords [ j ] . X , mesh - > texcoords [ j ] . Y } ;
2021-05-02 22:15:09 +00:00
}
2021-03-20 11:47:51 +00:00
2021-12-14 16:40:03 +00:00
twod - > AddPoly ( tileGetTexture ( picnum , true ) , vertices . Data ( ) , vertices . Size ( ) , ( unsigned * ) indices - > Data ( ) , indices - > Size ( ) , translation , light ,
2022-08-04 21:47:01 +00:00
LegacyRenderStyles [ STYLE_Translucent ] , & viewport3d ) ;
2021-12-14 16:40:03 +00:00
}
2021-03-20 11:47:51 +00:00
}
2021-12-30 11:29:17 +00:00
qsort ( floorsprites . Data ( ) , floorsprites . Size ( ) , sizeof ( DCoreActor * ) , [ ] ( const void * a , const void * b )
2021-03-20 11:47:51 +00:00
{
2021-12-30 11:21:51 +00:00
auto A = * ( DCoreActor * * ) a ;
auto B = * ( DCoreActor * * ) b ;
2022-08-10 20:08:41 +00:00
if ( A - > spr . pos . Z < B - > spr . pos . Z ) return 1 ;
if ( A - > spr . pos . Z > B - > spr . pos . Z ) return - 1 ;
2022-01-08 20:18:18 +00:00
return A - > time - B - > time ; // ensures stable sort.
2021-03-20 11:47:51 +00:00
} ) ;
vertices . Resize ( 4 ) ;
2021-12-30 11:21:51 +00:00
for ( auto actor : floorsprites )
2021-03-20 11:47:51 +00:00
{
2021-12-30 11:21:51 +00:00
if ( ! gFullMap & & ! ( actor - > spr . cstat2 & CSTAT2_SPRITE_MAPPED ) ) continue ;
2022-08-17 18:40:11 +00:00
DVector2 pp [ 4 ] ;
2022-09-06 18:19:55 +00:00
GetFlatSpritePosition ( actor , actor - > spr . pos . XY ( ) , pp , nullptr , true ) ;
2021-03-20 11:47:51 +00:00
for ( unsigned j = 0 ; j < 4 ; j + + )
{
2022-09-20 00:07:15 +00:00
auto v = OutAutomapVector ( pp [ j ] - cpos , cangvect , gZoom , xydim ) ;
2022-08-31 13:10:40 +00:00
vertices [ j ] = { float ( v . X ) , float ( v . Y ) , j = = 1 | | j = = 2 ? 1.f : 0.f , j = = 2 | | j = = 3 ? 1.f : 0.f } ;
2021-03-20 11:47:51 +00:00
}
int shade ;
2021-12-30 15:51:56 +00:00
if ( ( actor - > sector ( ) - > ceilingstat & CSTAT_SECTOR_SKY ) ) shade = actor - > sector ( ) - > ceilingshade ;
else shade = actor - > sector ( ) - > floorshade ;
2021-12-30 11:21:51 +00:00
shade + = actor - > spr . shade ;
2021-03-20 11:47:51 +00:00
PalEntry color = shadeToLight ( shade ) ;
FRenderStyle rs = LegacyRenderStyles [ STYLE_Translucent ] ;
float alpha = 1 ;
2021-12-30 11:21:51 +00:00
if ( actor - > spr . cstat & CSTAT_SPRITE_TRANSLUCENT )
2021-03-20 11:47:51 +00:00
{
2021-12-30 11:21:51 +00:00
rs = GetRenderStyle ( 0 , ! ! ( actor - > spr . cstat & CSTAT_SPRITE_TRANS_FLIP ) ) ;
alpha = GetAlphaFromBlend ( ( actor - > spr . cstat & CSTAT_SPRITE_TRANS_FLIP ) ? DAMETH_TRANS2 : DAMETH_TRANS1 , 0 ) ;
2021-03-20 11:47:51 +00:00
color . a = uint8_t ( alpha * 255 ) ;
}
2021-12-30 11:21:51 +00:00
int translation = TRANSLATION ( Translation_Remap + curbasepal , actor - > spr . pal ) ;
int picnum = actor - > spr . picnum ;
2021-03-20 11:47:51 +00:00
const static unsigned indices [ ] = { 0 , 1 , 2 , 0 , 2 , 3 } ;
2022-08-04 21:47:01 +00:00
twod - > AddPoly ( tileGetTexture ( picnum , true ) , vertices . Data ( ) , vertices . Size ( ) , indices , 6 , translation , color , rs , & viewport3d ) ;
2021-03-20 11:47:51 +00:00
}
}
2020-09-06 18:49:43 +00:00
//---------------------------------------------------------------------------
//
//
//
//---------------------------------------------------------------------------
2022-09-07 09:37:50 +00:00
void DrawOverheadMap ( const DVector2 & plxy , const DAngle pl_angle , double const interpfrac )
2020-09-06 10:44:58 +00:00
{
2022-09-20 00:20:40 +00:00
if ( am_followplayer | | follow . X = = INT_MAX )
2020-09-06 21:12:47 +00:00
{
2022-09-20 00:31:01 +00:00
follow = plxy ;
2020-09-06 21:12:47 +00:00
}
2022-08-31 13:10:40 +00:00
2022-09-20 00:07:15 +00:00
follow_a = am_rotate ? pl_angle : DAngle270 ;
const DVector2 xydim = DVector2 ( screen - > GetWidth ( ) , screen - > GetHeight ( ) ) * 0.5 ;
const DVector2 avect = follow_a . ToVector ( ) ;
2022-08-31 13:10:40 +00:00
2022-09-20 00:07:15 +00:00
AutomapControl ( avect ) ;
2020-09-06 18:49:43 +00:00
if ( automapMode = = am_full )
{
twod - > ClearScreen ( ) ;
2022-09-20 00:07:15 +00:00
renderDrawMapView ( follow , avect , xydim ) ;
2020-09-06 18:49:43 +00:00
}
2022-08-31 13:10:40 +00:00
2022-09-20 00:07:15 +00:00
drawredlines ( follow , avect , xydim ) ;
drawwhitelines ( follow , avect , xydim ) ;
2022-09-07 09:37:50 +00:00
if ( ! gi - > DrawAutomapPlayer ( plxy , follow , follow_a , xydim , gZoom , interpfrac ) )
2022-08-31 13:10:40 +00:00
DrawPlayerArrow ( follow , follow_a , gZoom , pl_angle ) ;
2020-09-06 18:49:43 +00:00
2020-09-06 10:44:58 +00:00
}
2022-09-05 23:37:14 +00:00
//---------------------------------------------------------------------------
//
// Draws lines for alls in Duke/SW when cstat is CSTAT_SPRITE_ALIGNMENT_FACING.
//
//---------------------------------------------------------------------------
void DrawAutomapAlignmentFacing ( const spritetype & spr , const DVector2 & bpos , const DVector2 & cangvect , const double czoom , const DVector2 & xydim , const PalEntry & col )
{
auto v1 = OutAutomapVector ( bpos , cangvect , czoom , xydim ) ;
2022-11-25 12:13:50 +00:00
auto v2 = OutAutomapVector ( spr . Angles . Yaw . ToVector ( ) * 8. , cangvect , czoom ) ;
2022-09-05 23:37:14 +00:00
auto v3 = v2 . Rotated90CW ( ) ;
auto v4 = v1 + v2 ;
drawlinergb ( v1 - v2 , v4 , col ) ;
drawlinergb ( v1 - v3 , v4 , col ) ;
drawlinergb ( v1 + v3 , v4 , col ) ;
}
2022-09-20 00:26:57 +00:00
//---------------------------------------------------------------------------
//
// Draws lines for alls in Duke/SW when cstat is CSTAT_SPRITE_ALIGNMENT_WALL.
//
//---------------------------------------------------------------------------
void DrawAutomapAlignmentWall ( const spritetype & spr , const DVector2 & bpos , const DVector2 & cangvect , const double czoom , const DVector2 & xydim , const PalEntry & col )
{
2022-10-07 21:33:37 +00:00
auto xrep = spr . scale . X ;
2022-09-20 00:26:57 +00:00
auto xspan = tileWidth ( spr . picnum ) ;
auto xoff = tileLeftOffset ( spr . picnum ) + spr . xoffset ;
if ( ( spr . cstat & CSTAT_SPRITE_XFLIP ) > 0 ) xoff = - xoff ;
2022-11-25 12:13:50 +00:00
auto sprvec = spr . Angles . Yaw . ToVector ( ) . Rotated90CW ( ) * xrep ;
2022-09-20 00:26:57 +00:00
auto b1 = bpos - sprvec * ( ( xspan * 0.5 ) + xoff ) ;
auto b2 = b1 + sprvec * xspan ;
auto v1 = OutAutomapVector ( b1 , cangvect , czoom , xydim ) ;
auto v2 = OutAutomapVector ( b2 , cangvect , czoom , xydim ) ;
drawlinergb ( v1 , v2 , col ) ;
}
//---------------------------------------------------------------------------
//
// Draws lines for alls in Duke/SW when cstat is CSTAT_SPRITE_ALIGNMENT_FLOOR.
//
//---------------------------------------------------------------------------
void DrawAutomapAlignmentFloor ( const spritetype & spr , const DVector2 & bpos , const DVector2 & cangvect , const double czoom , const DVector2 & xydim , const PalEntry & col )
{
2022-10-07 21:33:37 +00:00
auto xrep = spr . scale . X ;
auto yrep = spr . scale . Y ;
2022-09-20 00:26:57 +00:00
auto xspan = tileWidth ( spr . picnum ) ;
auto yspan = tileHeight ( spr . picnum ) ;
auto xoff = tileLeftOffset ( spr . picnum ) ;
auto yoff = tileTopOffset ( spr . picnum ) ;
if ( isSWALL ( ) | | ( spr . cstat & CSTAT_SPRITE_ALIGNMENT_MASK ) ! = CSTAT_SPRITE_ALIGNMENT_SLOPE )
{
xoff + = spr . xoffset ;
yoff + = spr . yoffset ;
}
if ( ( spr . cstat & CSTAT_SPRITE_XFLIP ) > 0 ) xoff = - xoff ;
if ( ( spr . cstat & CSTAT_SPRITE_YFLIP ) > 0 ) yoff = - yoff ;
2022-11-25 12:13:50 +00:00
auto sprvec = spr . Angles . Yaw . ToVector ( ) ;
2022-09-20 00:26:57 +00:00
auto xscale = sprvec . Rotated90CW ( ) * xspan * xrep ;
auto yscale = sprvec * yspan * yrep ;
auto xybase = DVector2 ( ( ( xspan * 0.5 ) + xoff ) * xrep , ( ( yspan * 0.5 ) + yoff ) * yrep ) ;
auto b1 = bpos + ( xybase * sprvec . Y ) + ( xybase . Rotated90CW ( ) * sprvec . X ) ;
auto b2 = b1 - xscale ;
auto b3 = b2 - yscale ;
auto b4 = b1 - yscale ;
auto v1 = OutAutomapVector ( b1 , cangvect , czoom , xydim ) ;
auto v2 = OutAutomapVector ( b2 , cangvect , czoom , xydim ) ;
auto v3 = OutAutomapVector ( b3 , cangvect , czoom , xydim ) ;
auto v4 = OutAutomapVector ( b4 , cangvect , czoom , xydim ) ;
drawlinergb ( v1 , v2 , col ) ;
drawlinergb ( v2 , v3 , col ) ;
drawlinergb ( v3 , v4 , col ) ;
drawlinergb ( v4 , v1 , col ) ;
}