559 lines
13 KiB
C++
559 lines
13 KiB
C++
/*
|
|
** Command & Conquer Red Alert(tm)
|
|
** Copyright 2025 Electronic Arts Inc.
|
|
**
|
|
** 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/>.
|
|
*/
|
|
|
|
/****************************************************************************
|
|
*
|
|
* C O N F I D E N T I A L -- W E S T W O O D S T U D I O S
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*
|
|
* PROJECT
|
|
* VQA player library. (32-Bit protected mode)
|
|
*
|
|
* FILE
|
|
* task.c
|
|
*
|
|
* DESCRIPTION
|
|
* Loading and drawing delegation
|
|
*
|
|
* PROGRAMMER
|
|
* Bill Randolph
|
|
* Denzil E. Long, Jr.
|
|
*
|
|
* DATE
|
|
* July 25, 1995
|
|
*
|
|
*----------------------------------------------------------------------------
|
|
*
|
|
* PUBLIC
|
|
* VQA_Alloc - Allocate a VQAHandle to use.
|
|
* VQA_Free - Free a VQAHandle.
|
|
* VQA_Init - Initialize the VQAHandle IO.
|
|
* VQA_Play - Play the VQA movie.
|
|
* VQA_GetInfo - Get VQA movie information.
|
|
* VQA_GetStats - Get VQA movie statistics.
|
|
* VQA_Version - Get VQA library version number.
|
|
* VQA_IDString - Get the VQA player library's ID string.
|
|
*
|
|
* PRIVATE
|
|
* VQA_IO_Task - Loader task for multitasking.
|
|
* VQA_Rendering_Task - Drawer task for multitasking.
|
|
* User_Update - Page flip routine called by the task interrupt.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include <dos.h>
|
|
#include <mem.h>
|
|
#include <conio.h>
|
|
#include <sys\timeb.h>
|
|
#include <vqm32\all.h>
|
|
#include "vqaplayp.h"
|
|
|
|
|
|
/*---------------------------------------------------------------------------
|
|
* PRIVATE DECLARATIONS
|
|
*-------------------------------------------------------------------------*/
|
|
|
|
/* Externals */
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
extern int cdecl Check_Key(void);
|
|
extern int cdecl Get_Key(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_Alloc - Allocate a VQAHandle to use.
|
|
*
|
|
* SYNOPSIS
|
|
* VQAHandle = VQA_Alloc()
|
|
*
|
|
* VQAHandle *VQA_Alloc(void);
|
|
*
|
|
* FUNCTION
|
|
* Obtain a VQAHandle. This handle is used by most VQA library functions,
|
|
* and contains the current position in the file. This is the only legal
|
|
* way to obtain a VQAHandle.
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* VQA - Handle of a VQA.
|
|
*
|
|
****************************************************************************/
|
|
|
|
VQAHandle *VQA_Alloc(void)
|
|
{
|
|
VQAHandleP *vqa;
|
|
|
|
if ((vqa = (VQAHandleP *)malloc(sizeof(VQAHandleP))) != NULL) {
|
|
memset(vqa, 0, sizeof(VQAHandleP));
|
|
}
|
|
|
|
return ((VQAHandle *)vqa);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_Free - Free a VQAHandle.
|
|
*
|
|
* SYNOPSIS
|
|
* VQA_Free(VQA)
|
|
*
|
|
* void VQA_Free(VQAHandle *);
|
|
*
|
|
* FUNCTION
|
|
* Dispose of a VQAHandle. This is the only legal way to dispose of a
|
|
* VQAHandle.
|
|
*
|
|
* INPUTS
|
|
* VQA - Pointer to VQAHandle to dispose of.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
void VQA_Free(VQAHandle *vqa)
|
|
{
|
|
if (vqa) free(vqa);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_Init - Initialize the VQAHandle IO handler.
|
|
*
|
|
* SYNOPSIS
|
|
* VQA_Init(VQA, IOHandler)
|
|
*
|
|
* void VQA_Init(VQAHandle *, IOHandler *);
|
|
*
|
|
* FUNCTION
|
|
* Initialize the specified VQAHandle IO with the client provided custom
|
|
* IO handler.
|
|
*
|
|
* INPUTS
|
|
* VQA - Pointer to VQAHandle to initialize.
|
|
* IOHandler - Pointer to custom file I/O handler function.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
void VQA_Init(VQAHandle *vqa, long(*iohandler)(VQAHandle *vqa, long action,
|
|
void *buffer, long nbytes))
|
|
{
|
|
((VQAHandleP *)vqa)->IOHandler = iohandler;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_Play - Play the VQA movie.
|
|
*
|
|
* SYNOPSIS
|
|
* Error = VQA_Play(VQA, Mode)
|
|
*
|
|
* long VQA_Play(VQAHandle *, long);
|
|
*
|
|
* FUNCTION
|
|
* Playback the movie associated with the specified VQAHandle.
|
|
*
|
|
* INPUTS
|
|
* VQA - Pointer to handle of movie to play.
|
|
* Mode - Playback mode.
|
|
* VQAMODE_RUN - Run the movie until completion.
|
|
* VQAMODE_WALK - Walk the movie frame by frame.
|
|
* VQAMODE_PAUSE - Pause the movie.
|
|
* VQAMODE_STOP - Stop the movie (Shutdown).
|
|
*
|
|
* RESULT
|
|
* Error - 0 if successful, or error code.
|
|
*
|
|
****************************************************************************/
|
|
|
|
long VQA_Play(VQAHandle *vqa, long mode)
|
|
{
|
|
VQAData *vqabuf;
|
|
VQAConfig *config;
|
|
VQADrawer *drawer;
|
|
long rc;
|
|
long i;
|
|
long key;
|
|
|
|
/* Dereference commonly used data members for quick access. */
|
|
vqabuf = ((VQAHandleP *)vqa)->VQABuf;
|
|
drawer = &vqabuf->Drawer;
|
|
config = &((VQAHandleP *)vqa)->Config;
|
|
|
|
/* One time player priming. */
|
|
if (!(vqabuf->Flags & VQADATF_PRIMED)) {
|
|
|
|
/* Init the Drawer's configuration */
|
|
VQA_Configure_Drawer((VQAHandleP *)vqa);
|
|
|
|
/* If audio enabled & loaded, start playing */
|
|
#if(VQAAUDIO_ON)
|
|
if ((config->OptionFlags & VQAOPTF_AUDIO) && vqabuf->Audio.IsLoaded[0]) {
|
|
VQA_StartAudio((VQAHandleP *)vqa);
|
|
}
|
|
#endif
|
|
|
|
/* Initialize the timer */
|
|
i = ((vqabuf->Drawer.CurFrame->FrameNum * VQA_TIMETICKS)
|
|
/ config->DrawRate);
|
|
|
|
VQA_SetTimer((VQAHandleP *)vqa, i, config->TimerMethod);
|
|
vqabuf->StartTime = VQA_GetTime((VQAHandleP *)vqa);
|
|
|
|
/* Set up the Mono screen */
|
|
#if(VQAMONO_ON)
|
|
if (config->OptionFlags & VQAOPTF_MONO) {
|
|
VQA_InitMono((VQAHandleP *)vqa);
|
|
}
|
|
#endif
|
|
|
|
/* Priming is complete. */
|
|
vqabuf->Flags |= VQADATF_PRIMED;
|
|
}
|
|
|
|
/* Main Player Loop */
|
|
switch (mode) {
|
|
case VQAMODE_PAUSE:
|
|
if ((vqabuf->Flags & VQADATF_PAUSED) == 0) {
|
|
vqabuf->Flags |= VQADATF_PAUSED;
|
|
vqabuf->EndTime = VQA_GetTime((VQAHandleP *)vqa);
|
|
|
|
/* Stop the audio while the movie is paused. */
|
|
#if(VQAAUDIO_ON)
|
|
if (vqabuf->Audio.Flags & VQAAUDF_ISPLAYING) {
|
|
VQA_StopAudio((VQAHandleP *)vqa);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
rc = VQAERR_PAUSED;
|
|
break;
|
|
|
|
case VQAMODE_RUN:
|
|
case VQAMODE_WALK:
|
|
default:
|
|
|
|
/* Start up the movie if is it currently paused. */
|
|
if (vqabuf->Flags & VQADATF_PAUSED) {
|
|
vqabuf->Flags &= ~VQADATF_PAUSED;
|
|
|
|
/* Start the audio if it was previously on. */
|
|
#if(VQAAUDIO_ON)
|
|
if (config->OptionFlags & VQAOPTF_AUDIO) {
|
|
VQA_StartAudio((VQAHandleP *)vqa);
|
|
}
|
|
#endif
|
|
|
|
VQA_SetTimer((VQAHandleP *)vqa, vqabuf->EndTime, config->TimerMethod);
|
|
}
|
|
|
|
/* Load, Draw, Load, Draw, Load, Draw ... */
|
|
while ((vqabuf->Flags & (VQADATF_DDONE|VQADATF_LDONE))
|
|
!= (VQADATF_DDONE|VQADATF_LDONE)) {
|
|
|
|
/* Load a frame */
|
|
if (!(vqabuf->Flags & VQADATF_LDONE)) {
|
|
if ((rc = VQA_LoadFrame(vqa)) == 0) {
|
|
vqabuf->LoadedFrames++;
|
|
}
|
|
else if ((rc != VQAERR_NOBUFFER) && (rc != VQAERR_SLEEPING)) {
|
|
vqabuf->Flags |= VQADATF_LDONE;
|
|
rc = 0;
|
|
}
|
|
}
|
|
|
|
/* Draw a frame */
|
|
if ((config->DrawFlags & VQACFGF_NODRAW) == 0) {
|
|
if ((rc = (*(vqabuf->Draw_Frame))(vqa)) == 0) {
|
|
vqabuf->DrawnFrames++;
|
|
|
|
if (User_Update(vqa)) {
|
|
vqabuf->Flags |= (VQADATF_DDONE|VQADATF_LDONE);
|
|
}
|
|
}
|
|
else if ((vqabuf->Flags & VQADATF_LDONE)
|
|
&& (rc == VQAERR_NOBUFFER)) {
|
|
vqabuf->Flags |= VQADATF_DDONE;
|
|
}
|
|
} else {
|
|
vqabuf->Flags |= VQADATF_DDONE;
|
|
drawer->CurFrame->Flags = 0L;
|
|
drawer->CurFrame = drawer->CurFrame->Next;
|
|
}
|
|
|
|
/* Update Mono output */
|
|
#if(VQAMONO_ON)
|
|
if (config->OptionFlags & VQAOPTF_MONO) {
|
|
VQA_UpdateMono((VQAHandleP *)vqa);
|
|
}
|
|
#endif
|
|
|
|
if (mode == VQAMODE_WALK) {
|
|
break;
|
|
}
|
|
#if(VQASTANDALONE)
|
|
else {
|
|
|
|
/* Do single-stepping check. */
|
|
if (config->OptionFlags & VQAOPTF_STEP) {
|
|
while ((key = Check_Key()) == 0);
|
|
Get_Key();
|
|
|
|
/* Escape key still quits. */
|
|
if (key == 27) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* Check for ESC */
|
|
if ((key = Check_Key()) != 0) {
|
|
mode = VQAMODE_STOP;
|
|
break;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
break;
|
|
}
|
|
|
|
/* If the movie is finished or we are requested to stop then shutdown. */
|
|
if (((vqabuf->Flags & (VQADATF_DDONE|VQADATF_LDONE))
|
|
== (VQADATF_DDONE|VQADATF_LDONE)) || (mode == VQAMODE_STOP)) {
|
|
|
|
/* Record the end time; must be done before stopping audio, since we're
|
|
* getting the elapsed time from the audio DMA position.
|
|
*/
|
|
vqabuf->EndTime = VQA_GetTime((VQAHandleP *)vqa);
|
|
|
|
/* Stop audio, if it's playing. */
|
|
#if(VQAAUDIO_ON)
|
|
if (vqabuf->Audio.Flags & VQAAUDF_ISPLAYING) {
|
|
VQA_StopAudio((VQAHandleP *)vqa);
|
|
}
|
|
#endif
|
|
|
|
/* Movie is finished. */
|
|
rc = VQAERR_EOF;
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_GetInfo - Get VQA movie information.
|
|
*
|
|
* SYNOPSIS
|
|
* VQA_GetInfo(VQA, Info)
|
|
*
|
|
* void VQA_GetInfo(VQAHandle *, VQAInfo *);
|
|
*
|
|
* FUNCTION
|
|
* Retrieve information about the opened movie.
|
|
*
|
|
* INPUTS
|
|
* VQA - Pointer to VQAHandle of opened movie.
|
|
* Info - Pointer to VQAInfo structure to fill.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
void VQA_GetInfo(VQAHandle *vqa, VQAInfo *info)
|
|
{
|
|
VQAHeader *header;
|
|
|
|
/* Dereference header structure. */
|
|
header = &((VQAHandleP *)vqa)->Header;
|
|
|
|
info->NumFrames = header->Frames;
|
|
info->ImageHeight = header->ImageHeight;
|
|
info->ImageWidth = header->ImageWidth;
|
|
info->ImageBuf = ((VQAHandleP *)vqa)->VQABuf->Drawer.ImageBuf;
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_GetStats - Get VQA movie statistics.
|
|
*
|
|
* SYNOPSIS
|
|
* VQA_GetStats(VQA, Stats)
|
|
*
|
|
* void VQA_GetStats(VQAHandle *, VQAStatistics *);
|
|
*
|
|
* FUNCTION
|
|
* Retrieve the statistics for the VQA movie.
|
|
*
|
|
* INPUTS
|
|
* VQA - Handle of VQA movie to get statistics for.
|
|
* Stats - Pointer to VQAStatistics to fill.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
void VQA_GetStats(VQAHandle *vqa, VQAStatistics *stats)
|
|
{
|
|
VQAData *vqabuf;
|
|
|
|
/* Dereference VQAData structure from VQAHandle */
|
|
vqabuf = ((VQAHandleP *)vqa)->VQABuf;
|
|
|
|
stats->MemUsed = vqabuf->MemUsed;
|
|
stats->StartTime = vqabuf->StartTime;
|
|
stats->EndTime = vqabuf->EndTime;
|
|
stats->FramesLoaded = vqabuf->LoadedFrames;
|
|
stats->FramesDrawn = vqabuf->DrawnFrames;
|
|
stats->FramesSkipped = vqabuf->Drawer.NumSkipped;
|
|
stats->MaxFrameSize = vqabuf->Loader.MaxFrameSize;
|
|
|
|
#if(VQAAUDIO_ON)
|
|
stats->SamplesPlayed = vqabuf->Audio.SamplesPlayed;
|
|
#else
|
|
stats->SamplesPlayed = 0;
|
|
#endif
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_Version - Get VQA library version number.
|
|
*
|
|
* SYNOPSIS
|
|
* Version = VQA_Version()
|
|
*
|
|
* char *VQA_Version(void);
|
|
*
|
|
* FUNCTION
|
|
* Return the version of the VQA player library.
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* Version - Pointer to version number string.
|
|
*
|
|
****************************************************************************/
|
|
|
|
char *VQA_Version(void)
|
|
{
|
|
return(VQA_VERSION);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* VQA_IDString - Get the VQA player library's ID string.
|
|
*
|
|
* SYNOPSIS
|
|
* IDString = VQA_IDString()
|
|
*
|
|
* char *VQA_IDString(void);
|
|
*
|
|
* FUNCTION
|
|
* Return the ID string of this VQA player library.
|
|
*
|
|
* INPUTS
|
|
* NONE
|
|
*
|
|
* RESULT
|
|
* IDString - Pointer to ID string.
|
|
*
|
|
****************************************************************************/
|
|
|
|
char *VQA_IDString(void)
|
|
{
|
|
return (VQA_IDSTRING);
|
|
}
|
|
|
|
|
|
/****************************************************************************
|
|
*
|
|
* NAME
|
|
* User_Update - Page flip routine called by the task interrupt.
|
|
*
|
|
* SYNOPSIS
|
|
* User_Update(VQA)
|
|
*
|
|
* long User_Update(VQAHandle *);
|
|
*
|
|
* FUNCTION
|
|
*
|
|
* INPUTS
|
|
* VQA - Handle of VQA movie.
|
|
*
|
|
* RESULT
|
|
* NONE
|
|
*
|
|
****************************************************************************/
|
|
|
|
long User_Update(VQAHandle *vqa)
|
|
{
|
|
VQAData *vqabuf;
|
|
long rc = 0;
|
|
|
|
/* Dereference data members for quicker access. */
|
|
vqabuf = ((VQAHandleP *)vqa)->VQABuf;
|
|
|
|
if (vqabuf->Flags & VQADATF_UPDATE) {
|
|
|
|
/* Invoke the page flip routine */
|
|
rc = (*(vqabuf->Page_Flip))(vqa);
|
|
|
|
/* Update data for mono output */
|
|
vqabuf->Flipper.LastFrameNum = vqabuf->Flipper.CurFrame->FrameNum;
|
|
|
|
/* Mark the frame as loadable */
|
|
vqabuf->Flipper.CurFrame->Flags = 0L;
|
|
vqabuf->Flags &= (~VQADATF_UPDATE);
|
|
}
|
|
|
|
return (rc);
|
|
}
|
|
|