
/* ================================================================
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL DINGOO GAMES OR ITS CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* ====================================================================
*/ 

///////////////////////////////////////////////////////////////////////////////
// Wonderswan emulator
////////////////////////////////////////////////////////////////////////////////
//
// 13.04.2002: Fixed a small bug causing crashes
//
//
//
//
//////////////////////////////////////////////////////////////////////////////

#include "../inc/GameEngine.h"

INT16 *backbuffer;
INT16 *linesbuffer;

//--------------------------------------------------------------------------------------------------------
GameEngine::GameEngine( void* userdata [] ) : Engine( userdata )
{
	app_gameRunning=0;
	app_terminate=0;
	app_fullscreen=0;

	app_rotated=0;

	ws_videoEnhancementType=0;
	ws_colourScheme=COLOUR_SCHEME_DEFAULT;
	ws_system=WS_SYSTEM_AUTODETECT;

	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN\\Roms\\0025 - Puzzle Bobble.ws";
	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN\\Roms\\0021 - Pocket Fighter.ws";
	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN\\Roms\\0020 - Terrors.ws";
	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN COLOR\\Roms\\0033 - Final Fantasy II (JP).wsc";
	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN COLOR\\Roms\\0171 - Hunter X Hunter - Greed Island (JP).wsc";
	//ws_rom_path = "F:\\EMUGAMES\\WONDERSWAN COLOR\\Roms\\0173 - Riviera - Yakusoku no Chi Riviera (JP).wsc";

	//ws_rom_path = ".\\0173.wsc";
	ws_rom_path = ".\\0171.wsc";
}
//--------------------------------------------------------------------------------------------------------
GameEngine::~GameEngine( void )
{
	Free();
}
//--------------------------------------------------------------------------------------------------------
/// init all resources
result GameEngine::Init( void )
{
	char fullname[256] = ".\\Init.log";

	FILE* m_fp = fopen( fullname, _LS("wb+") );

	if(m_fp == NULL){
		return(S2D_UNKNOWN);
	}

	InitDLRes();
	// 16 FPS
	SetFPS( 60 );

	fprintf(m_fp,"SetFPS:  0x%.2x\n",24);

	ws_colourScheme = 0;

	if (ws_rom_path)
	{
		fprintf(m_fp,"ws_rom_path rom:  0x%.2x\n",ws_rom_path);

		if (ws_init(ws_rom_path))
		{
			fprintf(m_fp,"ws_init rom:  0x%.2x\n",ws_rom_path);

			app_rotated=ws_rotated();

			if (app_rotated)
			{
				A320_SCREEN_WIDTH = 240;
				A320_SCREEN_HEIGHT = 320;
			}
			else{  
				A320_SCREEN_WIDTH = 320;
				A320_SCREEN_HEIGHT = 240;
			}

			app_gameRunning=1;
			ws_set_system(ws_system);

			fprintf(m_fp,"ws_set_system rom:  0x%.2x\n",ws_system);

			ws_set_colour_scheme(ws_colourScheme);
			ws_reset();

			nNormalLast=0;
			nNormalFrac=0; 
			nTime=0;
			nCount=0;

			linesbuffer=(INT16*)malloc(A320_SCREEN_WIDTH*A320_SCREEN_HEIGHT*sizeof(INT16));
			backbuffer=(INT16*)malloc(A320_SCREEN_WIDTH*A320_SCREEN_HEIGHT*sizeof(INT16));

			memset((char*)linesbuffer,0x00,A320_SCREEN_WIDTH*A320_SCREEN_HEIGHT*sizeof(INT16));
			memset((char*)backbuffer,0x00,A320_SCREEN_WIDTH*A320_SCREEN_HEIGHT*sizeof(INT16));

			totalFrames=0;

			//startTime=clock();
			startTime=GetCurTime();
			nNormalLast=0; // Last value of timeGetTime()
			nNormalFrac=0; // Extra fraction we did
			nNormalLast=GetCurTime();
		}
	}

	// close file
	fclose(m_fp);

	return S2D_OK;
}
//--------------------------------------------------------------------------------------------------------
/// free all resources
void GameEngine::Free( void )
{
	ReleaseDLRes();
}
//--------------------------------------------------------------------------------------------------------
/// game logic before render
void GameEngine::Exec( void )
{

}
//--------------------------------------------------------------------------------------------------------
/// game logic after render
void GameEngine::Exec2( void )
{

}
//--------------------------------------------------------------------------------------------------------
/// pre-render proccess
void GameEngine::PreRender( void )
{

}
//--------------------------------------------------------------------------------------------------------
/// render
void GameEngine::Render( void )
{
	ws_emulate_standard(); 
	//ws_emulate_full();
}
//--------------------------------------------------------------------------------------------------------
void GameEngine::PostRender( void )
{
}

//--------------------------------------------------------------------------------------------------------
void GameEngine::DispDebugInfo( void )
{
}

//--------------------------------------------------------------------------------------------------------
void GameEngine::EnterGame( s32 MapId )
{ 

}
//--------------------------------------------------------------------------------------------------------
void GameEngine::ExitGame( void )
{
	Exit();
}
//--------------------------------------------------------------------------------------------------------
void GameEngine::PutHorizontalPixel(int x, int y, UINT16 color)
{
	Pixel* ptr = m_pDraw2D->GetVRAMPtr();

	UINT16 r,g,b;

	UINT16 red_mask = 0x7C00;
	UINT16 green_mask = 0x3E0;
	UINT16 blue_mask = 0x1F;

	r = (color & red_mask) >> 10;
	g = (color & green_mask) >> 5;
	b = (color & blue_mask);

	// Expand to 8-bit values:
	UINT16 red   = r << 3;
	UINT16 green = g << 3;
	UINT16 blue  = b << 3;

	Pixel color1(red,green,blue);
	s32 ofs = (x*A320_SCREEN_WIDTH) + (y);

	ptr[ofs] = color1;
}

//--------------------------------------------------------------------------------------------------------
void GameEngine::ws_emulate_standard(void)
{
	nTime=GetCurTime()-nNormalLast;     // calcule le temps écoulé depuis le dernier affichage

	// nTime est en mili-secondes.
	// détermine le nombre de trames à passer + 1
	nCount=(nTime*600 - nNormalFrac) /10000;  

	// si le nombre de trames à passer + 1 est nul ou négatif, ne rien faire pendant 2 ms
	if (nCount<=0) 
	{ 
		Sleep(2); 
	} // No need to do anything for a bit
	else
	{
		nNormalFrac+=nCount*10000;  // 
		nNormalLast+=nNormalFrac/600;  // add the duration of nNormalFrac frames
		nNormalFrac%=600;    // 

		// Pas plus de 9 (10-1) trames non affichées 
		if (nCount>10) 
			nCount=10; 

		int ws_key_esc=0;
		ws_key_start=0;
		ws_key_left=0;
		ws_key_right=0;
		ws_key_up=0;
		ws_key_down=0;
		ws_key_button_1=0;
		ws_key_button_2=0;

		if( m_pInput->IsKeyClick(KEY_R1) ){
			ws_key_esc = 1;
		}
		if( m_pInput->IsKeyClick(KEY_UP) ){
			ws_key_up = 1;
		}
		if( m_pInput->IsKeyClick(KEY_DN) ){
			ws_key_down = 1;
		}
		if( m_pInput->IsKeyClick(KEY_RT) ){
			ws_key_right = 1;
		}
		if( m_pInput->IsKeyClick(KEY_LF) ){
			ws_key_left = 1;
		}
		if( m_pInput->IsKeyClick(KEY_OK) ){
			ws_key_start = 1;
		}
		if( m_pInput->IsKeyClick(KEY_0) ){
			ws_key_button_1 = 1;
		}
		if( m_pInput->IsKeyClick(KEY_1) ){
			ws_key_button_2 = 1;
		}
		if( m_pInput->IsKeyClick(KEY_2) ){
			ws_cyclesByLine+=10;
		}
		if( m_pInput->IsKeyClick(KEY_3) ){
			ws_cyclesByLine-=10;
		}

		for (i=0;i<nCount-1;i++) 
			while (!ws_executeLine(backbuffer,0));

		while (!ws_executeLine(backbuffer,1));
		totalFrames++;
	}

	if (app_rotated)
	{
	}
	else
	{
		static INT16 temp[320*240];
		memcpy((char*)temp,(char*)backbuffer,A320_SCREEN_WIDTH*A320_SCREEN_HEIGHT*sizeof(INT16));

		for (int line=0;line<144;line++)
			for (int column=0;column<224;column++)
				PutHorizontalPixel(line+40,column+50,temp[column+(line<<7)+(line<<6)+(line<<5)]);
	}
}
//--------------------------------------------------------------------------------------------------------
void GameEngine::ws_emulate_full(void)
{
	nTime=GetCurTime()-nNormalLast;     // calcule le temps écoulé depuis le dernier affichage

	// nTime est en mili-secondes.
	// détermine le nombre de trames à passer + 1
	nCount=(nTime*600 - nNormalFrac) /10000;  

	// si le nombre de trames à passer + 1 est nul ou négatif, ne rien faire pendant 2 ms
	if (nCount<=0) 
	{ 
		Sleep(2); 
	} // No need to do anything for a bit
	else
	{
		nNormalFrac+=nCount*10000;  // 
		nNormalLast+=nNormalFrac/600;  // add the duration of nNormalFrac frames
		nNormalFrac%=600;    // 

		// Pas plus de 9 (10-1) trames non affichées 
		if (nCount>10) 
			nCount=10; 

		int ws_key_esc=0;
		ws_key_start=0;
		ws_key_left=0;
		ws_key_right=0;
		ws_key_up=0;
		ws_key_down=0;
		ws_key_button_1=0;
		ws_key_button_2=0;

		if( m_pInput->IsKeyClick(KEY_R1) ){
			ws_key_esc = 1;
		}
		if( m_pInput->IsKeyClick(KEY_UP) ){
			ws_key_up = 1;
		}
		if( m_pInput->IsKeyClick(KEY_DN) ){
			ws_key_down = 1;
		}
		if( m_pInput->IsKeyClick(KEY_RT) ){
			ws_key_right = 1;
		}
		if( m_pInput->IsKeyClick(KEY_LF) ){
			ws_key_left = 1;
		}
		if( m_pInput->IsKeyClick(KEY_OK) ){
			ws_key_start = 1;
		}
		if( m_pInput->IsKeyClick(KEY_0) ){
			ws_key_button_1 = 1;
		}
		if( m_pInput->IsKeyClick(KEY_1) ){
			ws_key_button_2 = 1;
		}
		if( m_pInput->IsKeyClick(KEY_2) ){
			ws_cyclesByLine+=10;
		}
		if( m_pInput->IsKeyClick(KEY_3) ){
			ws_cyclesByLine-=10;
		}

		for (i=0;i<nCount-1;i++) 
			while (!ws_executeLine(backbuffer,0));

		while (!ws_executeLine(backbuffer,1));
			totalFrames++;
	}

	if (app_rotated)
	{
	}
	else
	{
		static INT16 temp[320*240];
		memcpy((char*)temp,(char*)backbuffer,A320_SCREEN_WIDTH*A320_SCREEN_HEIGHT*sizeof(INT16));

		for (int line=0;line<A320_SCREEN_HEIGHT;line++)
			for (int column=0;column<A320_SCREEN_WIDTH;column++)
			{
				PutHorizontalPixel(line,column,temp[(column>>1)+(line<<6)+(line<<5)+(line<<4)]);
			}
	}
}

//--------------------------------------------------------------------------------------------------------
__inline void GameEngine::ws_drawDoubledScanline(INT16 *vs, INT16 *backbuffer_alias)
{
	register INT32 *vs_alias=(INT32*)vs;
	register INT32 data;

	for (int pixel=0;pixel<224;pixel+=8)
	{
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
		data=*backbuffer_alias++; data|=(data<<16); *vs_alias++=data; 
	}
}


//--------------------------------------------------------------------------------------------------------
Input* GameEngine::GetInput( void )
{ 
	return m_pInput;
}