////////////////////////////////////////////////////////////////////////////////
//
// 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
//
// title.cpp
// Project: Postal
//
// This module deals with displaying the title sequence and the loading of
// assets during that time.
//
// History:
//		12/04/96 MJR	Started.
//
//		01/28/97	JMI	Took out feet and title.bmp and replaced them with a simple
//							progress bar and Pile640K.bmp.
//
//		01/31/97	JMI	Now uses FullPath() to get full path for filespecs.
//
//		02/02/97	JMI	Now, once EndTitle() is called, the progress bar is 
//							guaranteed to be completely filled.  Also, changed
//							static sLastFillPos local to DoTitle() to module static
//							so it can be initialized in StartTitle() and, therefore,
//							the title screen can be restarted.
//
//		02/03/97	JMI	Updated paths to reflect SAK dir.
//
//		02/24/97 MJR	Put in new title screen and modified progress bar.
//
//		04/14/97	JMI	Now shows one BMP for a portion of the title progress and
//							then a different one for the rest.
//							You can select the starting bitmap on the call to 
//							StartTitle().
//							Eventually, I imagine this will be generalized further with
//							an array of res names and durations (one for RWS, one for
//							the publisher, and one for Postal).
//
//		04/14/97	JMI	Temporarily disabled progress meter for ABC News demo.
//
//		06/03/97	JMI	Now displays the pre-release excuse after the RWS logo.
//
//		06/04/97	JMI	Now you can select a title page relative to the last one
//							by specifying a number < 1.
//
//		06/04/97	JMI	Rearranged title screens and added RC logo.
//
//		06/11/97	JMI	Added check against g_GameSettings.m_szDontShowTitles.
//							Also, DisplayImage() now does a ReleaseAndPurge() instead
//							of an rspReleaseResource() to save what would currently
//							amount to about 1.2M of RAM.
//
//		06/11/97	JMI	Changed RResMgr::ReleaseAndPurge() call to 
//							rspReleaseAndPurge().
//
//		06/12/97	JMI	Now IsInList() uses rspStricmp().
//							
//		06/12/97	JMI	Now only updates the palette of the new image if it is
//							different from the current.
//
//		06/16/97	JMI	Now centers title screens and erases entire screen even
//							no palette change.
//
//		07/09/97	JMI	Now uses its own g_smidTitle for the title noise instead of
//							relying on the menu one.
//
//		07/18/97	JMI	Got rid of bogus immitation PlaySample functions.
//							Now there is one PlaySample() function.  Also, you now
//							MUST specify a category and you don't have to specify a
//							SoundInstance ptr to specify a volume.
//
//		07/23/97	JMI	Added rating.bmp as first title card.
//
//		08/08/97	JMI	Added parameter specifying whether to play musak to 
//							StartTitle().
//
//		08/18/97 BRH	Took out beta screen.
//
//		08/18/97 BRH	Added game ending sequence wiht backgrounds and audio.
//
//		08/18/97	JMI	Changed TitleRFileCallback to call Update() instead of
//							RMix::Do() (Update() calls RMix::Do() ) b/c Update()
//							makes the Mac load faster.
//
//		08/21/97	JMI	Changed call to Update() to UpdateSystem() and occurrences
//							of rspUpdateDisplay() to UpdateDisplay().
//
//		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.
//							Also, now loops the entire intro and does not abort it when
//							EndTitle() is called (it still stops the loopage, though).
//
//		08/23/97	JMI	Now you can get the sound instance of the title musak from
//							StartTitle().
//
//		08/30/97 BRH	Took out beta test screen.
//
//		09/01/97	BRH	Adjusted the final ending sequence so that the music starts
//							on a black screen, then the door is shown while you hear
//							the door slam sound, then it goes to the first sequence
//							picture of the tortured guy.
//
//		09/03/97	JMI	Many loops in Title_EndingSequence() wer calling RMix::Do()
//							instead of UpdateSystem().  While RMix::Do() will keep the
//							music running it does not give Blue a chance to realize
//							things like focus loss and video mode changes -- we should
//							always call UpdateSystem() in these loops.
//
//		09/04/97	JMI	Now calls UpdateSystem() every iteration instead of every
//							1/20th of a second.
//
//		09/07/97 BRH	You can now quit with Alt-F4 when the final end of
//							game sequence is playing.
//
//		09/07/97	JMI	Removed RipCord logo since the animated version is played
//							elsewhere (main.cpp).
//
//		09/08/97	JMI	Move Rip Cord static logo to front.
//
//		09/17/97	JMI	Removed unused heart beat interval timer, progress
//							meter calculations, and progress image loadage.
//
//		09/24/97 BRH	Added conditional compile based on LOCALE for the title
//							sequence.  The foreign versions have an additional
//							distributer screen after the ripcord logo, and the UK
//							warning screen is different.
//
//		09/25/97	JMI	Added #include of "comileOptions.h" so US, UK, etc. would
//							be defined.
//
//		09/30/97	JMI	Now sets and unsets RFile::ms_criticall in DisplayImage()
//							to guarantee it is being set during any title sequence.
//
//		10/21/97	JMI	A call to Title_DisableRipcordStaticLogo() will now disable
//							the RipCord static logo.
//
//		11/17/97	JMI	DoTitle() could theoretically blow m_adTitlePercent's 
//							bounds.
//
//		06/01/98 BRH	Removed the references to RIPCORD_LOGO_INDEX and the
//							code that disables the static logo to when the movie
//							logo is played etc.  Take2/AIM has requested that
//							the only logo on the game should be Running With Scissors
//							so we don't want Ripcord or Take2 logos at all.
//
//		09/27/99	JMI	Changed to allow deluxe violence disclaimer only in any 
//							locale satisfying the CompilerOptions macro VIOLENT_LOCALE.
//
//		01/20/00	MJR	Added screen for distributor logo.
//
//		03/30/00 MJR	Now uses TITLE_SHOW_DISTRIBUTOR to control whether the
//							distributor screen is shown.
//
////////////////////////////////////////////////////////////////////////////////
#define TITLE_CPP

#include "RSPiX.h"
#include "title.h"
#include "game.h"
#include "update.h"
#include "SampleMaster.h"
#include "CompileOptions.h"
#include "pvr.h"

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

#define TITLE_BG_W			640
#define TITLE_BG_H			400

#define TITLE_BG_X			(640 / 2 - TITLE_BG_W / 2)
#define TITLE_BG_Y			(480 / 2 - TITLE_BG_H / 2)

#define PROGRESS_W			(600-8)

#define TITLE_SOUND_UPDATE_INTERVAL 50

// Determines the number of elements in the passed array at compile time.
#define NUM_ELEMENTS(a)		(sizeof(a) / sizeof(a[0]) )

// Percentage of progress at which time we switch to the next image.
#define TOGGLE_BG_PERCENT			(100 / NUM_ELEMENTS(ms_apszFiles) + 1)

// Token delimiters.
#define TOKEN_DELIMITERS			"\t ,"

#define MAX_TITLES				10

#define NUM_IMAGES				NUM_ELEMENTS(ms_apszFiles)

#define MUSAK_START_TIME	0	// 11260
#define MUSAK_END_TIME		0

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

int32_t m_lTotalUnits;
int32_t m_lCummUnits;		// I will brace myself for an onslaught of jokes.
double m_adTitlePercent[MAX_TITLES+1];
static int16_t	m_sValid			= FALSE;

static int32_t		ms_lTitleRFileCallbackTime = 0;

// Indicates the currently displayed image.
static int16_t	ms_sImageNum		= 0;

// The instance of the title musak sample.
static SampleMaster::SoundInstance	ms_siMusak;
static SampleMaster::SoundInstance  ms_siEndingAudio;

static bool	ms_bDisableRipcordStaticLogo	= false;

// These are the images (in the order) to display.
//"Title/kallistios.bmp",
static char*	ms_apszFiles[]	=
	{		
	"Title/rating.bmp",	
	"Title/wave.bmp",
	"Title/chinchillaretro.bmp",
	"Title/Logo.bmp",
	"Title/Postal.bmp",
	};				 


extern PVR::cRenderMgr* g_pvrRenderer;

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

////////////////////////////////////////////////////////////////////////////////
// TitleRFileCallback
//
//	Callback that will call the Update() while the next background is being
// loaded.
//
////////////////////////////////////////////////////////////////////////////////

static void TitleRFileCallback(int32_t lBytes)
{
	int32_t lCurrentTime = rspGetMilliseconds();
	if ((lCurrentTime - ms_lTitleRFileCallbackTime) > TITLE_SOUND_UPDATE_INTERVAL)
	{
		UpdateSystem();
		ms_lTitleRFileCallbackTime = rspGetMilliseconds();
	}
}


////////////////////////////////////////////////////////////////////////////////
// Returns true if the specified string is in the comma separated list.
////////////////////////////////////////////////////////////////////////////////
static bool IsInList(	// Returns true if in list.  false otherwise.
	char*	pszSearchFor,	// In:  String to search for in pszSearchIn.
	char*	pszSearchIn)	// In:  Comma delimited list of strings to search in for
								// pszSearchFor.
	{
	bool	bFound	= false;	// Assume not found.

	// Copy to temp so strtok can tokenize leaving full of NULLs.
	char	szTokenize[512];
	strncpy(szTokenize, pszSearchIn, sizeof(szTokenize) - 1);
	szTokenize[sizeof(szTokenize) - 1] = '\0';

	// Tokenize.
	char*	pszToken	= strtok(szTokenize, TOKEN_DELIMITERS);
	while (pszToken != NULL)
		{
		if (rspStricmp(pszToken, pszSearchFor) == 0)
			{
			// Found it.
			bFound	= true;
			break;
			}

		pszToken	= strtok(NULL, TOKEN_DELIMITERS);
		}

	return bFound;
	}

////////////////////////////////////////////////////////////////////////////////
// Loads, displays, and disgards image from specified file.
////////////////////////////////////////////////////////////////////////////////
static PVR::cTexture* DisplayImage(	// Returns nothing.
	char*	pszImageFile)		// Filename of image (relative path).
	{		
						
	// Store the original callback.
	RFile::CritiCall	criticallRestore	= RFile::ms_criticall;

	// Set the callback
	RFile::ms_criticall = TitleRFileCallback;
	ms_lTitleRFileCallbackTime = rspGetMilliseconds();

	g_pvrRenderer->FlushBatchedDrawQueues();
	
	PVR::cTexture *tex = PVR::cTextureFactory::FromKmg(pszImageFile, 3, 2);
	g_pvrRenderer->DrawQuad(tex, 0,0, 640, 480, PVR::cRenderMgr::LayerBg);	

	// Restore the callback.
	RFile::ms_criticall = criticallRestore;
	return tex;
	}

////////////////////////////////////////////////////////////////////////////////
// Loads, displays, and disgards image from file specified via image num.
////////////////////////////////////////////////////////////////////////////////
static int16_t DisplayImageNum(	// Returns nothing.
	int16_t	sImageNum)				// In:  Image Num to show [1..n].
	{
	int16_t	sRes	= 0;	// Assume success.
	
	// Switch to array indexing mode.
	sImageNum--;

	// If not in list of no shows . . .
	while (sImageNum < NUM_ELEMENTS(ms_apszFiles) )
		{
		if (IsInList(ms_apszFiles[sImageNum], g_GameSettings.m_szDontShowTitles) == false)
			{
			break;
			}

		sImageNum++;
		}

	if (sImageNum < NUM_ELEMENTS(ms_apszFiles) )
		{		
			PVR::cTexture *tex;			
			switch (sImageNum)
			{
				case 0:
					tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_FIRST);
					break;
				case 1:					
					//tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_KOS);
					tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_CHINCHILLA);
					break;
				case 2:					
					//tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_KOS);
					tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_WAVE);
					
					break;
				case 3:					
					tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_SECOND);
					break;
				case 4:								
					tex = g_pvrRenderer->m_TextureRepository.Get(PVR_TEXTURE_SPLASH_THIRD);
					break;
				default:				
				break;
			}
			g_pvrRenderer->FlushBatchedDrawQueues();
			
			g_pvrRenderer->DrawQuad(tex, 0,0,640,480, PVR::cRenderMgr::LayerBg);						
			sRes	= 0;
		}
	
	return sRes;
	}

////////////////////////////////////////////////////////////////////////////////
//
// Start the title sequence, which includes some type of progress meter, which
// may or may not (hopefully not) look like a standard progress meter.  The
// total range of the progress bar is determined by lTotalUnits.  As far as
// this module is concerned, these units are completely abstract.
//
////////////////////////////////////////////////////////////////////////////////
extern int16_t StartTitle(							// Returns 0 if successfull, non-zero otherwise
	int16_t	sStartImage /*= 1*/,						// In:  Image to start with.  Values less
															// than 1 indicate a page relative to the
															// end.
	bool	bPlayMusak /*= false*/,					// In:  true to play title musak.
	SampleMaster::SoundInstance* psi /*= 0*/)	// Out:  Sound instance of musak.
	{
	int16_t sResult = 0;
		
	// Save total units and reset other stuff
	int16_t i;
	m_lTotalUnits = 0;
	for (i = 0; i < NUM_ELEMENTS(ms_apszFiles); i++)
		m_lTotalUnits += g_GameSettings.m_alTitleDurations[i];

	// Avoid divide by zero and other possible screw-ups.
	if (m_lTotalUnits <= 0)
		{
		m_lTotalUnits	= 1;
		}

	m_adTitlePercent[0] = 0;

	for (i = 0; i < NUM_ELEMENTS(ms_apszFiles); i++)
		m_adTitlePercent[i+1] = ((double) g_GameSettings.m_alTitleDurations[i] / (double) m_lTotalUnits) + m_adTitlePercent[i];	
	
	m_lCummUnits = 0;
	m_sValid = 0;

	// If value less than 1 . . .
	if (sStartImage < 1)
		{
		// It specifies a value relative to the end.
		sStartImage	+= NUM_ELEMENTS(ms_apszFiles);
		}
	

	// Display title screen		
	sResult = DisplayImageNum(sStartImage);
	if (sResult == 0)
		{
		// If told to play sample . . .
		if (bPlayMusak)
			{
			// If not already playing . . .
			if (IsSamplePlaying(ms_siMusak) == false)
				{					
				PlaySample(										// Returns nothing.
																// Does not fail.				
					g_smidTitleMusak,							// In:  Identifier of sample you want played.
					SampleMaster::BackgroundMusic,				// In:  Sound Volume Category for user adjustment
					255,										// In:  Initial Sound Volume (0 - 255)
					&ms_siMusak,								// Out: Handle for adjusting sound volume
					NULL,										// Out: Sample duration in ms, if not NULL.
					MUSAK_START_TIME,							// In:  Where to loop back to in milliseconds.
																	//	-1 indicates no looping (unless m_sLoop is
																	// explicitly set).
					MUSAK_END_TIME,								// In:  Where to loop back from in milliseconds.
																	// In:  If less than 1, the end + lLoopEndTime is used.
					true);										// In:  Call ReleaseAndPurge rather than Release after playing

				// Copy sound instance for user if given a destination for it.
				if (psi)
					{
					*psi	= ms_siMusak;
					}
				}
			}

		m_sValid				= TRUE;
		ms_sImageNum		= sStartImage;
		}
	else
		{
		TRACE("StartTitle(): Error loading %s!\n", ms_apszFiles[sStartImage - 1]);		
		}
	
	
	return sResult;
	}


////////////////////////////////////////////////////////////////////////////////
// TitleGetNumTitles - give the number of title screens in use
////////////////////////////////////////////////////////////////////////////////

extern int16_t TitleGetNumTitles(void)
	{		
		return NUM_ELEMENTS(ms_apszFiles);
	}

////////////////////////////////////////////////////////////////////////////////
//
// Update the title sequence.  The specified number of units are added to a
// running total.  The ration between the running total and the value passed to
// StartTitle() determines the new position of the progress meter.
//
////////////////////////////////////////////////////////////////////////////////
extern int16_t DoTitle(						// Returns 0 if successfull, non-zero otherwise
	int32_t lUnits)								// In:  Additional progess units
	{
	int16_t sResult = 0;	
	// Can't call this if StartTitle() didn't work
	if (m_sValid)
		{
		// Add to cummulative total
		m_lCummUnits += lUnits;

		// Calculate ratio and use it to determine how much progress bar juice
		// we should display.
		double dRatio = (double)m_lCummUnits / (double)m_lTotalUnits;
			
		// While we've passed the duration before displaying the next image.
		// This loop is intended to skip title cards that have 0 for their
		// duration.
		// NOTE that m_adTitlePercent is valid up to and including Num Images + 1.
		PVR::cTextureFactory::SetResMgr(&g_resmgrShell);		
		while (dRatio > m_adTitlePercent[ms_sImageNum])
			{
			
			// Advance image.
			if (ms_sImageNum++ < TitleGetNumTitles() )
				{								
				// If there's at least a smidgen of time allocated for this image . . .
				if (g_GameSettings.m_alTitleDurations[ms_sImageNum] )
					{					
		
					// Display new image.
					DisplayImageNum(ms_sImageNum);				
					}
				}
			else
				{
				break;
				}
			}
		
		}
	else
		{
		sResult = -1;
		TRACE("DoTitle(): It appears that StartTitle() wasn't called or didn't complete successfully!\n");
		}

	return sResult;
	}


////////////////////////////////////////////////////////////////////////////////
//
// When you are completely done, call EndTitle().  This gives the title sequence
// a chance to fully complete the progess meter (in case it never reached 100%
// due to an overestimated lTotalUnits) and allows all resources to be freed.
//
////////////////////////////////////////////////////////////////////////////////
extern int16_t EndTitle(void)				// Returns 0 if successfull, non-zero otherwise
	{
	int16_t sResult = 0;

	// It's okay to call this even if StartTitle() didn't work
	if (m_sValid)
		{
		// Display this stuff so we can easily tune the total units based on the
		// actual units that were passed to this module.
		TRACE("EndTitle(): lTotalUnits = %ld, lCummUnits = %ld\n", m_lTotalUnits, m_lCummUnits);
				
		// Always pretend we made it, even if we didn't.
		DoTitle(ABS(m_lTotalUnits - m_lCummUnits) );				
		rspUpdateDisplay();

		// Make sure last sample finishes

		while (IsSamplePlaying(g_smidTitle))
			UpdateSystem();

		// Reset.
		m_sValid	= FALSE;
		}

	// Remove all title screens apart from the main title bg.
	// todo: defines	
	g_pvrRenderer->m_TextureRepository.Delete(PVR_TEXTURE_SPLASH_FIRST);
	g_pvrRenderer->m_TextureRepository.Delete(PVR_TEXTURE_SPLASH_SECOND);
	g_pvrRenderer->m_TextureRepository.Delete(PVR_TEXTURE_SPLASH_WAVE);
	g_pvrRenderer->m_TextureRepository.Delete(PVR_TEXTURE_SPLASH_CHINCHILLA);
	//g_pvrRenderer->m_TextureRepository.Delete(PVR_TEXTURE_SPLASH_KOS);
	
	return sResult;
	}

////////////////////////////////////////////////////////////////////////////////
// Title_GameEndSequence
//
// Show the end of game sequence when the player wins.  This will include 4 
// screens and audio clips.
//
////////////////////////////////////////////////////////////////////////////////

void Title_GameEndSequence(void)
{
	int32_t lDisplayTime = 0;
	int32_t lTotalTime = 0;
	int32_t lSectionTime = 0;
	int32_t lCurrentTime;
	int32_t lUpdateTime;
	TRACE("So this is the big end of game sequence eh?\n");

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

	// Play the sound
	PlaySample(										// Returns nothing.
														// Does not fail.		
		g_smidEndingAudio,						// In:  Identifier of sample you want played.
		SampleMaster::Unspecified,				// In:  Sound Volume Category for user adjustment
		255,											// In:  Initial Sound Volume (0 - 255)
		&ms_siEndingAudio,						// Out: Handle for adjusting sound volume
		&lTotalTime,								// Out: Sample duration in ms, if not NULL.
		-1,											// In:  Where to loop back to in milliseconds.
														//	-1 indicates no looping (unless m_sLoop is
														// explicitly set).
		0,												// In:  Where to loop back from in milliseconds.
														// In:  If less than 1, the end + lLoopEndTime is used.
		true);										// In:  Call ReleaseAndPurge rather than Release after playing
	
	// Set the callback
	RFile::ms_criticall = TitleRFileCallback;
	ms_lTitleRFileCallbackTime = rspGetMilliseconds();

	// Show black while the audio starts and then put up the door when the door slam
	// sound is heard.
	lCurrentTime = rspGetMilliseconds();
	lDisplayTime = lCurrentTime + 2500;
	lTotalTime -= 2500;
	lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
	while (lCurrentTime < lDisplayTime)
	{
		if (lCurrentTime > lUpdateTime)
		{
			lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
		}
		UpdateSystem();
		// If they hit Alt-F4 then quit the loop
		if (rspGetQuitStatus())
			lCurrentTime = lDisplayTime;
		else
			lCurrentTime = rspGetMilliseconds();
	}

	PVR::cTexture *texA;
	PVR::cTexture *texB;
	PVR::cTextureFactory::SetResMgr(&g_resmgrShell);		

	// Show the door for a short time 	
	texA = DisplayImage("title/fdoor.bmp");			
	lCurrentTime = rspGetMilliseconds();
	lDisplayTime = lCurrentTime + 3000;
	lTotalTime -= 3000;
	lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
	while (lCurrentTime < lDisplayTime)
	{
		if (lCurrentTime > lUpdateTime)
		{
			lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
		}
		UpdateSystem();

		// If they hit Alt-F4, then quit the loop
		if (rspGetQuitStatus())
			lCurrentTime = lDisplayTime;
		else
			lCurrentTime = rspGetMilliseconds();
	}
	
	// Divide up the rest of the time.
	lSectionTime = lTotalTime / 4;
	
	// Display the ending backgrounds.
	texB = DisplayImage("title/corridor.bmp");			
	lDisplayTime = rspGetMilliseconds() + lSectionTime;
	lCurrentTime = rspGetMilliseconds();
	lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
	UpdateSystem();
	delete texA;
	while (lCurrentTime < lDisplayTime)
	{
		if (lCurrentTime > lUpdateTime)
		{
			lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
		}		
		UpdateSystem();		
		// If they hit Alt-F4, then quit the loop
		if (rspGetQuitStatus())
			lCurrentTime = lDisplayTime;
		else
			lCurrentTime = rspGetMilliseconds();
	}
	
	texA = DisplayImage("title/jacketbg.bmp");	
	lDisplayTime = rspGetMilliseconds() + lSectionTime;
	lCurrentTime = rspGetMilliseconds();
	lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
	UpdateSystem();
	delete texB;
	while (lCurrentTime < lDisplayTime)
	{
		if (lCurrentTime > lUpdateTime)
		{
			lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
		}
		UpdateSystem();
		// If they hit Alt-F4, then quit the loop
		if (rspGetQuitStatus())
			lCurrentTime = lDisplayTime;
		else
			lCurrentTime = rspGetMilliseconds();
	}

	texB = DisplayImage("title/torture2.bmp");
	lDisplayTime = rspGetMilliseconds() + lSectionTime;
	lCurrentTime = rspGetMilliseconds();
	lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
	UpdateSystem();
	delete texA;
	while (lCurrentTime < lDisplayTime)
	{
		if (lCurrentTime > lUpdateTime)
		{
			lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
		}
		UpdateSystem();
		// If they hit Alt-F4, then quit the loop
		if (rspGetQuitStatus())
			lCurrentTime = lDisplayTime;
		else
			lCurrentTime = rspGetMilliseconds();
	}

	texA = DisplayImage("title/fdoor.bmp");
	lDisplayTime = rspGetMilliseconds() + lSectionTime;
	lCurrentTime = rspGetMilliseconds();
	lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
	UpdateSystem();
	delete texB;
	while (lCurrentTime < lDisplayTime)
	{
		if (lCurrentTime > lUpdateTime)
		{
			lUpdateTime = lCurrentTime + TITLE_SOUND_UPDATE_INTERVAL;
		}
		UpdateSystem();
		// If they hit Alt-F4, then quit the loop
		if (rspGetQuitStatus())
			lCurrentTime = lDisplayTime;
		else
			lCurrentTime = rspGetMilliseconds();
	}

	g_pvrRenderer->ClearScreen(true);
	UpdateSystem();

	delete texA;	

	// Unset the callback
	RFile::ms_criticall = 0;
}

////////////////////////////////////////////////////////////////////////////////
// Disable RipCord static logo.
////////////////////////////////////////////////////////////////////////////////
extern void Title_DisableRipcordStaticLogo(void)
	{
	ms_bDisableRipcordStaticLogo	= true;
	}

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