2006-03-20 17:12:09 +00:00
/*
2014-06-01 17:55:23 +00:00
* Portions of this file are copyright Rebirth contributors and licensed as
* described in COPYING . txt .
* Portions of this file are copyright Parallax Software and licensed
* according to the Parallax license below .
* See COPYING . txt for license details .
2006-03-20 17:12:09 +00:00
THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
SOFTWARE CORPORATION ( " PARALLAX " ) . PARALLAX , IN DISTRIBUTING THE CODE TO
END - USERS , AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN , GRANTS A
ROYALTY - FREE , PERPETUAL LICENSE TO SUCH END - USERS FOR USE BY SUCH END - USERS
IN USING , DISPLAYING , AND CREATING DERIVATIVE WORKS THEREOF , SO LONG AS
SUCH USE , DISPLAY OR CREATION IS FOR NON - COMMERCIAL , ROYALTY OR REVENUE
FREE PURPOSES . IN NO EVENT SHALL THE END - USER USE THE COMPUTER CODE
CONTAINED HEREIN FOR REVENUE - BEARING PURPOSES . THE END - USER UNDERSTANDS
AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE .
COPYRIGHT 1993 - 1999 PARALLAX SOFTWARE CORPORATION . ALL RIGHTS RESERVED .
*/
/*
*
* Movie Playing Stuff
*
*/
# include <string.h>
# ifndef macintosh
2008-04-19 19:11:32 +00:00
# include <sys / types.h>
# include <sys / stat.h>
# include <fcntl.h>
2006-03-20 17:12:09 +00:00
# ifndef _MSC_VER
# include <unistd.h>
# endif
# endif // ! macintosh
# include <ctype.h>
# include "movie.h"
2010-03-17 09:44:19 +00:00
# include "window.h"
2006-03-20 17:12:09 +00:00
# include "console.h"
2010-09-02 13:55:28 +00:00
# include "config.h"
2014-07-20 01:09:55 +00:00
# include "physfsx.h"
2006-03-20 17:12:09 +00:00
# include "key.h"
2010-03-17 09:44:19 +00:00
# include "mouse.h"
2006-03-20 17:12:09 +00:00
# include "digi.h"
# include "songs.h"
# include "inferno.h"
# include "palette.h"
# include "strutil.h"
2012-07-07 18:35:06 +00:00
# include "dxxerror.h"
2006-03-20 17:12:09 +00:00
# include "u_mem.h"
# include "gr.h"
# include "gamefont.h"
# include "menu.h"
# include "libmve.h"
# include "text.h"
# include "screens.h"
2021-09-19 10:53:48 +00:00
# include "timer.h"
2006-03-20 17:12:09 +00:00
# include "physfsrwops.h"
2016-09-24 18:06:11 +00:00
# if DXX_USE_OGL
2006-03-20 17:12:09 +00:00
# include "ogl_init.h"
2006-12-19 02:25:50 +00:00
# endif
2013-03-03 19:41:09 +00:00
# include "args.h"
2006-03-20 17:12:09 +00:00
2014-12-06 17:56:56 +00:00
# include "compiler-range_for.h"
2020-06-10 02:25:32 +00:00
# include "partial_range.h"
2021-06-28 03:37:49 +00:00
# include "d_zip.h"
namespace dsx {
2006-03-20 17:12:09 +00:00
2015-08-12 03:11:46 +00:00
namespace {
2006-03-20 17:12:09 +00:00
// Subtitle data
2013-12-22 22:03:07 +00:00
struct subtitle {
2018-12-30 00:43:58 +00:00
typename std : : conditional < sizeof ( char * ) = = sizeof ( uint32_t ) , uint16_t , uint32_t > : : type first_frame , last_frame ;
const char * msg ;
2013-12-22 22:03:07 +00:00
} ;
2006-03-20 17:12:09 +00:00
# define MAX_ACTIVE_SUBTITLES 3
2015-01-23 03:55:06 +00:00
2021-09-12 16:20:52 +00:00
struct d_loaded_subtitle_state
2013-10-27 21:01:04 +00:00
{
2018-12-30 00:43:58 +00:00
unsigned Num_subtitles = 0 ;
std : : unique_ptr < char [ ] > subtitle_raw_data ;
2021-09-12 16:20:52 +00:00
std : : array < subtitle , 500 > Subtitles
# ifndef NDEBUG
= { }
# endif
;
2013-10-27 21:01:04 +00:00
} ;
2006-03-20 17:12:09 +00:00
2022-10-09 23:15:20 +00:00
static int init_subtitles ( d_loaded_subtitle_state & SubtitleState , std : : span < const char > filename ) ;
2015-01-23 03:55:06 +00:00
2006-03-20 17:12:09 +00:00
// Movielib data
2020-05-02 21:18:42 +00:00
constexpr std : : array < std : : array < char , 8 > , 3 > movielib_files { {
2016-07-16 16:52:04 +00:00
{ " intro " } , { " other " } , { " robots " }
} } ;
2015-08-12 03:11:46 +00:00
2006-03-20 17:12:09 +00:00
// Function Prototypes
2022-10-02 19:51:35 +00:00
static movie_play_status RunMovie ( const char * filename , std : : span < const char > subtitles , int highres_flag , play_movie_warn_missing , int dx , int dy ) ;
2006-03-20 17:12:09 +00:00
2021-09-12 16:20:52 +00:00
static void draw_subtitles ( const d_loaded_subtitle_state & , int frame_num ) ;
2006-03-20 17:12:09 +00:00
//-----------------------------------------------------------------------
2020-08-28 00:18:45 +00:00
struct movie_pause_window : window
{
2021-09-19 10:53:48 +00:00
movie_pause_window ( grs_canvas & src ) :
window ( src , 0 , 0 , src . cv_bitmap . bm_w , src . cv_bitmap . bm_h )
{
}
2020-08-28 00:18:45 +00:00
virtual window_event_result event_handler ( const d_event & ) override ;
} ;
2018-12-30 00:43:58 +00:00
}
2006-03-20 17:12:09 +00:00
2021-06-28 03:37:49 +00:00
}
2022-07-23 20:58:10 +00:00
unsigned int MovieFileRead ( SDL_RWops * const handle , void * buf , unsigned int count )
2021-01-17 22:23:23 +00:00
{
2022-07-23 20:58:10 +00:00
const unsigned numread = SDL_RWread ( handle , buf , 1 , count ) ;
2021-01-17 22:23:23 +00:00
return ( numread = = count ) ;
}
2006-03-20 17:12:09 +00:00
//-----------------------------------------------------------------------
2021-06-28 03:37:49 +00:00
namespace dsx {
2006-03-20 17:12:09 +00:00
//filename will actually get modified to be either low-res or high-res
//returns status. see values in movie.h
2022-10-02 19:51:35 +00:00
movie_play_status PlayMovie ( const std : : span < const char > subtitles , const char * const name , const play_movie_warn_missing must_have )
2006-03-20 17:12:09 +00:00
{
2007-10-01 20:42:35 +00:00
if ( GameArg . SysNoMovies )
2021-01-17 22:23:23 +00:00
return movie_play_status : : skipped ;
2006-03-20 17:12:09 +00:00
// Stop all digital sounds currently playing.
2010-06-14 08:13:16 +00:00
digi_stop_digi_sounds ( ) ;
2006-03-20 17:12:09 +00:00
// Stop all songs
songs_stop_all ( ) ;
2007-10-11 13:23:00 +00:00
// MD2211: if using SDL_Mixer, we never reinit the sound system
2015-11-24 04:05:36 +00:00
if ( CGameArg . SndDisableSdlMixer )
2007-10-11 13:23:00 +00:00
digi_close ( ) ;
2006-03-20 17:12:09 +00:00
// Start sound
2015-11-24 04:05:36 +00:00
MVE_sndInit ( ! CGameArg . SndNoSound ? 1 : - 1 ) ;
2006-03-20 17:12:09 +00:00
2022-10-02 19:51:35 +00:00
const auto ret = RunMovie ( name , subtitles , ! GameArg . GfxSkipHiresMovie , must_have , - 1 , - 1 ) ;
2006-03-20 17:12:09 +00:00
2007-10-11 13:23:00 +00:00
// MD2211: if using SDL_Mixer, we never reinit the sound system
2015-11-24 04:05:36 +00:00
if ( ! CGameArg . SndNoSound
2015-11-24 04:05:36 +00:00
& & CGameArg . SndDisableSdlMixer
2008-05-01 21:40:34 +00:00
)
2006-03-20 17:12:09 +00:00
digi_init ( ) ;
Screen_mode = - 1 ; //force screen reset
return ret ;
}
2021-06-28 03:37:49 +00:00
}
2021-01-17 22:23:23 +00:00
void MovieShowFrame ( const uint8_t * buf , int dstx , int dsty , int bufw , int bufh , int sw , int sh )
2006-03-20 17:12:09 +00:00
{
grs_bitmap source_bm ;
2013-01-06 21:03:57 +00:00
static palette_array_t old_pal ;
2010-06-19 16:42:07 +00:00
float scale = 1.0 ;
2008-03-25 13:12:27 +00:00
2013-01-06 21:11:53 +00:00
if ( old_pal ! = gr_palette )
2008-03-25 13:12:27 +00:00
{
2013-01-06 21:11:53 +00:00
old_pal = gr_palette ;
2008-03-25 13:12:27 +00:00
return ;
}
2013-01-06 21:11:53 +00:00
old_pal = gr_palette ;
2006-03-20 17:12:09 +00:00
source_bm . bm_x = source_bm . bm_y = 0 ;
source_bm . bm_w = source_bm . bm_rowsize = bufw ;
source_bm . bm_h = bufh ;
2016-05-28 17:31:26 +00:00
source_bm . set_type ( bm_mode : : linear ) ;
2017-01-15 00:03:13 +00:00
source_bm . clear_flags ( ) ;
2006-03-20 17:12:09 +00:00
source_bm . bm_data = buf ;
2008-03-20 23:23:46 +00:00
2010-06-19 16:42:07 +00:00
if ( dstx = = - 1 & & dsty = = - 1 ) // Fullscreen movie so set scale to fit the actual screen size
{
2016-06-05 01:04:26 +00:00
if ( ( static_cast < float > ( SWIDTH ) / SHEIGHT ) < ( static_cast < float > ( sw ) / bufh ) )
scale = ( static_cast < float > ( SWIDTH ) / sw ) ;
2010-06-19 16:42:07 +00:00
else
2016-06-05 01:04:26 +00:00
scale = ( static_cast < float > ( SHEIGHT ) / bufh ) ;
2010-06-19 16:42:07 +00:00
}
else // Other (robot) movie so set scale to min. screen dimension
{
2016-06-05 01:04:26 +00:00
if ( ( static_cast < float > ( SWIDTH ) / bufw ) < ( static_cast < float > ( SHEIGHT ) / bufh ) )
scale = ( static_cast < float > ( SWIDTH ) / sw ) ;
2010-06-19 16:42:07 +00:00
else
2016-06-05 01:04:26 +00:00
scale = ( static_cast < float > ( SHEIGHT ) / sh ) ;
2010-06-19 16:42:07 +00:00
}
if ( dstx = = - 1 ) // center it
dstx = ( SWIDTH / 2 ) - ( ( bufw * scale ) / 2 ) ;
if ( dsty = = - 1 ) // center it
dsty = ( SHEIGHT / 2 ) - ( ( bufh * scale ) / 2 ) ;
2016-09-24 18:06:11 +00:00
# if DXX_USE_OGL
2006-03-20 17:12:09 +00:00
glDisable ( GL_BLEND ) ;
2006-10-10 23:35:42 +00:00
2010-06-19 16:42:07 +00:00
ogl_ubitblt_i (
bufw * scale , bufh * scale ,
dstx , dsty ,
2021-01-17 22:23:23 +00:00
bufw , bufh , 0 , 0 , source_bm , grd_curcanv - > cv_bitmap , ( GameCfg . MovieTexFilt ) ? opengl_texture_filter : : trilinear : opengl_texture_filter : : classic ) ;
2006-10-10 23:35:42 +00:00
2006-03-20 17:12:09 +00:00
glEnable ( GL_BLEND ) ;
2006-08-30 18:12:04 +00:00
# else
2017-02-11 21:42:32 +00:00
gr_bm_ubitbltm ( * grd_curcanv , bufw , bufh , dstx , dsty , 0 , 0 , source_bm ) ;
2006-03-20 17:12:09 +00:00
# endif
2006-08-30 18:12:04 +00:00
}
2006-03-20 17:12:09 +00:00
//our routine to set the pallete, called from the movie code
2021-01-17 22:23:23 +00:00
void MovieSetPalette ( const unsigned char * p , unsigned start , unsigned count )
2006-03-20 17:12:09 +00:00
{
if ( count = = 0 )
return ;
//Color 0 should be black, and we get color 255
Assert ( start > = 1 & & start + count - 1 < = 254 ) ;
//Set color 0 to be black
2013-01-06 21:11:53 +00:00
gr_palette [ 0 ] . r = gr_palette [ 0 ] . g = gr_palette [ 0 ] . b = 0 ;
2006-03-20 17:12:09 +00:00
//Set color 255 to be our subtitle color
2013-01-06 21:11:53 +00:00
gr_palette [ 255 ] . r = gr_palette [ 255 ] . g = gr_palette [ 255 ] . b = 50 ;
2006-03-20 17:12:09 +00:00
//movie libs palette into our array
2013-01-06 21:11:53 +00:00
memcpy ( & gr_palette [ start ] , p + start * 3 , count * 3 ) ;
2006-03-20 17:12:09 +00:00
}
2021-06-28 03:37:49 +00:00
namespace dsx {
2021-01-17 22:23:23 +00:00
namespace {
Move window existence flag to a mixin, and track using std::shared_ptr
gcc-12 does enough escape analysis to notice that
newmenu::process_until_closed stores the address of a stack local into a
heap-allocated structure, but not enough analysis to notice that the
stack variable always outlives the escaped address. The compiler then
warns about the address escaping the local scope. Reworking the calling
code not to do this is somewhat invasive, and gcc seems unlikely to
change behavior. Switch to a less efficient implementation that does
not provoke a compiler warning:
- Store a shared_ptr<bool> in the object
- In the object's destructor, write through the pointer to clear the
shared boolean
- In the caller, store a copy of the shared_ptr<bool> as a local, and
use that copy to monitor the shared boolean
This is similar to a change proposed by JoeNotCharles
<https://github.com/dxx-rebirth/dxx-rebirth/pull/693/commits/10a2b2d33792bf7e40d2a9bc93bebb22804088ea>,
but differs in its details. Among other things, this version takes the
opportunity to move the variable out to a mixin, so that only windows
which expect to be tracked can be tracked. Previously, all windows were
capable of this, even though most never needed it.
2023-01-14 19:05:37 +00:00
struct movie : window , mixin_trackable_window
2006-03-20 17:12:09 +00:00
{
2020-08-28 00:18:45 +00:00
MVE_StepStatus result = MVE_StepStatus : : EndOfFile ;
int frame_num = 0 ;
int paused = 0 ;
2021-01-17 22:23:23 +00:00
const MVESTREAM_ptr_t pMovie ;
2021-09-12 16:20:52 +00:00
d_loaded_subtitle_state SubtitleState ;
2021-09-19 10:53:48 +00:00
movie ( grs_canvas & src , MVESTREAM_ptr_t mvestream ) :
window ( src , 0 , 0 , src . cv_bitmap . bm_w , src . cv_bitmap . bm_h ) ,
2021-01-17 22:23:23 +00:00
pMovie ( std : : move ( mvestream ) )
{
}
2020-08-28 00:18:45 +00:00
virtual window_event_result event_handler ( const d_event & ) override ;
2013-12-22 22:03:07 +00:00
} ;
2010-03-17 09:44:19 +00:00
2020-08-28 00:18:45 +00:00
window_event_result movie_pause_window : : event_handler ( const d_event & event )
2010-03-17 09:44:19 +00:00
{
2014-10-04 21:47:13 +00:00
switch ( event . type )
2010-03-17 09:44:19 +00:00
{
2010-03-24 07:26:52 +00:00
case EVENT_MOUSE_BUTTON_DOWN :
2022-02-27 14:23:53 +00:00
if ( event_mouse_get_button ( event ) ! = mbtn : : left )
2014-08-06 02:10:49 +00:00
return window_event_result : : ignored ;
2022-01-09 15:25:42 +00:00
[[fallthrough]] ;
2010-03-17 09:44:19 +00:00
case EVENT_KEY_COMMAND :
2020-08-28 00:18:45 +00:00
if ( const auto result = call_default_handler ( event ) ; result = = window_event_result : : ignored )
2014-08-06 02:10:49 +00:00
return window_event_result : : close ;
2020-08-28 00:18:45 +00:00
else
return result ;
2021-09-19 10:53:48 +00:00
case EVENT_IDLE :
timer_delay ( F1_0 / 4 ) ;
break ;
2010-03-17 09:44:19 +00:00
case EVENT_WINDOW_DRAW :
{
2013-09-02 23:21:13 +00:00
const char * msg = TXT_PAUSE ;
2011-09-26 23:31:19 +00:00
int y ;
2006-03-20 17:12:09 +00:00
2017-11-05 20:49:08 +00:00
gr_set_default_canvas ( ) ;
2017-03-10 01:22:25 +00:00
auto & canvas = * grd_curcanv ;
2018-05-19 23:21:42 +00:00
const auto & game_font = * GAME_FONT ;
2021-09-12 16:20:52 +00:00
const auto h = gr_get_string_size ( game_font , msg ) . height ;
2006-03-20 17:12:09 +00:00
2015-03-22 18:49:21 +00:00
y = ( grd_curscreen - > get_screen_height ( ) - h ) / 2 ;
2006-03-20 17:12:09 +00:00
2017-03-10 01:22:25 +00:00
gr_set_fontcolor ( canvas , 255 , - 1 ) ;
2006-03-20 17:12:09 +00:00
2018-05-19 23:21:42 +00:00
gr_ustring ( canvas , game_font , 0x8000 , y , msg ) ;
2010-03-17 09:44:19 +00:00
break ;
}
2010-06-14 08:13:16 +00:00
2010-03-17 09:44:19 +00:00
default :
break ;
}
2014-08-06 02:10:49 +00:00
return window_event_result : : ignored ;
2006-03-20 17:12:09 +00:00
}
2020-08-28 00:18:45 +00:00
window_event_result movie : : event_handler ( const d_event & event )
2006-03-20 17:12:09 +00:00
{
2014-10-04 21:47:13 +00:00
switch ( event . type )
2010-03-17 09:44:19 +00:00
{
2010-03-18 02:49:02 +00:00
case EVENT_WINDOW_ACTIVATED :
2020-08-28 00:18:45 +00:00
paused = 0 ;
2010-03-18 02:49:02 +00:00
break ;
case EVENT_WINDOW_DEACTIVATED :
2020-08-28 00:18:45 +00:00
paused = 1 ;
2011-01-14 21:56:00 +00:00
MVE_rmHoldMovie ( ) ;
2010-03-18 02:49:02 +00:00
break ;
2010-06-14 08:13:16 +00:00
2010-03-17 09:44:19 +00:00
case EVENT_KEY_COMMAND :
2021-09-19 10:53:48 +00:00
{
const auto key = event_key_get ( event ) ;
2010-06-14 08:13:16 +00:00
2010-03-17 09:44:19 +00:00
// If ESCAPE pressed, then quit movie.
if ( key = = KEY_ESC ) {
2021-01-17 22:23:23 +00:00
return window_event_result : : close ;
2010-03-17 09:44:19 +00:00
}
2010-06-14 08:13:16 +00:00
2010-03-17 09:44:19 +00:00
// If PAUSE pressed, then pause movie
if ( ( key = = KEY_PAUSE ) | | ( key = = KEY_COMMAND + KEY_P ) )
{
2021-09-19 10:53:48 +00:00
if ( auto pause_window = window_create < movie_pause_window > ( w_canv ) )
2020-08-28 00:18:45 +00:00
{
2020-12-20 20:39:07 +00:00
( void ) pause_window ;
2010-03-17 09:44:19 +00:00
MVE_rmHoldMovie ( ) ;
2020-08-28 00:18:45 +00:00
}
2014-08-06 02:10:49 +00:00
return window_event_result : : handled ;
2010-03-17 09:44:19 +00:00
}
break ;
2021-09-19 10:53:48 +00:00
}
2010-03-17 09:44:19 +00:00
2010-03-18 02:49:02 +00:00
case EVENT_WINDOW_DRAW :
2020-08-28 00:18:45 +00:00
if ( ! paused )
2010-03-17 09:44:19 +00:00
{
2020-08-28 00:18:45 +00:00
result = MVE_rmStepMovie ( * pMovie . get ( ) ) ;
2021-01-17 22:23:23 +00:00
if ( result = = MVE_StepStatus : : EndOfFile )
return window_event_result : : close ;
2020-08-28 00:18:45 +00:00
if ( result ! = MVE_StepStatus : : Continue )
2010-03-18 02:49:02 +00:00
{
2020-08-28 00:18:45 +00:00
return window_event_result : : handled ;
2010-03-18 02:49:02 +00:00
}
2010-03-17 09:44:19 +00:00
}
2020-08-28 00:18:45 +00:00
draw_subtitles ( SubtitleState , frame_num ) ;
2010-06-14 08:13:16 +00:00
2010-03-17 09:44:19 +00:00
gr_palette_load ( gr_palette ) ;
2010-06-14 08:13:16 +00:00
2020-08-28 00:18:45 +00:00
if ( ! paused )
frame_num + + ;
2010-03-17 09:44:19 +00:00
break ;
2010-06-14 08:13:16 +00:00
2010-07-25 01:22:44 +00:00
case EVENT_WINDOW_CLOSE :
2021-01-17 22:23:23 +00:00
break ;
2010-03-17 09:44:19 +00:00
default :
break ;
}
2014-08-06 02:10:49 +00:00
return window_event_result : : ignored ;
2006-03-20 17:12:09 +00:00
}
//returns status. see movie.h
2022-10-02 19:51:35 +00:00
movie_play_status RunMovie ( const char * const filename , const std : : span < const char > subtitles , const int hires_flag , const play_movie_warn_missing warn_missing , const int dx , const int dy )
2006-03-20 17:12:09 +00:00
{
int track = 0 ;
2016-09-24 18:06:11 +00:00
# if DXX_USE_OGL
2013-01-06 21:03:57 +00:00
palette_array_t pal_save ;
2006-03-20 17:12:09 +00:00
# endif
// Open Movie file. If it doesn't exist, no movie, just return.
2021-07-25 23:00:56 +00:00
auto & & [ filehndl , physfserr ] = PHYSFSRWOPS_openRead ( filename ) ;
2006-03-20 17:12:09 +00:00
if ( ! filehndl )
{
2022-07-23 20:58:10 +00:00
con_printf ( warn_missing = = play_movie_warn_missing : : verbose ? CON_VERBOSE : CON_URGENT , " Failed to open movie <%s>: %s " , filename , PHYSFS_getErrorByCode ( physfserr ) ) ;
2021-01-17 22:23:23 +00:00
return movie_play_status : : skipped ;
2015-04-26 20:15:56 +00:00
}
2021-01-17 22:23:23 +00:00
MVESTREAM_ptr_t mvestream ;
if ( MVE_rmPrepMovie ( mvestream , filehndl . get ( ) , dx , dy , track ) )
{
2021-01-17 22:23:23 +00:00
return movie_play_status : : skipped ;
2021-01-17 22:23:23 +00:00
}
2015-04-26 20:15:56 +00:00
const auto reshow = hide_menus ( ) ;
2021-09-19 10:53:48 +00:00
auto wind = window_create < movie > ( grd_curscreen - > sc_canvas , std : : move ( mvestream ) ) ;
2022-10-09 23:15:20 +00:00
init_subtitles ( wind - > SubtitleState , subtitles ) ;
2020-08-28 00:18:45 +00:00
2016-09-24 18:06:11 +00:00
# if DXX_USE_OGL
2007-02-08 15:36:56 +00:00
set_screen_mode ( SCREEN_MOVIE ) ;
2013-01-06 21:03:57 +00:00
gr_copy_palette ( pal_save , gr_palette ) ;
2006-03-20 17:12:09 +00:00
gr_palette_load ( gr_palette ) ;
2015-04-26 20:15:56 +00:00
( void ) hires_flag ;
2006-09-29 00:54:55 +00:00
# else
2015-05-14 02:23:13 +00:00
gr_set_mode ( hires_flag ? screen_mode { 640 , 480 } : screen_mode { 320 , 200 } ) ;
2006-03-20 17:12:09 +00:00
# endif
Move window existence flag to a mixin, and track using std::shared_ptr
gcc-12 does enough escape analysis to notice that
newmenu::process_until_closed stores the address of a stack local into a
heap-allocated structure, but not enough analysis to notice that the
stack variable always outlives the escaped address. The compiler then
warns about the address escaping the local scope. Reworking the calling
code not to do this is somewhat invasive, and gcc seems unlikely to
change behavior. Switch to a less efficient implementation that does
not provoke a compiler warning:
- Store a shared_ptr<bool> in the object
- In the object's destructor, write through the pointer to clear the
shared boolean
- In the caller, store a copy of the shared_ptr<bool> as a local, and
use that copy to monitor the shared boolean
This is similar to a change proposed by JoeNotCharles
<https://github.com/dxx-rebirth/dxx-rebirth/pull/693/commits/10a2b2d33792bf7e40d2a9bc93bebb22804088ea>,
but differs in its details. Among other things, this version takes the
opportunity to move the variable out to a mixin, so that only windows
which expect to be tracked can be tracked. Previously, all windows were
capable of this, even though most never needed it.
2023-01-14 19:05:37 +00:00
for ( const auto exists = wind - > track ( ) ; * exists ; )
2020-08-28 00:18:45 +00:00
event_process ( ) ;
2021-01-17 22:23:23 +00:00
wind = nullptr ;
2006-03-20 17:12:09 +00:00
2010-03-30 03:47:51 +00:00
if ( reshow )
show_menus ( ) ;
2006-03-20 17:12:09 +00:00
// Restore old graphic state
Screen_mode = - 1 ; //force reset of screen mode
2016-09-24 18:06:11 +00:00
# if DXX_USE_OGL
2013-01-06 21:03:57 +00:00
gr_copy_palette ( gr_palette , pal_save ) ;
2006-03-20 17:12:09 +00:00
gr_palette_load ( pal_save ) ;
# endif
2021-01-17 22:23:23 +00:00
return movie_play_status : : started ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
}
2006-03-20 17:12:09 +00:00
//returns 1 if frame updated ok
2022-09-24 17:47:52 +00:00
int RotateRobot ( MVESTREAM_ptr_t & pMovie , SDL_RWops * const RoboFile )
2006-03-20 17:12:09 +00:00
{
2018-10-10 02:01:12 +00:00
auto err = MVE_rmStepMovie ( * pMovie . get ( ) ) ;
2006-03-20 17:12:09 +00:00
gr_palette_load ( gr_palette ) ;
2018-10-10 02:01:12 +00:00
if ( err = = MVE_StepStatus : : EndOfFile ) //end of movie, so reset
2006-03-20 17:12:09 +00:00
{
2022-09-24 17:47:52 +00:00
SDL_RWseek ( RoboFile , 0 , SEEK_SET ) ;
if ( MVE_rmPrepMovie ( pMovie , RoboFile , SWIDTH / 2.3 , SHEIGHT / 2.3 , 0 ) )
2006-03-20 17:12:09 +00:00
{
Int3 ( ) ;
return 0 ;
}
2018-10-10 02:01:12 +00:00
err = MVE_rmStepMovie ( * pMovie . get ( ) ) ;
2006-03-20 17:12:09 +00:00
}
2018-10-10 02:01:12 +00:00
if ( err ! = MVE_StepStatus : : Continue )
{
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
return 0 ;
}
return 1 ;
}
2014-10-29 03:01:18 +00:00
void DeInitRobotMovie ( MVESTREAM_ptr_t & pMovie )
2006-03-20 17:12:09 +00:00
{
2014-10-29 02:59:08 +00:00
pMovie . reset ( ) ;
2006-03-20 17:12:09 +00:00
}
2022-09-24 17:47:52 +00:00
RWops_ptr InitRobotMovie ( const char * filename , MVESTREAM_ptr_t & pMovie )
2006-03-20 17:12:09 +00:00
{
2007-10-01 20:42:35 +00:00
if ( GameArg . SysNoMovies )
2022-09-24 17:47:52 +00:00
return nullptr ;
2006-03-20 17:12:09 +00:00
2013-12-07 00:47:27 +00:00
con_printf ( CON_DEBUG , " RoboFile=%s " , filename ) ;
2006-03-20 17:12:09 +00:00
MVE_sndInit ( - 1 ) ; //tell movies to play no sound for robots
2022-09-24 17:47:52 +00:00
auto & & [ RoboFile , physfserr ] = PHYSFSRWOPS_openRead ( filename ) ;
2006-03-20 17:12:09 +00:00
if ( ! RoboFile )
{
2021-07-25 23:00:56 +00:00
con_printf ( CON_URGENT , " Failed to open movie <%s>: %s " , filename , PHYSFS_getErrorByCode ( physfserr ) ) ;
2022-09-24 17:47:52 +00:00
return nullptr ;
2006-03-20 17:12:09 +00:00
}
2015-02-08 17:43:29 +00:00
if ( MVE_rmPrepMovie ( pMovie , RoboFile . get ( ) , SWIDTH / 2.3 , SHEIGHT / 2.3 , 0 ) ) {
2006-03-20 17:12:09 +00:00
Int3 ( ) ;
2022-09-24 17:47:52 +00:00
return nullptr ;
2006-03-20 17:12:09 +00:00
}
2022-09-24 17:47:52 +00:00
return std : : move ( RoboFile ) ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
namespace {
2006-03-20 17:12:09 +00:00
/*
* Subtitle system code
*/
2010-06-14 08:13:16 +00:00
//search for next field following whitespace
2013-10-27 22:00:14 +00:00
static char * next_field ( char * p )
2006-03-20 17:12:09 +00:00
{
while ( * p & & ! isspace ( * p ) )
p + + ;
if ( ! * p )
return NULL ;
while ( * p & & isspace ( * p ) )
p + + ;
if ( ! * p )
return NULL ;
return p ;
}
2022-10-09 23:15:20 +00:00
static int init_subtitles ( d_loaded_subtitle_state & SubtitleState , const std : : span < const char > filename )
2006-03-20 17:12:09 +00:00
{
2022-10-09 23:15:20 +00:00
if ( filename . empty ( ) )
2013-10-27 21:01:04 +00:00
return 0 ;
2006-03-20 17:12:09 +00:00
int size , read_count ;
char * p ;
int have_binary = 0 ;
2018-12-30 00:43:58 +00:00
SubtitleState . Num_subtitles = 0 ;
2006-03-20 17:12:09 +00:00
2010-09-02 13:55:28 +00:00
if ( ! GameCfg . MovieSubtitles )
2018-12-30 00:43:58 +00:00
{
con_puts ( CON_VERBOSE , " Rebirth: movie subtitles are disabled " ) ;
2006-03-20 17:12:09 +00:00
return 0 ;
2018-12-30 00:43:58 +00:00
}
2006-03-20 17:12:09 +00:00
2022-10-09 23:15:20 +00:00
auto & & [ ifile , physfserr ] = PHYSFSX_openReadBuffered ( filename . data ( ) ) ; //try text version
2006-03-20 17:12:09 +00:00
if ( ! ifile ) { //no text version, try binary version
2022-10-09 23:15:20 +00:00
std : : array < char , FILENAME_LEN > filename2 ;
2022-10-09 23:15:20 +00:00
if ( ! change_filename_extension ( filename2 , filename . data ( ) , " txb " ) )
{
con_printf ( CON_NORMAL , " Rebirth: skipping subtitles because cannot open \" %s \" ( \" %s \" ) " , filename . data ( ) , PHYSFS_getErrorByCode ( physfserr ) ) ;
return 0 ;
}
2022-10-09 23:15:20 +00:00
auto & & [ ifile2 , physfserr2 ] = PHYSFSX_openReadBuffered ( filename2 . data ( ) ) ;
2021-07-25 23:00:56 +00:00
if ( ! ifile2 )
2018-12-30 00:43:58 +00:00
{
2022-10-09 23:15:20 +00:00
con_printf ( CON_VERBOSE , " Rebirth: skipping subtitles because cannot open \" %s \" or \" %s \" ( \" %s \" , \" %s \" ) " , filename . data ( ) , filename2 . data ( ) , PHYSFS_getErrorByCode ( physfserr ) , PHYSFS_getErrorByCode ( physfserr2 ) ) ;
2006-03-20 17:12:09 +00:00
return 0 ;
2018-12-30 00:43:58 +00:00
}
2021-07-25 23:00:56 +00:00
ifile = std : : move ( ifile2 ) ;
2006-03-20 17:12:09 +00:00
have_binary = 1 ;
2022-10-09 23:15:20 +00:00
con_printf ( CON_VERBOSE , " Rebirth: found encoded subtitles in \" %s \" " , filename2 . data ( ) ) ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
else
2022-10-09 23:15:20 +00:00
con_printf ( CON_VERBOSE , " Rebirth: found text subtitles in \" %s \" " , filename . data ( ) ) ;
2006-03-20 17:12:09 +00:00
2011-06-01 07:59:55 +00:00
size = PHYSFS_fileLength ( ifile ) ;
2006-03-20 17:12:09 +00:00
2020-05-02 21:18:42 +00:00
const auto subtitle_raw_data = ( SubtitleState . subtitle_raw_data = std : : make_unique < char [ ] > ( size + 1 ) ) . get ( ) ;
2011-06-01 07:59:55 +00:00
read_count = PHYSFS_read ( ifile , subtitle_raw_data , 1 , size ) ;
2015-01-17 18:31:42 +00:00
ifile . reset ( ) ;
2006-03-20 17:12:09 +00:00
if ( read_count ! = size ) {
2018-12-30 00:43:58 +00:00
con_puts ( CON_VERBOSE , " Rebirth: skipping subtitles because cannot read full subtitle file " ) ;
2006-03-20 17:12:09 +00:00
return 0 ;
}
2018-12-30 00:43:58 +00:00
subtitle_raw_data [ size ] = 0 ;
2006-03-20 17:12:09 +00:00
p = subtitle_raw_data ;
while ( p & & p < subtitle_raw_data + size ) {
char * endp ;
2010-06-14 08:13:16 +00:00
endp = strchr ( p , ' \n ' ) ;
2006-03-20 17:12:09 +00:00
if ( endp ) {
if ( endp [ - 1 ] = = ' \r ' )
endp [ - 1 ] = 0 ; //handle 0d0a pair
* endp = 0 ; //string termintor
}
if ( have_binary )
decode_text_line ( p ) ;
if ( * p ! = ' ; ' ) {
2018-12-30 00:43:58 +00:00
const auto Num_subtitles = SubtitleState . Num_subtitles ;
auto & Subtitles = SubtitleState . Subtitles ;
auto & s = Subtitles [ SubtitleState . Num_subtitles + + ] ;
s . first_frame = atoi ( p ) ;
2006-03-20 17:12:09 +00:00
p = next_field ( p ) ; if ( ! p ) continue ;
2018-12-30 00:43:58 +00:00
s . last_frame = atoi ( p ) ;
2006-03-20 17:12:09 +00:00
p = next_field ( p ) ; if ( ! p ) continue ;
2018-12-30 00:43:58 +00:00
s . msg = p ;
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:58 +00:00
if ( Num_subtitles )
{
assert ( s . first_frame > = Subtitles [ Num_subtitles - 1 ] . first_frame ) ;
}
assert ( s . last_frame > = s . first_frame ) ;
2006-03-20 17:12:09 +00:00
}
p = endp + 1 ;
}
return 1 ;
}
//draw the subtitles for this frame
2021-09-12 16:20:52 +00:00
static void draw_subtitles ( const d_loaded_subtitle_state & SubtitleState , const int frame_num )
2006-03-20 17:12:09 +00:00
{
2021-09-12 16:20:52 +00:00
static std : : array < uint16_t , MAX_ACTIVE_SUBTITLES > active_subtitles ;
2016-10-15 00:53:15 +00:00
static int next_subtitle ;
static unsigned num_active_subtitles ;
2014-09-26 02:42:16 +00:00
int y ;
2006-03-20 17:12:09 +00:00
int must_erase = 0 ;
if ( frame_num = = 0 ) {
num_active_subtitles = 0 ;
next_subtitle = 0 ;
2020-12-27 22:03:09 +00:00
gr_set_curfont ( * grd_curcanv , * GAME_FONT ) ;
2017-02-11 21:42:32 +00:00
gr_set_fontcolor ( * grd_curcanv , 255 , - 1 ) ;
2006-03-20 17:12:09 +00:00
}
//get rid of any subtitles that have expired
2018-12-30 00:43:58 +00:00
auto & Subtitles = SubtitleState . Subtitles ;
2014-09-26 02:42:16 +00:00
for ( int t = 0 ; t < num_active_subtitles ; )
2006-03-20 17:12:09 +00:00
if ( frame_num > Subtitles [ active_subtitles [ t ] ] . last_frame ) {
int t2 ;
for ( t2 = t ; t2 < num_active_subtitles - 1 ; t2 + + )
active_subtitles [ t2 ] = active_subtitles [ t2 + 1 ] ;
num_active_subtitles - - ;
must_erase = 1 ;
}
else
t + + ;
2010-06-14 08:13:16 +00:00
//get any subtitles new for this frame
2018-12-30 00:43:58 +00:00
while ( next_subtitle < SubtitleState . Num_subtitles & & frame_num > = Subtitles [ next_subtitle ] . first_frame ) {
2006-03-20 17:12:09 +00:00
if ( num_active_subtitles > = MAX_ACTIVE_SUBTITLES )
Error ( " Too many active subtitles! " ) ;
active_subtitles [ num_active_subtitles + + ] = next_subtitle ;
next_subtitle + + ;
}
//find y coordinate for first line of subtitles
2018-05-19 23:21:42 +00:00
const auto & & line_spacing = LINE_SPACING ( * grd_curcanv - > cv_font , * GAME_FONT ) ;
2015-06-13 22:42:22 +00:00
y = grd_curcanv - > cv_bitmap . bm_h - ( line_spacing * ( MAX_ACTIVE_SUBTITLES + 2 ) ) ;
2006-03-20 17:12:09 +00:00
//erase old subtitles if necessary
if ( must_erase ) {
2020-07-16 02:31:04 +00:00
gr_rect ( * grd_curcanv , 0 , y , grd_curcanv - > cv_bitmap . bm_w - 1 , grd_curcanv - > cv_bitmap . bm_h - 1 , color_palette_index { 0 } ) ;
2006-03-20 17:12:09 +00:00
}
//now draw the current subtitles
2016-10-15 00:53:15 +00:00
range_for ( const auto & t , partial_range ( active_subtitles , num_active_subtitles ) )
{
2018-05-19 23:21:42 +00:00
gr_string ( * grd_curcanv , * grd_curcanv - > cv_font , 0x8000 , y , Subtitles [ t ] . msg ) ;
2015-06-13 22:42:22 +00:00
y + = line_spacing ;
2006-03-20 17:12:09 +00:00
}
}
2021-07-25 23:00:56 +00:00
static PHYSFS_ErrorCode init_movie ( const char * movielib , char resolution , int required , LoadedMovie & movie )
2006-03-20 17:12:09 +00:00
{
2021-06-28 03:37:49 +00:00
std : : array < char , FILENAME_LEN + 2 > filename ;
snprintf ( & filename [ 0 ] , filename . size ( ) , " %s-%c.mvl " , movielib , resolution ) ;
auto r = PHYSFSX_addRelToSearchPath ( & filename [ 0 ] , movie . pathname , physfs_search_path : : prepend ) ;
2021-07-25 23:00:56 +00:00
if ( r ! = PHYSFS_ERR_OK )
2014-12-06 17:56:56 +00:00
{
2021-06-28 03:37:49 +00:00
movie . pathname [ 0 ] = 0 ;
2021-07-25 23:00:56 +00:00
con_printf ( required ? CON_URGENT : CON_VERBOSE , " Failed to open movielib <%s>: %s " , & filename [ 0 ] , PHYSFS_getErrorByCode ( r ) ) ;
2014-12-06 17:56:56 +00:00
}
return r ;
}
2006-03-20 17:12:09 +00:00
2022-09-24 17:47:52 +00:00
static std : : pair < PHYSFS_ErrorCode , movie_resolution > init_movie ( const char * movielib , int required , LoadedMovie & movie )
2014-12-06 17:56:56 +00:00
{
if ( ! GameArg . GfxSkipHiresMovie )
2006-03-20 17:12:09 +00:00
{
2021-07-25 23:00:56 +00:00
if ( auto r = init_movie ( movielib , ' h ' , required , movie ) ; r = = PHYSFS_ERR_OK )
2022-09-24 17:47:52 +00:00
return { r , movie_resolution : : high } ;
2006-03-20 17:12:09 +00:00
}
2022-09-24 17:47:52 +00:00
return { init_movie ( movielib , ' l ' , required , movie ) , movie_resolution : : low } ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
}
2006-03-20 17:12:09 +00:00
//find and initialize the movie libraries
2021-06-28 03:37:49 +00:00
std : : unique_ptr < BuiltinMovies > init_movies ( )
2006-03-20 17:12:09 +00:00
{
2007-10-01 20:42:35 +00:00
if ( GameArg . SysNoMovies )
2021-06-28 03:37:49 +00:00
return nullptr ;
2006-03-20 17:12:09 +00:00
2021-06-28 03:37:49 +00:00
auto r = std : : make_unique < BuiltinMovies > ( ) ;
for ( auto & & [ f , m ] : zip ( movielib_files , r - > movies ) )
init_movie ( & f [ 0 ] , 1 , m ) ;
return r ;
2006-03-20 17:12:09 +00:00
}
2021-06-28 03:37:49 +00:00
LoadedMovie : : ~ LoadedMovie ( )
2007-03-31 20:21:32 +00:00
{
2021-06-28 03:37:49 +00:00
const auto movielib = pathname . data ( ) ;
2014-12-06 17:56:56 +00:00
if ( ! * movielib )
return ;
2021-06-28 03:37:49 +00:00
if ( ! PHYSFS_unmount ( movielib ) )
con_printf ( CON_URGENT , " Cannot close movielib <%s>: %s " , movielib , PHYSFS_getLastError ( ) ) ;
2021-07-25 23:00:56 +00:00
else
con_printf ( CON_VERBOSE , " Unloaded movielib <%s> " , movielib ) ;
2007-03-31 20:21:32 +00:00
}
2006-03-20 17:12:09 +00:00
2022-09-24 17:47:52 +00:00
std : : unique_ptr < LoadedMovieWithResolution > init_extra_robot_movie ( const char * movielib )
2006-03-20 17:12:09 +00:00
{
2007-10-01 20:42:35 +00:00
if ( GameArg . SysNoMovies )
2021-06-28 03:37:49 +00:00
return nullptr ;
2022-09-24 17:47:52 +00:00
auto r = std : : make_unique < LoadedMovieWithResolution > ( ) ;
if ( auto & & [ code , resolution ] = init_movie ( movielib , 0 , * r ) ; code ! = PHYSFS_ERR_OK )
2021-06-28 03:37:49 +00:00
return nullptr ;
2022-09-24 17:47:52 +00:00
else
{
r - > resolution = resolution ;
return r ;
}
2021-06-28 03:37:49 +00:00
}
2006-03-20 17:12:09 +00:00
}