
/* ================================================================
* 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 temp[224*144];

//--------------------------------------------------------------------------------------------------------
GameEngine::GameEngine( void* userdata [] ) : Engine( userdata )
{
	s2d::Log::On();

	s2d::Log::Output("INICIANDO....\n");

	//Init pointer to VRAM
	ptr = m_pDraw2D->GetVRAMPtr();

	//Init mask to convert RGB565
	red_mask = 0x7C00;
	green_mask = 0x3E0;
	blue_mask = 0x1F;

	//Clear 
	m_pDraw2D->Clear(255,255,255);

	//Init variables
	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;

	//ROM
	ws_rom_path = (char*)userdata[2];
	ws_rom_path = ".\\GAME\\WSC\\0178.ws";

	//Init texture
	m_pImgS2d = new Texture();

	//Paint Area
	rcTest.left = 0;
	rcTest.top = 0;
	rcTest.right = 320;
	rcTest.bottom = 240;
}
//--------------------------------------------------------------------------------------------------------
GameEngine::~GameEngine( void )
{
	Free();
}
//--------------------------------------------------------------------------------------------------------
/// init all resources
result GameEngine::Init( void )
{
	InitDLRes();
	// 16 FPS
	SetFPS( 32 );

	ws_colourScheme = 0;

	if (ws_rom_path)
	{
		s2d::Log::Output("ws_rom_path rom:  %s \n", ws_rom_path);

		if (ws_init(ws_rom_path))
		{
			s2d::Log::Output("ws_init rom:  %s \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);
			ws_set_colour_scheme(ws_colourScheme);
			ws_reset();

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

			totalFrames=0;

			nTime=0;
			nCount=0;
			startTime=GetCurTime();
			nNormalLast=0; // Last value of timeGetTime()
			nNormalFrac=0; // Extra fraction we did
			nNormalLast=GetCurTime();
		}else{
			ExitGame();
		}
	}

	return S2D_OK;
}
//--------------------------------------------------------------------------------------------------------
/// free all resources
void GameEngine::Free( void )
{
	ReleaseDLRes();
	//m_Scene.Free();
	//SAFE_DELETE_ARRAY( m_pAudioData );
	//m_TexMgr.FreeAll();
}
//--------------------------------------------------------------------------------------------------------
/// 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::PutPixel(int x, int y, UINT16 color)
{
	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::ConvertFormat()
{
	for (int line=0;line<144;line++){
		for (int column=0;column<224;column++){
			r = (backbuffer[column+(line<<7)+(line<<6)+(line<<5)] & red_mask) >> 10;
			g = (backbuffer[column+(line<<7)+(line<<6)+(line<<5)] & green_mask) >> 5;
			b = (backbuffer[column+(line<<7)+(line<<6)+(line<<5)] & blue_mask);

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

			Pixel color1(red,green,blue);
			backbuffer[column+(line<<7)+(line<<6)+(line<<5)]=color1.m_rgb;
		}
	}
}
//--------------------------------------------------------------------------------------------------------
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<=10) 
	{ 
		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; 

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

		while (!ws_executeLine(backbuffer,1));
		
		//frames
		totalFrames++;

		if (app_rotated){
			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++){
					PutPixel(line+40,column+50,temp[column+(line<<7)+(line<<6)+(line<<5)]);
				}
				JoyPadControl();
			}
		}
		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++){
					PutPixel(line+40,column+50,temp[column+(line<<7)+(line<<6)+(line<<5)]);
				}
				JoyPadControl();
			}
		}
	}
}
//--------------------------------------------------------------------------------------------------------
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<=10) 
	{ 
		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; 

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

		while (!ws_executeLine(backbuffer,1));
		
		//frames
		totalFrames++;
	
		if (app_rotated){
			JoyPadControl();

			ConvertFormat();
			memcpy((char*)temp,(char*)backbuffer,224*144*sizeof(INT16));

			m_pImgS2d->CreateFromMemory(TF_TRUECOLOR,224,144,&temp,sizeof(INT16),NULL);

			m_pDraw2D->SetTexture( m_pImgS2d );		
			m_pDraw2D->DrawStretchOverlay(rcTest,NULL);
			m_pImgS2d->Free();
		}
		else{
			JoyPadControl();

			ConvertFormat();
			memcpy((char*)temp,(char*)backbuffer,224*144*sizeof(INT16));		

			m_pImgS2d->CreateFromMemory(TF_TRUECOLOR,224,144,&temp,sizeof(INT16),NULL);

			m_pDraw2D->SetTexture( m_pImgS2d );		
			m_pDraw2D->DrawStretchOverlay(rcTest,NULL);
			m_pImgS2d->Free();
		}
	}

}

//--------------------------------------------------------------------------------------------------------
Input* GameEngine::GetInput( void )
{ 
	return m_pInput;
}
//--------------------------------------------------------------------------------------------------------
void GameEngine::JoyPadControl(void)
{
	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->IsKeyDown(KEY_UP) ){
		ws_key_up = 1;
		//s2d::Log::Output("KeyClick KEY_UP \n");
	}
	if( m_pInput->IsKeyDown(KEY_DN) ){
		ws_key_down = 1;
		//s2d::Log::Output("KeyClick KEY_DN \n");
	}
	if( m_pInput->IsKeyDown(KEY_RT) ){
		ws_key_right = 1;
		//s2d::Log::Output("KeyClick KEY_RT \n");
	}
	if( m_pInput->IsKeyDown(KEY_LF) ){
		ws_key_left = 1;
		//s2d::Log::Output("KeyClick KEY_LF \n");
	}
	
	//SKEY_3  - A
	if( m_pInput->IsKeyDown(KEY_0) ){
		ws_key_button_1 = 1;
		//s2d::Log::Output("KeyClick KEY_0 \n");
	}
	//SKEY_1  - B
	if( m_pInput->IsKeyDown(KEY_1) ){
		ws_key_button_2 = 1;
		//s2d::Log::Output("KeyClick KEY_1 \n");
	}

	//SKEY_3  - X
	if( m_pInput->IsKeyDown(KEY_3) ){
		ws_cyclesByLine+=10;
		s2d::Log::Output("KeyClick KEY_3 - X _______ ws_cyclesByLine= %i \n", ws_cyclesByLine);
	}
	//SKEY_4  - Y
	if( m_pInput->IsKeyDown(KEY_4) ){
		ws_cyclesByLine-=10;
		s2d::Log::Output("KeyClick KEY_4 - Y _______ ws_cyclesByLine= %i \n", ws_cyclesByLine);
	}

	//SKEY_9 - POWER
	if( m_pInput->IsKeyDown(KEY_9) ){
		//s2d::Log::Output("KeyClick KEY_9 - POWER\n");
		ws_reset();
		ExitGame();
	}

	//SKEY_SELECT - SELECT
	if( m_pInput->IsKeyDown(KEY_L1) ){
		//s2d::Log::Output("KeyClick KEY_L1 - SELECT \n");
	}
	//SKEY_SELECT - START
	if( m_pInput->IsKeyDown(KEY_R1) ){
		ws_key_start = 1;
		//s2d::Log::Output("KeyClick KEY_R1 - START \n");
	}

	//SKEY_L - L
	if( m_pInput->IsKeyDown(KEY_L2) ){
		//s2d::Log::Output("KeyClick KEY_L2 - L \n");
	}
	//SKEY_R - R
	if( m_pInput->IsKeyDown(KEY_R2) ){
		//s2d::Log::Output("KeyClick KEY_R2 - R \n");
	}

	//TODO: OTROS BOTONES SIN MAPEAR
	if( m_pInput->IsKeyDown(KEY_OK) ){
		s2d::Log::Output("KeyClick KEY_OK \n");
	}
	if( m_pInput->IsKeyDown(KEY_2) ){
		s2d::Log::Output("KeyClick KEY_2 \n");
	}
	if( m_pInput->IsKeyDown(KEY_5) ){
		s2d::Log::Output("KeyClick KEY_5 \n");
	}
	if( m_pInput->IsKeyDown(KEY_6) ){
		s2d::Log::Output("KeyClick KEY_6 \n");
	}
	if( m_pInput->IsKeyDown(KEY_7) ){
		s2d::Log::Output("KeyClick KEY_7 \n");
	}
	if( m_pInput->IsKeyDown(KEY_8) ){
		s2d::Log::Output("KeyClick KEY_8 \n");
	}

}