Unload robot movies on exit

This commit is contained in:
Kp 2021-06-28 03:37:49 +00:00
parent 76a7361786
commit d0d7545ec1
6 changed files with 127 additions and 60 deletions

View file

@ -73,6 +73,7 @@ constexpr std::integral_constant<uint8_t, 127> MAX_SECRET_LEVELS_PER_MISSION{};
#define FULL_MISSION_HOGSIZE 7595079 // v1.1 - 1.2 #define FULL_MISSION_HOGSIZE 7595079 // v1.1 - 1.2
#define FULL_10_MISSION_HOGSIZE 7107354 // v1.0 #define FULL_10_MISSION_HOGSIZE 7107354 // v1.0
#define MAC_FULL_MISSION_HOGSIZE 7110007 // v1.1 - 1.2 #define MAC_FULL_MISSION_HOGSIZE 7110007 // v1.1 - 1.2
#include "movie.h"
#endif #endif
//where the missions go //where the missions go
@ -132,6 +133,8 @@ public:
}; };
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II) #if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
namespace dsx {
struct Mission : Mission_path struct Mission : Mission_path
{ {
std::unique_ptr<ubyte[]> secret_level_table; // originating level no for each secret level std::unique_ptr<ubyte[]> secret_level_table; // originating level no for each secret level
@ -149,6 +152,7 @@ struct Mission : Mission_path
#if defined(DXX_BUILD_DESCENT_II) #if defined(DXX_BUILD_DESCENT_II)
descent_version_type descent_version; // descent 1 or descent 2? descent_version_type descent_version; // descent 1 or descent 2?
std::unique_ptr<d_fname> alternate_ham_file; std::unique_ptr<d_fname> alternate_ham_file;
std::unique_ptr<LoadedMovie> extra_robot_movie;
#endif #endif
/* Explicitly default move constructor and move operator= /* Explicitly default move constructor and move operator=
* *
@ -203,6 +207,8 @@ extern Mission_ptr Current_mission; // current mission
#endif #endif
#define PLAYING_BUILTIN_MISSION (Current_mission->builtin_hogsize != 0) #define PLAYING_BUILTIN_MISSION (Current_mission->builtin_hogsize != 0)
#define ANARCHY_ONLY_MISSION (1 == Current_mission->anarchy_only_flag) #define ANARCHY_ONLY_MISSION (1 == Current_mission->anarchy_only_flag)
}
#endif #endif
//values for d1 built-in mission //values for d1 built-in mission

View file

@ -20,10 +20,14 @@
using namespace dcx; using namespace dcx;
namespace {
static unsigned short *backBuf1, *backBuf2; static unsigned short *backBuf1, *backBuf2;
static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, const unsigned char **pData, const unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb); static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, const unsigned char **pData, const unsigned char **pOffData, int *pDataRemain, int *curXb, int *curYb);
}
void decodeFrame16(unsigned char *pFrame, const unsigned char *pMap, int mapRemain, const unsigned char *pData, int dataRemain) void decodeFrame16(unsigned char *pFrame, const unsigned char *pMap, int mapRemain, const unsigned char *pData, int dataRemain)
{ {
unsigned short offset; unsigned short offset;
@ -86,6 +90,8 @@ void decodeFrame16(unsigned char *pFrame, const unsigned char *pMap, int mapRema
} }
} }
namespace {
static uint16_t GETPIXEL(const unsigned char **buf, int off) static uint16_t GETPIXEL(const unsigned char **buf, int off)
{ {
unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8); unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8);
@ -104,12 +110,12 @@ struct position_t
int x, y; int x, y;
}; };
static inline constexpr position_t relClose(int i) static constexpr position_t relClose(int i)
{ {
return {(i & 0xf) - 8, (i >> 4) - 8}; return {(i & 0xf) - 8, (i >> 4) - 8};
} }
static inline constexpr position_t relFar0(int i, int sign) static constexpr position_t relFar0(int i, int sign)
{ {
return { return {
sign * (8 + (i % 7)), sign * (8 + (i % 7)),
@ -117,7 +123,7 @@ static inline constexpr position_t relFar0(int i, int sign)
}; };
} }
static inline constexpr position_t relFar56(int i, int sign) static constexpr position_t relFar56(int i, int sign)
{ {
return { return {
sign * (-14 + (i - 56) % 29), sign * (-14 + (i - 56) % 29),
@ -125,7 +131,7 @@ static inline constexpr position_t relFar56(int i, int sign)
}; };
} }
static inline constexpr position_t relFar(int i, int sign) static constexpr position_t relFar(int i, int sign)
{ {
return (i < 56) ? relFar0(i, sign) : relFar56(i, sign); return (i < 56) ? relFar0(i, sign) : relFar56(i, sign);
} }
@ -136,7 +142,7 @@ struct lookup_table_t
}; };
template <std::size_t... N> template <std::size_t... N>
static inline constexpr lookup_table_t genLoopkupTable(std::index_sequence<N...>) static constexpr lookup_table_t genLoopkupTable(std::index_sequence<N...>)
{ {
return lookup_table_t{ return lookup_table_t{
{{relClose(N)...}}, {{relClose(N)...}},
@ -716,3 +722,5 @@ static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, c
*pFrame = pDstBak+8; *pFrame = pDstBak+8;
} }
}

View file

@ -15,6 +15,8 @@
#include "mvelib.h" #include "mvelib.h"
#include <memory> #include <memory>
namespace {
static const char MVE_HEADER[] = "Interplay MVE File\x1A"; static const char MVE_HEADER[] = "Interplay MVE File\x1A";
constexpr short MVE_HDRCONST1 = 0x001A; constexpr short MVE_HDRCONST1 = 0x001A;
constexpr short MVE_HDRCONST2 = 0x0100; constexpr short MVE_HDRCONST2 = 0x0100;
@ -40,6 +42,8 @@ static int _mvefile_fetch_next_chunk(MVEFILE *movie);
static int _mvestream_open(MVESTREAM *movie, void *stream); static int _mvestream_open(MVESTREAM *movie, void *stream);
static void _mvestream_reset(MVESTREAM *movie); static void _mvestream_reset(MVESTREAM *movie);
}
/************************************************************ /************************************************************
* public MVEFILE functions * public MVEFILE functions
************************************************************/ ************************************************************/
@ -70,6 +74,8 @@ std::unique_ptr<MVEFILE> mvefile_open(void *stream)
return file; return file;
} }
namespace {
/* /*
* reset a MVE file * reset a MVE file
*/ */
@ -99,6 +105,8 @@ static bool have_segment_header(const MVEFILE *movie)
return true; return true;
} }
}
/* /*
* get the size of the next segment * get the size of the next segment
*/ */
@ -262,6 +270,8 @@ MVEFILE::~MVEFILE()
{ {
} }
namespace {
/* /*
* open the file stream in thie object * open the file stream in thie object
*/ */
@ -359,6 +369,8 @@ static uint16_t _mve_get_ushort(const unsigned char *data)
return value; return value;
} }
}
/* /*
* allocate an MVESTREAM * allocate an MVESTREAM
*/ */
@ -371,6 +383,8 @@ MVESTREAM::~MVESTREAM()
{ {
} }
namespace {
/* /*
* open an MVESTREAM object * open an MVESTREAM object
*/ */
@ -388,3 +402,5 @@ static void _mvestream_reset(MVESTREAM *movie)
{ {
mvefile_reset(movie->movie.get()); mvefile_reset(movie->movie.get());
} }
}

View file

@ -62,6 +62,9 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#include "compiler-range_for.h" #include "compiler-range_for.h"
#include "partial_range.h" #include "partial_range.h"
#include "d_zip.h"
namespace dsx {
namespace { namespace {
@ -88,13 +91,6 @@ constexpr std::array<std::array<char, 8>, 3> movielib_files{{
{"intro"}, {"other"}, {"robots"} {"intro"}, {"other"}, {"robots"}
}}; }};
struct loaded_movie_t
{
std::array<char, FILENAME_LEN + 2> filename;
};
static loaded_movie_t extra_robot_movie_mission;
static RWops_ptr RoboFile; static RWops_ptr RoboFile;
// Function Prototypes // Function Prototypes
@ -112,6 +108,8 @@ struct movie_pause_window : window
} }
}
void *MovieMemoryAllocate(std::size_t size) void *MovieMemoryAllocate(std::size_t size)
{ {
return d_malloc(size); return d_malloc(size);
@ -130,6 +128,7 @@ unsigned int MovieFileRead(void *handle, void *buf, unsigned int count)
//----------------------------------------------------------------------- //-----------------------------------------------------------------------
namespace dsx {
//filename will actually get modified to be either low-res or high-res //filename will actually get modified to be either low-res or high-res
//returns status. see values in movie.h //returns status. see values in movie.h
@ -170,6 +169,8 @@ movie_play_status PlayMovie(const char *subtitles, const char *filename, int mus
return ret; return ret;
} }
}
void MovieShowFrame(const uint8_t *buf, int dstx, int dsty, int bufw, int bufh, int sw, int sh) void MovieShowFrame(const uint8_t *buf, int dstx, int dsty, int bufw, int bufh, int sw, int sh)
{ {
grs_bitmap source_bm; grs_bitmap source_bm;
@ -243,6 +244,8 @@ void MovieSetPalette(const unsigned char *p, unsigned start, unsigned count)
memcpy(&gr_palette[start],p+start*3,count*3); memcpy(&gr_palette[start],p+start*3,count*3);
} }
namespace dsx {
namespace { namespace {
struct movie : window struct movie : window
@ -443,14 +446,12 @@ int RotateRobot(MVESTREAM_ptr_t &pMovie)
return 1; return 1;
} }
void DeInitRobotMovie(MVESTREAM_ptr_t &pMovie) void DeInitRobotMovie(MVESTREAM_ptr_t &pMovie)
{ {
pMovie.reset(); pMovie.reset();
RoboFile.reset(); // Close Movie File RoboFile.reset(); // Close Movie File
} }
int InitRobotMovie(const char *filename, MVESTREAM_ptr_t &pMovie) int InitRobotMovie(const char *filename, MVESTREAM_ptr_t &pMovie)
{ {
if (GameArg.SysNoMovies) if (GameArg.SysNoMovies)
@ -636,60 +637,60 @@ static void draw_subtitles(const d_subtitle_state &SubtitleState, const int fram
} }
} }
static int init_movie(const char *movielib, char resolution, int required, loaded_movie_t &movie) static int init_movie(const char *movielib, char resolution, int required, LoadedMovie &movie)
{ {
snprintf(&movie.filename[0], movie.filename.size(), "%s-%c.mvl", movielib, resolution); std::array<char, FILENAME_LEN + 2> filename;
std::array<char, PATH_MAX> pathname; snprintf(&filename[0], filename.size(), "%s-%c.mvl", movielib, resolution);
auto r = PHYSFSX_addRelToSearchPath(&movie.filename[0], pathname, physfs_search_path::prepend); auto r = PHYSFSX_addRelToSearchPath(&filename[0], movie.pathname, physfs_search_path::prepend);
if (!r) if (!r)
{ {
if (required || CGameArg.DbgVerbose) con_printf(required ? CON_URGENT : CON_VERBOSE, "Can't open movielib <%s>: %s", &filename[0], PHYSFS_getLastError());
con_printf(CON_URGENT, "Can't open movielib <%s>: %s", &movie.filename[0], PHYSFS_getLastError()); movie.pathname[0] = 0;
movie.filename[0] = 0;
} }
return r; return r;
} }
static void init_movie(const char *movielib, int required, loaded_movie_t &movie) static int init_movie(const char *movielib, int required, LoadedMovie &movie)
{ {
if (!GameArg.GfxSkipHiresMovie) if (!GameArg.GfxSkipHiresMovie)
{ {
if (init_movie(movielib, 'h', required, movie)) if (auto r = init_movie(movielib, 'h', required, movie))
return; return r;
} }
init_movie(movielib, 'l', required, movie); return init_movie(movielib, 'l', required, movie);
} }
} }
//find and initialize the movie libraries //find and initialize the movie libraries
void init_movies() std::unique_ptr<BuiltinMovies> init_movies()
{ {
if (GameArg.SysNoMovies) if (GameArg.SysNoMovies)
return; return nullptr;
range_for (auto &i, movielib_files) auto r = std::make_unique<BuiltinMovies>();
{ for (auto &&[f, m] : zip(movielib_files, r->movies))
loaded_movie_t m; init_movie(&f[0], 1, m);
init_movie(&i[0], 1, m); return r;
}
} }
void close_extra_robot_movie() LoadedMovie::~LoadedMovie()
{ {
const auto movielib = &extra_robot_movie_mission.filename[0]; const auto movielib = pathname.data();
if (!*movielib) if (!*movielib)
return; return;
if (!PHYSFSX_contfile_close(movielib)) if (!PHYSFS_unmount(movielib))
{ con_printf(CON_URGENT, "Cannot close movielib <%s>: %s", movielib, PHYSFS_getLastError());
con_printf(CON_URGENT, "Can't close movielib <%s>: %s", movielib, PHYSFS_getLastError());
}
*movielib = 0;
} }
void init_extra_robot_movie(const char *movielib) std::unique_ptr<LoadedMovie> init_extra_robot_movie(const char *movielib)
{ {
if (GameArg.SysNoMovies) if (GameArg.SysNoMovies)
return; return nullptr;
init_movie(movielib, 0, extra_robot_movie_mission); auto r = std::make_unique<LoadedMovie>();
if (!init_movie(movielib, 0, *r))
return nullptr;
return r;
}
} }

View file

@ -25,8 +25,11 @@ COPYRIGHT 1993-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED.
#pragma once #pragma once
#ifdef __cplusplus #include <limits.h>
#include "d2x-rebirth/libmve/mvelib.h" #include "d2x-rebirth/libmve/mvelib.h"
#include "dsx-ns.h"
namespace dsx {
#define MOVIE_ABORT_ON 1 #define MOVIE_ABORT_ON 1
#define MOVIE_ABORT_OFF 0 #define MOVIE_ABORT_OFF 0
@ -50,12 +53,25 @@ int InitRobotMovie(const char *filename, MVESTREAM_ptr_t &pMovie);
int RotateRobot(MVESTREAM_ptr_t &pMovie); int RotateRobot(MVESTREAM_ptr_t &pMovie);
void DeInitRobotMovie(MVESTREAM_ptr_t &pMovie); void DeInitRobotMovie(MVESTREAM_ptr_t &pMovie);
// find and initialize the movie libraries struct LoadedMovie
void init_movies(); {
std::array<char, PATH_MAX> pathname;
LoadedMovie()
{
pathname[0] = 0;
}
~LoadedMovie();
};
void init_extra_robot_movie(const char *filename); struct BuiltinMovies
void close_extra_robot_movie(); {
std::array<LoadedMovie, 3> movies;
};
// find and initialize the movie libraries
std::unique_ptr<BuiltinMovies> init_movies();
std::unique_ptr<LoadedMovie> init_extra_robot_movie(const char *filename);
extern int MovieHires; // specifies whether movies use low or high res extern int MovieHires; // specifies whether movies use low or high res
#endif }

View file

@ -239,9 +239,11 @@ static const mle *compare_mission_by_pathname(const mission_entry_predicate miss
} }
Mission_ptr Current_mission; // currently loaded mission
} }
Mission_ptr Current_mission; // currently loaded mission namespace {
static bool null_or_space(char c) static bool null_or_space(char c)
{ {
@ -552,8 +554,13 @@ static bool ml_sort_func(const mle &e0,const mle &e1)
return d_stricmp(e0.mission_name,e1.mission_name) < 0; return d_stricmp(e0.mission_name,e1.mission_name) < 0;
} }
}
//returns 1 if file read ok, else 0 //returns 1 if file read ok, else 0
namespace dsx { namespace dsx {
namespace {
static int read_mission_file(mission_list_type &mission_list, mission_candidate_search_path &pathname) static int read_mission_file(mission_list_type &mission_list, mission_candidate_search_path &pathname)
{ {
if (const auto mfile = PHYSFSX_openReadBuffered(pathname.data())) if (const auto mfile = PHYSFSX_openReadBuffered(pathname.data()))
@ -621,9 +628,7 @@ static int read_mission_file(mission_list_type &mission_list, mission_candidate_
return 0; return 0;
} }
}
namespace dsx {
static void add_d1_builtin_mission_to_list(mission_list_type &mission_list) static void add_d1_builtin_mission_to_list(mission_list_type &mission_list)
{ {
int size; int size;
@ -667,7 +672,6 @@ static void add_d1_builtin_mission_to_list(mission_list_type &mission_list)
mission->builtin_hogsize = 0; mission->builtin_hogsize = 0;
#endif #endif
} }
}
#if defined(DXX_BUILD_DESCENT_II) #if defined(DXX_BUILD_DESCENT_II)
template <std::size_t N1, std::size_t N2> template <std::size_t N1, std::size_t N2>
@ -716,8 +720,6 @@ static void add_builtin_mission_to_list(mission_list_type &mission_list, d_fname
} }
#endif #endif
namespace dsx {
static void add_missions_to_list(mission_list_type &mission_list, mission_candidate_search_path &path, const mission_candidate_search_path::iterator rel_path, const mission_filter_mode mission_filter) static void add_missions_to_list(mission_list_type &mission_list, mission_candidate_search_path &path, const mission_candidate_search_path::iterator rel_path, const mission_filter_mode mission_filter)
{ {
/* rel_path must point within the array `path`. /* rel_path must point within the array `path`.
@ -798,8 +800,13 @@ static void add_missions_to_list(mission_list_type &mission_list, mission_candid
DXX_POISON_MEMORY(std::next(rel_path), path.end(), 0xcc); DXX_POISON_MEMORY(std::next(rel_path), path.end(), 0xcc);
} }
} }
} }
}
namespace {
/* move <mission_name> to <place> on mission list, increment <place> */ /* move <mission_name> to <place> on mission list, increment <place> */
static void promote (mission_list_type &mission_list, const char *const name, std::size_t &top_place) static void promote (mission_list_type &mission_list, const char *const name, std::size_t &top_place)
{ {
@ -813,6 +820,8 @@ static void promote (mission_list_type &mission_list, const char *const name, st
} }
} }
}
Mission::~Mission() Mission::~Mission()
{ {
// May become more complex with the editor // May become more complex with the editor
@ -824,13 +833,13 @@ Mission::~Mission()
} }
} }
//fills in the global list of missions. Returns the number of missions //fills in the global list of missions. Returns the number of missions
//in the list. If anarchy_mode is set, then also add anarchy-only missions. //in the list. If anarchy_mode is set, then also add anarchy-only missions.
namespace dsx { namespace dsx {
namespace {
static mission_list_type build_mission_list(const mission_filter_mode mission_filter) static mission_list_type build_mission_list(const mission_filter_mode mission_filter)
{ {
//now search for levels on disk //now search for levels on disk
@ -872,6 +881,8 @@ static mission_list_type build_mission_list(const mission_filter_mode mission_fi
return mission_list; return mission_list;
} }
}
#if defined(DXX_BUILD_DESCENT_II) #if defined(DXX_BUILD_DESCENT_II)
//values for built-in mission //values for built-in mission
@ -921,6 +932,8 @@ int load_mission_ham()
#endif #endif
} }
namespace {
#define tex ".tex" #define tex ".tex"
static void set_briefing_filename(d_fname &f, const char *const v, std::size_t d) static void set_briefing_filename(d_fname &f, const char *const v, std::size_t d)
{ {
@ -955,18 +968,19 @@ static void record_briefing(d_fname &f, std::array<char, PATH_MAX> &buf)
} }
#undef tex #undef tex
}
//loads the specfied mission from the mission list. //loads the specfied mission from the mission list.
//build_mission_list() must have been called. //build_mission_list() must have been called.
//Returns true if mission loaded ok, else false. //Returns true if mission loaded ok, else false.
namespace dsx { namespace dsx {
namespace {
static const char *load_mission(const mle *const mission) static const char *load_mission(const mle *const mission)
{ {
char *v; char *v;
#if defined(DXX_BUILD_DESCENT_II)
close_extra_robot_movie();
#endif
Current_mission = std::make_unique<Mission>(static_cast<const Mission_path &>(*mission)); Current_mission = std::make_unique<Mission>(static_cast<const Mission_path &>(*mission));
Current_mission->builtin_hogsize = mission->builtin_hogsize; Current_mission->builtin_hogsize = mission->builtin_hogsize;
Current_mission->mission_name.copy_if(mission->mission_name); Current_mission->mission_name.copy_if(mission->mission_name);
@ -1192,11 +1206,13 @@ static const char *load_mission(const mle *const mission)
free_polygon_models(LevelSharedPolygonModelState); free_polygon_models(LevelSharedPolygonModelState);
if (load_mission_ham()) if (load_mission_ham())
init_extra_robot_movie(&*Current_mission->filename); Current_mission->extra_robot_movie = init_extra_robot_movie(&*Current_mission->filename);
#endif #endif
return nullptr; return nullptr;
} }
}
//loads the named mission if exists. //loads the named mission if exists.
//Returns nullptr if mission loaded ok, else error string. //Returns nullptr if mission loaded ok, else error string.
const char *load_mission_by_name (const mission_entry_predicate mission_name, const mission_name_type name_match_mode) const char *load_mission_by_name (const mission_entry_predicate mission_name, const mission_name_type name_match_mode)
@ -1424,6 +1440,8 @@ window_event_result mission_menu::callback_handler(const d_event &event, window_
return window_event_result::ignored; return window_event_result::ignored;
} }
namespace {
using mission_menu_create_state_ptr = std::unique_ptr<mission_menu_create_state>; using mission_menu_create_state_ptr = std::unique_ptr<mission_menu_create_state>;
static mission_menu_create_state_ptr prepare_mission_menu_state(const mission_list_type &mission_list, const char *const LastMission, const std::size_t extra_strings) static mission_menu_create_state_ptr prepare_mission_menu_state(const mission_list_type &mission_list, const char *const LastMission, const std::size_t extra_strings)
@ -1457,6 +1475,8 @@ static mission_menu_create_state_ptr prepare_mission_menu_state(const mission_li
return p; return p;
} }
}
namespace dsx { namespace dsx {
int select_mission(const mission_filter_mode mission_filter, const menu_title message, window_event_result (*when_selected)(void)) int select_mission(const mission_filter_mode mission_filter, const menu_title message, window_event_result (*when_selected)(void))