// // 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; } RedAlertShapeHeader; typedef struct { unsigned short iden; // Always 0! unsigned short width; // Width of the frames. unsigned short height; // Height of the frames. unsigned short NumFrames; } TiberianSunShapeHeader; typedef struct { unsigned short FrameX; unsigned short FrameY; unsigned short FrameWidth; unsigned short FrameHeight; unsigned int Flags; byte FrameColor[4]; unsigned int Reserved; unsigned int DataOffset; } TiberianSunShapeFrameInfo; #define INITIAL_BIG_SHAPE_BUFFER_SIZE (64 * 1024 * 1024) #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 = TRUE; 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= 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(RedAlertShapeHeader)) ); // 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(RedAlertShapeHeader)) ); // 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(RedAlertShapeHeader)) ), // &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); // } //} bool Get_Build_TS_Shape(const void *dataptr) { if(dataptr) { const TiberianSunShapeHeader* ts = (const TiberianSunShapeHeader*)dataptr; if(ts->iden == 0) { return true; } return false; } return false; } TiberianSunShapeFrameInfo *Get_Build_TS_FrameInfo(const void *dataptr, int frameNum) { const byte* tsptr = (const byte*)dataptr; return (TiberianSunShapeFrameInfo*)((byte*)(tsptr + (sizeof(TiberianSunShapeFrameInfo) * frameNum) + sizeof(TiberianSunShapeHeader))); } void *Get_Build_TS_FrameOffset(const void *dataptr, int framenum) { TiberianSunShapeFrameInfo* frameInfo = Get_Build_TS_FrameInfo(dataptr, framenum); return (void *)(((byte *)dataptr) + frameInfo->DataOffset); } /*********************************************************************************************** * 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) { if(Get_Build_TS_Shape(dataptr)) { const TiberianSunShapeHeader* ts = (const TiberianSunShapeHeader*)dataptr; return ts->NumFrames; } return(((RedAlertShapeHeader const *)dataptr)->frames); } return(0); } unsigned short Get_Build_Frame_X(void const *dataptr, int frame) { if (dataptr) { if (Get_Build_TS_Shape(dataptr)) { return Get_Build_TS_FrameInfo(dataptr, frame)->FrameX; } return(((RedAlertShapeHeader const *)dataptr)->x); } return(0); } unsigned short Get_Build_Frame_Y(void const *dataptr, int frame) { if (dataptr) { if (Get_Build_TS_Shape(dataptr)) { return Get_Build_TS_FrameInfo(dataptr, frame)->FrameY; } return(((RedAlertShapeHeader const *)dataptr)->y); } return(0); } bool Get_Build_Is_Compressed(void const *dataptr, int frame) { if(dataptr) { if (Get_Build_TS_Shape(dataptr)) { return Get_Build_TS_FrameInfo(dataptr, frame)->Flags & 2; } return false; } return false; } /*********************************************************************************************** * 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, int frame) { if (dataptr) { if(Get_Build_TS_Shape(dataptr)) { if(frame == -1) { const TiberianSunShapeHeader* ts = (const TiberianSunShapeHeader*)dataptr; return ts->width; } return Get_Build_TS_FrameInfo(dataptr, frame)->FrameWidth; } return(((RedAlertShapeHeader 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, int frame) { if (dataptr) { if (Get_Build_TS_Shape(dataptr)) { if (frame == -1) { const TiberianSunShapeHeader* ts = (const TiberianSunShapeHeader*)dataptr; return ts->height; } return Get_Build_TS_FrameInfo(dataptr, frame)->FrameHeight; } return(((RedAlertShapeHeader const *)dataptr)->height); } return(0); } bool Get_Build_Frame_Palette(void const * dataptr, void * palette) { if (dataptr && (((RedAlertShapeHeader const *)dataptr)->flags & 1)) { char const * ptr = (char const *)Add_Long_To_Pointer( dataptr, ( (( (long)sizeof(unsigned long) << 1) * ((RedAlertShapeHeader *) dataptr)->frames ) + 16 + sizeof(RedAlertShapeHeader) ) ); memcpy(palette, ptr, 768L); return(true); } return(false); }