#include "cDisplay.h"

cDisplay::cDisplay(){
	pDD = NULL;
	pDDClipper = NULL;
	pDDPalette = NULL;

}

cDisplay::~cDisplay(){
	Destroy();
}

bool cDisplay::Create(HWND _hWnd){
	if(pDD) return false;

	hWnd = _hWnd;
	if(DirectDrawCreate(NULL, &pDD, NULL) != DD_OK){
		MessageBox(NULL, "DirectX Initialization Failed.\nPlease reinstall DirectX3.0\n\nDirectDrawCreate() Failed", "DirectX Error!", MB_OK);
		return false;
	}
	CooperativeLevel = 0;
	// cPicture 에 cDisplay를 바인딩한다.

	cPicture::SetDisplay(this);

	return true;
}

bool cDisplay::CreatePalette(){
	DDSURFACEDESC ddsd;
	DWORD rv;
	int i;

	DestroyPalette();

	ddsd.dwSize = sizeof(DDSURFACEDESC);
	if(pDD->GetDisplayMode(&ddsd) != DD_OK) return false;

	// 디스플레이가 256개 이하의 색상을 표시할 경우 팔레트를 생성한다.
	switch(ddsd.ddpfPixelFormat.dwRGBBitCount){
	case 4:
		for(i = 0; i < 16; i ++){
			PaletteEntry[i].peRed = ((i & 4) >> 2) * 128 + ((i & 8) >> 3) * 128;
			PaletteEntry[i].peGreen = ((i & 2) >> 1) * 128 + ((i & 8) >> 3) * 128;
			PaletteEntry[i].peBlue = (i & 1) * 128 + ((i & 8) >> 3) * 128;
			PaletteEntry[i].peFlags = 0;
		}
		if(pDD->CreatePalette(DDPCAPS_4BIT, PaletteEntry, &pDDPalette, NULL) != DD_OK) return false;
		break;
	case 8:
		for(i = 0; i < 256; i ++){
			PaletteEntry[i].peRed = ((i & 48) >> 4) * 64 + ((i & 192) >> 6) * 64;
			PaletteEntry[i].peGreen = ((i & 12) >> 2) * 64 + ((i & 192) >> 6) * 64;
			PaletteEntry[i].peBlue = (i & 3) * 64 + ((i & 192) >> 6) * 64;
			PaletteEntry[i].peFlags = 0;
		}
		rv = pDD->CreatePalette(DDPCAPS_8BIT, PaletteEntry, &pDDPalette, NULL);
		if(rv != DD_OK)
			return false;
		break;
	default:
		return true;
	}
	
	return true;
}

void cDisplay::Destroy(){
	DestroyPalette();
	if(pDD){
		pDD->Release();
		pDD = NULL;
	}
}

void cDisplay::DestroyPalette(){
	if(pDDPalette){
		pDDPalette->Release();
		pDDPalette = NULL;
	}
}

bool cDisplay::SetCooperativeLevel(DWORD Mode){
	CooperativeLevel = Mode;
	if(pDD->SetCooperativeLevel(hWnd, Mode) != DD_OK)
		return false;

	if(!CreatePalette())
		return false;
	return true;
}

bool cDisplay::SetDisplayMode(DWORD Width, DWORD Height, DWORD BPP){
	if(pDD->SetDisplayMode(Width, Height, BPP) != DD_OK)
		return false;
	if(!CreatePalette())
		return false;
	return true;
}

bool cDisplay::RestoreDisplayMode(){
	return pDD->RestoreDisplayMode() == DD_OK;
}


// 더블 버퍼의 생성 권한은 디스플레이만이 맏는다.
bool cDisplay::CreateDoubleBuffer(){
	if((CooperativeLevel & DDSCL_EXCLUSIVE)
		&& (CooperativeLevel & DDSCL_FULLSCREEN)){
		// 플립핑이 가능한 이중 표면을 만든다.
		if(!FrontPic.Create(1)) 
			return false;
		BackPic = FrontPic.GetBackPic();
	}else{
		// 플립핑이 불가능한 일반 표면을 만든다.
		if(!FrontPic.Create()) return false;
		if(!BackPic.Create(FrontPic)) return false;
	}
	if(pDDPalette){
		if(FrontPic.GetDDS()->SetPalette(pDDPalette) != DD_OK)
			return false;
	}
	CreateClipper();
	return true;

}

void cDisplay::DestroyDoubleBuffer(){
	DestroyClipper();
	BackPic.Destroy();
	FrontPic.Destroy();
}


bool cDisplay::CreateClipper(){
	// 클립퍼를 붙인다.
	if(pDD->CreateClipper(0, &pDDClipper, NULL) != DD_OK)
		return false;
	if(pDDClipper->SetHWnd(0, hWnd) != DD_OK)
		return false;
	if(FrontPic.GetDDS()->SetClipper(pDDClipper) != DD_OK)
		return false;
	if(BackPic.GetDDS()->SetClipper(pDDClipper) != DD_OK)
		return false;
	return true;

}

void cDisplay::DestroyClipper(){
	if(pDDClipper){
		pDDClipper->Release();
		pDDClipper = NULL;
	}
}