Browse Source

Implement video playback in storm

Clean up after video should also be better now
pull/31/head
Anders Jenbo 7 years ago
parent
commit
22a3657ee4
  1. 2
      3rdParty/Storm/Source/storm.h
  2. 3
      CMakeLists.txt
  3. 13
      SourceS/miniwin.h
  4. 6
      SourceX/miniwin.cpp
  5. 169
      SourceX/movie.cpp
  6. 204
      SourceX/storm.cpp

2
3rdParty/Storm/Source/storm.h vendored

@ -907,7 +907,7 @@ BOOL STORMAPI STransCreateI(void *pBuffer, int width, int height, int bpp, int a
BOOL STORMAPI SVidDestroy();
BOOL STORMAPI SVidGetSize(HANDLE video, int width, int height, int zero);
BOOL STORMAPI SVidInitialize(HANDLE video);
BOOL STORMAPI SVidPlayBegin(char *filename, int arg4, int a3, int a4, int a5, int a6, HANDLE* video);
BOOL STORMAPI SVidPlayBegin(char *filename, int a2, int a3, int a4, int a5, int flags, HANDLE *video);
BOOL STORMAPI SVidPlayContinueSingle(HANDLE video, int a2, int a3);
BOOL STORMAPI SVidPlayEnd(HANDLE video);

3
CMakeLists.txt

@ -118,7 +118,7 @@ add_library(devilution STATIC
Source/minitext.cpp
Source/missiles.cpp
Source/monster.cpp
# Source/movie.cpp
Source/movie.cpp
Source/mpqapi.cpp
Source/msgcmd.cpp
Source/msg.cpp
@ -159,7 +159,6 @@ add_executable(devilutionx
SourceX/miniwin_msg_sdl.cpp
SourceX/stub_rand.cpp
SourceX/miniwin_thread.cpp
SourceX/movie.cpp
SourceX/sound.cpp
SourceX/storm.cpp
SourceX/storm_net.cpp

13
SourceS/miniwin.h

@ -252,12 +252,12 @@ typedef struct tagWNDCLASSEXA {
typedef unsigned long _fsize_t; /* Could be 64 bits for Win32 */
struct _finddata_t {
unsigned attrib;
time_t time_create; /* -1 for FAT file systems */
time_t time_access; /* -1 for FAT file systems */
time_t time_write;
_fsize_t size;
char name[260];
unsigned attrib;
time_t time_create; /* -1 for FAT file systems */
time_t time_access; /* -1 for FAT file systems */
time_t time_write;
_fsize_t size;
char name[260];
};
typedef WORD ATOM;
@ -407,6 +407,7 @@ HWND CreateWindowExA(
#define CreateWindowEx CreateWindowExA
HWND WINAPI FindWindowA(LPCSTR lpClassName, LPCSTR lpWindowName);
#define FindWindow FindWindowA
BOOL InvalidateRect(HWND hWnd, const RECT *lpRect, BOOL bErase);
BOOL UpdateWindow(HWND hWnd);
BOOL ShowWindow(HWND hWnd, int nCmdShow);
WINUSERAPI ATOM WINAPI RegisterClassExA(const WNDCLASSEX *lpwcx);

6
SourceX/miniwin.cpp

@ -278,6 +278,12 @@ HWND CreateWindowExA(
return window;
}
BOOL InvalidateRect(HWND hWnd, const RECT *lpRect, BOOL bErase)
{
DUMMY();
return TRUE;
}
/**
* @brief Appears to be used to clear the FB on init
*/

169
SourceX/movie.cpp

@ -1,169 +0,0 @@
#include "../3rdParty/libsmacker/smacker.h"
#include "pch.h"
PALETTEENTRY previousPalette[256];
BYTE movie_playing;
BOOL loop_movie; // TODO
void __fastcall play_movie(char *pszMovie, BOOL user_can_close)
{
DUMMY_PRINT("%s", pszMovie);
void *video_stream;
movie_playing = TRUE;
sound_disable_music(TRUE);
sfx_stop();
effects_play_sound("Sfx\\Misc\\blank.wav");
HANDLE directsound;
SFileOpenFile(pszMovie, &directsound);
BYTE *fileBuffer;
int bytestoread = SFileGetFileSize(directsound, 0);
fileBuffer = DiabloAllocPtr(bytestoread);
SFileReadFile(directsound, fileBuffer, bytestoread, NULL, 0);
/* file meta-info */
unsigned long width, height, nFrames;
unsigned char a_channels[7], a_depth[7];
unsigned long a_rate[7];
unsigned char *palette_data;
smk smacker;
smacker = smk_open_memory(fileBuffer, bytestoread);
if (smacker != NULL) {
double usPerFrame;
smk_info_all(smacker, NULL, &nFrames, &usPerFrame);
smk_info_video(smacker, &width, &height, NULL);
smk_info_audio(smacker, NULL, a_channels, a_depth, a_rate);
SDL_AudioDeviceID deviceId;
if (a_depth[0] != 0) {
SDL_AudioSpec audioFormat;
SDL_zero(audioFormat);
audioFormat.freq = a_rate[0];
audioFormat.format = a_depth[0] == 16 ? AUDIO_S16 : AUDIO_U8;
audioFormat.channels = a_channels[0];
deviceId = SDL_OpenAudioDevice(NULL, 0, &audioFormat, NULL, 0);
if (deviceId == 0) {
printf("SDL_OpenAudioDevice: %s\n", SDL_GetError());
movie_playing = false;
} else {
SDL_PauseAudioDevice(deviceId, 0); /* start audio playing. */
}
}
smk_enable_all(smacker, -1);
smk_first(smacker); // Decode first frame
smk_info_video(smacker, &width, &height, NULL);
SDL_DestroyTexture(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_RenderSetLogicalSize(renderer, width, height);
memcpy(previousPalette, orig_palette, 1024);
// Copy frame to buffer
SDL_Surface *videoSurface = SDL_CreateRGBSurfaceWithFormatFrom(
smk_get_video(smacker),
width,
height,
8,
width,
SDL_PIXELFORMAT_INDEX8);
SDL_Rect src_rect = { 64, 160, 0, 0 };
SDL_Color colors[256];
SDL_Palette *vpalette = SDL_AllocPalette(256);
if (SDL_SetSurfacePalette(videoSurface, vpalette) != 0) {
SDL_Log("SDL_SetSurfacePalette: %s\n", SDL_GetError());
movie_playing = false;
}
int now;
SDL_Event event;
double frameEnd = SDL_GetTicks() * 1000 + usPerFrame;
do {
while (SDL_PollEvent(&event)) {
switch (event.type) {
case SDL_KEYDOWN:
case SDL_MOUSEBUTTONDOWN:
if (user_can_close) {
movie_playing = false;
}
break;
case SDL_QUIT:
exit(0);
}
}
if (a_depth[0] != 0 && SDL_QueueAudio(deviceId, smk_get_audio(smacker, 0), smk_get_audio_size(smacker, 0)) == -1) {
printf("SDL_QueueAudio: %s\n", SDL_GetError());
}
now = SDL_GetTicks() * 1000;
if (now >= frameEnd) {
continue; // Skip video if the system is to slow
}
if (smk_palette_updated(smacker)) {
palette_data = smk_get_palette(smacker);
for (int i = 0; i < 256; i++) {
colors[i].r = palette_data[i * 3 + 0];
colors[i].g = palette_data[i * 3 + 1];
colors[i].b = palette_data[i * 3 + 2];
colors[i].a = SDL_ALPHA_OPAQUE;
orig_palette[i].peFlags = 0;
orig_palette[i].peRed = palette_data[i * 3 + 0];
orig_palette[i].peGreen = palette_data[i * 3 + 1];
orig_palette[i].peBlue = palette_data[i * 3 + 2];
}
memcpy(logical_palette, orig_palette, 1024);
if (SDL_SetPaletteColors(vpalette, colors, 0, 256) != 0) {
SDL_Log("SDL_SetPaletteColors: %s\n", SDL_GetError());
break;
}
}
if (SDL_BlitSurface(videoSurface, NULL, pal_surface, &src_rect) != 0) {
SDL_Log("SDL_BlitSurface: %s\n", SDL_GetError());
break;
}
SetFadeLevel(256); // present frame
now = SDL_GetTicks() * 1000;
if (now < frameEnd) {
usleep(frameEnd - now); // wait with next frame if the system is to fast
}
frameEnd += usPerFrame;
if (smk_next(smacker) == SMK_DONE) {
if (loop_movie)
smk_first(smacker);
else
movie_playing = false;
}
} while (movie_playing);
if (a_depth[0] != 0) {
SDL_ClearQueuedAudio(deviceId);
SDL_CloseAudioDevice(deviceId);
}
smk_close(smacker);
memcpy(orig_palette, previousPalette, 1024);
SDL_DestroyTexture(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
}
}

204
SourceX/storm.cpp

@ -1,4 +1,5 @@
#include "../3rdParty/Radon/Radon/include/Radon.hpp"
#include "../3rdParty/libsmacker/smacker.h"
#include "pch.h"
DWORD nLastError = 0;
@ -360,17 +361,193 @@ BOOL STORMAPI SRegSaveValue(const char *keyname, const char *valuename, BYTE fla
//{
// UNIMPLEMENTED();
//}
//
// BOOL STORMAPI SVidPlayBegin(char *filename, int arg4, int a3, int a4, int a5, int a6, HANDLE
// *video)
//{
// UNIMPLEMENTED();
//}
//
// BOOL STORMAPI SVidPlayEnd(HANDLE video)
//{
// UNIMPLEMENTED();
//}
double SVidFrameEnd;
double SVidFrameLength;
BYTE SVidLoop;
smk SVidSMK;
PALETTEENTRY SVidPreviousPalette[256];
SDL_Palette *SVidPalette;
SDL_Surface *SVidSurface;
BYTE *SVidBuffer;
SDL_AudioDeviceID deviceId;
BOOL STORMAPI SVidPlayBegin(char *filename, int a2, int a3, int a4, int a5, int flags, HANDLE *video)
{
if (flags & 0x10000 || flags & 0x20000000) {
return FALSE;
}
SVidLoop = flags & 0x40000;
bool enableVideo = !(flags & 0x100000);
bool enableAudio = !(flags & 0x1000000);
//0x8 // Non-interlaced
//0x200, 0x800 // Upscale video
//0x80000 // Center horizontally
//0x800000 // Edge detection
//0x200800 // Clear FB
SFileOpenFile(filename, video);
int bytestoread = SFileGetFileSize(*video, 0);
SVidBuffer = DiabloAllocPtr(bytestoread);
SFileReadFile(*video, SVidBuffer, bytestoread, NULL, 0);
SVidSMK = smk_open_memory(SVidBuffer, bytestoread);
if (SVidSMK == NULL) {
return FALSE;
}
deviceId = 0;
unsigned char channels[7], depth[7];
unsigned long rate[7];
smk_info_audio(SVidSMK, NULL, channels, depth, rate);
if (enableAudio && depth[0] != 0) {
smk_enable_audio(SVidSMK, 0, enableAudio);
SDL_AudioSpec audioFormat;
SDL_zero(audioFormat);
audioFormat.freq = rate[0];
audioFormat.format = depth[0] == 16 ? AUDIO_S16 : AUDIO_U8;
audioFormat.channels = channels[0];
deviceId = SDL_OpenAudioDevice(NULL, 0, &audioFormat, NULL, 0);
if (deviceId == 0) {
SDL_Log("SDL_OpenAudioDevice: %s\n", SDL_GetError());
return FALSE;
} else {
SDL_PauseAudioDevice(deviceId, 0); /* start audio playing. */
}
}
unsigned long width, height, nFrames;
smk_info_all(SVidSMK, NULL, &nFrames, &SVidFrameLength);
smk_info_video(SVidSMK, &width, &height, NULL);
smk_enable_video(SVidSMK, enableVideo);
smk_first(SVidSMK); // Decode first frame
smk_info_video(SVidSMK, &width, &height, NULL);
SDL_DestroyTexture(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, width, height);
SDL_RenderSetLogicalSize(renderer, width, height);
memcpy(SVidPreviousPalette, orig_palette, 1024);
// Copy frame to buffer
SVidSurface = SDL_CreateRGBSurfaceWithFormatFrom(
smk_get_video(SVidSMK),
width,
height,
8,
width,
SDL_PIXELFORMAT_INDEX8);
SVidPalette = SDL_AllocPalette(256);
if (SDL_SetSurfacePalette(SVidSurface, SVidPalette) != 0) {
SDL_Log("SDL_SetSurfacePalette: %s\n", SDL_GetError());
return FALSE;
}
SVidFrameEnd = SDL_GetTicks() * 1000 + SVidFrameLength;
return TRUE;
}
BOOL SVidLoadNextFrame()
{
SVidFrameEnd += SVidFrameLength;
if (smk_next(SVidSMK) == SMK_DONE) {
if (!SVidLoop) {
return FALSE;
}
smk_first(SVidSMK);
}
return TRUE;
}
BOOL __cdecl SVidPlayContinue(void)
{
if (smk_palette_updated(SVidSMK)) {
SDL_Color colors[256];
unsigned char *palette_data = smk_get_palette(SVidSMK);
for (int i = 0; i < 256; i++) {
colors[i].r = palette_data[i * 3 + 0];
colors[i].g = palette_data[i * 3 + 1];
colors[i].b = palette_data[i * 3 + 2];
colors[i].a = SDL_ALPHA_OPAQUE;
orig_palette[i].peFlags = 0;
orig_palette[i].peRed = palette_data[i * 3 + 0];
orig_palette[i].peGreen = palette_data[i * 3 + 1];
orig_palette[i].peBlue = palette_data[i * 3 + 2];
}
memcpy(logical_palette, orig_palette, 1024);
if (SDL_SetPaletteColors(SVidPalette, colors, 0, 256) != 0) {
SDL_Log("SDL_SetPaletteColors: %s\n", SDL_GetError());
return FALSE;
}
}
if (SDL_GetTicks() * 1000 >= SVidFrameEnd) {
return SVidLoadNextFrame(); // Skip video and audio if the system is to slow
}
printf("oiasjdf %d\n", deviceId);
if (deviceId && SDL_QueueAudio(deviceId, smk_get_audio(SVidSMK, 0), smk_get_audio_size(SVidSMK, 0)) == -1) {
SDL_Log("SDL_QueueAudio: %s\n", SDL_GetError());
return FALSE;
}
if (SDL_GetTicks() * 1000 >= SVidFrameEnd) {
return SVidLoadNextFrame(); // Skip video if the system is to slow
}
SDL_Rect pal_surface_offset = { 64, 160, 0, 0 };
if (SDL_BlitSurface(SVidSurface, NULL, pal_surface, &pal_surface_offset) != 0) {
SDL_Log("SDL_BlitSurface: %s\n", SDL_GetError());
return FALSE;
}
SetFadeLevel(256); // present frame
double now = SDL_GetTicks() * 1000;
if (now < SVidFrameEnd) {
usleep(SVidFrameEnd - now); // wait with next frame if the system is to fast
}
return SVidLoadNextFrame();
}
BOOL STORMAPI SVidPlayEnd(HANDLE video)
{
if (deviceId) {
SDL_ClearQueuedAudio(deviceId);
SDL_CloseAudioDevice(deviceId);
deviceId = 0;
}
if (SVidSMK)
smk_close(SVidSMK);
if (SVidBuffer) {
mem_free_dbg(SVidBuffer);
SVidBuffer = NULL;
}
SFileCloseFile(video);
video = NULL;
memcpy(orig_palette, SVidPreviousPalette, 1024);
SDL_DestroyTexture(texture);
texture = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, SCREEN_WIDTH, SCREEN_HEIGHT);
SDL_RenderSetLogicalSize(renderer, SCREEN_WIDTH, SCREEN_HEIGHT);
return TRUE;
}
BOOL STORMAPI SErrDisplayError(DWORD dwErrMsg, const char *logfilename, int logline, const char *message,
BOOL allowOption, int exitCode)
@ -457,11 +634,6 @@ void __cdecl SDrawRealizePalette(void)
DUMMY();
}
// bool __cdecl SVidPlayContinue(void)
//{
// UNIMPLEMENTED();
//}
BOOL __stdcall SFileEnableDirectAccess(BOOL enable)
{
DUMMY();

Loading…
Cancel
Save