diff --git a/CMakeLists.txt b/CMakeLists.txt index 7103b773c..3b3473864 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -388,6 +388,7 @@ set(devilutionx_SRCS Source/dvlnet/loopback.cpp Source/dvlnet/packet.cpp Source/storm/storm.cpp + Source/storm/storm_file_wrapper.cpp Source/storm/storm_net.cpp Source/storm/storm_sdl_rw.cpp Source/storm/storm_svid.cpp diff --git a/Source/movie.cpp b/Source/movie.cpp index b16b7f052..c146fc05e 100644 --- a/Source/movie.cpp +++ b/Source/movie.cpp @@ -37,28 +37,28 @@ void play_movie(const char *pszMovie, bool user_can_close) effects_play_sound("Sfx\\Misc\\blank.wav"); #endif - SVidPlayBegin(pszMovie, loop_movie ? 0x100C0808 : 0x10280808, &video_stream); - tagMSG Msg; - while (video_stream != nullptr && movie_playing) { - while (movie_playing && FetchMessage(&Msg)) { - switch (Msg.message) { - case DVL_WM_KEYDOWN: - case DVL_WM_LBUTTONDOWN: - case DVL_WM_RBUTTONDOWN: - if (user_can_close || (Msg.message == DVL_WM_KEYDOWN && Msg.wParam == DVL_VK_ESCAPE)) - movie_playing = false; - break; - case DVL_WM_QUIT: - SVidPlayEnd(video_stream); - diablo_quit(0); - break; + if (SVidPlayBegin(pszMovie, loop_movie ? 0x100C0808 : 0x10280808, &video_stream)) { + tagMSG Msg; + while (movie_playing) { + while (movie_playing && FetchMessage(&Msg)) { + switch (Msg.message) { + case DVL_WM_KEYDOWN: + case DVL_WM_LBUTTONDOWN: + case DVL_WM_RBUTTONDOWN: + if (user_can_close || (Msg.message == DVL_WM_KEYDOWN && Msg.wParam == DVL_VK_ESCAPE)) + movie_playing = false; + break; + case DVL_WM_QUIT: + SVidPlayEnd(video_stream); + diablo_quit(0); + break; + } } + if (!SVidPlayContinue()) + break; } - if (!SVidPlayContinue()) - break; - } - if (video_stream != nullptr) SVidPlayEnd(video_stream); + } #ifndef NOSOUND sound_disable_music(false); diff --git a/Source/storm/storm_file_wrapper.cpp b/Source/storm/storm_file_wrapper.cpp new file mode 100644 index 000000000..8528dc7da --- /dev/null +++ b/Source/storm/storm_file_wrapper.cpp @@ -0,0 +1,74 @@ +#include "storm_file_wrapper.h" + +#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE + +#include "storm/storm.h" +#include "utils/log.hpp" + +namespace devilution { +extern "C" { + +#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_IMPL_FOPENCOOKIE + +ssize_t SFileCookieRead(void *cookie, char *buf, size_t nbytes) +{ + DWORD numRead = 0; + if (!SFileReadFile(static_cast(cookie), buf, nbytes, &numRead, nullptr)) { + const DWORD errCode = SErrGetLastError(); + if (errCode != STORM_ERROR_HANDLE_EOF) { + Log("SFileRwRead error: {} ERROR CODE {}", (unsigned int)nbytes, (unsigned int)errCode); + } + } + return numRead; +} + +int SFileCookieSeek(void *cookie, off64_t *pos, int whence) +{ + int swhence; + switch (whence) { + case SEEK_SET: + swhence = DVL_FILE_BEGIN; + break; + case SEEK_CUR: + swhence = DVL_FILE_CURRENT; + break; + case SEEK_END: + swhence = DVL_FILE_END; + break; + default: + return -1; + } + const std::uint64_t spos = SFileSetFilePointer(static_cast(cookie), *pos, swhence); + if (spos == static_cast(-1)) { + Log("SFileRwSeek error: {}", (unsigned int)SErrGetLastError()); + return -1; + } + *pos = static_cast(spos); + return 0; +} + +int SFileCookieClose(void *cookie) +{ + return SFileCloseFile(static_cast(cookie)) ? 0 : -1; +} + +} // extern "C" +#endif + +FILE *FILE_FromStormHandle(HANDLE handle) +{ +#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_IMPL_FOPENCOOKIE + cookie_io_functions_t ioFns; + std::memset(&ioFns, 0, sizeof(ioFns)); + ioFns.read = &SFileCookieRead; + ioFns.seek = &SFileCookieSeek; + ioFns.close = &SFileCookieClose; + return fopencookie(handle, "rb", ioFns); +#else +#error "unimplemented" +#endif +} + +} // namespace devilution + +#endif diff --git a/Source/storm/storm_file_wrapper.h b/Source/storm/storm_file_wrapper.h new file mode 100644 index 000000000..dbf2ee495 --- /dev/null +++ b/Source/storm/storm_file_wrapper.h @@ -0,0 +1,17 @@ +/** A pointer to a Storm file as a `FILE *`. Only available on some platforms. */ +#pragma once +#if defined(__linux__) || defined(__FreeBSD__) || defined(__DragonFly__) +#include + +#include "miniwin/miniwin.h" + +#define DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE +#define DEVILUTIONX_STORM_FILE_WRAPPER_IMPL_FOPENCOOKIE + +namespace devilution { + +FILE *FILE_FromStormHandle(HANDLE handle); + +} // namespace devilution + +#endif diff --git a/Source/storm/storm_svid.cpp b/Source/storm/storm_svid.cpp index 2d09b5a90..bf2669488 100644 --- a/Source/storm/storm_svid.cpp +++ b/Source/storm/storm_svid.cpp @@ -17,10 +17,11 @@ #include "dx.h" #include "options.h" #include "palette.h" +#include "storm/storm_file_wrapper.h" #include "storm/storm.h" #include "utils/display.h" -#include "utils/sdl_compat.h" #include "utils/log.hpp" +#include "utils/sdl_compat.h" namespace devilution { namespace { @@ -39,7 +40,10 @@ smk SVidSMK; SDL_Color SVidPreviousPalette[256]; SDL_Palette *SVidPalette; SDL_Surface *SVidSurface; + +#ifndef DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE std::unique_ptr SVidBuffer; +#endif bool IsLandscapeFit(unsigned long srcW, unsigned long srcH, unsigned long dstW, unsigned long dstH) { @@ -129,10 +133,10 @@ bool SVidLoadNextFrame() } // namespace -void SVidPlayBegin(const char *filename, int flags, HANDLE *video) +bool SVidPlayBegin(const char *filename, int flags, HANDLE *video) { if (flags & 0x10000 || flags & 0x20000000) { - return; + return false; } SVidLoop = false; @@ -146,14 +150,19 @@ void SVidPlayBegin(const char *filename, int flags, HANDLE *video) //0x200800 // Clear FB SFileOpenFile(filename, video); - +#ifdef DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE + FILE *file = FILE_FromStormHandle(*video); + SVidSMK = smk_open_filepointer(file, SMK_MODE_DISK); +#else int bytestoread = SFileGetFileSize(*video, nullptr); SVidBuffer = std::make_unique(bytestoread); SFileReadFile(*video, SVidBuffer.get(), bytestoread, nullptr, nullptr); - + SFileCloseFile(*video); + *video = nullptr; SVidSMK = smk_open_memory(SVidBuffer.get(), bytestoread); +#endif if (SVidSMK == nullptr) { - return; + return false; } #ifndef NOSOUND @@ -236,6 +245,7 @@ void SVidPlayBegin(const char *filename, int flags, HANDLE *video) SVidFrameEnd = SDL_GetTicks() * 1000 + SVidFrameLength; SDL_FillRect(GetOutputSurface(), nullptr, 0x000000); + return true; } bool SVidPlayContinue() @@ -358,7 +368,9 @@ void SVidPlayEnd(HANDLE video) if (SVidSMK != nullptr) smk_close(SVidSMK); +#ifndef DEVILUTIONX_STORM_FILE_WRAPPER_AVAILABLE SVidBuffer = nullptr; +#endif SDL_FreePalette(SVidPalette); SVidPalette = nullptr; @@ -366,9 +378,6 @@ void SVidPlayEnd(HANDLE video) SDL_FreeSurface(SVidSurface); SVidSurface = nullptr; - SFileCloseFile(video); - video = nullptr; - memcpy(orig_palette, SVidPreviousPalette, sizeof(orig_palette)); #ifndef USE_SDL1 if (renderer != nullptr) { diff --git a/Source/storm/storm_svid.h b/Source/storm/storm_svid.h index d8d5af999..a66356321 100644 --- a/Source/storm/storm_svid.h +++ b/Source/storm/storm_svid.h @@ -4,7 +4,7 @@ namespace devilution { -void SVidPlayBegin(const char *filename, int flags, HANDLE *video); +bool SVidPlayBegin(const char *filename, int flags, HANDLE *video); bool SVidPlayContinue(); void SVidPlayEnd(HANDLE video);