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"
# 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
2018-12-30 00:43:58 +00:00
struct d_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 ;
2020-05-02 21:18:42 +00:00
std : : array < subtitle , 500 > Subtitles ;
2013-10-27 21:01:04 +00:00
} ;
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:58 +00:00
static int init_subtitles ( d_subtitle_state & SubtitleState , 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
2015-02-08 17:43:29 +00:00
static RWops_ptr RoboFile ;
2006-03-20 17:12:09 +00:00
// Function Prototypes
2021-01-17 22:23:23 +00:00
static movie_play_status RunMovie ( const char * filename , const char * subtitles , int highres_flag , int allow_abort , int dx , int dy ) ;
2006-03-20 17:12:09 +00:00
2018-12-30 00:43:58 +00:00
static void draw_subtitles ( const d_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
{
using window : : window ;
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
}
2021-01-17 22:23:23 +00:00
void * MovieMemoryAllocate ( std : : size_t size )
{
return d_malloc ( size ) ;
}
void MovieMemoryFree ( void * p )
{
d_free ( p ) ;
}
2021-01-17 22:23:23 +00:00
unsigned int MovieFileRead ( void * handle , void * buf , unsigned int count )
{
const unsigned numread = SDL_RWread ( reinterpret_cast < SDL_RWops * > ( handle ) , buf , 1 , count ) ;
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
2021-01-17 22:23:23 +00:00
movie_play_status PlayMovie ( const char * subtitles , const char * filename , int must_have )
2006-03-20 17:12:09 +00:00
{
char name [ FILENAME_LEN ] , * p ;
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
strcpy ( name , filename ) ;
if ( ( p = strchr ( name , ' . ' ) ) = = NULL ) //add extension, if missing
2018-05-18 02:47:32 +00:00
strcat ( name , " .MVE " ) ;
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
2021-01-17 22:23:23 +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 {
2020-08-28 00:18:45 +00:00
struct movie : 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 ;
2018-12-30 00:43:58 +00:00
d_subtitle_state SubtitleState ;
2021-01-17 22:23:23 +00:00
movie ( grs_canvas & src , int x , int y , int w , int h , MVESTREAM_ptr_t mvestream ) :
window ( src , x , y , w , h ) ,
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 :
2011-01-14 09:51:13 +00:00
if ( event_mouse_get_button ( event ) ! = 0 )
2014-08-06 02:10:49 +00:00
return window_event_result : : ignored ;
2019-04-04 04:29:03 +00:00
DXX_BOOST_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 ;
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 ;
2015-09-29 02:41:22 +00:00
int h ;
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 ;
gr_get_string_size ( game_font , msg , nullptr , & h , nullptr ) ;
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
{
2010-03-17 09:44:19 +00:00
int key ;
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 :
2011-01-14 09:51:13 +00:00
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 ) )
{
2020-12-20 20:39:07 +00:00
if ( auto pause_window = window_create < movie_pause_window > ( grd_curscreen - > sc_canvas , 0 , 0 , SWIDTH , SHEIGHT ) )
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 ;
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
2021-01-17 22:23:23 +00:00
movie_play_status RunMovie ( const char * const filename , const char * const subtitles , const int hires_flag , const int must_have , 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 )
{
2021-07-25 23:00:56 +00:00
con_printf ( must_have ? CON_URGENT : CON_VERBOSE , " 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-01-17 22:23:23 +00:00
auto wind = window_create < movie > ( grd_curscreen - > sc_canvas , 0 , 0 , SWIDTH , SHEIGHT , std : : move ( mvestream ) ) ;
2021-01-17 22:23:23 +00:00
bool exists = true ;
wind - > track ( & exists ) ;
2020-08-28 00:18:45 +00:00
init_subtitles ( wind - > SubtitleState , subtitles ) ;
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
2021-01-17 22:23:23 +00:00
while ( 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
2015-02-08 17:43:29 +00:00
filehndl . reset ( ) ; // Close Movie File
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
2014-10-29 03:01:18 +00:00
int RotateRobot ( MVESTREAM_ptr_t & pMovie )
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
{
2015-02-08 17:43:29 +00:00
SDL_RWseek ( RoboFile . get ( ) , 0 , SEEK_SET ) ;
if ( MVE_rmPrepMovie ( pMovie , RoboFile . get ( ) , 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 ( ) ;
2015-02-08 17:43:29 +00:00
RoboFile . reset ( ) ; // Close Movie File
2006-03-20 17:12:09 +00:00
}
2014-10-29 03:01:18 +00:00
int 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 )
2006-03-20 17:12:09 +00:00
return 0 ;
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
2021-07-25 23:00:56 +00:00
auto & & [ filehndl , physfserr ] = PHYSFSRWOPS_openRead ( filename ) ;
RoboFile = std : : move ( filehndl ) ;
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 ) ) ;
2021-01-17 22:23:23 +00:00
return 0 ;
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 ( ) ;
return 0 ;
}
return 1 ;
}
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 ;
}
2018-12-30 00:43:58 +00:00
static int init_subtitles ( d_subtitle_state & SubtitleState , const char * const filename )
2006-03-20 17:12:09 +00:00
{
2013-10-27 21:01:04 +00:00
if ( ! filename )
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
2021-07-25 23:00:56 +00:00
auto & & [ ifile , physfserr ] = PHYSFSX_openReadBuffered ( filename ) ; //try text version
2006-03-20 17:12:09 +00:00
if ( ! ifile ) { //no text version, try binary version
char filename2 [ FILENAME_LEN ] ;
2006-10-10 00:47:10 +00:00
change_filename_extension ( filename2 , filename , " .txb " ) ;
2021-07-25 23:00:56 +00:00
auto & & [ ifile2 , physfserr2 ] = PHYSFSX_openReadBuffered ( filename2 ) ;
if ( ! ifile2 )
2018-12-30 00:43:58 +00:00
{
2021-07-25 23:00:56 +00:00
con_printf ( CON_VERBOSE , " Rebirth: skipping subtitles because cannot open \" %s \" or \" %s \" ( \" %s \" , \" %s \" ) " , filename , filename2 , 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 ;
2018-12-30 00:43:58 +00:00
con_printf ( CON_VERBOSE , " Rebirth: found encoded subtitles in \" %s \" " , filename2 ) ;
2006-03-20 17:12:09 +00:00
}
2018-12-30 00:43:58 +00:00
else
con_printf ( CON_VERBOSE , " Rebirth: found text subtitles in \" %s \" " , filename ) ;
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
2018-12-30 00:43:58 +00:00
static void draw_subtitles ( const d_subtitle_state & SubtitleState , const int frame_num )
2006-03-20 17:12:09 +00:00
{
static int active_subtitles [ MAX_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 ) )
if ( t ! = - 1 )
{
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
2021-07-25 23:00:56 +00:00
static PHYSFS_ErrorCode 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 )
2021-06-28 03:37:49 +00:00
return r ;
2006-03-20 17:12:09 +00:00
}
2021-06-28 03:37:49 +00:00
return init_movie ( movielib , ' l ' , required , movie ) ;
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
2021-06-28 03:37:49 +00:00
std : : unique_ptr < LoadedMovie > 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 ;
auto r = std : : make_unique < LoadedMovie > ( ) ;
2021-07-25 23:00:56 +00:00
if ( init_movie ( movielib , 0 , * r ) ! = PHYSFS_ERR_OK )
2021-06-28 03:37:49 +00:00
return nullptr ;
return r ;
}
2006-03-20 17:12:09 +00:00
}