////////////////////////////////////////////////////////////////////////////////
//
// Copyright 2016 RWS Inc, All Rights Reserved
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of version 2 of the GNU General Public License as published by
// the Free Software Foundation
//
// 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.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
//
// MenuTrans.cpp
// Project: Nostril (aka Postal)
//
// This module sets up the system and RSPiX.
//
// History:
//		11/19/96 MJR	Started.
//
//		08/04/97	JMI	Although the Remap() function was calling 
//							rspLockVideoBuffer(), it was effectively ignoring it.  That
//							is, it passed 'dummy' vars which it did not use to access
//							the screen.  These values MUST be used or there is very
//							little point in locking the video buffer in the first place.
//							This probably occurs all over the place.  I'm pretty sure
//							I've done it this way in spots.
//
//		08/21/97	JMI	Changed occurrences of rspUpdateDisplay() to 
//							UpdateDisplay().
//
//		08/22/97	JMI	Changed to use rspLockBuffer() (the BLiT library version
//							of locking the composite buffer).
//
//		08/22/97	JMI	Changed calls to UpdateDisplay() back to rspUpdateDisplay()
//							since we no longer need UpdateDisplay() now that we are
//							using rspLock/Unlock* functions properly.
//							Also, put locks around accesses (Blits, Rects, etc.) to the
//							composite buffer.
//
////////////////////////////////////////////////////////////////////////////////
//
// Things to change:
//
// I don't currently care much for the fade to red -- it looks pretty damn
// plain.
//
// This currently requires a huge amount of memory since it needs to save the
// screen data so that the effect can be run backwards.  The problem with this
// is that it means we're always wasting alot more memory while running the
// game than we would otherwise need to, because we have to be ready to pop up
// the menu (and hence to use this effect) at any time.
//
// One possible way to use less memory is to save the screen data to the
// hard drive and load it back when we need it.  I'm not sure how slow this
// will be, and I'm also not sure what's involved in actually doing this since
// the buffer is really just a stub, which may not support saving properly.
//
// Not sure what to do about EndMenuTrans().  Original idea was to be able to
// call it at any time, and you could either tell it finish the effect as
// quickly as possible or to abort, which might leave the screen in an ugly
// state.  The idea was that if the user hit a key or something that meant
// "skip this stupid effect", that we could quickly do so.  I'm not sure how
// actual usage will turn out, so for now, I'm ignoring the flag being passed
// to this function.
//
////////////////////////////////////////////////////////////////////////////////

#include "RSPiX.h"
#ifdef PATHS_IN_INCLUDES
#else
#endif

#include "game.h"
#include "MenuTrans.h"
#include "update.h"

#include "pvr.h"


////////////////////////////////////////////////////////////////////////////////
// Macros/types/etc.
////////////////////////////////////////////////////////////////////////////////

// Define number of shades along with mask that will create that many shades
//#define NUM_SHADES				32
//#define SHADE_MASK				0xf8
#define NUM_SHADES				16
#define SHADE_MASK				0xf0

// Define range of palette indices to be affected (inclusive).
// THIS RANGE MUST BE AT LEAST TWICE AS LARGE AS NUM_SHADES!!!
#define EFFECT_BEG			10
#define EFFECT_END			245
#define EFFECT_LEN			((EFFECT_END - EFFECT_BEG) + 1)

#define SHADE_BEG				((EFFECT_END + 1) - NUM_SHADES)
#define SHADE_END				(EFFECT_END)
#define SHADE_LEN				((SHADE_END - SHADE_BEG) + 1)

#define NONSHADE_BEG			EFFECT_BEG
#define NONSHADE_END			(SHADE_BEG - 1)
#define NONSHADE_LEN			((NONSHADE_END - NONSHADE_BEG) + 1)

// Simple struct for working with palettes
typedef struct
	{
	uint8_t r;
	uint8_t g;
	uint8_t b;
	uint8_t x;
	} rgb;


////////////////////////////////////////////////////////////////////////////////
// Variables/data
////////////////////////////////////////////////////////////////////////////////

//static rgb* m_pOrig;
//static rgb* m_pWork;
//static rgb* m_pSaveStep4;
//static uint8_t* m_pUnmapStep4;
//static uint8_t* m_pUnmapStep5;
//static RImage* m_pim;

static int16_t m_sStep;
static bool m_bFinishASAP;
static int32_t m_lTotalTime;
static int32_t m_lBaseTime;

static double m_dReduce = 1.0;


////////////////////////////////////////////////////////////////////////////////
// Function prototypes
////////////////////////////////////////////////////////////////////////////////

static void Remap(
	uint8_t* aucMap);


////////////////////////////////////////////////////////////////////////////////
// Call this to start the menu transition effect
////////////////////////////////////////////////////////////////////////////////
extern void StartMenuTrans(
	int32_t lTotalTime)										// In:  Effect time (in ms) must be >= 0
	{
	// Default to step 0 (nothing) in case something goes wrong
	m_sStep = 0;

	// Save total time
	if (lTotalTime < 0)
		{
		TRACE("StartMenuTransIn(): Moronic time specified: %ld -- changed to 0!\n", lTotalTime);
		lTotalTime = 0;
		}
	m_lTotalTime = lTotalTime;

	// Clear finish flag
	m_bFinishASAP = false;

	// todo: clean up

	// Allocate lots of stuff
//	m_pOrig = new rgb[256];
//	m_pWork = new rgb[256];
//	m_pSaveStep4 = new rgb[256];
//	m_pUnmapStep4 = new uint8_t[256];
//	m_pUnmapStep5 = new uint8_t[256];

//	m_pim = new RImage;

	// Everything's cool, so set for first step
		m_sStep = 1;
}

extern PVR::cRenderMgr *g_pvrRenderer;

////////////////////////////////////////////////////////////////////////////////
//
// The starting time of the effect is considered to be the first time this
// function is called (NOT when InitMenuTransIn() is called!)
//
// The return value is true when the effect has completed, false otherwise.
////////////////////////////////////////////////////////////////////////////////
extern bool DoPreMenuTrans(void)
	{
	//---------------------------------------------------------------------------
	// Step 1: Start
	//
	// Get the current palette and the current time and go on to the next step.
	// This could have been done in the init function, but I didn't want the
	// timing to start then, but rather on the first call to this function.
	//---------------------------------------------------------------------------
	
	// todo: clean up
	PVR::cTexture *tex = nullptr;

	if (m_sStep == 1)
		{
		// Get base time for next step
		m_lBaseTime = rspGetMilliseconds();
		
		// Go to next step
		m_sStep = 2;
		}
	//---------------------------------------------------------------------------
	// Step 2: Fade colors
	//
	// Over the specified period of time, we transform the original palette
	// entries into MAX_SHADES shades of red.
	//---------------------------------------------------------------------------
	else if (m_sStep == 2)
		{
		// Calculate how far into the effect we are based on the elapsed time
		// since we started.  If the total time specified by the user was 0, or
		// if we're being asked to finish the effect ASAP, we go right to 100%.
		double dPercent;
		if ((m_lTotalTime == 0) || m_bFinishASAP)
			{
			dPercent = 1.0;
			}
		else
			{
			dPercent = (double)(rspGetMilliseconds() - m_lBaseTime) / (double)m_lTotalTime;
			
			if (dPercent > 1.0)
				dPercent = 1.0;
			}

			g_pvrRenderer->m_fGlobalGScale = 1.0f - dPercent;
			g_pvrRenderer->m_fGlobalBScale = 1.0f - dPercent;

		// If we're done with the fade, go to next step
		if (dPercent == 1.0)			
			m_sStep = 3;					
		}
	//---------------------------------------------------------------------------
	// Step 3: Consolidate
	//
	// At this point, the palette entries are all set to any of several shades of
	// red.  Since the range of entries we're dealing with is at least twice the
	// maximum number of shades of red, there will definitely be some duplicate
	// entries.  We remap the pixels to get rid of the duplicates, at the same
	// time creating some unused entries.  We set flags showing which entries are
	// used and which are free in preperation for the next step.
	//---------------------------------------------------------------------------
	else if (m_sStep == 3)
	// Condition return value based on whether or not we're done
	{				
		return true;
	}

	return false;
	}


////////////////////////////////////////////////////////////////////////////////
//
// The starting time of the effect is considered to be the first time this
// function is called (NOT when InitMenuTransIn() is called!)
//
// The return value is true when the effect has completed, false otherwise.
////////////////////////////////////////////////////////////////////////////////
extern bool DoPostMenuTrans(void)
	{

		// todo: clean up
	//	return true;
	
	//PVR::cTexture *tex = nullptr;

	//---------------------------------------------------------------------------
	// Step 6: Undo Step 5
	//---------------------------------------------------------------------------
	if (m_sStep == 3)
		{
		// Restore palette to where it was prior to step 5

		// Get base time for next step
		m_lBaseTime = rspGetMilliseconds();
		
		// Go to next step
		m_sStep = 4;
		}
	//---------------------------------------------------------------------------
	// Step 9: Do a reverse-fade of the colors
	//---------------------------------------------------------------------------
	else if (m_sStep == 4)
		{
		// Calculate how far into the effect we are based on the elapsed time
		// since we started.  If the total time specified by the user was 0, or
		// if we're being asked to finish the effect ASAP, we go right to 100%.
		double dPercent;
		if ((m_lTotalTime == 0) || m_bFinishASAP)
			{
			dPercent = 1.0;
			}
		else
			{
			dPercent = (double)(rspGetMilliseconds() - m_lBaseTime) / (double)m_lTotalTime;
			if (dPercent > 1.0)
				dPercent = 1.0;
			}

			g_pvrRenderer->m_fGlobalGScale = dPercent;
			g_pvrRenderer->m_fGlobalBScale = dPercent;

		// If we're done with the fade, go to next step
		if (dPercent == 1.0)
			m_sStep = 5;
		}

	// Condition return value based on whether or not we're done
	if (m_sStep == 5)
		return true;
	return false;
	}


////////////////////////////////////////////////////////////////////////////////
//
////////////////////////////////////////////////////////////////////////////////
extern void EndMenuTrans(
	bool bFinish)											// In: true to finish effect, false to abort it
	{
	// If step isn't over 0 then there's nothing to do
	if (m_sStep > 0)
		{
		// Check if caller wants to finish effect
		if (bFinish)
			{
			// Finish the effect
			m_bFinishASAP = bFinish;
//			while (!DoMenuTrans())
//				;
			}
	
		// Reset step to "nothing"
		m_sStep = 0;
		}
	}


////////////////////////////////////////////////////////////////////////////////
// Remap the pixels using the specified map
////////////////////////////////////////////////////////////////////////////////
static void Remap(
	uint8_t* aucMap)
	{
	
	}


////////////////////////////////////////////////////////////////////////////////
// EOF
////////////////////////////////////////////////////////////////////////////////
