/*
** 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 .
*/
/***************************************************************************
** 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 Name : VQAVIEW *
* *
* File Name : MOVIES.CPP *
* *
* Programmer : Michael Grayford *
* *
* Start Date : *
* *
* Last Update : Nov 29, 1995 [MG] *
* *
*-------------------------------------------------------------------------*
* Functions: *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
//==========================================================================
// INCLUDES
//==========================================================================
#include
#include
#include
#include
#include
#include
#include
//==========================================================================
// PRIVATE FUNCTIONS
//==========================================================================
void VQA_Test( char *filename );
void Create_Palette_Interpolation_Table( void );
void Interpolate_2X_Scale( GraphicBufferClass *source, GraphicBufferClass *dest );
//==========================================================================
// PRIVATE GLOBALS
//==========================================================================
extern "C"{
extern unsigned char *InterpolationPalette;
extern unsigned char Palette_Interpolation_Table[SIZE_OF_PALETTE][SIZE_OF_PALETTE];
extern void __cdecl Asm_Create_Palette_Interpolation_Table(void);
extern void __cdecl Asm_Interpolate (unsigned char* src_ptr ,
unsigned char* dest_ptr ,
int lines ,
int src_width ,
int dest_width);
}
unsigned char Palette_Interpolation_Table[ SIZE_OF_PALETTE ][ SIZE_OF_PALETTE ];
unsigned char *InterpolationPalette;
VQAClass *TestVqa;
#if( ! DRAW_TO_VIDEO )
GraphicBufferClass *Draw_Page = NULL;
GraphicBufferClass *Back_Page = NULL;
GraphicBufferClass *Hid_Page = NULL;
#endif
/***************************************************************************
* Initialize_Movie_System - Allocate memory needed for caching and any *
* permanent Movie data. *
* *
* INPUT: NONE *
* *
* OUTPUT: int - an error value *
* *
* WARNINGS: Yellow alert! *
* *
* HISTORY: *
* 09/29/1995 MG : Created. *
*=========================================================================*/
int Initialize_Movie_System( void )
{
#if( ! DRAW_TO_VIDEO )
//
// Set up the graphic pages:
// Draw_Page - the page that the VQA library draws to. (Normal RAM)
// Back_Page - the page that the drawn image is scaled to. (Normal RAM)
// Hid_Page - the page in video RAM that the scaled image is copied to before copy to screen.
//
Draw_Page = new GraphicBufferClass ( MOVIE_WIDTH, MOVIE_HEIGHT );
Back_Page = new GraphicBufferClass ( VIDEO_MODE_WIDTH, VIDEO_MODE_HEIGHT );
Hid_Page = new GraphicBufferClass ( VIDEO_MODE_WIDTH, VIDEO_MODE_HEIGHT, (GBC_Enum)(GBC_VIDEOMEM) );
#endif
//
// Okay, we're cool.
//
return( VQA_INIT_NO_ERROR );
}
/***************************************************************************
* Free_Movie_System - Free up memory used by Movie cache system and any *
* permanent Movie data. *
* *
* INPUT: NONE *
* *
* OUTPUT: NONE *
* *
* WARNINGS: Red alert! *
* *
* HISTORY: *
* 09/29/1995 MG : Created. *
*=========================================================================*/
void Free_Movie_System( void )
{
#if( ! DRAW_TO_VIDEO )
if ( Draw_Page ) {
delete( Draw_Page );
}
if ( Back_Page ) {
delete( Back_Page );
}
if ( Hid_Page ) {
delete( Hid_Page );
}
Draw_Page = NULL;
Back_Page = NULL;
Hid_Page = NULL;
#endif
return;
}
/***************************************************************************
* Choose_Movie - Brings up choice of VQA files. *
* *
* INPUT: NONE *
* *
* OUTPUT: NONE *
* *
* WARNINGS: *
* *
* HISTORY: *
* 05/15/1995 MG : Created. *
*=========================================================================*/
void Choose_Movie( WindowHandle window_handle )
{
int i;
char temp_file[_MAX_FNAME + _MAX_EXT];
static OPENFILENAME open_file_dlg;
static char path_filename[ _MAX_PATH*500 ];
static char filename[ _MAX_FNAME + _MAX_EXT ];
static char *filters[] = {
"VQA files (*.VQA)", "*.vqa",
"All Files", "*.*",
"" } ;
filename[0]=0;
memset (&path_filename[0],0,_MAX_PATH*500);
open_file_dlg.lStructSize = sizeof( OPENFILENAME );
open_file_dlg.hwndOwner = window_handle;
open_file_dlg.hInstance = NULL;
open_file_dlg.lpstrFilter = filters[ 0 ];
open_file_dlg.lpstrCustomFilter = NULL;
open_file_dlg.nMaxCustFilter = 0;
open_file_dlg.nFilterIndex = 1;
open_file_dlg.lpstrFile = path_filename;
open_file_dlg.nMaxFile = _MAX_PATH*500;
open_file_dlg.lpstrFileTitle = filename;
open_file_dlg.nMaxFileTitle = _MAX_FNAME + _MAX_EXT;
open_file_dlg.lpstrInitialDir = NULL;
open_file_dlg.lpstrTitle = "Choose a VQA to run";
open_file_dlg.Flags = OFN_FILEMUSTEXIST | OFN_ALLOWMULTISELECT;
open_file_dlg.nFileOffset = 0;
open_file_dlg.nFileExtension = 0;
open_file_dlg.lpstrDefExt = "vqa";
open_file_dlg.lCustData = 0l;
open_file_dlg.lpfnHook = NULL;
open_file_dlg.lpTemplateName = NULL;
if ( GetOpenFileName( &open_file_dlg ) ) {
if ( filename[ 0 ] != '\0' ) {
VQA_Test( filename );
} else {
int last_file=0;
for (i=0 ; iLock();
draw_surface_ptr = (char *) draw_buffer_ptr->Get_Offset();
draw_buffer_ptr->Unlock();
//
// Clear the drawing surface with color 0.
//
draw_buffer_ptr->Lock();
temp_ptr = draw_surface_ptr;
for ( i = 0; i < (MOVIE_WIDTH * MOVIE_HEIGHT); i ++ ) {
*temp_ptr = COLOR_BLACK;
temp_ptr ++;
}
draw_buffer_ptr->Unlock();
//
// Create a new VQA object.
//
TestVqa = new VQAClass(
filename,
draw_surface_ptr,
FROM_DISK,
callback_function_ptr );
//
// Allocate the buffers for the VQA.
//
if ( TestVqa->Open_And_Load_Buffers() ) {
TestVqa->Read_Palettes();
//
// Play the VQA.
//
TestVqa->Play_VQA( PLAY_ALL_FRAMES );
//
// Close the VQA.
//
TestVqa->Close_And_Free_VQA();
TestVqa->Write_Palettes();
delete TestVqa;
}
}
/***************************************************************************
* DRAW_TO_VIDEO_CALLBACK -- Callback after a VQA frame is drawn to video *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/22/1995 MG : Created. *
*=========================================================================*/
long Draw_To_Video_Callback( unsigned char *buffer, long frame_number )
{
return( 0 );
}
/***************************************************************************
* DRAW_TO_BUFFER_CALLBACK -- Copies the drawn frame to the screen *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 11/22/1995 MG : Created. *
*=========================================================================*/
long Draw_To_Buffer_Callback( unsigned char *buffer, long frame_number )
{
//
// Frame was skipped, bail.
//
if ( buffer == NULL ) {
return( 0 );
}
#if( ! DRAW_TO_VIDEO )
//
// Do the cool interpolated, interlaced scale.
//
#if( 1 )
Interpolate_2X_Scale( Draw_Page, Back_Page );
Back_Page->Blit( *Screen_Buffer, 0, 0, 0, 100, 640, 314 );
#endif
//
// Draw 320x200 to Normal RAM, scale to Screen.
//
#if( 0 )
Draw_Page->Scale( *Screen_Buffer );
#endif
//
// Draw 320x200 to Normal RAM, scale to Normal RAM, Blit to Hid, Blit to Screen.
//
#if( 0 )
Draw_Page->Scale( *Back_Page );
Back_Page->Blit( *Hid_Page );
Hid_Page->Blit( *Screen_Buffer );
#endif
//
// Draw 320x200 to Normal RAM, scale to Normal RAM, Blit to Screen.
//
#if( 0 )
Draw_Page->Scale( *Back_Page );
Back_Page->Blit( *Screen_Buffer );
#endif
//
// Draw 320x200 to Normal RAM, Blit to Screen.
//
#if( 0 )
Draw_Page->Blit( *Screen_Buffer );
#endif
#endif
return( 0 );
}
/***************************************************************************
* CREATE_PALETTE_INTERPOLATION_TABLE *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/06/1995 MG : Created. *
*=========================================================================*/
void Create_Palette_Interpolation_Table( void )
{
// InterpolationPalette = (unsigned char*)CurrentPalette;
// Asm_Create_Palette_Interpolation_Table();
//#if 0
int i;
int j;
int p;
unsigned char *first_palette_ptr;
unsigned char *second_palette_ptr;
unsigned char *match_pal_ptr;
int first_r;
int first_g;
int first_b;
int second_r;
int second_g;
int second_b;
int diff_r;
int diff_g;
int diff_b;
int dest_r;
int dest_g;
int dest_b;
int distance;
int closest_distance;
int index_of_closest_color;
//
// Create an interpolation table for the current palette.
//
first_palette_ptr = (unsigned char *) CurrentPalette;
for ( i = 0; i < SIZE_OF_PALETTE; i ++ ) {
//
// Get the first palette entry's RGB.
//
first_r = *first_palette_ptr;
first_palette_ptr ++;
first_g = *first_palette_ptr;
first_palette_ptr ++;
first_b = *first_palette_ptr;
first_palette_ptr ++;
second_palette_ptr = (unsigned char *) CurrentPalette;
for ( j = 0; j < SIZE_OF_PALETTE; j ++ ) {
//
// Get the second palette entry's RGB.
//
second_r = *second_palette_ptr;
second_palette_ptr ++;
second_g = *second_palette_ptr;
second_palette_ptr ++;
second_b = *second_palette_ptr;
second_palette_ptr ++;
//
// Now calculate the RGB halfway between the first and second colors.
//
dest_r = ( first_r + second_r ) >> 1;
dest_g = ( first_g + second_g ) >> 1;
dest_b = ( first_b + second_b ) >> 1;
//
// Now find the color in the palette that most closely matches the interpolated color.
//
index_of_closest_color = 0;
// closest_distance = (256 * 256) * 3;
closest_distance = 500000;
match_pal_ptr = (unsigned char *) CurrentPalette;
for ( p = 0; p < SIZE_OF_PALETTE; p ++ ) {
diff_r = ( ((int) (*match_pal_ptr)) - dest_r );
match_pal_ptr ++;
diff_g = ( ((int) (*match_pal_ptr)) - dest_g );
match_pal_ptr ++;
diff_b = ( ((int) (*match_pal_ptr)) - dest_b );
match_pal_ptr ++;
distance = ( diff_r * diff_r ) + ( diff_g * diff_g ) + ( diff_b * diff_b );
if ( distance < closest_distance ) {
closest_distance = distance;
index_of_closest_color = p;
}
}
Palette_Interpolation_Table[ i ][ j ] = (unsigned char) index_of_closest_color;
}
}
return;
//#endif
}
#if( 1 )
/***************************************************************************
* INTERPOLATE_2X_SCALE *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/06/1995 MG : Created. *
*=========================================================================*/
void Interpolate_2X_Scale( GraphicBufferClass *source, GraphicBufferClass *dest)
{
unsigned char *src_ptr;
unsigned char *dest_ptr;
unsigned char *last_dest_ptr;
unsigned char *end_of_source;
int src_width;
int dest_width;
// int width_counter;
BOOL source_locked = FALSE;
BOOL dest_locked = FALSE;
/*
** Lock video surfaces if requred
*/
if (source->Get_IsDirectDraw()){
if (!source->Lock()) return;
source_locked = TRUE;
}
if (dest->Get_IsDirectDraw()){
if (!dest->Lock()) {
if (source_locked){
source->Unlock();
}
return;
}
dest_locked = TRUE;
}
//
// Get pointers to the source and destination buffers.
//
src_ptr = (unsigned char *) source->Get_Offset();
dest_ptr = (unsigned char *) dest->Get_Offset();
end_of_source = src_ptr + ( source->Get_Width() * source->Get_Height() );
//
// Get width of source and dest buffers.
//
src_width = source->Get_Width();
dest_width = 2*(dest->Get_Width() + dest->Get_XAdd() + dest->Get_Pitch());
last_dest_ptr = dest_ptr;
Asm_Interpolate ( src_ptr , dest_ptr , source->Get_Height() , src_width , dest_width);
if (source_locked) source->Unlock();
if (dest_locked) dest->Unlock();
return;
}
#endif
#if( 0 )
/***************************************************************************
* INTERPOLATE_2X_SCALE *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/06/1995 MG : Created. *
*=========================================================================*/
void Interpolate_2X_Scale( GraphicBufferClass *source, GraphicBufferClass *dest )
{
unsigned char *src_ptr;
unsigned char *dest_ptr;
unsigned char *end_of_source;
int src_width;
int dest_width;
int width_counter;
//
// Get pointers to the source and destination buffers.
//
src_ptr = (unsigned char *) source->Get_Offset();
dest_ptr = (unsigned char *) dest->Get_Offset();
end_of_source = src_ptr + ( source->Get_Width() * source->Get_Height() );
//
// Get width of source and dest buffers.
//
src_width = source->Get_Width();
dest_width = dest->Get_Width();
//
// Copy over the first pixel (upper left).
//
*dest_ptr = *src_ptr;
src_ptr ++;
dest_ptr ++;
//
// Scale copy.
//
width_counter = 0;
while ( src_ptr < end_of_source ) {
//
// Blend this pixel with the one to the left and place this new color in the dest buffer.
//
*dest_ptr = Palette_Interpolation_Table[ (*src_ptr) ][ (*( src_ptr - 1 )) ];
dest_ptr ++;
//
// Now place the source pixel into the dest buffer.
//
*dest_ptr = *src_ptr;
src_ptr ++;
dest_ptr ++;
width_counter ++;
if ( width_counter == src_width ) {
width_counter = 0;
dest_ptr += dest_width;
}
}
return;
}
#endif
#if( 0 )
/***************************************************************************
* INTERPOLATE_2X_SCALE *
* *
* INPUT: *
* *
* OUTPUT: *
* *
* WARNINGS: *
* *
* HISTORY: *
* 12/06/1995 MG : Created. *
*=========================================================================*/
void Interpolate_2X_Scale( GraphicBufferClass *source, GraphicBufferClass *dest )
{
unsigned char *src_ptr;
unsigned char *dest_ptr;
unsigned char *dest2_ptr;
unsigned char *end_of_source;
int src_width;
int dest_width;
int width_counter;
//
// Get pointers to the source and destination buffers.
//
src_ptr = (unsigned char *) source->Get_Offset();
dest_ptr = (unsigned char *) dest->Get_Offset();
end_of_source = src_ptr + ( source->Get_Width() * source->Get_Height() );
//
// Get width of source and dest buffers.
//
src_width = source->Get_Width();
dest_width = dest->Get_Width();
//
// Copy over the first pixel (upper left).
//
*dest_ptr = *src_ptr;
src_ptr ++;
dest_ptr += 2;
dest2_ptr = dest_ptr + dest_width + 1;
//
// Scale copy.
//
width_counter = 0;
while ( src_ptr < end_of_source ) {
//
// Blend this pixel with the one to the left and place this new color in the dest buffer.
//
*dest2_ptr = Palette_Interpolation_Table[ (*src_ptr) ][ (*( src_ptr - 1 )) ];
dest2_ptr += 2;
//
// Now place the source pixel into the dest buffer.
//
*dest_ptr = *src_ptr;
src_ptr ++;
dest_ptr += 2;
width_counter ++;
if ( width_counter == src_width ) {
width_counter = 0;
dest_ptr += dest_width;
dest2_ptr += dest_width;
}
}
return;
}
#endif