CnC_Remastered_Collection/REDALERT/2KEYFRAM.CPP
PG-SteveT 03416d24e1 Initial Source Code commit
Initial commit of original Tiberian Dawn and Red Alert source code converted to build as DLLs, and compatible with the release version of Command & Conquer Remastered.
2020-05-27 12:16:20 -07:00

588 lines
22 KiB
C++

//
// Copyright 2020 Electronic Arts Inc.
//
// TiberianDawn.DLL and RedAlert.dll and corresponding source code 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.
// TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed
// in the hope that it will be useful, but with permitted additional restrictions
// under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT
// distributed with this program. You should have received a copy of the
// GNU General Public License along with permitted additional restrictions
// with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection
/* $Header: /CounterStrike/2KEYFRAM.CPP 1 3/03/97 10:24a Joe_bostic $ */
/***********************************************************************************************
*** 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 : Command & Conquer *
* *
* File Name : KEYFRAME.CPP *
* *
* Programmer : Joe L. Bostic *
* *
* Start Date : 06/25/95 *
* *
* Last Update : June 25, 1995 [JLB] *
* *
*---------------------------------------------------------------------------------------------*
* Functions: *
* Get_Build_Frame_Count -- Fetches the number of frames in data block. *
* Get_Build_Frame_Width -- Fetches the width of the shape image. *
* Get_Build_Frame_Height -- Fetches the height of the shape image. *
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
#include "function.h"
#define SUBFRAMEOFFS 7 // 3 1/2 frame offsets loaded (2 offsets/frame)
#define Apply_Delta(buffer, delta) Apply_XOR_Delta((char*)(buffer), (char*)(delta))
typedef struct {
unsigned short frames;
unsigned short x;
unsigned short y;
unsigned short width;
unsigned short height;
unsigned short largest_frame_size;
short flags;
} KeyFrameHeaderType;
#define INITIAL_BIG_SHAPE_BUFFER_SIZE 8000000
#define THEATER_BIG_SHAPE_BUFFER_SIZE 4000000
#define UNCOMPRESS_MAGIC_NUMBER 56789
unsigned BigShapeBufferLength = INITIAL_BIG_SHAPE_BUFFER_SIZE;
unsigned TheaterShapeBufferLength = THEATER_BIG_SHAPE_BUFFER_SIZE;
extern "C"{
char *BigShapeBufferStart = NULL;
char *TheaterShapeBufferStart = NULL;
BOOL UseBigShapeBuffer = FALSE;
bool IsTheaterShape = false;
}
#ifdef FIXIT_SCORE_CRASH
/*
** Global required to fix the score screen crash bug by allowing disabling of uncompressed shapes.
*/
bool OriginalUseBigShapeBuffer = false;
#endif //FIXIT
char *BigShapeBufferPtr = NULL;
int TotalBigShapes=0;
BOOL ReallocShapeBufferFlag = FALSE;
char *TheaterShapeBufferPtr = NULL;
int TotalTheaterShapes = 0;
#define MAX_SLOTS 1500
#define THEATER_SLOT_START 1000
char **KeyFrameSlots [MAX_SLOTS];
int TotalSlotsUsed=0;
int TheaterSlotsUsed = THEATER_SLOT_START;
typedef struct tShapeHeaderType{
unsigned draw_flags;
char *shape_data;
int shape_buffer; //1 if shape is in theater buffer
} ShapeHeaderType;
static int Length;
void *Get_Shape_Header_Data(void *ptr)
{
if (UseBigShapeBuffer) {
ShapeHeaderType *header = (ShapeHeaderType*) ptr;
return ((void*) (header->shape_data + (long)(header->shape_buffer ? TheaterShapeBufferStart : BigShapeBufferStart) ) );
} else {
return (ptr);
}
}
int Get_Last_Frame_Length(void)
{
return(Length);
}
void Reset_Theater_Shapes (void)
{
/*
** Delete any previously allocated slots
*/
for (int i=THEATER_SLOT_START ; i<TheaterSlotsUsed ; i++) {
delete [] KeyFrameSlots [i];
}
TheaterShapeBufferPtr = TheaterShapeBufferStart;
TotalTheaterShapes = 0;
TheaterSlotsUsed = THEATER_SLOT_START;
}
void Reallocate_Big_Shape_Buffer(void)
{
if (ReallocShapeBufferFlag) {
BigShapeBufferLength += 2000000; //Extra 2 Mb of uncompressed shape space
BigShapeBufferPtr -= (unsigned)BigShapeBufferStart;
Memory_Error = NULL;
BigShapeBufferStart = (char*)Resize_Alloc(BigShapeBufferStart, BigShapeBufferLength);
Memory_Error = &Memory_Error_Handler;
/*
** If we have run out of memory then disable the uncompressed shapes
** It may still be possible to continue with compressed shapes
*/
if (!BigShapeBufferStart) {
UseBigShapeBuffer = false;
return;
}
BigShapeBufferPtr += (unsigned)BigShapeBufferStart;
ReallocShapeBufferFlag = FALSE;
}
}
//#ifdef FIXIT_SCORE_CRASH
/***********************************************************************************************
* Disable_Uncompressed_Shapes -- Temporarily turns off shape decompression *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/19/96 2:37PM ST : Created *
*=============================================================================================*/
void Disable_Uncompressed_Shapes (void)
{
UseBigShapeBuffer = false;
}
/***********************************************************************************************
* Enable_Uncompressed_Shapes -- Restores state of shape decompression before it was disabled *
* *
* *
* *
* INPUT: Nothing *
* *
* OUTPUT: Nothing *
* *
* WARNINGS: None *
* *
* HISTORY: *
* 11/19/96 2:37PM ST : Created *
*=============================================================================================*/
void Enable_Uncompressed_Shapes (void)
{
UseBigShapeBuffer = OriginalUseBigShapeBuffer;
}
//#endif //FIXIT
void Check_Use_Compressed_Shapes (void)
{
#if (1) // Uncompressed shapes enabled for performance reasons. We don't need to worry about memory.
// Uncompressed shapes don't seem to work in RA for rotated/scaled objects so wherever scale/rotate is used,
// we will need to disable it (like in Techno_Draw_Object). ST - 11/6/2019 2:09PM
UseBigShapeBuffer = true;
OriginalUseBigShapeBuffer = true;
#else
MEMORYSTATUS mem_info;
mem_info.dwLength=sizeof(mem_info);
GlobalMemoryStatus(&mem_info);
UseBigShapeBuffer = (mem_info.dwTotalPhys > 16*1024*1024) ? TRUE : FALSE;
#ifdef FIXIT_SCORE_CRASH
/*
** Keep track of our original decision about whether to use cached shapes.
** This is needed for the score screen crash fix.
*/
OriginalUseBigShapeBuffer = UseBigShapeBuffer;
#endif //FIXIT
#endif
}
unsigned long Build_Frame(void const *dataptr, unsigned short framenumber, void *buffptr)
{
#ifdef FIXIT_SCORE_CRASH
char *ptr;
unsigned long offcurr, offdiff;
#else
char *ptr, *lockptr;//, *uncomp_ptr;
unsigned long offcurr, off16, offdiff;
#endif
unsigned long offset[SUBFRAMEOFFS];
KeyFrameHeaderType *keyfr;
unsigned short buffsize, currframe, subframe;
unsigned long length = 0;
char frameflags;
unsigned long return_value;
char *temp_shape_ptr;
//
// valid pointer??
//
Length = 0;
if ( !dataptr || !buffptr ) {
return(0);
}
//
// look at header then check that frame to build is not greater
// than total frames
//
keyfr = (KeyFrameHeaderType *) dataptr;
if ( framenumber >= keyfr->frames ) {
return(0);
}
if (UseBigShapeBuffer) {
/*
** If we havnt yet allocated memory for uncompressed shapes then do so now.
**
*/
if (!BigShapeBufferStart) {
BigShapeBufferStart = (char*)Alloc(BigShapeBufferLength, MEM_NORMAL);
BigShapeBufferPtr = BigShapeBufferStart;
/*
** Allocate memory for theater specific uncompressed shapes
*/
TheaterShapeBufferStart = (char*) Alloc (TheaterShapeBufferLength, MEM_NORMAL);
TheaterShapeBufferPtr = TheaterShapeBufferStart;
}
/*
** If we are running out of memory (<10k left) for uncompressed shapes
** then allocate some more.
*/
if (( (unsigned)BigShapeBufferStart + BigShapeBufferLength) - (unsigned)BigShapeBufferPtr < 128000) {
ReallocShapeBufferFlag = TRUE;
}
/*
** If this animation was not previously uncompressed then
** allocate memory to keep the pointers to the uncompressed data
** for these animation frames
*/
if (keyfr->x != UNCOMPRESS_MAGIC_NUMBER) {
keyfr->x = UNCOMPRESS_MAGIC_NUMBER;
if (IsTheaterShape) {
keyfr->y = TheaterSlotsUsed;
TheaterSlotsUsed++;
} else {
keyfr->y = TotalSlotsUsed;
TotalSlotsUsed++;
}
/*
** Allocate and clear the memory for the shape info
*/
KeyFrameSlots[keyfr->y]= new char *[keyfr->frames];
memset (KeyFrameSlots[keyfr->y] , 0 , keyfr->frames*4);
}
/*
** If this frame was previously uncompressed then just return
** a pointer to the raw data
*/
if (*(KeyFrameSlots[keyfr->y]+framenumber)) {
if (IsTheaterShape) {
return ((unsigned long)TheaterShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber));
} else {
return ((unsigned long)BigShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber));
}
}
}
// calc buff size
buffsize = keyfr->width * keyfr->height;
// get offset into data
ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)framenumber << 3) + sizeof(KeyFrameHeaderType)) );
Mem_Copy( ptr, &offset[0], 12L );
frameflags = (char)(offset[0] >> 24);
if ( (frameflags & KF_KEYFRAME) ) {
ptr = (char *)Add_Long_To_Pointer( dataptr, (offset[0] & 0x00FFFFFFL) );
if (keyfr->flags & 1 ) {
ptr = (char *)Add_Long_To_Pointer( ptr, 768L );
}
length = LCW_Uncompress( ptr, buffptr, buffsize );
} else { // key delta or delta
if ( (frameflags & KF_DELTA) ) {
currframe = (unsigned short)offset[1];
ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)currframe << 3) + sizeof(KeyFrameHeaderType)) );
Mem_Copy( ptr, &offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) );
}
// key frame
offcurr = offset[1] & 0x00FFFFFFL;
// key delta
offdiff = (offset[0] & 0x00FFFFFFL) - offcurr;
ptr = (char *)Add_Long_To_Pointer( dataptr, offcurr );
if (keyfr->flags & 1 ) {
ptr = (char *)Add_Long_To_Pointer( ptr, 768L );
}
#ifndef FIXIT_SCORE_CRASH
off16 = (unsigned long)lockptr & 0x00003FFFL;
#endif
length = LCW_Uncompress( ptr, buffptr, buffsize );
if (length > buffsize) {
return(0);
}
#ifndef FIXIT_SCORE_CRASH
if ( ((offset[2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) {
ptr = (char *)Add_Long_To_Pointer( ptr, offdiff );
off16 = (unsigned long)ptr & 0x00003FFFL;
offcurr += offdiff;
offdiff = 0;
}
#endif
length = buffsize;
Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff));
if ( (frameflags & KF_DELTA) ) {
// adjust to delta after the keydelta
currframe++;
subframe = 2;
while (currframe <= framenumber) {
offdiff = (offset[subframe] & 0x00FFFFFFL) - offcurr;
#ifndef FIXIT_SCORE_CRASH
if ( ((offset[subframe+2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) {
ptr = (char *)Add_Long_To_Pointer( ptr, offdiff );
off16 = (unsigned long)lockptr & 0x00003FFFL;
offcurr += offdiff;
offdiff = 0;
}
#endif
length = buffsize;
Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff));
currframe++;
subframe += 2;
if ( subframe >= (SUBFRAMEOFFS - 1) &&
currframe <= framenumber ) {
Mem_Copy( Add_Long_To_Pointer( dataptr,
(((unsigned long)currframe << 3) +
sizeof(KeyFrameHeaderType)) ),
&offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) );
subframe = 0;
}
}
}
}
if (UseBigShapeBuffer) {
/*
** Save the uncompressed shape data so we dont have to uncompress it
** again next time its drawn.
** We keep a space free before the raw shape data so we can add line
** header info before the shape is drawn for the first time
*/
if (IsTheaterShape) {
/*
** Shape is a theater specific shape
*/
return_value = (unsigned long) TheaterShapeBufferPtr;
temp_shape_ptr = TheaterShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType);
/*
** align the actual shape data
*/
if (3 & (unsigned)temp_shape_ptr) {
temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc);
}
memcpy (temp_shape_ptr , buffptr , length);
((ShapeHeaderType *)TheaterShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated
((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)TheaterShapeBufferStart; //pointer to old raw shape data
((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_buffer = 1; //Theater buffer
*(KeyFrameSlots[keyfr->y]+framenumber) = TheaterShapeBufferPtr - (unsigned)TheaterShapeBufferStart;
TheaterShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr);
/*
** Align the next shape
*/
if (3 & (unsigned)TheaterShapeBufferPtr) {
TheaterShapeBufferPtr = (char *)((unsigned)(TheaterShapeBufferPtr + 3) & 0xfffffffc);
}
Length = length;
return (return_value);
} else {
return_value=(unsigned long)BigShapeBufferPtr;
temp_shape_ptr = BigShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType);
/*
** align the actual shape data
*/
if (3 & (unsigned)temp_shape_ptr) {
temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc);
}
memcpy (temp_shape_ptr , buffptr , length);
((ShapeHeaderType *)BigShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated
((ShapeHeaderType *)BigShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)BigShapeBufferStart; //pointer to old raw shape data
((ShapeHeaderType *)BigShapeBufferPtr)->shape_buffer = 0; //Normal Big Shape Buffer
*(KeyFrameSlots[keyfr->y]+framenumber) = BigShapeBufferPtr - (unsigned)BigShapeBufferStart;
BigShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr);
// Align the next shape
if (3 & (unsigned)BigShapeBufferPtr) {
BigShapeBufferPtr = (char *)((unsigned)(BigShapeBufferPtr + 3) & 0xfffffffc);
}
Length = length;
return (return_value);
}
} else {
return ((unsigned long)buffptr);
}
}
/***********************************************************************************************
* Get_Build_Frame_Count -- Fetches the number of frames in data block. *
* *
* Use this routine to determine the number of shapes within the data block. *
* *
* INPUT: dataptr -- Pointer to the keyframe shape data block. *
* *
* OUTPUT: Returns with the number of shapes in the data block. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Commented. *
*=============================================================================================*/
unsigned short Get_Build_Frame_Count(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->frames);
}
return(0);
}
unsigned short Get_Build_Frame_X(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->x);
}
return(0);
}
unsigned short Get_Build_Frame_Y(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->y);
}
return(0);
}
/***********************************************************************************************
* Get_Build_Frame_Width -- Fetches the width of the shape image. *
* *
* Use this routine to fetch the width of the shapes within the keyframe shape data block. *
* All shapes within the block have the same width. *
* *
* INPUT: dataptr -- Pointer to the keyframe shape data block. *
* *
* OUTPUT: Returns with the width of the shapes in the block -- expressed in pixels. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Commented *
*=============================================================================================*/
unsigned short Get_Build_Frame_Width(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->width);
}
return(0);
}
/***********************************************************************************************
* Get_Build_Frame_Height -- Fetches the height of the shape image. *
* *
* Use this routine to fetch the height of the shapes within the keyframe shape data block. *
* All shapes within the block have the same height. *
* *
* INPUT: dataptr -- Pointer to the keyframe shape data block. *
* *
* OUTPUT: Returns with the height of the shapes in the block -- expressed in pixels. *
* *
* WARNINGS: none *
* *
* HISTORY: *
* 06/25/1995 JLB : Commented *
*=============================================================================================*/
unsigned short Get_Build_Frame_Height(void const *dataptr)
{
if (dataptr) {
return(((KeyFrameHeaderType const *)dataptr)->height);
}
return(0);
}
bool Get_Build_Frame_Palette(void const * dataptr, void * palette)
{
if (dataptr && (((KeyFrameHeaderType const *)dataptr)->flags & 1)) {
char const * ptr = (char const *)Add_Long_To_Pointer( dataptr,
( (( (long)sizeof(unsigned long) << 1) *
((KeyFrameHeaderType *) dataptr)->frames ) +
16 + sizeof(KeyFrameHeaderType) ) );
memcpy(palette, ptr, 768L);
return(true);
}
return(false);
}