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_10_MISSION_HOGSIZE 7107354 // v1.0
#define MAC_FULL_MISSION_HOGSIZE 7110007 // v1.1 - 1.2
#include "movie.h"
#endif
//where the missions go
@ -132,6 +133,8 @@ public:
};
#if defined(DXX_BUILD_DESCENT_I) || defined(DXX_BUILD_DESCENT_II)
namespace dsx {
struct Mission : Mission_path
{
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)
descent_version_type descent_version; // descent 1 or descent 2?
std::unique_ptr<d_fname> alternate_ham_file;
std::unique_ptr<LoadedMovie> extra_robot_movie;
#endif
/* Explicitly default move constructor and move operator=
*
@ -203,6 +207,8 @@ extern Mission_ptr Current_mission; // current mission
#endif
#define PLAYING_BUILTIN_MISSION (Current_mission->builtin_hogsize != 0)
#define ANARCHY_ONLY_MISSION (1 == Current_mission->anarchy_only_flag)
}
#endif
//values for d1 built-in mission

View file

@ -20,10 +20,14 @@
using namespace dcx;
namespace {
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);
}
void decodeFrame16(unsigned char *pFrame, const unsigned char *pMap, int mapRemain, const unsigned char *pData, int dataRemain)
{
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)
{
unsigned short val = (*buf)[0+off] | ((*buf)[1+off] << 8);
@ -104,12 +110,12 @@ struct position_t
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};
}
static inline constexpr position_t relFar0(int i, int sign)
static constexpr position_t relFar0(int i, int sign)
{
return {
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 {
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);
}
@ -136,7 +142,7 @@ struct lookup_table_t
};
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{
{{relClose(N)...}},
@ -716,3 +722,5 @@ static void dispatchDecoder16(unsigned short **pFrame, unsigned char codeType, c
*pFrame = pDstBak+8;
}
}

View file

@ -15,6 +15,8 @@
#include "mvelib.h"
#include <memory>
namespace {
static const char MVE_HEADER[] = "Interplay MVE File\x1A";
constexpr short MVE_HDRCONST1 = 0x001A;
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 void _mvestream_reset(MVESTREAM *movie);
}
/************************************************************
* public MVEFILE functions
************************************************************/
@ -70,6 +74,8 @@ std::unique_ptr<MVEFILE> mvefile_open(void *stream)
return file;
}
namespace {
/*
* reset a MVE file
*/
@ -99,6 +105,8 @@ static bool have_segment_header(const MVEFILE *movie)
return true;
}
}
/*
* get the size of the next segment
*/
@ -262,6 +270,8 @@ MVEFILE::~MVEFILE()
{
}
namespace {
/*
* open the file stream in thie object
*/
@ -359,6 +369,8 @@ static uint16_t _mve_get_ushort(const unsigned char *data)
return value;
}
}
/*
* allocate an MVESTREAM
*/
@ -371,6 +383,8 @@ MVESTREAM::~MVESTREAM()
{
}
namespace {
/*
* open an MVESTREAM object
*/
@ -388,3 +402,5 @@ static void _mvestream_reset(MVESTREAM *movie)
{
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 "partial_range.h"
#include "d_zip.h"
namespace dsx {
namespace {
@ -88,13 +91,6 @@ constexpr std::array<std::array<char, 8>, 3> movielib_files{{
{"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;
// Function Prototypes
@ -112,6 +108,8 @@ struct movie_pause_window : window
}
}
void *MovieMemoryAllocate(std::size_t 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
//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;
}
}
void MovieShowFrame(const uint8_t *buf, int dstx, int dsty, int bufw, int bufh, int sw, int sh)
{
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);
}
namespace dsx {
namespace {
struct movie : window
@ -443,14 +446,12 @@ int RotateRobot(MVESTREAM_ptr_t &pMovie)
return 1;
}
void DeInitRobotMovie(MVESTREAM_ptr_t &pMovie)
{
pMovie.reset();
RoboFile.reset(); // Close Movie File
}
int InitRobotMovie(const char *filename, MVESTREAM_ptr_t &pMovie)
{
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, PATH_MAX> pathname;
auto r = PHYSFSX_addRelToSearchPath(&movie.filename[0], pathname, physfs_search_path::prepend);
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);
if (!r)
{
if (required || CGameArg.DbgVerbose)
con_printf(CON_URGENT, "Can't open movielib <%s>: %s", &movie.filename[0], PHYSFS_getLastError());
movie.filename[0] = 0;
con_printf(required ? CON_URGENT : CON_VERBOSE, "Can't open movielib <%s>: %s", &filename[0], PHYSFS_getLastError());
movie.pathname[0] = 0;
}
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 (init_movie(movielib, 'h', required, movie))
return;
if (auto r = init_movie(movielib, 'h', required, movie))
return r;
}
init_movie(movielib, 'l', required, movie);
return init_movie(movielib, 'l', required, movie);
}
}
//find and initialize the movie libraries
void init_movies()
std::unique_ptr<BuiltinMovies> init_movies()
{
if (GameArg.SysNoMovies)
return;
return nullptr;
range_for (auto &i, movielib_files)
{
loaded_movie_t m;
init_movie(&i[0], 1, m);
}
auto r = std::make_unique<BuiltinMovies>();
for (auto &&[f, m] : zip(movielib_files, r->movies))
init_movie(&f[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)
return;
if (!PHYSFSX_contfile_close(movielib))
{
con_printf(CON_URGENT, "Can't close movielib <%s>: %s", movielib, PHYSFS_getLastError());
}
*movielib = 0;
if (!PHYSFS_unmount(movielib))
con_printf(CON_URGENT, "Cannot close movielib <%s>: %s", movielib, PHYSFS_getLastError());
}
void init_extra_robot_movie(const char *movielib)
std::unique_ptr<LoadedMovie> init_extra_robot_movie(const char *movielib)
{
if (GameArg.SysNoMovies)
return;
init_movie(movielib, 0, extra_robot_movie_mission);
return nullptr;
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
#ifdef __cplusplus
#include <limits.h>
#include "d2x-rebirth/libmve/mvelib.h"
#include "dsx-ns.h"
namespace dsx {
#define MOVIE_ABORT_ON 1
#define MOVIE_ABORT_OFF 0
@ -50,12 +53,25 @@ int InitRobotMovie(const char *filename, MVESTREAM_ptr_t &pMovie);
int RotateRobot(MVESTREAM_ptr_t &pMovie);
void DeInitRobotMovie(MVESTREAM_ptr_t &pMovie);
// find and initialize the movie libraries
void init_movies();
struct LoadedMovie
{
std::array<char, PATH_MAX> pathname;
LoadedMovie()
{
pathname[0] = 0;
}
~LoadedMovie();
};
void init_extra_robot_movie(const char *filename);
void close_extra_robot_movie();
struct BuiltinMovies
{
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
#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)
{
@ -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;
}
}
//returns 1 if file read ok, else 0
namespace dsx {
namespace {
static int read_mission_file(mission_list_type &mission_list, mission_candidate_search_path &pathname)
{
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;
}
}
namespace dsx {
static void add_d1_builtin_mission_to_list(mission_list_type &mission_list)
{
int size;
@ -667,7 +672,6 @@ static void add_d1_builtin_mission_to_list(mission_list_type &mission_list)
mission->builtin_hogsize = 0;
#endif
}
}
#if defined(DXX_BUILD_DESCENT_II)
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
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)
{
/* 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);
}
}
}
}
namespace {
/* 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)
{
@ -813,6 +820,8 @@ static void promote (mission_list_type &mission_list, const char *const name, st
}
}
}
Mission::~Mission()
{
// 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
//in the list. If anarchy_mode is set, then also add anarchy-only missions.
namespace dsx {
namespace {
static mission_list_type build_mission_list(const mission_filter_mode mission_filter)
{
//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;
}
}
#if defined(DXX_BUILD_DESCENT_II)
//values for built-in mission
@ -921,6 +932,8 @@ int load_mission_ham()
#endif
}
namespace {
#define tex ".tex"
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
}
//loads the specfied mission from the mission list.
//build_mission_list() must have been called.
//Returns true if mission loaded ok, else false.
namespace dsx {
namespace {
static const char *load_mission(const mle *const mission)
{
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->builtin_hogsize = mission->builtin_hogsize;
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);
if (load_mission_ham())
init_extra_robot_movie(&*Current_mission->filename);
Current_mission->extra_robot_movie = init_extra_robot_movie(&*Current_mission->filename);
#endif
return nullptr;
}
}
//loads the named mission if exists.
//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)
@ -1424,6 +1440,8 @@ window_event_result mission_menu::callback_handler(const d_event &event, window_
return window_event_result::ignored;
}
namespace {
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)
@ -1457,6 +1475,8 @@ static mission_menu_create_state_ptr prepare_mission_menu_state(const mission_li
return p;
}
}
namespace dsx {
int select_mission(const mission_filter_mode mission_filter, const menu_title message, window_event_result (*when_selected)(void))