//Copyright Paul Reiche, Fred Ford. 1992-2002

/*
 *  This program 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 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 */

#include "gfxintrn.h"
#include "libs/graphics/gfx_common.h"
#include "libs/graphics/drawcmd.h"
#include "libs/timelib.h"
#include "libs/misc.h"
		// for TFB_DEBUG_HALT


int ScreenWidth;
int ScreenHeight;
int ScreenWidthActual;
int ScreenHeightActual;
int ScreenColorDepth;
int GraphicsDriver;
int TFB_DEBUG_HALT = 0;

volatile int TransitionAmount = 255;
RECT TransitionClipRect;

static int gscale = GSCALE_IDENTITY;
static int gscale_mode = TFB_SCALE_NEAREST;

void
DrawFromExtraScreen (RECT *r)
{
	TFB_DrawScreen_Copy(r, TFB_SCREEN_EXTRA, TFB_SCREEN_MAIN);
}

void
LoadIntoExtraScreen (RECT *r)
{
	TFB_DrawScreen_Copy(r, TFB_SCREEN_MAIN, TFB_SCREEN_EXTRA);
}

int
SetGraphicScale (int scale)
{
	int old_scale = gscale;
	gscale = (scale ? scale : GSCALE_IDENTITY);
	return old_scale;
}

int
GetGraphicScale (void)
{
	return gscale;
}

int
SetGraphicScaleMode (int mode)
{
	int old_mode = gscale_mode;
	assert (mode >= TFB_SCALE_NEAREST && mode <= TFB_SCALE_TRILINEAR);
	gscale_mode = mode;
	return old_mode;
}

int
GetGraphicScaleMode (void)
{
	return gscale_mode;
}

/* Batching and Unbatching functions.  A "Batch" is a collection of
   DrawCommands that will never be flipped to the screen half-rendered.
   BatchGraphics and UnbatchGraphics function vaguely like a non-blocking
   recursive lock to do this respect. */
void
BatchGraphics (void)
{
	TFB_BatchGraphics ();
}

void
UnbatchGraphics (void)
{
	TFB_UnbatchGraphics ();
}

/* Sleeps this thread until all Draw Commands queued by that thread have
   been processed. */

void
FlushGraphics (void)
{
	TFB_DrawScreen_WaitForSignal ();
}

static void
ExpandRect (RECT *rect, int expansion)
{
	if (rect->corner.x - expansion >= 0)
	{
		rect->extent.width += expansion;
		rect->corner.x -= expansion;
	}
	else
	{
		rect->extent.width += rect->corner.x;
		rect->corner.x = 0;
	}

	if (rect->corner.y - expansion >= 0)
	{
		rect->extent.height += expansion;
		rect->corner.y -= expansion;
	}
	else
	{
		rect->extent.height += rect->corner.y;
		rect->corner.y = 0;
	}

	if (rect->corner.x + rect->extent.width + expansion <= ScreenWidth)
		rect->extent.width += expansion;
	else
		rect->extent.width = ScreenWidth - rect->corner.x;

	if (rect->corner.y + rect->extent.height + expansion <= ScreenHeight)
		rect->extent.height += expansion;
	else
		rect->extent.height = ScreenHeight - rect->corner.y;
}

void
SetTransitionSource (const RECT *pRect)
{
	RECT ActualRect;

	if (pRect)
	{	/* expand the rect to accomodate scalers in OpenGL mode */
		ActualRect = *pRect;
		pRect = &ActualRect;
		ExpandRect (&ActualRect, 2);
	}
	TFB_DrawScreen_Copy (pRect, TFB_SCREEN_MAIN, TFB_SCREEN_TRANSITION);
}

// ScreenTransition() is synchronous (does not return until transition done)
void
ScreenTransition (int TransType, const RECT *pRect)
{
	const TimePeriod DURATION = ONE_SECOND * 31 / 60;
	TimeCount startTime;
	(void) TransType;  /* dodge compiler warning */

	if (pRect)
	{
		TransitionClipRect = *pRect;
	}
	else
	{
		TransitionClipRect.corner.x = 0;
		TransitionClipRect.corner.y = 0;
		TransitionClipRect.extent.width = ScreenWidth;
		TransitionClipRect.extent.height = ScreenHeight;
	}

	TFB_UploadTransitionScreen ();
	
	TransitionAmount = 0;
	FlushGraphics ();
	startTime = GetTimeCounter ();
	while (TransitionAmount < 255)
	{
		TimePeriod deltaT;
		int newAmount;

		SleepThread (ONE_SECOND / 100);

		deltaT = GetTimeCounter () - startTime;
		newAmount = deltaT * 255 / DURATION;
		if (newAmount > 255)
			newAmount = 255;

		TransitionAmount = newAmount;
	}
}
