KEYFRAME.CPP (22446B)
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: F:\projects\c&c\vcs\code\keyframe.cpv 2.14 16 Oct 1995 16:48:54 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 12000*1024 57 #define THEATER_BIG_SHAPE_BUFFER_SIZE 1000*1024 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 char *BigShapeBufferPtr = NULL; 69 int TotalBigShapes=0; 70 BOOL ReallocShapeBufferFlag = FALSE; 71 bool OriginalUseBigShapeBuffer = false; 72 73 char *TheaterShapeBufferPtr = NULL; 74 int TotalTheaterShapes = 0; 75 76 77 78 #define MAX_SLOTS 1500 79 #define THEATER_SLOT_START 1000 80 81 char **KeyFrameSlots [MAX_SLOTS]; 82 int TotalSlotsUsed=0; 83 int TheaterSlotsUsed = THEATER_SLOT_START; 84 85 86 typedef struct tShapeHeaderType{ 87 unsigned draw_flags; 88 char *shape_data; 89 int shape_buffer; //1 if shape is in theater buffer 90 } ShapeHeaderType; 91 92 static int Length; 93 94 void *Get_Shape_Header_Data(void *ptr) 95 { 96 if (UseBigShapeBuffer){ 97 98 ShapeHeaderType *header = (ShapeHeaderType*) ptr; 99 return ((void*) (header->shape_data + (long)(header->shape_buffer ? TheaterShapeBufferStart : BigShapeBufferStart) ) ); 100 101 }else{ 102 return (ptr); 103 } 104 } 105 106 int Get_Last_Frame_Length(void) 107 { 108 return(Length); 109 } 110 111 112 113 void Reset_Theater_Shapes (void) 114 { 115 /* 116 ** Delete any previously allocated slots 117 */ 118 for (int i=THEATER_SLOT_START ; i<TheaterSlotsUsed ; i++){ 119 delete [] KeyFrameSlots [i]; 120 } 121 122 TheaterShapeBufferPtr = TheaterShapeBufferStart; 123 TotalTheaterShapes = 0; 124 TheaterSlotsUsed = THEATER_SLOT_START; 125 } 126 127 128 129 void Reallocate_Big_Shape_Buffer(void) 130 { 131 if (ReallocShapeBufferFlag){ 132 BigShapeBufferLength += 200 * 1024; //Extra 2 Mb of uncompressed shape space 133 BigShapeBufferPtr -= (unsigned)BigShapeBufferStart; 134 Memory_Error = NULL; 135 BigShapeBufferStart = (char*)Resize_Alloc(BigShapeBufferStart, BigShapeBufferLength); 136 Memory_Error = &Memory_Error_Handler; 137 /* 138 ** If we have run out of memory then disable the uncompressed shapes 139 ** It may still be possible to continue with compressed shapes 140 */ 141 if (!BigShapeBufferStart){ 142 UseBigShapeBuffer = false; 143 return; 144 } 145 BigShapeBufferPtr += (unsigned)BigShapeBufferStart; 146 ReallocShapeBufferFlag = FALSE; 147 } 148 } 149 150 151 152 153 void Check_Use_Compressed_Shapes (void) 154 { 155 MEMORYSTATUS mem_info; 156 157 mem_info.dwLength=sizeof(mem_info); 158 GlobalMemoryStatus(&mem_info); 159 160 UseBigShapeBuffer = (mem_info.dwTotalPhys > 16*1024*1024) ? TRUE : FALSE; 161 OriginalUseBigShapeBuffer = UseBigShapeBuffer; 162 163 // UseBigShapeBuffer = false; 164 } 165 166 167 168 169 /*********************************************************************************************** 170 * Disable_Uncompressed_Shapes -- Temporarily turns off shape decompression * 171 * * 172 * * 173 * * 174 * INPUT: Nothing * 175 * * 176 * OUTPUT: Nothing * 177 * * 178 * WARNINGS: None * 179 * * 180 * HISTORY: * 181 * 11/19/96 2:37PM ST : Created * 182 *=============================================================================================*/ 183 void Disable_Uncompressed_Shapes (void) 184 { 185 UseBigShapeBuffer = false; 186 } 187 188 189 190 /*********************************************************************************************** 191 * Enable_Uncompressed_Shapes -- Restores state of shape decompression before it was disabled * 192 * * 193 * * 194 * * 195 * INPUT: Nothing * 196 * * 197 * OUTPUT: Nothing * 198 * * 199 * WARNINGS: None * 200 * * 201 * HISTORY: * 202 * 11/19/96 2:37PM ST : Created * 203 *=============================================================================================*/ 204 void Enable_Uncompressed_Shapes (void) 205 { 206 UseBigShapeBuffer = OriginalUseBigShapeBuffer; 207 } 208 209 210 #define FIXIT_SCORE_CRASH 211 212 unsigned long Build_Frame(void const *dataptr, unsigned short framenumber, void *buffptr) 213 { 214 #ifdef FIXIT_SCORE_CRASH 215 char * ptr; 216 unsigned long offcurr, offdiff; 217 #else 218 char * ptr, * lockptr; 219 unsigned long offcurr, off16, offdiff; 220 #endif 221 unsigned long offset[SUBFRAMEOFFS]; 222 KeyFrameHeaderType *keyfr; 223 unsigned short buffsize, currframe, subframe; 224 unsigned long length = 0; 225 char frameflags; 226 unsigned long return_value; 227 char *temp_shape_ptr; 228 229 // 230 // valid pointer?? 231 // 232 Length = 0; 233 if ( !dataptr || !buffptr ) { 234 return(0); 235 } 236 237 // 238 // look at header then check that frame to build is not greater 239 // than total frames 240 // 241 keyfr = (KeyFrameHeaderType *) dataptr; 242 243 if ( framenumber >= keyfr->frames ) { 244 return(0); 245 } 246 247 248 if (UseBigShapeBuffer){ 249 /* 250 ** If we havnt yet allocated memory for uncompressed shapes then do so now. 251 ** 252 */ 253 if (!BigShapeBufferStart){ 254 BigShapeBufferStart = (char*)Alloc(BigShapeBufferLength, MEM_NORMAL); 255 BigShapeBufferPtr = BigShapeBufferStart; 256 /* 257 ** Allocate memory for theater specific uncompressed shapes 258 */ 259 TheaterShapeBufferStart = (char*) Alloc (TheaterShapeBufferLength, MEM_NORMAL); 260 TheaterShapeBufferPtr = TheaterShapeBufferStart; 261 } 262 263 264 /* 265 ** Track memory usage in uncompressed shape buffers. 266 */ 267 static bool show_info = true; 268 269 if ((Frame & 0xff) == 0){ 270 271 if (show_info){ 272 273 char debugstr [128]; 274 sprintf (debugstr, "C&C95 - Big shape buffer is now %d Kb.\n", BigShapeBufferLength / 1024); 275 CCDebugString (debugstr); 276 277 sprintf (debugstr, "C&C95 - %d Kb Used in big shape buffer.\n", (unsigned)((unsigned)BigShapeBufferPtr - (unsigned)BigShapeBufferStart)/1024); 278 CCDebugString (debugstr); 279 280 sprintf (debugstr, "C&C95 - %d Kb Used in theater shape buffer.\n", (unsigned)((unsigned)TheaterShapeBufferPtr - (unsigned)TheaterShapeBufferStart)/1024); 281 CCDebugString (debugstr); 282 show_info = false; 283 } 284 285 }else{ 286 show_info = true; 287 288 } 289 290 291 /* 292 ** If we are running out of memory (<128k left) for uncompressed shapes 293 ** then allocate some more. 294 */ 295 if (( (unsigned)BigShapeBufferStart + BigShapeBufferLength) - (unsigned)BigShapeBufferPtr < 128*1024){ 296 ReallocShapeBufferFlag = TRUE; 297 } 298 299 /* 300 ** If this animation was not previously uncompressed then 301 ** allocate memory to keep the pointers to the uncompressed data 302 ** for these animation frames 303 */ 304 if (keyfr->x != UNCOMPRESS_MAGIC_NUMBER){ 305 keyfr->x = UNCOMPRESS_MAGIC_NUMBER; 306 if (IsTheaterShape){ 307 keyfr->y = TheaterSlotsUsed; 308 TheaterSlotsUsed++; 309 }else{ 310 keyfr->y = TotalSlotsUsed; 311 TotalSlotsUsed++; 312 } 313 /* 314 ** Allocate and clear the memory for the shape info 315 */ 316 KeyFrameSlots[keyfr->y]= new char *[keyfr->frames]; 317 memset (KeyFrameSlots[keyfr->y] , 0 , keyfr->frames*4); 318 } 319 320 /* 321 ** If this frame was previously uncompressed then just return 322 ** a pointer to the raw data 323 */ 324 if (*(KeyFrameSlots[keyfr->y]+framenumber)){ 325 if (IsTheaterShape){ 326 return ((unsigned long)TheaterShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber)); 327 }else{ 328 return ((unsigned long)BigShapeBufferStart + (unsigned long)*(KeyFrameSlots[keyfr->y]+framenumber)); 329 } 330 } 331 } 332 333 // calc buff size 334 buffsize = keyfr->width * keyfr->height; 335 336 // get offset into data 337 ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)framenumber << 3) + sizeof(KeyFrameHeaderType)) ); 338 Mem_Copy( ptr, &offset[0], 12L ); 339 frameflags = (char)(offset[0] >> 24); 340 341 342 if ( (frameflags & KF_KEYFRAME) ) { 343 344 ptr = (char *)Add_Long_To_Pointer( dataptr, (offset[0] & 0x00FFFFFFL) ); 345 346 if (keyfr->flags & 1 ) { 347 ptr = (char *)Add_Long_To_Pointer( ptr, 768L ); 348 } 349 length = LCW_Uncompress( ptr, buffptr, buffsize ); 350 } else { // key delta or delta 351 352 if ( (frameflags & KF_DELTA) ) { 353 currframe = (unsigned short)offset[1]; 354 355 ptr = (char *)Add_Long_To_Pointer( dataptr, (((unsigned long)currframe << 3) + sizeof(KeyFrameHeaderType)) ); 356 Mem_Copy( ptr, &offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) ); 357 } 358 359 // key frame 360 offcurr = offset[1] & 0x00FFFFFFL; 361 362 // key delta 363 offdiff = (offset[0] & 0x00FFFFFFL) - offcurr; 364 365 ptr = (char *)Add_Long_To_Pointer( dataptr, offcurr ); 366 367 if (keyfr->flags & 1 ) { 368 ptr = (char *)Add_Long_To_Pointer( ptr, 768L ); 369 } 370 371 #ifndef FIXIT_SCORE_CRASH 372 off16 = (unsigned long)lockptr & 0x00003FFFL; 373 #endif 374 length = LCW_Uncompress( ptr, buffptr, buffsize ); 375 376 if (length > buffsize) { 377 return(0); 378 } 379 380 #ifndef FIXIT_SCORE_CRASH 381 if ( ((offset[2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) { 382 383 ptr = (char *)Add_Long_To_Pointer( ptr, offdiff ); 384 off16 = (unsigned long)ptr & 0x00003FFFL; 385 386 offcurr += offdiff; 387 offdiff = 0; 388 } 389 #endif 390 length = buffsize; 391 Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff)); 392 393 if ( (frameflags & KF_DELTA) ) { 394 // adjust to delta after the keydelta 395 396 currframe++; 397 subframe = 2; 398 399 while (currframe <= framenumber) { 400 offdiff = (offset[subframe] & 0x00FFFFFFL) - offcurr; 401 402 #ifndef FIXIT_SCORE_CRASH 403 if ( ((offset[subframe+2] & 0x00FFFFFFL) - offcurr) >= (0x00010000L - off16) ) { 404 405 ptr = (char *)Add_Long_To_Pointer( ptr, offdiff ); 406 off16 = (unsigned long)lockptr & 0x00003FFFL; 407 408 offcurr += offdiff; 409 offdiff = 0; 410 } 411 #endif 412 413 length = buffsize; 414 Apply_Delta(buffptr, Add_Long_To_Pointer(ptr, offdiff)); 415 416 currframe++; 417 subframe += 2; 418 419 if ( subframe >= (SUBFRAMEOFFS - 1) && 420 currframe <= framenumber ) { 421 Mem_Copy( Add_Long_To_Pointer( dataptr, 422 (((unsigned long)currframe << 3) + 423 sizeof(KeyFrameHeaderType)) ), 424 &offset[0], (long)(SUBFRAMEOFFS * sizeof(unsigned long)) ); 425 subframe = 0; 426 } 427 } 428 } 429 } 430 431 if (UseBigShapeBuffer){ 432 /* 433 ** Save the uncompressed shape data so we dont have to uncompress it 434 ** again next time its drawn. 435 ** We keep a space free before the raw shape data so we can add line 436 ** header info before the shape is drawn for the first time 437 */ 438 439 if (IsTheaterShape){ 440 /* 441 ** Shape is a theater specific shape 442 */ 443 return_value = (unsigned long) TheaterShapeBufferPtr; 444 temp_shape_ptr = TheaterShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType); 445 /* 446 ** align the actual shape data 447 */ 448 if (3 & (unsigned)temp_shape_ptr){ 449 temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc); 450 } 451 452 memcpy (temp_shape_ptr , buffptr , length); 453 ((ShapeHeaderType *)TheaterShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated 454 ((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)TheaterShapeBufferStart; //pointer to old raw shape data 455 ((ShapeHeaderType *)TheaterShapeBufferPtr)->shape_buffer = 1; //Theater buffer 456 *(KeyFrameSlots[keyfr->y]+framenumber) = TheaterShapeBufferPtr - (unsigned)TheaterShapeBufferStart; 457 TheaterShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr); 458 /* 459 ** Align the next shape 460 */ 461 if (3 & (unsigned)TheaterShapeBufferPtr){ 462 TheaterShapeBufferPtr = (char *)((unsigned)(TheaterShapeBufferPtr + 3) & 0xfffffffc); 463 } 464 Length = length; 465 return (return_value); 466 467 }else{ 468 469 470 return_value=(unsigned long)BigShapeBufferPtr; 471 temp_shape_ptr = BigShapeBufferPtr + keyfr->height+sizeof(ShapeHeaderType); 472 /* 473 ** align the actual shape data 474 */ 475 if (3 & (unsigned)temp_shape_ptr){ 476 temp_shape_ptr = (char *) ((unsigned)(temp_shape_ptr + 3) & 0xfffffffc); 477 } 478 memcpy (temp_shape_ptr , buffptr , length); 479 ((ShapeHeaderType *)BigShapeBufferPtr)->draw_flags = -1; //Flag that headers need to be generated 480 ((ShapeHeaderType *)BigShapeBufferPtr)->shape_data = temp_shape_ptr - (unsigned)BigShapeBufferStart; //pointer to old raw shape data 481 ((ShapeHeaderType *)BigShapeBufferPtr)->shape_buffer = 0; //Normal Big Shape Buffer 482 *(KeyFrameSlots[keyfr->y]+framenumber) = BigShapeBufferPtr - (unsigned)BigShapeBufferStart; 483 BigShapeBufferPtr = (char*)(length + (unsigned)temp_shape_ptr); 484 // Align the next shape 485 if (3 & (unsigned)BigShapeBufferPtr){ 486 BigShapeBufferPtr = (char *)((unsigned)(BigShapeBufferPtr + 3) & 0xfffffffc); 487 } 488 Length = length; 489 return (return_value); 490 } 491 492 }else{ 493 return ((unsigned long)buffptr); 494 } 495 } 496 497 498 /*********************************************************************************************** 499 * Get_Build_Frame_Count -- Fetches the number of frames in data block. * 500 * * 501 * Use this routine to determine the number of shapes within the data block. * 502 * * 503 * INPUT: dataptr -- Pointer to the keyframe shape data block. * 504 * * 505 * OUTPUT: Returns with the number of shapes in the data block. * 506 * * 507 * WARNINGS: none * 508 * * 509 * HISTORY: * 510 * 06/25/1995 JLB : Commented. * 511 *=============================================================================================*/ 512 unsigned short Get_Build_Frame_Count(void const *dataptr) 513 { 514 if (dataptr) { 515 return(((KeyFrameHeaderType const *)dataptr)->frames); 516 } 517 return(0); 518 } 519 520 521 unsigned short Get_Build_Frame_X(void const *dataptr) 522 { 523 if (dataptr) { 524 return(((KeyFrameHeaderType const *)dataptr)->x); 525 } 526 return(0); 527 } 528 529 530 unsigned short Get_Build_Frame_Y(void const *dataptr) 531 { 532 if (dataptr) { 533 return(((KeyFrameHeaderType const *)dataptr)->y); 534 } 535 return(0); 536 } 537 538 539 /*********************************************************************************************** 540 * Get_Build_Frame_Width -- Fetches the width of the shape image. * 541 * * 542 * Use this routine to fetch the width of the shapes within the keyframe shape data block. * 543 * All shapes within the block have the same width. * 544 * * 545 * INPUT: dataptr -- Pointer to the keyframe shape data block. * 546 * * 547 * OUTPUT: Returns with the width of the shapes in the block -- expressed in pixels. * 548 * * 549 * WARNINGS: none * 550 * * 551 * HISTORY: * 552 * 06/25/1995 JLB : Commented * 553 *=============================================================================================*/ 554 unsigned short Get_Build_Frame_Width(void const *dataptr) 555 { 556 if (dataptr) { 557 return(((KeyFrameHeaderType const *)dataptr)->width); 558 } 559 return(0); 560 } 561 562 563 /*********************************************************************************************** 564 * Get_Build_Frame_Height -- Fetches the height of the shape image. * 565 * * 566 * Use this routine to fetch the height of the shapes within the keyframe shape data block. * 567 * All shapes within the block have the same height. * 568 * * 569 * INPUT: dataptr -- Pointer to the keyframe shape data block. * 570 * * 571 * OUTPUT: Returns with the height of the shapes in the block -- expressed in pixels. * 572 * * 573 * WARNINGS: none * 574 * * 575 * HISTORY: * 576 * 06/25/1995 JLB : Commented * 577 *=============================================================================================*/ 578 unsigned short Get_Build_Frame_Height(void const *dataptr) 579 { 580 if (dataptr) { 581 return(((KeyFrameHeaderType const *)dataptr)->height); 582 } 583 return(0); 584 } 585 586 587 bool Get_Build_Frame_Palette(void const * dataptr, void * palette) 588 { 589 if (dataptr && (((KeyFrameHeaderType const *)dataptr)->flags & 1)) { 590 char const * ptr = (char const *)Add_Long_To_Pointer( dataptr, 591 ( (( (long)sizeof(unsigned long) << 1) * 592 ((KeyFrameHeaderType *) dataptr)->frames ) + 593 16 + sizeof(KeyFrameHeaderType) ) ); 594 595 memcpy(palette, ptr, 768L); 596 return(true); 597 } 598 return(false); 599 }