// GBMachine.h: interface for the CGBMachine class.
//
//////////////////////////////////////////////////////////////////////

#if !defined(AFX_GBMACHINE_H__B4428095_51EF_4DD3_8F6E_8A7CC25E8B62__INCLUDED_)
#define AFX_GBMACHINE_H__B4428095_51EF_4DD3_8F6E_8A7CC25E8B62__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "platform.h"

// class CZ80m;
// class CMemory;
#include "Z80m.h"
#include "Memory.h"
#include "mbc.h"
#include "config.h"
#include "interrupt.h"
#include "Input.h"


#if defined(NMGB_PLATFORM_WIN32)
	#define GB_RGB(r,g,b) ((r)|((g)<<5)|((b)<<10))
#elif defined(NMGB_PLATFORM_NDS)
	#define GB_RGB(r,g,b) (((r)|((g)<<5)|((b)<<10)) | BIT(15))
#elif defined(NMGB_PLATFORM_3DS)
	#define GB_RGB(r,g,b) ((r<<19)|(g<<11)|(b<<3))
#endif

class CGBMachine
{
public:
	CGBMachine(const char* sInnerROMFile);
	virtual ~CGBMachine();
	void Init();
	void SetMBC(CMBC* pMBC);
public:

	//ENABLE_HW
	inline u32 EnableHW()
	{
		return m_dwEnableHW;
	}
	inline void EnableHW(u32 dwEnableHW)
	{
		m_dwEnableHW |= dwEnableHW;
	}
	inline void DisableAllHW()
	{
		m_dwEnableHW = 0;	
	}

	//HWType
	inline EHWType GetHWType()
	{
		return m_HWType;
	}
	inline void SetHWType(EHWType type)
	{
		m_HWType = type;
	}

	//IME
	inline bool IME()
	{
		return m_bIME;
	}
	inline void IME(bool bIME)
	{
		m_bIME = bIME;
	}

	//STOP
// 	inline bool Stop()
// 	{
// 		return m_bStop;
// 	}
// 	inline void Stop(bool bStop)
// 	{
// 		m_bStop = bStop;
// 	}

	//HALT
	inline int HaltStop()
	{
		return m_nHaltStop;
	}
	inline void HaltStop(int nState)
	{
		m_nHaltStop = nState;
	}

	virtual void LoadInnerROM(const char* sInnerROMFile, u32 InnerROMSize = 256);

	virtual void DrawScanLine();

	inline bool BootingInnerROM()
	{
		return m_bBootingInnerROM;
	}
	inline void BootingInnerROM(bool bBoot)
	{
		m_bBootingInnerROM = bBoot;
	}
	inline u8* InnerROM()
	{
		return m_pInnerROM;
	}
	inline CMBC* GetMBC()
	{
		return m_pMBC;
	}

	inline CMemory* GetMemory()
	{
		return &m_Memory;
	}

	inline CZ80m* GetCPU()
	{
		return &m_CPU;
	}
	
	inline void Start()
	{
		m_CPU.ExecStep();
	}
	//////////////////////////////////////////////////////////////////////////
	inline u32 GetGray(u32 number)
	{
		return m_nPalettes[number & 3];
	}
	inline void SetFrameBuffer(u8* framebuffer1, u8* framebuffer2)
	{
		#if defined(NMGB_PLATFORM_3DS)
			m_pFrameBuffer[0] = framebuffer1;
			m_pFrameBuffer[1] = framebuffer2;
		#else
			m_pFrameBuffer[0] = (u16*)framebuffer1;
			m_pFrameBuffer[1] = (u16*)framebuffer2;
		#endif
	}
 	inline void SetKeyState(int n, u32 key)
 	{
 		m_Input.SetKey(n, key);
 	}
 	
private:
	u32				m_dwEnableHW;
	EHWType			m_HWType;
	//////////////////////////////////////////////////////////////////////////
	CZ80m			m_CPU;
	CMemory			m_Memory;
	CInterrupt		m_Interrupt;
	CInput			m_Input;
	CMBC*			m_pMBC;
	//////////////////////////////////////////////////////////////////////////
	u8*				m_pInnerROM; 

	bool			m_bIME;
	int				m_nHaltStop;
	bool			m_bStop;
	bool			m_bHalt;
	bool			m_bBootingInnerROM;

	u32				m_nPalettes[4];
public:
#if defined(NMGB_PLATFORM_3DS)
	u8*				m_pFrameBuffer[2];
 	inline void putpixel_FB(int y, int x, u32 color)
	{
		static int x_,y_,yy,base_index;
		x_ = 239 - y;
		y_ = x;
		yy=(y_<<8)-(y_<<4);
		base_index = 3*(x_+yy);
		m_pFrameBuffer[m_nCurFrame][base_index] 	= color & 0xff;				//b
		m_pFrameBuffer[m_nCurFrame][base_index+1]	= (color>>8) & 0xff;	//g
		m_pFrameBuffer[m_nCurFrame][base_index+2]	= (color>>16) & 0xff;	//r
	}	
#else
	u16*				m_pFrameBuffer[2];
#endif	
	u8				m_nCurFrame;
	//int				m_nCurrentScanLine; //Scan Line
public:
	static u8		m_cNintendoLogo[0x30];
};

typedef class CGBMachine	CGBPMachine;

class CGBCMachine : public CGBMachine
{
public:
	CGBCMachine(const char* sInnerROMFile);
public:
	void DrawScanLine();
};

class CSGBMachine : public CGBMachine
{
public:
	CSGBMachine(const char* sInnerROMFile);
public:
	void DrawScanLine();
};

extern CGBMachine*	g_pGameBoy;

#endif // !defined(AFX_GBMACHINE_H__B4428095_51EF_4DD3_8F6E_8A7CC25E8B62__INCLUDED_)
