2KEYFRAM.CPP (22397B)
1 // 2 // Copyright 2020 Electronic Arts Inc. 3 // 4 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is free 5 // software: you can redistribute it and/or modify it under the terms of 6 // the GNU General Public License as published by the Free Software Foundation, 7 // either version 3 of the License, or (at your option) any later version. 8 9 // TiberianDawn.DLL and RedAlert.dll and corresponding source code is distributed 10 // in the hope that it will be useful, but with permitted additional restrictions 11 // under Section 7 of the GPL. See the GNU General Public License in LICENSE.TXT 12 // distributed with this program. You should have received a copy of the 13 // GNU General Public License along with permitted additional restrictions 14 // with this program. If not, see https://github.com/electronicarts/CnC_Remastered_Collection 15 16 /* $Header: /CounterStrike/2KEYFRAM.CPP 1 3/03/97 10:24a Joe_bostic $ */ 17 /*********************************************************************************************** 18 *** 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 *** 19 *********************************************************************************************** 20 * * 21 * Project Name : Command & Conquer * 22 * * 23 * File Name : KEYFRAME.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : 06/25/95 * 28 * * 29 * Last Update : June 25, 1995 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * Get_Build_Frame_Count -- Fetches the number of frames in data block. * 34 * Get_Build_Frame_Width -- Fetches the width of the shape image. * 35 * Get_Build_Frame_Height -- Fetches the height of the shape image. * 36 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 37 38 39 #include "function.h" 40 41 #define SUBFRAMEOFFS 7 // 3 1/2 frame offsets loaded (2 offsets/frame) 42 43 44 #define Apply_Delta(buffer, delta) Apply_XOR_Delta((char*)(buffer), (char*)(delta)) 45 46 typedef struct { 47 unsigned short frames; 48 unsigned short x; 49 unsigned short y; 50 unsigned short width; 51 unsigned short height; 52 unsigned short largest_frame_size; 53 short flags; 54 } KeyFrameHeaderType; 55 56 #define INITIAL_BIG_SHAPE_BUFFER_SIZE 8000000 57 #define THEATER_BIG_SHAPE_BUFFER_SIZE 4000000 58 #define UNCOMPRESS_MAGIC_NUMBER 56789 59 60 unsigned BigShapeBufferLength = INITIAL_BIG_SHAPE_BUFFER_SIZE; 61 unsigned TheaterShapeBufferLength = THEATER_BIG_SHAPE_BUFFER_SIZE; 62 extern "C"{ 63 char *BigShapeBufferStart = NULL; 64 char *TheaterShapeBufferStart = NULL; 65 BOOL UseBigShapeBuffer = FALSE; 66 bool IsTheaterShape = false; 67 } 68 #ifdef FIXIT_SCORE_CRASH 69 /* 70 ** Global required to fix the score screen crash bug by allowing disabling of uncompressed shapes. 71 */ 72 bool OriginalUseBigShapeBuffer = false; 73 #endif //FIXIT 74 char *BigShapeBufferPtr = NULL; 75 int TotalBigShapes=0; 76 BOOL ReallocShapeBufferFlag = FALSE; 77 78 char *TheaterShapeBufferPtr = NULL; 79 int TotalTheaterShapes = 0; 80 81 82 #define MAX_SLOTS 1500 83 #define THEATER_SLOT_START 1000 84 85 char **KeyFrameSlots [MAX_SLOTS]; 86 int TotalSlotsUsed=0; 87 int TheaterSlotsUsed = THEATER_SLOT_START; 88 89 90 91 typedef struct tShapeHeaderType{ 92 unsigned draw_flags; 93 char *shape_data; 94 int shape_buffer; //1 if shape is in theater buffer 95 } ShapeHeaderType; 96 97 static int Length; 98 99 void *Get_Shape_Header_Data(void *ptr) 100 { 101 if (UseBigShapeBuffer) { 102 103 ShapeHeaderType *header = (ShapeHeaderType*) ptr; 104 return ((void*) (header->shape_data + (long)(header->shape_buffer ? TheaterShapeBufferStart : BigShapeBufferStart) ) ); 105 106 } else { 107 return (ptr); 108 } 109 } 110 111 int Get_Last_Frame_Length(void) 112 { 113 return(Length); 114 } 115 116 117 void Reset_Theater_Shapes (void) 118 { 119 /* 120 ** Delete any previously allocated slots 121 */ 122 for (int i=THEATER_SLOT_START ; i<TheaterSlotsUsed ; i++) { 123 delete [] KeyFrameSlots [i]; 124 } 125 126 TheaterShapeBufferPtr = TheaterShapeBufferStart; 127 TotalTheaterShapes = 0; 128 TheaterSlotsUsed = THEATER_SLOT_START; 129 } 130 131 132 void Reallocate_Big_Shape_Buffer(void) 133 { 134 if (ReallocShapeBufferFlag) { 135 BigShapeBufferLength += 2000000; //Extra 2 Mb of uncompressed shape space 136 BigShapeBufferPtr -= (unsigned)BigShapeBufferStart; 137 Memory_Error = NULL; 138 BigShapeBufferStart = (char*)Resize_Alloc(BigShapeBufferStart, BigShapeBufferLength); 139 Memory_Error = &Memory_Error_Handler; 140 /* 141 ** If we have run out of memory then disable the uncompressed shapes 142 ** It may still be possible to continue with compressed shapes 143 */ 144 if (!BigShapeBufferStart) { 145 UseBigShapeBuffer = false; 146 return; 147 } 148 BigShapeBufferPtr += (unsigned)BigShapeBufferStart; 149 ReallocShapeBufferFlag = FALSE; 150 } 151 } 152 153 154 //#ifdef FIXIT_SCORE_CRASH 155 /*********************************************************************************************** 156 * Disable_Uncompressed_Shapes -- Temporarily turns off shape decompression * 157 * * 158 * * 159 * * 160 * INPUT: Nothing * 161 * * 162 * OUTPUT: Nothing * 163 * * 164 * WARNINGS: None * 165 * * 166 * HISTORY: * 167 * 11/19/96 2:37PM ST : Created * 168 *=============================================================================================*/ 169 void Disable_Uncompressed_Shapes (void) 170 { 171 UseBigShapeBuffer = false; 172 } 173 174 175 176 /*********************************************************************************************** 177 * Enable_Uncompressed_Shapes -- Restores state of shape decompression before it was disabled * 178 * * 179 * * 180 * * 181 * INPUT: Nothing * 182 * * 183 * OUTPUT: Nothing * 184 * * 185 * WARNINGS: None * 186 * * 187 * HISTORY: * 188 * 11/19/96 2:37PM ST : Created * 189 *=============================================================================================*/ 190 void Enable_Uncompressed_Shapes (void) 191 { 192 UseBigShapeBuffer = OriginalUseBigShapeBuffer; 193 } 194 //#endif //FIXIT 195 196 void Check_Use_Compressed_Shapes (void) 197 { 198 #if (1) // Uncompressed shapes enabled for performance reasons. We don't need to worry about memory. 199 // Uncompressed shapes don't seem to work in RA for rotated/scaled objects so wherever scale/rotate is used, 200 // we will need to disable it (like in Techno_Draw_Object). ST - 11/6/2019 2:09PM 201 UseBigShapeBuffer = true; 202 OriginalUseBigShapeBuffer = true; 203 204 #else 205 MEMORYSTATUS mem_info; 206 207 mem_info.dwLength=sizeof(mem_info); 208 GlobalMemoryStatus(&mem_info); 209 210 UseBigShapeBuffer = (mem_info.dwTotalPhys > 16*1024*1024) ? TRUE : FALSE; 211 #ifdef FIXIT_SCORE_CRASH 212 /* 213 ** Keep track of our original decision about whether to use cached shapes. 214 ** This is needed for the score screen crash fix. 215 */ 216 OriginalUseBigShapeBuffer = UseBigShapeBuffer; 217 #endif //FIXIT 218 #endif 219 } 220 221 222 223 224 225 unsigned long Build_Frame(void const *dataptr, unsigned short framenumber, void *buffptr) 226 { 227 #ifdef FIXIT_SCORE_CRASH 228 char *ptr; 229 unsigned long offcurr, offdiff; 230 #else 231 char *ptr, *lockptr;//, *uncomp_ptr; 232 unsigned long offcurr, off16, offdiff; 233 #endif 234 unsigned long offset[SUBFRAMEOFFS]; 235 KeyFrameHeaderType *keyfr; 236 unsigned short buffsize, currframe, subframe; 237 unsigned long length = 0; 238 char frameflags; 239 unsigned long return_value; 240 char *temp_shape_ptr; 241 242 // 243 // valid pointer?? 244 // 245 Length = 0; 246 if ( !dataptr || !buffptr ) { 247 return(0); 248 } 249 250 // 251 // look at header then check that frame to build is not greater 252 // than total frames 253 // 254 keyfr = (KeyFrameHeaderType *) dataptr; 255 256 if ( framenumber >= keyfr->frames ) { 257 return(0); 258 } 259 260 261 if (UseBigShapeBuffer) { 262 /* 263 ** If we havnt yet allocated memory for uncompressed shapes then do so now. 264 ** 265 */ 266 if (!BigShapeBufferStart) { 267 BigShapeBufferStart = (char*)Alloc(BigShapeBufferLength, MEM_NORMAL); 268 BigShapeBufferPtr = BigShapeBufferStart; 269 270 /* 271 ** Allocate memory for theater specific uncompressed shapes 272 */ 273 TheaterShapeBufferStart = (char*) Alloc (TheaterShapeBufferLength, MEM_NORMAL); 274 TheaterShapeBufferPtr = TheaterShapeBufferStart; 275 } 276 277 /* 278 ** If we are running out of memory (<10k left) for uncompressed shapes 279 ** then allocate some more. 280 */ 281 if (( (unsigned)BigShapeBufferStart + BigShapeBufferLength) - (unsigned)BigShapeBufferPtr < 128000) { 282 ReallocShapeBufferFlag = TRUE; 283 } 284 285 /* 286 ** If this animation was not previously uncompressed then 287 ** allocate memory to keep the pointers to the uncompressed data 288 ** for these animation frames 289 */ 290 if (keyfr->x != UNCOMPRESS_MAGIC_NUMBER) { 291 keyfr->x = UNCOMPRESS_MAGIC_NUMBER; 292 if (IsTheaterShape) { 293 keyfr->y = TheaterSlotsUsed; 294 TheaterSlotsUsed++; 295 } else { 296 keyfr->y = TotalSlotsUsed; 297 TotalSlotsUsed++; 298 } 299 /* 300 ** Allocate and clear the memory for the shape info 301 */ 302 KeyFrameSlots[keyfr->y]= new char *[keyfr->frames]; 303 memset (KeyFrameSlots[keyfr->y] , 0 , keyfr->frames*4); 304 } 305 306 /* 307 ** If this frame was previously uncompressed then just return 308 ** a pointer to the raw data 309 */ 310 if (*(KeyFrameSlots[keyfr->y]+framenumber)) { 311 if (IsTheaterShape) { 312 return ((unsigned long)TheaterShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber)); 313 } else { 314 return ((unsigned long)BigShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber)); 315 } 316 } 317 } 318 319 // calc buff size 320 buffsize = keyfr->width * keyfr->height; 321 322 // get offset into data 323 ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)framenumber << 3) + sizeof(KeyFrameHeaderType)) ); 324 Mem_Copy( ptr, &offset[0], 12L ); 325 frameflags = (char)(offset[0] >> 24); 326 327 328 if ( (frameflags & KF_KEYFRAME) ) { 329 330 ptr = (char *)Add_Long_To_Pointer( dataptr, (offset[0] & 0x00FFFFFFL) ); 331 332 if (keyfr->flags & 1 ) { 333 ptr = (char *)Add_Long_To_Pointer( ptr, 768L ); 334 } 335 length = LCW_Uncompress( ptr, buffptr, buffsize ); 336 } else { // key delta or delta 337 338 if ( (frameflags & KF_DELTA) ) { 339 currframe = (unsigned short)offset[1]; 340 341 ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)currframe << 3) + sizeof(KeyFrameHeaderType)) ); 342 Mem_Copy( ptr, &offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) ); 343 } 344 345 // key frame 346 offcurr = offset[1] & 0x00FFFFFFL; 347 348 // key delta 349 offdiff = (offset[0] & 0x00FFFFFFL) - offcurr; 350 351 ptr = (char *)Add_Long_To_Pointer( dataptr, offcurr ); 352 353 if (keyfr->flags & 1 ) { 354 ptr = (char *)Add_Long_To_Pointer( ptr, 768L ); 355 } 356 357 #ifndef FIXIT_SCORE_CRASH 358 off16 = (unsigned long)lockptr & 0x00003FFFL; 359 #endif 360 361 length = LCW_Uncompress( ptr, buffptr, buffsize ); 362 363 if (length > buffsize) { 364 return(0); 365 } 366 367 #ifndef FIXIT_SCORE_CRASH 368 if ( ((offset[2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) { 369 370 ptr = (char *)Add_Long_To_Pointer( ptr, offdiff ); 371 off16 = (unsigned long)ptr & 0x00003FFFL; 372 373 offcurr += offdiff; 374 offdiff = 0; 375 } 376 #endif 377 378 length = buffsize; 379 Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff)); 380 381 if ( (frameflags & KF_DELTA) ) { 382 // adjust to delta after the keydelta 383 384 currframe++; 385 subframe = 2; 386 387 while (currframe <= framenumber) { 388 offdiff = (offset[subframe] & 0x00FFFFFFL) - offcurr; 389 390 #ifndef FIXIT_SCORE_CRASH 391 if ( ((offset[subframe+2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) { 392 393 ptr = (char *)Add_Long_To_Pointer( ptr, offdiff ); 394 off16 = (unsigned long)lockptr & 0x00003FFFL; 395 396 offcurr += offdiff; 397 offdiff = 0; 398 } 399 #endif 400 401 length = buffsize; 402 Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff)); 403 404 currframe++; 405 subframe += 2; 406 407 if ( subframe >= (SUBFRAMEOFFS - 1) && 408 currframe <= framenumber ) { 409 Mem_Copy( Add_Long_To_Pointer( dataptr, 410 (((unsigned long)currframe << 3) + 411 sizeof(KeyFrameHeaderType)) ), 412 &offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) ); 413 subframe = 0; 414 } 415 } 416 } 417 } 418 419 420 if (UseBigShapeBuffer) { 421 /* 422 ** Save the uncompressed shape data so we dont have to uncompress it 423 ** again next time its drawn. 424 ** We keep a space free before the raw shape data so we can add line 425 ** header info before the shape is drawn for the first time 426 */ 427 428 if (IsTheaterShape) { 429 /* 430 ** Shape is a theater specific shape 431 */ 432 return_value = (unsigned long) TheaterShapeBufferPtr; 433 temp_shape_ptr = TheaterShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType); 434 /* 435 ** align the actual shape data 436 */ 437 if (3 & (unsigned)temp_shape_ptr) { 438 temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc); 439 } 440 441 memcpy (temp_shape_ptr , buffptr , length); 442 ((ShapeHeaderType *)TheaterShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated 443 ((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)TheaterShapeBufferStart; //pointer to old raw shape data 444 ((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_buffer = 1; //Theater buffer 445 *(KeyFrameSlots[keyfr->y]+framenumber) = TheaterShapeBufferPtr - (unsigned)TheaterShapeBufferStart; 446 TheaterShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr); 447 /* 448 ** Align the next shape 449 */ 450 if (3 & (unsigned)TheaterShapeBufferPtr) { 451 TheaterShapeBufferPtr = (char *)((unsigned)(TheaterShapeBufferPtr + 3) & 0xfffffffc); 452 } 453 Length = length; 454 return (return_value); 455 456 } else { 457 458 459 return_value=(unsigned long)BigShapeBufferPtr; 460 temp_shape_ptr = BigShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType); 461 /* 462 ** align the actual shape data 463 */ 464 if (3 & (unsigned)temp_shape_ptr) { 465 temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc); 466 } 467 memcpy (temp_shape_ptr , buffptr , length); 468 ((ShapeHeaderType *)BigShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated 469 ((ShapeHeaderType *)BigShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)BigShapeBufferStart; //pointer to old raw shape data 470 ((ShapeHeaderType *)BigShapeBufferPtr)->shape_buffer = 0; //Normal Big Shape Buffer 471 *(KeyFrameSlots[keyfr->y]+framenumber) = BigShapeBufferPtr - (unsigned)BigShapeBufferStart; 472 BigShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr); 473 // Align the next shape 474 if (3 & (unsigned)BigShapeBufferPtr) { 475 BigShapeBufferPtr = (char *)((unsigned)(BigShapeBufferPtr + 3) & 0xfffffffc); 476 } 477 Length = length; 478 return (return_value); 479 } 480 481 } else { 482 return ((unsigned long)buffptr); 483 } 484 } 485 486 487 /*********************************************************************************************** 488 * Get_Build_Frame_Count -- Fetches the number of frames in data block. * 489 * * 490 * Use this routine to determine the number of shapes within the data block. * 491 * * 492 * INPUT: dataptr -- Pointer to the keyframe shape data block. * 493 * * 494 * OUTPUT: Returns with the number of shapes in the data block. * 495 * * 496 * WARNINGS: none * 497 * * 498 * HISTORY: * 499 * 06/25/1995 JLB : Commented. * 500 *=============================================================================================*/ 501 unsigned short Get_Build_Frame_Count(void const *dataptr) 502 { 503 if (dataptr) { 504 return(((KeyFrameHeaderType const *)dataptr)->frames); 505 } 506 return(0); 507 } 508 509 510 unsigned short Get_Build_Frame_X(void const *dataptr) 511 { 512 if (dataptr) { 513 return(((KeyFrameHeaderType const *)dataptr)->x); 514 } 515 return(0); 516 } 517 518 519 unsigned short Get_Build_Frame_Y(void const *dataptr) 520 { 521 if (dataptr) { 522 return(((KeyFrameHeaderType const *)dataptr)->y); 523 } 524 return(0); 525 } 526 527 528 /*********************************************************************************************** 529 * Get_Build_Frame_Width -- Fetches the width of the shape image. * 530 * * 531 * Use this routine to fetch the width of the shapes within the keyframe shape data block. * 532 * All shapes within the block have the same width. * 533 * * 534 * INPUT: dataptr -- Pointer to the keyframe shape data block. * 535 * * 536 * OUTPUT: Returns with the width of the shapes in the block -- expressed in pixels. * 537 * * 538 * WARNINGS: none * 539 * * 540 * HISTORY: * 541 * 06/25/1995 JLB : Commented * 542 *=============================================================================================*/ 543 unsigned short Get_Build_Frame_Width(void const *dataptr) 544 { 545 if (dataptr) { 546 return(((KeyFrameHeaderType const *)dataptr)->width); 547 } 548 return(0); 549 } 550 551 552 /*********************************************************************************************** 553 * Get_Build_Frame_Height -- Fetches the height of the shape image. * 554 * * 555 * Use this routine to fetch the height of the shapes within the keyframe shape data block. * 556 * All shapes within the block have the same height. * 557 * * 558 * INPUT: dataptr -- Pointer to the keyframe shape data block. * 559 * * 560 * OUTPUT: Returns with the height of the shapes in the block -- expressed in pixels. * 561 * * 562 * WARNINGS: none * 563 * * 564 * HISTORY: * 565 * 06/25/1995 JLB : Commented * 566 *=============================================================================================*/ 567 unsigned short Get_Build_Frame_Height(void const *dataptr) 568 { 569 if (dataptr) { 570 return(((KeyFrameHeaderType const *)dataptr)->height); 571 } 572 return(0); 573 } 574 575 576 bool Get_Build_Frame_Palette(void const * dataptr, void * palette) 577 { 578 if (dataptr && (((KeyFrameHeaderType const *)dataptr)->flags & 1)) { 579 char const * ptr = (char const *)Add_Long_To_Pointer( dataptr, 580 ( (( (long)sizeof(unsigned long) << 1) * 581 ((KeyFrameHeaderType *) dataptr)->frames ) + 582 16 + sizeof(KeyFrameHeaderType) ) ); 583 584 memcpy(palette, ptr, 768L); 585 return(true); 586 } 587 return(false); 588 }