2024-05-01 12:38:01 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2002-2024 D2X Project
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
2024-05-05 15:36:16 +00:00
|
|
|
#define AUDIO
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-29 21:52:51 +00:00
|
|
|
#include <chrono>
|
2024-05-04 13:21:01 +00:00
|
|
|
#include <cstring>
|
2024-05-11 13:32:18 +00:00
|
|
|
#include <deque>
|
|
|
|
#include <memory>
|
2024-05-29 21:52:51 +00:00
|
|
|
#include <thread>
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-05 18:01:12 +00:00
|
|
|
#include "byteswap.h"
|
2024-05-29 21:52:51 +00:00
|
|
|
#include "chrono_timer.h"
|
2024-05-01 11:33:32 +00:00
|
|
|
#include "decoders.h"
|
2024-05-04 13:21:01 +00:00
|
|
|
#include "mvelib.h"
|
|
|
|
#include "mve_audio.h"
|
2024-05-11 19:47:13 +00:00
|
|
|
|
|
|
|
#ifdef AUDIO
|
2024-07-07 01:28:57 +00:00
|
|
|
#include "movie_sound.h"
|
2024-05-11 19:47:13 +00:00
|
|
|
#endif
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-29 21:52:51 +00:00
|
|
|
#define MVE_OPCODE_ENDOFSTREAM 0x00 // mcmd_end
|
|
|
|
#define MVE_OPCODE_ENDOFCHUNK 0x01 // mcmd_next
|
|
|
|
#define MVE_OPCODE_CREATETIMER 0x02 // mcmd_syncInit
|
|
|
|
#define MVE_OPCODE_INITAUDIOBUFFERS 0x03 // mcmd_sndConfigure
|
|
|
|
#define MVE_OPCODE_STARTSTOPAUDIO 0x04 // mcmd_sndSync
|
|
|
|
#define MVE_OPCODE_INITVIDEOBUFFERS 0x05 // mcmd_nfConfig
|
|
|
|
#define MVE_OPCODE_UNKNOWN_06 0x06 // mcmd_nfDecomp
|
|
|
|
#define MVE_OPCODE_DISPLAYVIDEO 0x07 // mcmd_sfShowFrame
|
|
|
|
#define MVE_OPCODE_AUDIOFRAMEDATA 0x08 // mcmd_sndAdd
|
|
|
|
#define MVE_OPCODE_AUDIOFRAMESILENCE 0x09 // mcmd_sndSilence
|
|
|
|
#define MVE_OPCODE_INITVIDEOMODE 0x0A // mcmd_gfxMode
|
|
|
|
#define MVE_OPCODE_UNKNOWN_0B 0x0B // mcmd_palMakeSynthPalette
|
|
|
|
#define MVE_OPCODE_SETPALETTE 0x0C // mcmd_palLoadPalette
|
|
|
|
#define MVE_OPCODE_SETPALETTECOMPRESSED 0x0D // mcmd_palLoadCompPalette
|
|
|
|
#define MVE_OPCODE_UNKNOWN_0E 0x0E // mcmd_nfChanges
|
|
|
|
#define MVE_OPCODE_SETDECODINGMAP 0x0F // mcmd_nfParms
|
|
|
|
#define MVE_OPCODE_UNKNOWN_10 0x10 // mcmd_nfDecompChg
|
|
|
|
#define MVE_OPCODE_VIDEODATA 0x11 // mcmd_nfPkDecomp
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
#define MVE_AUDIO_FLAGS_STEREO 1
|
|
|
|
#define MVE_AUDIO_FLAGS_16BIT 2
|
2024-05-01 11:33:32 +00:00
|
|
|
#define MVE_AUDIO_FLAGS_COMPRESSED 4
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
int g_spdFactorNum = 0;
|
|
|
|
static int g_spdFactorDenom = 10;
|
2024-05-01 11:33:32 +00:00
|
|
|
static int g_frameUpdated = 0;
|
|
|
|
|
2024-05-05 18:01:12 +00:00
|
|
|
static short get_short(const unsigned char *data) {
|
|
|
|
return D3::convert_le<int16_t>(data[0] | (data[1] << 8));
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 18:01:12 +00:00
|
|
|
static unsigned short get_ushort(const unsigned char *data) {
|
|
|
|
return D3::convert_le<uint16_t>(data[0] | (data[1] << 8));
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 18:01:12 +00:00
|
|
|
static int get_int(const unsigned char *data) {
|
|
|
|
return D3::convert_le<int32_t>(data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24));
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static unsigned int unhandled_chunks[32 * 256];
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int default_seg_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
|
|
|
unhandled_chunks[major << 8 | minor]++;
|
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
* general handlers
|
|
|
|
*************************/
|
2024-05-01 12:38:01 +00:00
|
|
|
static int end_movie_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
|
|
|
return 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
* timer handlers
|
|
|
|
*************************/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* timer variables
|
|
|
|
*/
|
|
|
|
static int timer_created = 0;
|
2024-05-01 12:38:01 +00:00
|
|
|
static int micro_frame_delay = 0;
|
|
|
|
static int timer_started = 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
static unsigned long int timer_expire = 0;
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
unsigned long int timer_getmicroseconds() {
|
2024-05-29 21:52:51 +00:00
|
|
|
return D3::ChronoTimer::GetTimeUS();
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
void timer_sleepmicroseconds(unsigned long int usec) {
|
2024-05-29 21:52:51 +00:00
|
|
|
std::this_thread::sleep_for(std::chrono::microseconds(usec));
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int create_timer_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
|
|
|
long temp;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (timer_created)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
timer_created = 1;
|
|
|
|
|
|
|
|
micro_frame_delay = get_int(data) * (int)get_short(data + 4);
|
|
|
|
if (g_spdFactorNum != 0) {
|
|
|
|
temp = micro_frame_delay;
|
|
|
|
temp *= g_spdFactorNum;
|
|
|
|
temp /= g_spdFactorDenom;
|
|
|
|
micro_frame_delay = (int)temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 15:36:16 +00:00
|
|
|
static void timer_stop() {
|
2024-05-01 12:38:01 +00:00
|
|
|
timer_expire = 0;
|
|
|
|
timer_started = 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 15:36:16 +00:00
|
|
|
static void timer_start() {
|
2024-05-01 12:38:01 +00:00
|
|
|
timer_expire = timer_getmicroseconds();
|
|
|
|
timer_expire += micro_frame_delay;
|
|
|
|
timer_started = 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-07-01 00:59:23 +00:00
|
|
|
#ifdef AUDIO
|
|
|
|
static std::unique_ptr<D3::MovieSoundDevice> snd_ds;
|
|
|
|
static int mve_audio_enabled = 1;
|
|
|
|
#else
|
|
|
|
static int mve_audio_enabled = 0;
|
|
|
|
#endif
|
|
|
|
|
2024-05-05 15:36:16 +00:00
|
|
|
static void do_timer_wait() {
|
2024-05-29 21:52:51 +00:00
|
|
|
uint64_t ts;
|
|
|
|
uint64_t tv;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (!timer_started)
|
|
|
|
return;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
tv = timer_getmicroseconds();
|
|
|
|
if (tv > timer_expire)
|
|
|
|
goto end;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
ts = timer_expire - tv;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
timer_sleepmicroseconds(ts);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
end:
|
|
|
|
timer_expire += micro_frame_delay;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
* audio handlers
|
|
|
|
*************************/
|
2024-05-04 13:21:01 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int create_audiobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len,
|
|
|
|
void *context) {
|
2024-05-01 11:33:32 +00:00
|
|
|
#ifdef AUDIO
|
2024-05-01 12:38:01 +00:00
|
|
|
if (!mve_audio_enabled)
|
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-11 19:47:13 +00:00
|
|
|
int flags = get_ushort(data + 2);
|
|
|
|
int sample_rate = get_ushort(data + 4);
|
2024-11-03 20:39:51 +00:00
|
|
|
// int desired_buffer = get_int(data + 6);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-11 19:47:13 +00:00
|
|
|
int channels = (flags & MVE_AUDIO_FLAGS_STEREO) ? 2 : 1;
|
|
|
|
int sample_size = (flags & MVE_AUDIO_FLAGS_16BIT) ? 2 : 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-11 19:47:13 +00:00
|
|
|
bool is_compressed = false;
|
2024-05-05 15:36:16 +00:00
|
|
|
if (minor > 0 && (flags & MVE_AUDIO_FLAGS_COMPRESSED)) {
|
2024-05-11 19:47:13 +00:00
|
|
|
is_compressed = true;
|
2024-05-01 12:38:01 +00:00
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-08-29 13:29:46 +00:00
|
|
|
snd_ds = std::make_unique<D3::MovieSoundDevice>(sample_rate, sample_size, channels, is_compressed);
|
2024-05-01 11:33:32 +00:00
|
|
|
#endif
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int play_audio_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
2024-05-01 11:33:32 +00:00
|
|
|
#ifdef AUDIO
|
2024-05-11 19:47:13 +00:00
|
|
|
if (snd_ds && snd_ds->IsInitialized()) {
|
|
|
|
snd_ds->Play();
|
2024-05-01 12:38:01 +00:00
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
#endif
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int audio_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
2024-05-01 11:33:32 +00:00
|
|
|
#ifdef AUDIO
|
2024-05-01 12:38:01 +00:00
|
|
|
static const int selected_chan = 1;
|
2024-07-10 22:33:15 +00:00
|
|
|
if (snd_ds && snd_ds->IsInitialized()) {
|
2024-05-11 13:32:18 +00:00
|
|
|
int chan = get_ushort(data + 2);
|
2024-07-12 13:04:03 +00:00
|
|
|
int size = get_ushort(data + 4);
|
2024-05-01 12:38:01 +00:00
|
|
|
if (chan & selected_chan) {
|
2024-07-12 13:04:03 +00:00
|
|
|
void *buf = malloc(size);
|
2024-05-01 12:38:01 +00:00
|
|
|
if (major == MVE_OPCODE_AUDIOFRAMEDATA) {
|
2024-07-12 13:37:28 +00:00
|
|
|
mveaudio_process((char *)buf, data, snd_ds->GetSampleSize(), snd_ds->IsCompressed());
|
2024-05-01 12:38:01 +00:00
|
|
|
} else {
|
2024-05-11 13:32:18 +00:00
|
|
|
// SILENCE, MORTALS!
|
2024-07-12 13:04:03 +00:00
|
|
|
memset(data, 0, size);
|
2024-05-01 12:38:01 +00:00
|
|
|
}
|
2024-07-12 13:04:03 +00:00
|
|
|
snd_ds->FillBuffer((char *)buf, size);
|
|
|
|
free(buf);
|
2024-05-01 12:38:01 +00:00
|
|
|
}
|
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
#endif
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*************************
|
|
|
|
* video handlers
|
|
|
|
*************************/
|
|
|
|
|
|
|
|
static int videobuf_created = 0;
|
|
|
|
static int video_initialized = 0;
|
|
|
|
int g_width, g_height;
|
2024-05-11 13:32:18 +00:00
|
|
|
void *g_vBuffers = nullptr, *g_vBackBuf1, *g_vBackBuf2;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
|
|
|
static int g_destX, g_destY;
|
|
|
|
static int g_screenWidth, g_screenHeight;
|
2024-05-11 13:32:18 +00:00
|
|
|
static unsigned char *g_pCurMap = nullptr;
|
2024-05-01 12:38:01 +00:00
|
|
|
static int g_nMapLength = 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
static int g_truecolor;
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int create_videobuf_handler(unsigned char major, unsigned char minor, unsigned char *data, int len,
|
|
|
|
void *context) {
|
|
|
|
short w, h;
|
|
|
|
short count, truecolor;
|
|
|
|
|
|
|
|
if (videobuf_created)
|
|
|
|
return 1;
|
|
|
|
else
|
|
|
|
videobuf_created = 1;
|
|
|
|
|
|
|
|
w = get_short(data);
|
|
|
|
h = get_short(data + 2);
|
|
|
|
|
|
|
|
if (minor > 0) {
|
|
|
|
count = get_short(data + 4);
|
|
|
|
} else {
|
|
|
|
count = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (minor > 1) {
|
|
|
|
truecolor = get_short(data + 6);
|
|
|
|
} else {
|
|
|
|
truecolor = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_width = w << 3;
|
|
|
|
g_height = h << 3;
|
|
|
|
|
|
|
|
/* TODO: * 4 causes crashes on some files */
|
|
|
|
/* only malloc once */
|
2024-05-11 13:32:18 +00:00
|
|
|
if (g_vBuffers == nullptr)
|
2024-05-01 12:38:01 +00:00
|
|
|
g_vBackBuf1 = g_vBuffers = mve_alloc(g_width * g_height * 8);
|
|
|
|
if (truecolor) {
|
|
|
|
g_vBackBuf2 = (unsigned short *)g_vBackBuf1 + (g_width * g_height);
|
|
|
|
} else {
|
|
|
|
g_vBackBuf2 = (unsigned char *)g_vBackBuf1 + (g_width * g_height);
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(g_vBackBuf1, 0, g_width * g_height * 4);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
g_truecolor = truecolor;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int display_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len,
|
|
|
|
void *context) {
|
|
|
|
if (g_destX == -1) // center it
|
|
|
|
g_destX = (g_screenWidth - g_width) >> 1;
|
|
|
|
if (g_destY == -1) // center it
|
|
|
|
g_destY = (g_screenHeight - g_height) >> 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-04 22:24:44 +00:00
|
|
|
mve_showframe((unsigned char *)g_vBackBuf1, g_width, g_height, 0, 0, g_width, g_height, g_destX, g_destY,
|
|
|
|
g_truecolor);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
g_frameUpdated = 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int init_video_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
|
|
|
short width, height;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (video_initialized)
|
|
|
|
return 1; /* maybe we actually need to change width/height here? */
|
|
|
|
else
|
|
|
|
video_initialized = 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
width = get_short(data);
|
|
|
|
height = get_short(data + 2);
|
|
|
|
g_screenWidth = width;
|
|
|
|
g_screenHeight = height;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int video_palette_handler(unsigned char major, unsigned char minor, unsigned char *data, int len,
|
|
|
|
void *context) {
|
|
|
|
short start, count;
|
|
|
|
unsigned char *p;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
start = get_short(data);
|
|
|
|
count = get_short(data + 2);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
p = data + 4;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_setpalette(p - 3 * start, start, count);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int video_codemap_handler(unsigned char major, unsigned char minor, unsigned char *data, int len,
|
|
|
|
void *context) {
|
|
|
|
g_pCurMap = data;
|
|
|
|
g_nMapLength = len;
|
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int video_data_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
|
|
|
unsigned char *temp;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-11-03 20:39:51 +00:00
|
|
|
// short nFrameHot = get_short(data);
|
|
|
|
// short nFrameCold = get_short(data + 2);
|
|
|
|
// short nXoffset = get_short(data + 4);
|
|
|
|
// short nYoffset = get_short(data + 6);
|
|
|
|
// short nXsize = get_short(data + 8);
|
|
|
|
// short nYsize = get_short(data + 10);
|
2024-05-11 13:32:18 +00:00
|
|
|
unsigned short nFlags = get_ushort(data + 12);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (nFlags & 1) {
|
|
|
|
temp = (unsigned char *)g_vBackBuf1;
|
|
|
|
g_vBackBuf1 = g_vBackBuf2;
|
|
|
|
g_vBackBuf2 = temp;
|
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
/* convert the frame */
|
|
|
|
if (g_truecolor) {
|
|
|
|
decodeFrame16((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data + 14, len - 14);
|
|
|
|
} else {
|
2024-05-04 09:02:23 +00:00
|
|
|
decodeFrame8((unsigned char *)g_vBackBuf1, g_pCurMap, g_nMapLength, data + 14, len - 14);
|
2024-05-01 12:38:01 +00:00
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
static int end_chunk_handler(unsigned char major, unsigned char minor, unsigned char *data, int len, void *context) {
|
2024-05-11 13:32:18 +00:00
|
|
|
g_pCurMap = nullptr;
|
2024-05-01 12:38:01 +00:00
|
|
|
return 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
void MVE_ioCallbacks(mve_cb_Read io_read) { mve_read = io_read; }
|
|
|
|
|
|
|
|
void MVE_memCallbacks(mve_cb_Alloc mem_alloc, mve_cb_Free mem_free) {
|
|
|
|
mve_alloc = mem_alloc;
|
|
|
|
mve_free = mem_free;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
void MVE_sfCallbacks(mve_cb_ShowFrame showframe) { mve_showframe = showframe; }
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
void MVE_palCallbacks(mve_cb_SetPalette setpalette) { mve_setpalette = setpalette; }
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-05 00:52:52 +00:00
|
|
|
MVESTREAM* MVE_rmPrepMovie(void *src, int x, int y, int track) {
|
|
|
|
MVESTREAM *mve;
|
2024-05-01 12:38:01 +00:00
|
|
|
mve = mve_open(src);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (!mve)
|
2024-05-05 00:52:52 +00:00
|
|
|
return nullptr;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
g_destX = x;
|
|
|
|
g_destY = y;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-04 22:24:44 +00:00
|
|
|
for (int i = 0; i < 32; i++)
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_set_handler(mve, i, default_seg_handler);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_set_handler(mve, MVE_OPCODE_ENDOFSTREAM, end_movie_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_ENDOFCHUNK, end_chunk_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_CREATETIMER, create_timer_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_INITAUDIOBUFFERS, create_audiobuf_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_STARTSTOPAUDIO, play_audio_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_INITVIDEOBUFFERS, create_videobuf_handler);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_set_handler(mve, MVE_OPCODE_DISPLAYVIDEO, display_video_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMEDATA, audio_data_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_AUDIOFRAMESILENCE, audio_data_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_INITVIDEOMODE, init_video_handler);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_set_handler(mve, MVE_OPCODE_SETPALETTE, video_palette_handler);
|
|
|
|
mve_set_handler(mve, MVE_OPCODE_SETPALETTECOMPRESSED, default_seg_handler);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_set_handler(mve, MVE_OPCODE_SETDECODINGMAP, video_codemap_handler);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_set_handler(mve, MVE_OPCODE_VIDEODATA, video_data_handler);
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_play_next_chunk(mve); /* video initialization chunk */
|
|
|
|
if (mve_audio_enabled)
|
|
|
|
mve_play_next_chunk(mve); /* audio initialization chunk */
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-05 00:52:52 +00:00
|
|
|
return mve;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
void MVE_getVideoSpec(MVE_videoSpec *vSpec) {
|
|
|
|
vSpec->screenWidth = g_screenWidth;
|
|
|
|
vSpec->screenHeight = g_screenHeight;
|
|
|
|
vSpec->width = g_width;
|
|
|
|
vSpec->height = g_height;
|
|
|
|
vSpec->truecolor = g_truecolor;
|
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-05 00:52:52 +00:00
|
|
|
int MVE_rmStepMovie(MVESTREAM *mve) {
|
2024-05-01 12:38:01 +00:00
|
|
|
static int init_timer = 0;
|
|
|
|
int cont = 1;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (!timer_started)
|
|
|
|
timer_start();
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
while (cont && !g_frameUpdated) // make a "step" be a frame, not a chunk...
|
|
|
|
cont = mve_play_next_chunk(mve);
|
|
|
|
g_frameUpdated = 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (!cont)
|
|
|
|
return MVE_ERR_EOF;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
if (micro_frame_delay && !init_timer) {
|
|
|
|
timer_start();
|
|
|
|
init_timer = 1;
|
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
do_timer_wait();
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
return 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-05 00:52:52 +00:00
|
|
|
void MVE_rmEndMovie(MVESTREAM *mve) {
|
2024-05-01 12:38:01 +00:00
|
|
|
timer_stop();
|
|
|
|
timer_created = 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
|
|
|
#ifdef AUDIO
|
2024-05-11 19:47:13 +00:00
|
|
|
snd_ds.reset();
|
2024-05-01 11:33:32 +00:00
|
|
|
#endif
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_free(g_vBuffers);
|
2024-05-05 00:52:52 +00:00
|
|
|
g_vBuffers = nullptr;
|
|
|
|
g_pCurMap = nullptr;
|
2024-05-01 12:38:01 +00:00
|
|
|
g_nMapLength = 0;
|
|
|
|
videobuf_created = 0;
|
|
|
|
video_initialized = 0;
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_close(mve);
|
2024-05-05 00:52:52 +00:00
|
|
|
mve = nullptr;
|
2024-05-01 11:33:32 +00:00
|
|
|
}
|
|
|
|
|
2024-05-01 12:38:01 +00:00
|
|
|
void MVE_rmHoldMovie() { timer_started = 0; }
|
2024-05-01 11:33:32 +00:00
|
|
|
|
2024-09-04 11:26:33 +00:00
|
|
|
void MVE_sndInit(bool enable) {
|
2024-05-01 11:33:32 +00:00
|
|
|
#ifdef AUDIO
|
2024-07-10 22:33:15 +00:00
|
|
|
if (enable) {
|
2024-05-01 12:38:01 +00:00
|
|
|
mve_audio_enabled = 1;
|
2024-07-10 22:33:15 +00:00
|
|
|
} else {
|
|
|
|
mve_audio_enabled = 0;
|
|
|
|
}
|
2024-05-01 11:33:32 +00:00
|
|
|
#endif
|
|
|
|
}
|