﻿//
//	DirectDraw sample
//

#include "sample1.h"

//	画面更新
void UpdateFrame(void)
{
	const char szText[] = " DirectDraw 描画！";

	//	画面消去
	DDBLTFX		ddBltFx;
	ZeroMemory(&ddBltFx, sizeof(DDBLTFX));
	ddBltFx.dwSize = sizeof(DDBLTFX);
	lpBackSurface->Blt(NULL, NULL, NULL, DDBLT_COLORFILL | DDBLT_WAIT, &ddBltFx);

	//	DirectDrawサーフェスへGDIを使って文字を書く
	static int y = 0, nStep = +1;
	HDC hDC;
	lpBackSurface->GetDC(&hDC);
	TextOut(hDC, 100, y, szText, lstrlen(szText));
	lpBackSurface->ReleaseDC(hDC);

	y += nStep;
	if((y > SCREEN_HEIGHT - 20) || (y <= 0)){
		nStep = nStep * -1;	//	反転
	}

	//	フリップ
	lpPrimarySurface->Flip(NULL, DDFLIP_WAIT);

	return;
}

//	DirectDrawの初期化
BOOL DirectDrawInit(HWND hWnd)
{
	HRESULT hr;

	//	DirectDraw7オブジェクトの作成
	hr = DirectDrawCreateEx(NULL, (void**)&lpDD, IID_IDirectDraw7, NULL);
	if(hr != DD_OK){
		DebugMessage("DirectDraw7オブジェクトの生成に失敗しました\n");
		return FALSE;
	}

	//	画面モードを設定する
	hr = lpDD->SetCooperativeLevel(hWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN);
	if(hr != DD_OK){
		DebugMessage("画面モードの設定に失敗しました\n");
		RELEASE(lpDD);
		return FALSE;
	}

	//	画面サイズと色深度を設定する
	hr = lpDD->SetDisplayMode(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, 0, 0);
	if(hr != DD_OK){
		DebugMessage("画面サイズの設定に失敗しました\n");
		RELEASE(lpDD);
		return FALSE;
	}

	//	サーフェースを作成する
	DDSURFACEDESC2 ddsd;
	ZeroMemory(&ddsd, sizeof(ddsd));
	ddsd.dwSize = sizeof(ddsd);
	ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX;
	ddsd.dwBackBufferCount = 1;

	//	プライマリサーフェース作成
	hr = lpDD->CreateSurface(&ddsd, &lpPrimarySurface, NULL);
	if(hr != DD_OK){
		DebugMessage("プライマリーサーフェスの生成に失敗しました\n");
		RELEASE(lpDD);
		return FALSE;
	}

	//	バックバッファ作成
	DDSCAPS2 ddscaps;
	ZeroMemory(&ddscaps, sizeof(ddscaps));
	ddscaps.dwCaps = DDSCAPS_BACKBUFFER;
	hr = lpPrimarySurface->GetAttachedSurface(&ddscaps, &lpBackSurface);
	if(hr != DD_OK){
		DebugMessage("バックサーフェスの生成に失敗しました\n");
		RELEASE(lpPrimarySurface);
		RELEASE(lpDD);
		return FALSE;
	}

	return TRUE;
}

//	DirectDrawの破棄
BOOL DirectDrawExit(void)
{
	RELEASE(lpBackSurface);
	RELEASE(lpPrimarySurface);
	RELEASE(lpDD);

	return TRUE;
}

//	Windowsメッセージの処理
long CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg){
	case WM_KEYDOWN:
		switch(wParam){
		case VK_ESCAPE:
			PostMessage(hWnd, WM_CLOSE, 0, 0);
			break;
		}
		break;
	case WM_SETCURSOR:
		SetCursor(NULL);	//	これがないとカーソルが表示される
		return TRUE;
	case WM_DESTROY:
		DirectDrawExit();
		PostQuitMessage(0);
		break;
	default:
		break;
	}

	return DefWindowProc(hWnd, msg, wParam, lParam);
}

//	プログラムの初期化(ウィンドウ作成など)
BOOL Init(HINSTANCE hInstance)
{
	hInst = hInstance;

	//	ウィンドウクラスの登録
	WNDCLASS	wc;
	wc.style = CS_HREDRAW | CS_VREDRAW;// | CS_DBLCLKS;
	wc.lpfnWndProc = (WNDPROC)WndProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = sizeof(DWORD);
	wc.hInstance = hInst;
	wc.hIcon = NULL;
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = APP_CLASS;

	if(!RegisterClass(&wc)){
		DebugMessage("ウィンドウクラスの登録に失敗しました\n");
		return FALSE;
	}

	//	ウィンドウの生成
	hWndMain = CreateWindowEx(WS_EX_TOPMOST,
		APP_CLASS, APP_TITLE,
		WS_POPUP | WS_VISIBLE,
		0,
		0,
		GetSystemMetrics(SM_CXSCREEN),
		GetSystemMetrics(SM_CYSCREEN),
		NULL, NULL, hInst, NULL);
	if(!hWndMain){
		DebugMessage("ウィンドウの生成に失敗しました\n");
		return FALSE;
	}

	//	DirectDrawの初期化
	if(!DirectDrawInit(hWndMain)){
		DebugMessage("DirectDrawの初期化に失敗しました\n");
		return FALSE;
	}

	//	準備ができたら描画
	ShowWindow(hWndMain, SW_SHOW);
	UpdateWindow(hWndMain);

	return TRUE;
}

//	Windowsメッセージの受信
int MainThread(void)
{
	MSG		msg;

	while(1){
		if(PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)){
			if(!GetMessage(&msg, NULL, 0, 0)){
				break;
			}
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		else{
			//	メッセージが来ない時はひたすら描画処理を呼ぶ
			UpdateFrame();
		}
	}

	return msg.wParam;
}

//	デバッグ文出力
void DebugMessage(const char *pFormat, ...)
{
	char	szBuff[1024];
	va_list	argptr;

	va_start(argptr, pFormat);
	vsprintf(szBuff, pFormat, argptr);

	va_end(argptr);

	OutputDebugString(szBuff);

	return;
}

//	WinMain
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPreInst, LPSTR lpCmdLine, int nCmdShow)
{
	Init(hInst);	//	プログラムの初期化(ウィンドウ作成など)
	MainThread();	//	メインスレッド

	return 0;
}
