//
// 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/GSCREEN.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 : GSCREEN.CPP                                                  *
 *                                                                                             *
 *                   Programmer : Joe L. Bostic                                                *
 *                                                                                             *
 *                   Start Date : 12/15/94                                                     *
 *                                                                                             *
 *                  Last Update : January 19, 1995 [JLB]                                       *
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 *   GScreenClass::Add_A_Button -- Add a gadget to the game input system.                      *
 *   GScreenClass::Blit_Display -- Redraw the display from the hidpage to the seenpage.        *
 *   GScreenClass::Flag_To_Redraw -- Flags the display to be redrawn.                          *
 *   GScreenClass::GScreenClass -- Default constructor for GScreenClass.                       *
 *   GScreenClass::Init -- Init's the entire display hierarchy by calling all Init routines.   *
 *   GScreenClass::Init_Clear -- Sets the map to a known state.                                *
 *   GScreenClass::Init_IO -- Initializes the Button list ('Buttons').                         *
 *   GScreenClass::Init_Theater -- Performs theater-specific initializations.                  *
 *   GScreenClass::Input -- Fetches input and processes gadgets.                               *
 *   GScreenClass::One_Time -- Handles one time class setups.                                  *
 *   GScreenClass::Remove_A_Button -- Removes a gadget from the game input system.             *
 *   GScreenClass::Render -- General drawing dispatcher an display update function.            *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "function.h"


GadgetClass * GScreenClass::Buttons = 0;

GraphicBufferClass * GScreenClass::ShadowPage = 0;


/***********************************************************************************************
 * GScreenClass::GScreenClass -- Default constructor for GScreenClass.                         *
 *                                                                                             *
 *    This constructor merely sets the display system, so that it will redraw the first time   *
 *    the render function is called.                                                           *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/15/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
GScreenClass::GScreenClass(void)
{
	IsToUpdate = true;
	IsToRedraw = true;
}


/***********************************************************************************************
 * GScreenClass::One_Time -- Handles one time class setups.                                    *
 *                                                                                             *
 * This routine (and all those that overload it) must perform truly one-time initialization.   *
 * Such init's would normally be done in the constructor, but other aspects of the game may    *
 * not have been initialized at the time the constructors are called (such as the file system, *
 * the display, or other WWLIB subsystems), so many initializations should be deferred to the  *
 * One_Time init's.                                                                            *
 *                                                                                             *
 * Any variables set in this routine should be declared as static, so they won't be modified   *
 * by the load/save process.  Non-static variables will be over-written by a loaded game.      *
 *                                                                                             *
 * This function allocates the shadow buffer that is used for quick screen updates. If         *
 * there were any data files to load, they would be loaded at this time as well.               *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   Call this routine only ONCE at the beginning of the game.                       *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/15/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void GScreenClass::One_Time(void)
{
	/*
	**	Allocate the screen shadow page. This page is used to reduce access to the
	**	actual screen memory. It contains a duplicate of what the SEENPAGE is.
	*/
	Buttons = 0;
	ShadowPage = new GraphicBufferClass(320, 200);
	if (ShadowPage) {
		ShadowPage->Clear();
		HidPage.Clear();
	}
}


/***********************************************************************************************
 * GScreenClass::Init -- Init's the entire display hierarchy by calling all Init routines.     *
 *                                                                                             *
 * This routine shouldn't be overloaded.  It's the main map initialization routine, and will   *
 * perform a complete map initialization, from mixfiles to clearing the buffers.  Calling this *
 * routine results in calling every initialization routine in the entire map hierarchy.        *
 *                                                                                             *
 * INPUT:                                                                                      *
 *      theater      theater to initialize to                                                  *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *      none.                                                                                  *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *      none.                                                                                  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/28/1994 BR : Created.                                                                  *
 *=============================================================================================*/
void GScreenClass::Init(TheaterType theater)
{
	Init_Clear();
	Init_IO();
	Init_Theater(theater);
}


/***********************************************************************************************
 * GScreenClass::Init_Clear -- Sets the map to a known state.                                  *
 *                                                                                             *
 * This routine (and those that overload it) clears any buffers and variables to a known       *
 * state.  It assumes that all buffers are allocated & valid.  The map should be displayable   *
 * after calling this function, and should draw basically an empty display.                    *
 *                                                                                             *
 * INPUT:                                                                                      *
 *      none.                                                                                  *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *      none.                                                                                  *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *      none.                                                                                  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/28/1994 BR : Created.                                                                  *
 *=============================================================================================*/
void GScreenClass::Init_Clear(void)
{
	/*
	** Clear the ShadowPage & HidPage to force a complete shadow blit.
	*/
	if (ShadowPage) {
		ShadowPage->Clear();
		HidPage.Clear();
	}

	IsToRedraw = true;
}


/***********************************************************************************************
 * GScreenClass::Init_Theater -- Performs theater-specific initializations.                    *
 *                                                                                             *
 * This routine (and those that overload it) performs any theater-specific initializations     *
 * needed.  This will include setting the palette, setting up remap tables, etc.  This routine *
 * only needs to be called when the theater has changed.                                       *
 *                                                                                             *
 * INPUT:                                                                                      *
 *      none.                                                                                  *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *      none.                                                                                  *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *      none.                                                                                  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/28/1994 BR : Created.                                                                  *
 *=============================================================================================*/
void GScreenClass::Init_Theater(TheaterType )
{
}


/***********************************************************************************************
 * GScreenClass::Init_IO -- Initializes the Button list ('Buttons').                           *
 *                                                                                             *
 * INPUT:                                                                                      *
 *      none.                                                                                  *
 *                                                                                             *
 * OUTPUT:                                                                                     *
 *      none.                                                                                  *
 *                                                                                             *
 * WARNINGS:                                                                                   *
 *      none.                                                                                  *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/28/1994 BR : Created.                                                                  *
 *=============================================================================================*/
void GScreenClass::Init_IO(void)
{
	/*
	** Reset the button list.  This means that any other elements of the map that need
	** buttons must attach them after this routine is called!
	*/
	Buttons = 0;
}


/***********************************************************************************************
 * GScreenClass::Flag_To_Redraw -- Flags the display to be redrawn.                            *
 *                                                                                             *
 *    This function is used to flag the display system whether any rendering is needed. The    *
 *    parameter tells the system either to redraw EVERYTHING, or just that something somewhere *
 *    has changed and the individual Draw_It functions must be called. When a sub system       *
 *    determines that it needs to render something local to itself, it would call this routine *
 *    with a false parameter. If the entire screen gets trashed or needs to be rebuilt, then   *
 *    this routine will be called with a true parameter.                                       *
 *                                                                                             *
 * INPUT:   complete -- bool; Should the ENTIRE screen be redrawn?                             *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   This doesn't actually draw the screen, it merely sets flags so that when the    *
 *             Render() function is called, the appropriate drawing steps will be performed.   *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/15/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void GScreenClass::Flag_To_Redraw(bool complete)
{
	IsToUpdate = true;
	if (complete) {
		IsToRedraw = true;
	}
}


/***********************************************************************************************
 * GScreenClass::Input -- Fetches input and processes gadgets.                                 *
 *                                                                                             *
 *    This routine will fetch the keyboard/mouse input and dispatch this through the gadget    *
 *    system.                                                                                  *
 *                                                                                             *
 * INPUT:   key      -- Reference to the key code (for future examination).                    *
 *                                                                                             *
 *          x,y      -- Reference to mouse coordinates (for future examination).               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/19/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void GScreenClass::Input(KeyNumType & key, int & x, int & y)
{
	key = Keyboard->Check();

	x = Keyboard->Mouse_X();
	y = Keyboard->Mouse_Y();

	if (Buttons != NULL) {

		/*
		** If any buttons need redrawing, they will do so in the Input routine, and
		** they should draw themselves to the HidPage.  So, flag ourselves for a Blit
		** to show the newly drawn buttons.
		*/
		if (Buttons->Is_List_To_Redraw()) {
			Flag_To_Redraw(false);
		}

#ifdef WIN32
		GraphicViewPortClass * oldpage= Set_Logic_Page(HidPage);
#else
		GraphicBufferClass * oldpage= Set_Logic_Page(HidPage);
#endif

		key = Buttons->Input();

		Set_Logic_Page(oldpage);

	} else {

		if (key != 0) {
			key = Keyboard->Get();
		}
	}

	AI(key, x, y);
}


/***********************************************************************************************
 * GScreenClass::Add_A_Button -- Add a gadget to the game input system.                        *
 *                                                                                             *
 *    This will add a gadget to the game input system. The gadget will be processed in         *
 *    subsequent calls to the GScreenClass::Input() function.                                  *
 *                                                                                             *
 * INPUT:   gadget   -- Reference to the gadget that will be added to the input system.        *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/19/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void GScreenClass::Add_A_Button(GadgetClass & gadget)
{
	/*
	**	If this gadget is already in the list, remove it before adding it in:
	**	- If 1st gadget in list, use Remove_A_Button to remove it, to reset the
	**	  value of 'Buttons' appropriately
	**	- Otherwise, just call the Remove function for that gadget to remove it
	**	  from any list it may be in
	*/
	if (Buttons == &gadget) {
		Remove_A_Button(gadget);
	} else {
		gadget.Remove();
	}

	/*
	**	Now add the gadget to our list:
	**	- If there are not buttons, start the list with this one
	**	- Otherwise, add it to the tail of the existing list
	*/
	if (Buttons) {
		gadget.Add_Tail(*Buttons);
	} else {
		Buttons = &gadget;
	}
}


/***********************************************************************************************
 * GScreenClass::Remove_A_Button -- Removes a gadget from the game input system.               *
 *                                                                                             *
 * INPUT:   gadget   -- Reference to the gadget that will be removed from the input system.    *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   'gadget' MUST be already a part of 'Buttons', or the new value of 'Buttons'     *
 *               will be invalid!                                                              *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   01/19/1995 JLB : Created.                                                                 *
 *=============================================================================================*/
void GScreenClass::Remove_A_Button(GadgetClass & gadget)
{
	Buttons = gadget.Remove();
}


/***********************************************************************************************
 * GScreenClass::Render -- General drawing dispatcher an display update function.              *
 *                                                                                             *
 *    This routine should be called in the main game loop (once every game frame). It will     *
 *    call the Draw_It() function if necessary. All rendering is performed to the LogicPage    *
 *    which is set to the HIDPAGE. After rendering has been performed, the HIDPAGE is          *
 *    copied to the visible page.                                                              *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   This actually updates the graphic display. As a result it can take quite a      *
 *             while to perform.                                                               *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   12/15/1994 JLB : Created.                                                                 *
 *=============================================================================================*/
void GScreenClass::Render(void)
{
	//This is unnessasary surely?	ST - 10/16/96 2:30PM
	//if (Buttons && Buttons->Is_List_To_Redraw()) {
	//	IsToRedraw = true;
	//}


	if (IsToUpdate || IsToRedraw) {
		BStart(BENCH_GSCREEN_RENDER);

#ifdef WIN32
		GraphicViewPortClass * oldpage= Set_Logic_Page(HidPage);
#else
		GraphicBufferClass * oldpage= Set_Logic_Page(HidPage);

		if (IsToRedraw) {
			Hide_Mouse();
			SeenPage.To_Buffer(0, 0, 320, 200, ShadowPage);
			Show_Mouse();
		}
#endif

		Draw_It(IsToRedraw);

		if (Buttons) Buttons->Draw_All(false);

#ifdef SCENARIO_EDITOR
		/*
		** Draw the Editor's buttons
		*/
		if (Debug_Map) {
			if (Buttons) {
				Buttons->Draw_All();
			}
		}
#endif
		/*
		** Draw the multiplayer message system to the Hidpage at this point.
		** This way, they'll Blit along with the rest of the map.
		*/
		if (Session.Messages.Num_Messages() > 0) {
			Session.Messages.Set_Width(
				Lepton_To_Cell(Map.TacLeptonWidth) * ICON_PIXEL_W);
		}
		Session.Messages.Draw();

		//Blit_Display(); // 5/19/20 SKY - Skip copying to scene page, we can get the data directly from hidden page
		IsToUpdate = false;
		IsToRedraw = false;

		BEnd(BENCH_GSCREEN_RENDER);
		Set_Logic_Page(oldpage);
	}
}


/***********************************************************************************************
 * GScreenClass::Blit_Display -- Redraw the display from the hidpage to the seenpage.          *
 *                                                                                             *
 *    This routine is used to copy the correct display from the HIDPAGE                        *
 *    to the SEENPAGE.                                                                         *
 *                                                                                             *
 * INPUT:   none                                                                               *
 *                                                                                             *
 * OUTPUT:  none                                                                               *
 *                                                                                             *
 * WARNINGS:   none                                                                            *
 *                                                                                             *
 * HISTORY:                                                                                    *
 *   02/14/1994 JLB : Created.                                                                 *
 *   05/01/1994 JLB : Converted to member function.                                            *
 *=============================================================================================*/
extern "C" {
	void ModeX_Blit (GraphicBufferClass * source);
}

void GScreenClass::Blit_Display(void)
{
	BStart(BENCH_BLIT_DISPLAY);
	#ifdef WIN32
		if (SeenBuff.Get_Width()!=320) {
			WWMouse->Draw_Mouse(&HidPage);
			HidPage.Blit(SeenBuff , 0 , 0 , 0 , 0 , HidPage.Get_Width() , HidPage.Get_Height() , (BOOL) FALSE );
			WWMouse->Erase_Mouse(&HidPage, FALSE);
		} else {
			//PG ModeX_Blit(&HiddenPage);
		}
	#else
		Shadow_Blit(0, 0, 320, 200, HidPage, SeenPage, ShadowPage->Get_Buffer());
	#endif
	BEnd(BENCH_BLIT_DISPLAY);
}