GSCREEN.CPP (29987B)
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\gscreen.cpv 2.17 16 Oct 1995 16:51:34 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 : GSCREEN.CPP * 24 * * 25 * Programmer : Joe L. Bostic * 26 * * 27 * Start Date : 12/15/94 * 28 * * 29 * Last Update : January 19, 1995 [JLB] * 30 * * 31 *---------------------------------------------------------------------------------------------* 32 * Functions: * 33 * GScreenClass::GScreenClass -- Default constructor for GScreenClass. * 34 * GScreenClass::One_Time -- Handles one time class setups. * 35 * GScreenClass::Init -- Init's the entire display hierarchy by calling all Init routines. * 36 * GScreenClass::Init_Clear -- Sets the map to a known state. * 37 * GScreenClass::Init_Theater -- Performs theater-specific initializations. * 38 * GScreenClass::Init_IO -- Initializes the Button list ('Buttons'). * 39 * GScreenClass::Flag_To_Redraw -- Flags the display to be redrawn. * 40 * GScreenClass::Blit_Display -- Redraw the display from the hidpage to the seenpage. * 41 * GScreenClass::Render -- General drawing dispatcher an display update function. * 42 * GScreenClass::Input -- Fetches input and processes gadgets. * 43 * GScreenClass::Add_A_Button -- Add a gadget to the game input system. * 44 * GScreenClass::Remove_A_Button -- Removes a gadget from the game input system. * 45 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */ 46 47 #include "function.h" 48 49 #include <filepcx.h> 50 51 GadgetClass * GScreenClass::Buttons = 0; 52 53 GraphicBufferClass * GScreenClass::ShadowPage = 0; 54 55 56 /*********************************************************************************************** 57 * GScreenClass::GScreenClass -- Default constructor for GScreenClass. * 58 * * 59 * This constructor merely sets the display system, so that it will redraw the first time * 60 * the render function is called. * 61 * * 62 * INPUT: none * 63 * * 64 * OUTPUT: none * 65 * * 66 * WARNINGS: none * 67 * * 68 * HISTORY: * 69 * 12/15/1994 JLB : Created. * 70 *=============================================================================================*/ 71 GScreenClass::GScreenClass(void) 72 { 73 IsToUpdate = true; 74 IsToRedraw = true; 75 } 76 77 78 /*********************************************************************************************** 79 * GScreenClass::One_Time -- Handles one time class setups. * 80 * * 81 * This routine (and all those that overload it) must perform truly one-time initialization. * 82 * Such init's would normally be done in the constructor, but other aspects of the game may * 83 * not have been initialized at the time the constructors are called (such as the file system, * 84 * the display, or other WWLIB subsystems), so many initializations should be deferred to the * 85 * One_Time init's. * 86 * * 87 * Any variables set in this routine should be declared as static, so they won't be modified * 88 * by the load/save process. Non-static variables will be over-written by a loaded game. * 89 * * 90 * This function allocates the shadow buffer that is used for quick screen updates. If * 91 * there were any data files to load, they would be loaded at this time as well. * 92 * * 93 * INPUT: none * 94 * * 95 * OUTPUT: none * 96 * * 97 * WARNINGS: Call this routine only ONCE at the beginning of the game. * 98 * * 99 * HISTORY: * 100 * 12/15/1994 JLB : Created. * 101 *=============================================================================================*/ 102 void GScreenClass::One_Time(void) 103 { 104 /* 105 ** Allocate the screen shadow page. This page is used to reduce access to the 106 ** actual screen memory. It contains a duplicate of what the SEENPAGE is. 107 */ 108 Buttons = 0; 109 ShadowPage = new GraphicBufferClass(320,200); 110 if (ShadowPage) { 111 ShadowPage->Clear(); 112 HiddenPage.Clear(); 113 } 114 } 115 116 117 /*********************************************************************************************** 118 * GScreenClass::Init -- Init's the entire display hierarchy by calling all Init routines. * 119 * * 120 * This routine shouldn't be overloaded. It's the main map initialization routine, and will * 121 * perform a complete map initialization, from mixfiles to clearing the buffers. Calling this * 122 * routine results in calling every initialization routine in the entire map hierarchy. * 123 * * 124 * INPUT: * 125 * theater theater to initialize to * 126 * * 127 * OUTPUT: * 128 * none. * 129 * * 130 * WARNINGS: * 131 * none. * 132 * * 133 * HISTORY: * 134 * 12/28/1994 BR : Created. * 135 *=============================================================================================*/ 136 void GScreenClass::Init(TheaterType theater) 137 { 138 Init_Clear(); 139 Init_IO(); 140 Init_Theater(theater); 141 } 142 143 144 /*********************************************************************************************** 145 * GScreenClass::Init_Clear -- Sets the map to a known state. * 146 * * 147 * This routine (and those that overload it) clears any buffers and variables to a known * 148 * state. It assumes that all buffers are allocated & valid. The map should be displayable * 149 * after calling this function, and should draw basically an empty display. * 150 * * 151 * INPUT: * 152 * none. * 153 * * 154 * OUTPUT: * 155 * none. * 156 * * 157 * WARNINGS: * 158 * none. * 159 * * 160 * HISTORY: * 161 * 12/28/1994 BR : Created. * 162 *=============================================================================================*/ 163 void GScreenClass::Init_Clear(void) 164 { 165 /* 166 ** Clear the ShadowPage & HidPage to force a complete shadow blit. 167 */ 168 if (ShadowPage) { 169 ShadowPage->Clear(); 170 HiddenPage.Clear(); 171 } 172 173 IsToRedraw = true; 174 } 175 176 177 /*********************************************************************************************** 178 * GScreenClass::Init_Theater -- Performs theater-specific initializations. * 179 * * 180 * This routine (and those that overload it) performs any theater-specific initializations * 181 * needed. This will include setting the palette, setting up remap tables, etc. This routine * 182 * only needs to be called when the theater has changed. * 183 * * 184 * INPUT: * 185 * none. * 186 * * 187 * OUTPUT: * 188 * none. * 189 * * 190 * WARNINGS: * 191 * none. * 192 * * 193 * HISTORY: * 194 * 12/28/1994 BR : Created. * 195 *=============================================================================================*/ 196 void GScreenClass::Init_Theater(TheaterType ) 197 { 198 } 199 200 201 /*********************************************************************************************** 202 * GScreenClass::Init_IO -- Initializes the Button list ('Buttons'). * 203 * * 204 * INPUT: * 205 * none. * 206 * * 207 * OUTPUT: * 208 * none. * 209 * * 210 * WARNINGS: * 211 * none. * 212 * * 213 * HISTORY: * 214 * 12/28/1994 BR : Created. * 215 *=============================================================================================*/ 216 void GScreenClass::Init_IO(void) 217 { 218 /* 219 ** Reset the button list. This means that any other elements of the map that need 220 ** buttons must attach them after this routine is called! 221 */ 222 Buttons = 0; 223 224 } 225 226 227 /*********************************************************************************************** 228 * GScreenClass::Flag_To_Redraw -- Flags the display to be redrawn. * 229 * * 230 * This function is used to flag the display system whether any rendering is needed. The * 231 * parameter tells the system either to redraw EVERYTHING, or just that something somewhere * 232 * has changed and the individual Draw_It functions must be called. When a sub system * 233 * determines that it needs to render something local to itself, it would call this routine * 234 * with a false parameter. If the entire screen gets trashed or needs to be rebuilt, then * 235 * this routine will be called with a true parameter. * 236 * * 237 * INPUT: complete -- bool; Should the ENTIRE screen be redrawn? * 238 * * 239 * OUTPUT: none * 240 * * 241 * WARNINGS: This doesn't actually draw the screen, it merely sets flags so that when the * 242 * Render() function is called, the appropriate drawing steps will be performed. * 243 * * 244 * HISTORY: * 245 * 12/15/1994 JLB : Created. * 246 *=============================================================================================*/ 247 void GScreenClass::Flag_To_Redraw(bool complete) 248 { 249 IsToUpdate = true; 250 if (complete) { 251 IsToRedraw = true; 252 } 253 } 254 255 256 /*********************************************************************************************** 257 * GScreenClass::Input -- Fetches input and processes gadgets. * 258 * * 259 * This routine will fetch the keyboard/mouse input and dispatch this through the gadget * 260 * system. * 261 * * 262 * INPUT: key -- Reference to the key code (for future examination). * 263 * * 264 * x,y -- Reference to mouse coordinates (for future examination). * 265 * * 266 * OUTPUT: none * 267 * * 268 * WARNINGS: none * 269 * * 270 * HISTORY: * 271 * 01/19/1995 JLB : Created. * 272 *=============================================================================================*/ 273 void GScreenClass::Input(KeyNumType & key, int & x, int & y) 274 { 275 key = Keyboard::Check(); 276 277 x = Keyboard::Mouse_X(); 278 y = Keyboard::Mouse_Y(); 279 280 if (Buttons) { 281 282 /* 283 ** If any buttons need redrawing, they will do so in the Input routine, and 284 ** they should draw themselves to the HidPage. So, flag ourselves for a Blit 285 ** to show the newly drawn buttons. 286 */ 287 if (Buttons->Is_List_To_Redraw()) { 288 Flag_To_Redraw(false); 289 } 290 291 GraphicViewPortClass * oldpage= Set_Logic_Page(HidPage); 292 293 key = Buttons->Input(); 294 295 Set_Logic_Page(oldpage); 296 297 } else { 298 if (key) { 299 key = Keyboard::Get(); 300 } 301 } 302 AI(key, x, y); 303 304 } 305 306 307 /*********************************************************************************************** 308 * GScreenClass::Add_A_Button -- Add a gadget to the game input system. * 309 * * 310 * This will add a gadget to the game input system. The gadget will be processed in * 311 * subsiquent calls to the GScreenClass::Input() function. * 312 * * 313 * INPUT: gadget -- Reference to the gadget that will be added to the input system. * 314 * * 315 * OUTPUT: none * 316 * * 317 * WARNINGS: none * 318 * * 319 * HISTORY: * 320 * 01/19/1995 JLB : Created. * 321 *=============================================================================================*/ 322 void GScreenClass::Add_A_Button(GadgetClass & gadget) 323 { 324 /*------------------------------------------------------------------------ 325 If this gadget is already in the list, remove it before adding it in: 326 - If 1st gadget in list, use Remove_A_Button to remove it, to reset the 327 value of 'Buttons' appropriately 328 - Otherwise, just call the Remove function for that gadget to remove it 329 from any list it may be in 330 ------------------------------------------------------------------------*/ 331 if (Buttons == &gadget) { 332 Remove_A_Button(gadget); 333 } else { 334 gadget.Remove(); 335 } 336 337 /*------------------------------------------------------------------------ 338 Now add the gadget to our list: 339 - If there are not buttons, start the list with this one 340 - Otherwise, add it to the tail of the existing list 341 ------------------------------------------------------------------------*/ 342 if (Buttons) { 343 gadget.Add_Tail(*Buttons); 344 } else { 345 Buttons = &gadget; 346 } 347 } 348 349 350 /*********************************************************************************************** 351 * GScreenClass::Remove_A_Button -- Removes a gadget from the game input system. * 352 * * 353 * INPUT: gadget -- Reference to the gadget that will be removed from the input system. * 354 * * 355 * OUTPUT: none * 356 * * 357 * WARNINGS: 'gadget' MUST be already a part of 'Buttons', or the new value of 'Buttons' * 358 * will be invalid! * 359 * * 360 * HISTORY: * 361 * 01/19/1995 JLB : Created. * 362 *=============================================================================================*/ 363 void GScreenClass::Remove_A_Button(GadgetClass & gadget) 364 { 365 Buttons = gadget.Remove(); 366 } 367 368 369 /*********************************************************************************************** 370 * GScreenClass::Render -- General drawing dispatcher an display update function. * 371 * * 372 * This routine should be called in the main game loop (once every game frame). It will * 373 * call the Draw_It() function if necessary. All rendering is performed to the LogicPage * 374 * which is set to the HIDPAGE. After rendering has been performed, the HIDPAGE is * 375 * copied to the visible page. * 376 * * 377 * INPUT: none * 378 * * 379 * OUTPUT: none * 380 * * 381 * WARNINGS: This actually updates the graphic display. As a result it can take quite a * 382 * while to perform. * 383 * * 384 * HISTORY: * 385 * 12/15/1994 JLB : Created. * 386 *=============================================================================================*/ 387 void GScreenClass::Render(void) 388 { 389 //if (Buttons && Buttons->Is_List_To_Redraw()) { 390 // IsToRedraw = true; 391 //} 392 393 394 if (IsToUpdate || IsToRedraw) { 395 396 //WWMouse->Erase_Mouse(&HidPage, TRUE); 397 GraphicViewPortClass * oldpage= Set_Logic_Page(HidPage); 398 399 //if (IsToRedraw) { 400 // Hide_Mouse(); 401 // SeenBuff.To_Buffer(0, 0, 320, 200, ShadowPage); 402 // Show_Mouse(); 403 //} 404 Draw_It(IsToRedraw); 405 406 if (Buttons) Buttons->Draw_All(false); 407 408 #ifdef SCENARIO_EDITOR 409 /* 410 ** Draw the Editor's buttons 411 */ 412 if (Debug_Map) { 413 if (Buttons) { 414 Buttons->Draw_All(); 415 } 416 } 417 #endif 418 /* 419 ** Draw the multiplayer message system to the Hidpage at this point. 420 ** This way, they'll Blit along with the rest of the map. 421 */ 422 if (Messages.Num_Messages() > 0) { 423 Messages.Set_Width(Lepton_To_Cell(Map.TacLeptonWidth) * ICON_PIXEL_W); 424 } 425 Messages.Draw(); 426 427 //Blit_Display(); // 5/19/20 SKY - Skip copying to scene page, we can get the data directly from hidden page 428 IsToUpdate = false; 429 IsToRedraw = false; 430 431 Set_Logic_Page(oldpage); 432 } 433 } 434 435 436 437 #ifdef CHEAT_KEYS 438 439 #define MAX_SCREENS_SAVED 30*15 // Enough for 30 seconds @ 15 fps 440 441 GraphicBufferClass *ScreenList[MAX_SCREENS_SAVED]; 442 int CurrentScreen = 0; 443 bool ScreenRecording = false; 444 445 void Add_Current_Screen(void) 446 { 447 #if (0) // ST - 1/2/2019 5:51PM 448 if (ScreenRecording){ 449 ScreenList[CurrentScreen] = new GraphicBufferClass; 450 ScreenList[CurrentScreen]->Init ( SeenBuff.Get_Width(), SeenBuff.Get_Height(), NULL, 0, (GBC_Enum) 0); 451 SeenBuff.Blit (*ScreenList[CurrentScreen]); 452 453 CurrentScreen++; 454 455 if (CurrentScreen == MAX_SCREENS_SAVED){ 456 457 char filename[20]; 458 for (int i = 0 ; i < MAX_SCREENS_SAVED ; i++){ 459 sprintf (filename, "SCRN%04d.PCX", i); 460 Write_PCX_File (filename,*ScreenList[i], (unsigned char *)CurrentPalette); 461 delete ScreenList[i]; 462 } 463 464 CurrentScreen = 0; 465 ScreenRecording = 0; 466 467 } 468 } 469 #endif 470 } 471 472 #endif //CHEAT_KEYS 473 474 475 extern bool CanVblankSync; 476 477 /*********************************************************************************************** 478 * GScreenClass::Blit_Display -- Redraw the display from the hidpage to the seenpage. * 479 * * 480 * This routine is used to copy the correct display from the HIDPAGE * 481 * to the SEENPAGE. * 482 * * 483 * INPUT: none * 484 * * 485 * OUTPUT: none * 486 * * 487 * WARNINGS: none * 488 * * 489 * HISTORY: * 490 * 02/14/1994 JLB : Created. * 491 * 05/01/1994 JLB : Converted to member function. * 492 *=============================================================================================*/ 493 void GScreenClass::Blit_Display(void) 494 { 495 if (SeenBuff.Get_Width()!=320){ 496 #if (0) 497 if (HidPage.Get_IsDirectDraw() && (Options.GameSpeed >1 || Options.ScrollRate==6 && CanVblankSync) ){ 498 WWMouse->Draw_Mouse(&HidPage); 499 SeenBuff.Get_Graphic_Buffer()->Get_DD_Surface()->Flip(NULL , DDFLIP_WAIT); 500 SeenBuff.Blit (HidPage , 0 , 0 , 0 , 0 , SeenBuff.Get_Width() , SeenBuff.Get_Height() , (BOOL) FALSE ); 501 #ifdef CHEAT_KEYS 502 Add_Current_Screen(); 503 #endif 504 //HidPage.Blit ( SeenBuff , 0 , 0 , 0 , 0 , HidPage.Get_Width() , HidPage.Get_Height() , (BOOL) FALSE ); 505 WWMouse->Erase_Mouse(&HidPage, FALSE); 506 }else{ 507 #else //(0) 508 WWMouse->Draw_Mouse(&HidPage); 509 HidPage.Blit ( SeenBuff , 0 , 0 , 0 , 0 , HidPage.Get_Width() , HidPage.Get_Height() , (BOOL) FALSE ); 510 #ifdef CHEAT_KEYS 511 Add_Current_Screen(); 512 #endif 513 WWMouse->Erase_Mouse(&HidPage, FALSE); 514 #endif //(0) 515 #if (0) 516 } 517 #endif //(0) 518 519 } else { 520 // ST - 1/2/2019 5:26PM 521 //ModeX_Blit (&HiddenPage); 522 } 523 524 } 525 526 527 528