// ScreenD2D.cpp: файл реализации
//

#include "stdafx.h"
#include "BK.h"
#include "Board.h"
#include "Screen.h"

template<class Interface>
inline void
SafeRelease(
    Interface **ppInterfaceToRelease
)
{
	if (*ppInterfaceToRelease != NULL)
	{
		(*ppInterfaceToRelease)->Release();
		(*ppInterfaceToRelease) = NULL;
	}
}

#define Color_Black         0x000000
#define Color_Red           0xff0000
#define Color_Green         0x00ff00
#define Color_Blue          0x0000ff
#define Color_Yellow        0xffff00
#define Color_Cyan          0x00ffff
#define Color_Magenta       0xff00ff
#define Color_Brown         0x800000
#define Color_Violet        0x8000ff
#define Color_DarkRed       0xcc0000
#define Color_White         0xffffff
#define Color_LightGreen    0x80ff00
#define Color_Salatovyi     0x00ff80
#define Color_VioletBlue    0x3333cc
const DWORD CScreen::ScreenView_ColorPalettes[16][4] =
{
	//                                                            Palette#     01           10          11
	Color_Black, Color_Blue, Color_Green, Color_Red,                // 00    синий   |   зеленый  |  красный
	Color_Black, Color_Yellow, Color_Magenta, Color_Red,            // 01   желтый   |  сиреневый |  красный
	Color_Black, Color_Cyan, Color_Blue, Color_Magenta,             // 02   голубой  |    синий   | сиреневый
	Color_Black, Color_Green, Color_Cyan, Color_Yellow,             // 03   зеленый  |   голубой  |  желтый
	Color_Black, Color_Magenta, Color_Cyan, Color_White,            // 04  сиреневый |   голубой  |   белый
	Color_Black, Color_White, Color_White, Color_White,             // 05    белый   |    белый   |   белый
	Color_Black, Color_DarkRed, Color_Brown, Color_Red,             // 06  темн-красн| красн-корич|  красный !!!
	Color_Black, Color_LightGreen, Color_Green, Color_Yellow,       // 07  салатовый | светл-зелен|  желтый  !!!
	Color_Black, Color_Violet, Color_VioletBlue, Color_Magenta,     // 08  фиолетовый| фиол-синий | сиреневый !!!
	Color_Black, Color_LightGreen, Color_VioletBlue, Color_Brown,   // 09 светл-зелен| фиол-синий |красн-корич !!!
	Color_Black, Color_Green, Color_Violet, Color_DarkRed,          // 10  салатовый | фиолетовый |темн-красный !!!
	Color_Black, Color_Cyan, Color_Yellow, Color_Red,               // 11   голубой  |   желтый   |  красный
	Color_Black, Color_Red, Color_Green, Color_Cyan,                // 12   красный  |   зеленый  |  голубой
	Color_Black, Color_Cyan, Color_Yellow, Color_White,             // 13   голубой  |   желтый   |   белый
	Color_Black, Color_Yellow, Color_Green, Color_White,            // 14   желтый   |   зеленый  |   белый
	Color_Black, Color_Cyan, Color_Green, Color_White,              // 15   голубой  |   зеленый  |   белый
};
//0,1,2,3
const DWORD CScreen::MonochromePalette[2][4] =
{
	Color_Black, Color_White, Color_Black, Color_White,
	Color_Black, Color_Black, Color_White, Color_White
};

const DWORD CScreen::AdaptMonochromePalette[2][4] =
{
	Color_Black, 0x999999, 0xcccccc, Color_White,
	Color_Black, 0x999999, 0xcccccc, Color_White
};

// CScreen
const int CScreen::TEXTURE_WIDTH  = (SCREEN_WIDTH   *TEXTURE_MULTIPLER_X);
const int CScreen::TEXTURE_HEIGHT = (SCREEN_HEIGHT *TEXTURE_MULTIPLER_Y);

// const double CScreen::BK_ASPECT_RATIO = (1.0);
// const int CScreen::BK_SCREEN_HEIGHT = 512;
// const int CScreen::BK_SCREEN_WIDTH = (int)(BK_SCREEN_HEIGHT * (BK_ASPECT_RATIO)+1);
const double CScreen::BK_ASPECT_RATIO = ((double)4 / 3);
const int CScreen::BK_SCREEN_WIDTH = (768);
const int CScreen::BK_SCREEN_HEIGHT = (int)(BK_SCREEN_WIDTH / (BK_ASPECT_RATIO));

IMPLEMENT_DYNAMIC(CScreen, CWnd)

CScreen::CScreen(void)
	: m_pParent(NULL)
	, m_hwndScreen(NULL)  // Screen View window handle
	, m_pDirect2dFactory(NULL)
	, m_pRenderTarget(NULL)
	, m_pRenderTargetFS(NULL)
	, m_pCurrentRenderTarget(NULL)
	, m_pBitmap(NULL)
	, m_bits(NULL)
	, m_colTable32(NULL)
	, m_monTable32(NULL)
	, m_nOfs(0330)
	, m_nPaletteNum(0)
	, m_bMWHdn(FALSE)

	, m_bColorMode(TRUE)
	, m_bFullScreen(FALSE)
	, m_bExtended(FALSE)
	, m_bAdapt(FALSE)
{
	m_nFrame = 0;
	m_curFPS = 0;
	m_msec = GetTickCount();
}

CScreen::~CScreen(void)
{
	ScreenView_Done();
}


BEGIN_MESSAGE_MAP(CScreen, CWnd)
	ON_WM_CREATE()
	ON_WM_SETFOCUS()
	ON_WM_LBUTTONDOWN()
END_MESSAGE_MAP()



// обработчики сообщений CScreen
HRESULT CScreen::ScreenView_Init()
{
	ASSERT(m_hwndScreen != NULL);
	HRESULT hr;
	InitColorTables();
	m_nPitch = TEXTURE_WIDTH * sizeof(DWORD);
	m_bits = new DWORD[TEXTURE_WIDTH * TEXTURE_HEIGHT];
	ZeroMemory(m_bits, TEXTURE_WIDTH * TEXTURE_HEIGHT * sizeof(DWORD));
	// Create a Direct2D factory.
	hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pDirect2dFactory);

	if (SUCCEEDED(hr))
	{
		D2D1_RENDER_TARGET_PROPERTIES rtprop = D2D1::RenderTargetProperties();
		D2D1_PIXEL_FORMAT pixelFormat = D2D1::PixelFormat(
		                                    DXGI_FORMAT_B8G8R8A8_UNORM, //поддерживается только _UNORM
		                                    D2D1_ALPHA_MODE_IGNORE
		                                );
		rtprop.pixelFormat = pixelFormat;
		m_pDirect2dFactory->GetDesktopDpi(&rtprop.dpiX, &rtprop.dpiY);
		RECT rc; //размеры окна оконного режима
		::GetClientRect(m_hwndScreen, &rc);
		D2D1_SIZE_U size = D2D1::SizeU(
		                       rc.right - rc.left,
		                       rc.bottom - rc.top
		                   );
		m_rectWnd.left = 0.0f;
		m_rectWnd.top = 0.0f;
		m_rectWnd.right = (FLOAT)size.width;
		m_rectWnd.bottom = (FLOAT)size.height;
		rtprop.type = D2D1_RENDER_TARGET_TYPE_HARDWARE; //с D2D1_RENDER_TARGET_TYPE_HARDWARE работает только DXGI_FORMAT_R8G8B8A8
		//DXGI_FORMAT_B8G8R8A8 работает со всеми типами, _HARDWARE _SOFTWARE, _DEFAULT
		// Create a Direct2D render target.
		hr = m_pDirect2dFactory->CreateHwndRenderTarget(
		         rtprop,
		         D2D1::HwndRenderTargetProperties(m_hwndScreen, size),
		         &m_pRenderTarget
		     );

		if (FAILED(hr))
		{
			//если не удалось включить хардварное ускорение
			rtprop.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
			hr = m_pDirect2dFactory->CreateHwndRenderTarget(
			         rtprop,
			         D2D1::HwndRenderTargetProperties(m_hwndScreen, size),
			         &m_pRenderTarget
			     );
			//попробуем то, что предлагается по умолчанию.
		}

		if (SUCCEEDED(hr))
		{
			//теперь надо создать битмап
			D2D1_SIZE_U bmpsize;
			bmpsize.width = TEXTURE_WIDTH;
			bmpsize.height = TEXTURE_HEIGHT;
			D2D1_BITMAP_PROPERTIES bmprp = D2D1::BitmapProperties();
			bmprp.pixelFormat = pixelFormat;
			hr = m_pRenderTarget->CreateBitmap(bmpsize, bmprp, &m_pBitmap);
		}
		//теперь то же самое, но для полноэкранного режима
		size = D2D1::SizeU(
		           m_rectFullScreen.right - m_rectFullScreen.left,
		           m_rectFullScreen.bottom - m_rectFullScreen.top
		       );
		rtprop.type = D2D1_RENDER_TARGET_TYPE_HARDWARE; //с D2D1_RENDER_TARGET_TYPE_HARDWARE работает только DXGI_FORMAT_R8G8B8A8
		//DXGI_FORMAT_B8G8R8A8 работает со всеми типами, _HARDWARE _SOFTWARE, _DEFAULT
		// Create a Direct2D render target.
		hr = m_pDirect2dFactory->CreateHwndRenderTarget(
		         rtprop,
		         D2D1::HwndRenderTargetProperties(m_hwndFullScreen, size),
		         &m_pRenderTargetFS
		     );

		if (FAILED(hr))
		{
			//если не удалось включить хардварное ускорение
			rtprop.type = D2D1_RENDER_TARGET_TYPE_DEFAULT;
			hr = m_pDirect2dFactory->CreateHwndRenderTarget(
			         rtprop,
			         D2D1::HwndRenderTargetProperties(m_hwndFullScreen, size),
			         &m_pRenderTargetFS
			     );
			//попробуем то, что предлагается по умолчанию.
		}
	}

	return hr;
}

void CScreen::ScreenView_Done()
{
	SAFE_DELETE_ARRAY(m_bits);
	SAFE_DELETE_ARRAY(m_colTable32);
	SAFE_DELETE_ARRAY(m_monTable32);
	SafeRelease(&m_pBitmap);
	SafeRelease(&m_pRenderTarget);
	SafeRelease(&m_pRenderTargetFS);
	SafeRelease(&m_pDirect2dFactory);
}


BOOL CScreen::PreCreateWindow(CREATESTRUCT &cs)
{
	m_cwndParent = FromHandle(cs.hwndParent);
	cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
	return CWnd::PreCreateWindow(cs);
}

int CScreen::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
	{
		return -1;
	}

	// создадим окно для полноэкранного режима
	m_DDWnd.CreateEx(
	    WS_EX_APPWINDOW, //расширенные стили
	    NULL, //имя класса
	    NULL, //имя окна
	    WS_POPUP | WS_CLIPSIBLINGS, //стили окна
	    CRect(0, 0, 0, 0),  //позиция и размер окна
	    this, //родительское окно
	    0 //ID окна
	);
	//рассчитаем размеры окна полноэкранного режима
	FLOAT wx, wy, dx, dy;
	HDC dc = ::GetDC(NULL);
	m_rectFullScreen.left = 0;
	m_rectFullScreen.top = 0;
	m_rectFullScreen.right = GetDeviceCaps(dc, HORZRES);
	m_rectFullScreen.bottom = GetDeviceCaps(dc, VERTRES);
	::ReleaseDC(NULL, dc);
	dx = (FLOAT)m_rectFullScreen.right;     //ширина экрана
	dy = (FLOAT)m_rectFullScreen.bottom;    //высота экрана
	wx = dy * BK_ASPECT_RATIO;  //ширина экрана при высоте dy в пропорциях 4/3
	wy = dx / BK_ASPECT_RATIO;  //высота экрана при ширине dx в пропорциях 4/3

	//рассчитаем размеры рисуемой картинки в полноэкранном режиме
	if (dx <= dy) //если монитор повёрнут на 90 градусов, или нестандартный - квадратный
	{
		if (dx < wx) //если не влазит по ширине, вписываем в ширину
		{
			wy = dy;
			wx = (int)(wy * BK_ASPECT_RATIO);
		}
		else
		{
			//то вписываем картинку в высоту
			wx = dx;
			wy = (int)(wx / BK_ASPECT_RATIO);
		}
	}
	else    //если монитор в обычном положении
	{
		if (dx < wx) //если не влазит по ширине, вписываем в ширину
		{
			wx = dx;
			wy = (int)(wx / BK_ASPECT_RATIO);
		}
		else
		{
			//то вписываем картинку в высоту
			wy = dy;
			wx = (int)(wy * BK_ASPECT_RATIO);
		}
	}

	m_rectFSWnd.left = (dx - wx) / 2; //выравниваем по центру
	m_rectFSWnd.top = (dy - wy) / 2;
	m_rectFSWnd.right = wx;
	m_rectFSWnd.bottom = wy;
	m_hwndFullScreen = m_DDWnd.GetSafeHwnd();
	m_hwndScreen = GetSafeHwnd();

	if ((m_hwndScreen != NULL) && (m_hwndFullScreen != NULL))
	{
		if (SUCCEEDED(ScreenView_Init()))
		{
			if (m_bFullScreen)
			{
				SetFullScreenMode();
			}
			else
			{
				SetWindowMode();
			}

			return 0;
		}
	}

	return -1;
}


void CScreen::OnSetFocus(CWnd *pOldWnd)
{
	AfxGetMainWnd()->SetFocus();
}


void CScreen::OnLButtonDown(UINT nFlags, CPoint point)
{
	AfxGetMainWnd()->SetFocus();
	CWnd::OnLButtonDown(nFlags, point);
}

void CScreen::DrawScreen(BOOL bCheckFPS)
{
	if (m_bits == NULL)
	{
		return;
	}

	if (m_lockChangeMode.IsLocked() || m_lockBusy.IsLocked())
	{
		return;
	}

	m_lockBusy.Lock();
	HRESULT hr = m_pBitmap->CopyFromMemory(NULL, m_bits, m_nPitch);
	m_pCurrentRenderTarget->BeginDraw();
	m_pCurrentRenderTarget->SetTransform(D2D1::Matrix3x2F::Identity());
	m_pCurrentRenderTarget->SetAntialiasMode(D2D1_ANTIALIAS_MODE_ALIASED);
	// Draw a bitmap.
	m_pCurrentRenderTarget->DrawBitmap(
	    m_pBitmap,
	    m_rectCurrentViewport,
	    1.0f,
	    D2D1_BITMAP_INTERPOLATION_MODE_LINEAR
	);
	hr = m_pCurrentRenderTarget->EndDraw();

	if (bCheckFPS)
	{
		// Посчитаем FPS
		m_nFrame++;

		//GetTickCount64 - возвращает количество миллисекунд, прошедшее с момента старта системы
		//if ((m_mtmpsec = GetTickCount64()) - m_msec >= 1000)
		if ((m_mtmpsec = GetTickCount()) - m_msec >= 1000)
		{
			m_msec = m_mtmpsec;
			m_curFPS = m_nFrame;
			m_nFrame = 0;
		}
	}

	m_lockBusy.UnLock();
}

void CScreen::PrepareScreenRGB32(BYTE *ScreenBuffer)
{
	while (m_lockChangeMode.IsLocked());

	m_lockPrepare.Lock();
	// Get scroll value
	WORD v = (m_pParent) ? m_pParent->m_reg177664 : 01330;
	SetOffset(LOBYTE(v));
	SetExtendedMode(!(v & 01000));

	if (m_bits)
	{
		WORD scroll = (m_nOfs >= 0330) ? m_nOfs - 0330 : 050 + m_nOfs;
		BYTE *pVideo;
		DWORD *pBits, *pBitp, *pPalette;
		// Render to bitmap
		DWORD *pCurPalette = (m_bColorMode) ? m_colTable32 : m_monTable32;
		int linesToShow = m_bExtended ? SCREEN_HEIGHT / 4 : SCREEN_HEIGHT;

		for (int y = 0; y < linesToShow; ++y)
		{
			int yy = (y + scroll) & 0377;
			pBits = m_bits + (y * TEXTURE_MULTIPLER_Y * TEXTURE_WIDTH);
			pBitp = pBits; //указатель на начало строки
			pVideo = ScreenBuffer + (yy * 0100);

			for (int x = 0; x < SCREEN_WIDTH / 8; ++x)
			{
				pPalette = pCurPalette + (((m_nPaletteNum << 8) + *pVideo++) << 3);

				for (int i = 0; i < 8; ++i)
				{
					for (int u = 0; u < TEXTURE_MULTIPLER_X; ++u)
					{
						*pBits++ = *pPalette;
					}

					pPalette++;
				}
			}

			//теперь pBits - указатель на начало новой строки, а pBitp - указатель на начало предыдущей строки
			//скопируем строку столько раз, сколько надо будет
			for (int v = 1; v < TEXTURE_MULTIPLER_Y; ++v)
			{
				memcpy(pBits, pBitp, TEXTURE_WIDTH * sizeof(DWORD));
				pBits += TEXTURE_WIDTH;
				pBitp += TEXTURE_WIDTH;
			}
		}

		if (m_bExtended)
		{
			memset(m_bits, 0, (TEXTURE_HEIGHT - TEXTURE_HEIGHT / 4) * TEXTURE_WIDTH * sizeof(DWORD));
		}
	}

	m_lockPrepare.UnLock();
}

void CScreen::PrepareScreenLineByteRGB32(int nLineNum, int nByteNum, BYTE b)
{
	while (m_lockChangeMode.IsLocked());

	m_lockPrepare.Lock();

	if (m_bits)
	{
		DWORD *pCurPalette = (m_bColorMode) ? m_colTable32 : m_monTable32;
		int yy = 255 - (m_nOfs + 047 - nLineNum) & 0377;
		DWORD *pBits = m_bits + (yy * TEXTURE_MULTIPLER_Y * TEXTURE_WIDTH + nByteNum * 8 * TEXTURE_MULTIPLER_X);
		DWORD *pBitp = pBits; //указатель на начало строки

		if (m_bExtended && yy >= (SCREEN_HEIGHT / 4))
		{
			//обнуляем
			for (int i = 0; i < 8; ++i)
			{
				for (int u = 0; u < TEXTURE_MULTIPLER_X; ++u)
				{
					*pBits++ = 0;
				}
			}
		}
		else
		{
			//копируем 1 байт
			DWORD *pPalette = pCurPalette + (((m_nPaletteNum << 8) + b) << 3);

			for (int i = 0; i < 8; ++i)
			{
				for (int u = 0; u < TEXTURE_MULTIPLER_X; ++u)
				{
					*pBits++ = *pPalette;
				}

				pPalette++;
			}
		}

		pBits = pBitp + TEXTURE_WIDTH;

		//размножим по вертикали
		for (int v = 1; v < TEXTURE_MULTIPLER_Y; ++v)
		{
			memcpy(pBits, pBitp, 8 * TEXTURE_MULTIPLER_X * sizeof(DWORD));
			pBits += TEXTURE_WIDTH;
			pBitp += TEXTURE_WIDTH;
		}
	}

	m_lockPrepare.UnLock();
}

#define COLTABLE_SIZE (16*256*8)
//16 палитр, 256 вариантов значений байта, на каждый вариант - 8 DWORDов,
void CScreen::InitColorTables()
{
	while (m_lockPrepare.IsLocked()); //если выполняется подготовка, то подождём, пока процедуры не завершатся

	m_lockChangeMode.Lock();
	// Create color tables of all display modes for faster drawing
	SAFE_DELETE_ARRAY(m_colTable32);
	SAFE_DELETE_ARRAY(m_monTable32);
	m_colTable32 = new DWORD[COLTABLE_SIZE];
	m_monTable32 = new DWORD[COLTABLE_SIZE];

	for (int p = 0; p < 16; ++p) //для каждой из 16 палитр
	{
		//вот это делает одну палитру. а нам надо таких 16.
		for (int i = 0; i < 256; ++i) //для каждого значения байта (от 0 до 255) делаем маску, чтоб работать сразу с байтами и не заморачиваться с битами
		{
			DWORD *pColBuff32 = &m_colTable32[p * (256 * 8) + i * 8];
			DWORD *pMonBuff32 = &m_monTable32[p * (256 * 8) + i * 8];

			for (int n = 0; n < 4; ++n) //в каждом байте 4 двухбития, на каждые два бита, у нас отводится по 4 дворда
			{
				int n2 = n * 2;

				switch ((i >> n2) & 3)
				{
					// Black
					case 0:
						pColBuff32[n2] = ScreenView_ColorPalettes[p][0];
						pMonBuff32[n2++] = (m_bAdapt) ? AdaptMonochromePalette[0][0] : MonochromePalette[0][0];
						pColBuff32[n2] = ScreenView_ColorPalettes[p][0];
						pMonBuff32[n2] = (m_bAdapt) ? AdaptMonochromePalette[1][0] : MonochromePalette[1][0];
						break;

					// Blue and Gray
					case 1:
						pColBuff32[n2] = ScreenView_ColorPalettes[p][1];
						pMonBuff32[n2++] = (m_bAdapt) ? AdaptMonochromePalette[0][1] : MonochromePalette[0][1];
						pColBuff32[n2] = ScreenView_ColorPalettes[p][1];
						pMonBuff32[n2] = (m_bAdapt) ? AdaptMonochromePalette[1][1] : MonochromePalette[1][1];
						break;

					// Green and Gray
					case 2:
						pColBuff32[n2] = ScreenView_ColorPalettes[p][2];
						pMonBuff32[n2++] = (m_bAdapt) ? AdaptMonochromePalette[0][2] : MonochromePalette[0][2];
						pColBuff32[n2] = ScreenView_ColorPalettes[p][2];
						pMonBuff32[n2] = (m_bAdapt) ? AdaptMonochromePalette[1][2] : MonochromePalette[1][2];
						break;

					// Red
					case 3:
						pColBuff32[n2] = ScreenView_ColorPalettes[p][3];
						pMonBuff32[n2++] = (m_bAdapt) ? AdaptMonochromePalette[0][3] : MonochromePalette[0][3];
						pColBuff32[n2] = ScreenView_ColorPalettes[p][3];
						pMonBuff32[n2] = (m_bAdapt) ? AdaptMonochromePalette[1][3] : MonochromePalette[1][3];
						break;
				}
			}
		} //end for(i)
	} //end for(p)

	m_lockChangeMode.UnLock();
}

BOOL CScreen::SetFullScreenMode()
{
	while (m_lockBusy.IsLocked() || m_lockPrepare.IsLocked()); //если выполняется отрисовка, то подождём, пока процедуры не завершатся

	m_lockChangeMode.Lock();
	BOOL bRet = FALSE;

	// Show background window
	if (m_hwndFullScreen)
	{
		theApp.GetMainWnd()->ShowWindow(SW_HIDE);
		m_bMWHdn = TRUE;
		// Remove caption and border
		SetWindowLong(m_hwndFullScreen, GWL_STYLE, GetWindowLong(m_hwndFullScreen, GWL_STYLE) & (~(WS_CAPTION | WS_BORDER)));
		m_DDWnd.SetWindowPos(&wndTopMost, m_rectFullScreen.left, m_rectFullScreen.top, m_rectFullScreen.right, m_rectFullScreen.bottom, SWP_SHOWWINDOW);
		m_bFullScreen = TRUE;
		bRet = TRUE;
	}

	m_pCurrentRenderTarget = m_pRenderTargetFS;
	m_rectCurrentViewport = m_rectFSWnd;
	m_lockChangeMode.UnLock();
	return bRet;
}

BOOL CScreen::SetWindowMode()
{
	while (m_lockBusy.IsLocked() || m_lockPrepare.IsLocked()); //если выполняется отрисовка, то подождём, пока процедуры не завершатся

	m_lockChangeMode.Lock();

	// Hide Background window
	if (m_hwndFullScreen)
	{
		if (m_bMWHdn)
		{
			theApp.GetMainWnd()->ShowWindow(SW_SHOW);
			m_bMWHdn = FALSE;
		}

		m_DDWnd.SetWindowPos(NULL, 0, 0, 0, 0, SWP_HIDEWINDOW);
	}

	m_pCurrentRenderTarget = m_pRenderTarget;
	m_rectCurrentViewport = m_rectWnd;
	m_bFullScreen = FALSE;
	m_lockChangeMode.UnLock();
	return TRUE;
}

HBITMAP CScreen::GetScreenshot()
{
	HBITMAP hBm = CreateBitmap(TEXTURE_WIDTH, TEXTURE_HEIGHT, 1, 32, m_bits);
	return hBm;
}

void CScreen::AdjustLayout()
{
	if (m_cwndParent == NULL)
	{
		return;
	}

	CRect rcScreen(0, 0, BK_SCREEN_WIDTH, BK_SCREEN_HEIGHT);
	CRect rcNewScreen = rcScreen;
	CRect rcClient;
	m_cwndParent->GetClientRect(&rcClient);

	if (rcScreen.Width() * rcClient.Height() > rcClient.Width() * rcScreen.Height())
	{
		rcNewScreen.right = rcClient.Width();
		rcNewScreen.bottom = rcScreen.bottom * rcClient.Width() / rcScreen.right;
	}
	else
	{
		rcNewScreen.bottom = rcClient.Height();
		rcNewScreen.right = rcScreen.right * rcClient.Height() / rcScreen.bottom;
	}

	if (rcNewScreen.Width() > BK_SCREEN_WIDTH)
	{
		rcNewScreen.right = BK_SCREEN_WIDTH;
	}

	if (rcNewScreen.Height() > BK_SCREEN_HEIGHT)
	{
		rcNewScreen.bottom = BK_SCREEN_HEIGHT;
	}

	int x_offs = (rcClient.Width() - rcNewScreen.Width()) / 2;
	int y_offs = (rcClient.Height() - rcNewScreen.Height()) / 2;
	rcClient.right = rcClient.left + rcNewScreen.Width();
	rcClient.bottom = rcClient.top + rcNewScreen.Height();
	rcClient.OffsetRect(x_offs, y_offs);
	SetWindowPos(NULL, rcClient.left, rcClient.top, rcClient.Width(), rcClient.Height(), SWP_SHOWWINDOW);
}
