#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "resource.h"
#include "inpainting.h"

#define MYWNDCLASS  "MYWNDCLASS"
#define CAPTION     "數位影像處理期末PROJECT <Inpainting>"

#define WIDTH 540		//圖片的長 for 視窗 
#define HEIGHT 470		//圖片的高 for 視窗
#define pi 3.141592
#define DEGREE 1

//new added
#define MAX(a, b)  (((a) > (b)) ? (a) : (b)) 
#define MIN(a, b)  (((a) < (b)) ? (a) : (b))
int m_left, m_right, m_top, m_bottom;

double ComputeConfidence(int i, int j, int m_height, int m_width, double *m_confid) 
{
	int x, y;
	double confidence=0;
	for(y = MAX(j -winsize,0); y<= MIN(j+winsize,m_height-1); y++)
		for(x = MAX(i-winsize,0); x<=MIN(i+winsize, m_width-1); x++)
			confidence+= m_confid[y*m_width+x];
	confidence/= (winsize*2+1)*(winsize*2+1);
	return confidence;

}

gradient GetGradient(int i, int j, int m_height, int m_width, double *m_gray)
{
	gradient result;
	result.grad_x = (m_gray[j*m_width+i+1] - m_gray[j*m_width+i-1])/2.0;
	result.grad_y = (m_gray[(j+1)*m_width +i] - m_gray[(j-1)*m_width+i])/2.0;

	if(i==0)
		result.grad_x = m_gray[j*m_width+i+1] - m_gray[j*m_width+i];
	if(i==m_width-1)
		result.grad_x = m_gray[j*m_width+i] - m_gray[j*m_width+i-1];
	if(j==0)
		result.grad_y = m_gray[(j+1)*m_width +i] - m_gray[j*m_width+i];
	if(j==m_height-1)
		result.grad_y = m_gray[j*m_width +i] - m_gray[(j-1)*m_width+i];
	return result;
}
norm GetNorm(int i, int j, int m_height, int m_width, int *m_mark)
{
	norm result;
	int x, y, num=0;
	int neighbor_x[9];
	int neighbor_y[9];
	int record[9];
	int count = 0;
	int n_x, n_y, temp;
	double square;
	for(y = MAX(j-1,0); y<=MIN(j+1,m_height-1); y++)
		for(x = MAX(i-1,0); x<=MIN(i+1,m_width-1); x++)
		{
			count++;
			if(x==i&&y==j)continue;
			if(m_mark[y*m_width+x]==BOUNDARY)
			{
				num++;
				neighbor_x[num] = x;
				neighbor_y[num] = y;		
				record[num]=count;
			}
		}
		if(num==0||num==1) // if it doesn't have two neighbors, give it a random number to proceed
		{
			result.norm_x = 0.6;
			result.norm_y = 0.8;
			return result;
		}
		// draw a line between the two neighbors of the boundary pixel, then the norm is the perpendicular to the line
			n_x = neighbor_x[2]-neighbor_x[1];
			n_y = neighbor_y[2]-neighbor_y[1];
			temp=n_x;
			n_x = n_y;
			n_y = temp;
			square = pow((n_x*n_x + n_y*n_y),0.5);
		
	result.norm_x = n_x/square;
	result.norm_y = -n_y/square;
	return result;
}

double ComputeData(int i, int j, int m_height, int m_width, int *m_mark, double *m_gray)
{
	gradient grad, temp, grad_T;
	norm nn;
	double result;
	double magnitude;
	double max=0;
	int x, y;

	grad.grad_x=0;
	grad.grad_y=0;
	
	for(y = MAX(j -winsize,0); y<= MIN(j+winsize,m_height-1); y++)
		for( x = MAX(i-winsize,0); x<=MIN(i+winsize, m_width-1); x++)
		{
			// find the greatest gradient in this patch, this will be the gradient of 
			// this pixel(according to "detail paper")
			if(m_mark[y*m_width+x] >=0) // source pixel
			{
				//since I use four neighbors to calculate the gradient, make sure this four neighbors do not touch target region(big jump in gradient)
				if((y*m_width+x-1) < 0 || (y+1) >= m_height || (y-1) < 0 )
					continue;
				if(m_mark[y*m_width+x+1]<0||m_mark[y*m_width+x-1]<0||m_mark[(y+1)*m_width+x]<0||m_mark[(y-1)*m_width+x]<0)
					continue;
 				temp = GetGradient(x,y,m_height,m_width,m_gray); 
				magnitude = temp.grad_x*temp.grad_x+temp.grad_y*temp.grad_y;
				if(magnitude>max)
				{
					grad.grad_x = temp.grad_x;
					grad.grad_y = temp.grad_y;
					max = magnitude;
				}
			}
		}
		grad_T.grad_x = grad.grad_y;// perpendicular to the gradient: (x,y)->(y, -x)
		grad_T.grad_y = -grad.grad_x;

	nn = GetNorm(i,j, m_height, m_width, m_mark);
	result = nn.norm_x*grad_T.grad_x+nn.norm_y*grad_T.grad_y; // dot product
	result/=255; //"alpha" in the paper: normalization factor
	result = fabs(result);			
	return result;
}


double priority(int i, int j, int m_height, int m_width, double *m_confid, 
				int *m_mark, double *m_gray)
{
	double confidence, data;
	confidence = ComputeConfidence(i,j,m_height, m_width, m_confid); // confidence term
	data = ComputeData(i,j,m_height,m_width, m_mark, m_gray); // data term
	return confidence*data;
}

void draw_source(LPBYTE lpBMP, int m_width, int m_height, int *m_source, int *m_mark)
{
	// draw a window around the pixel, if all of the points 
	// within the window are source pixels, then this patch can be used as a source patch
	int flag, i, j, y, x;	
	for(j = 0; j<m_height; j++) {		
		for(i = 0; i<m_width; i++)
		{
			flag=1;
			if(i<=winsize||j<=winsize||i>=m_width-winsize||j>=m_height-winsize)
				m_source[j*m_width+i] = FALSE;  //cannot form a complete window
			else
			{
				for(y = j-winsize; y<=j+winsize; y++){				
					for(x = i-winsize; x<=i+winsize; x++){
						if(m_mark[y*m_width+x]!=SOURCE) {
							m_source[j*m_width+i]=FALSE;
							flag = FALSE;
							break;								
						}						
					}				
					if(flag==FALSE)
						break;				
				}			    
				if(flag!=FALSE)
					m_source[j*m_width+i]=TRUE;
			}			
		}
	}
}

void DrawBoundary(LPBYTE lpBMP, int m_width, int m_height, int *m_mark, double *m_confid)
{
	int i, j, x, y;
	
	for(y = 0; y < m_height; y++)	{
		for(x = 0; x < m_width; x++)
		{ 
			if( lpBMP[3*(y*m_width+x)] == 0 && lpBMP[3*(y*m_width+x)+1] == 255 
				&& lpBMP[3*(y*m_width+x)+2] == 0)// if the pixel is specified as boundary
			{
				m_mark[y*m_width+x] = TARGET;
				m_confid[y*m_width+x] = 0;
			}
			else {
				m_mark[y*m_width+x] = SOURCE;
				m_confid[y*m_width+x] = 1;
			}
		}
	}	
	for(j= 0; j< m_height; j++) {
	    for(i = 0; i< m_width; i++) {
			if(m_mark[j*m_width+i]==TARGET) {
				if(i<m_left)  m_left = i; // resize the rectangle to the range of target area
				if(i>m_right)  m_right = i;
				if(j>m_bottom)  m_bottom = j;
				if(j<m_top)  m_top = j;
				
				//if one of the four neighbours is source pixel, 
				//then this should be a boundary
				if(j==m_height-1||j==0||i==0||i==m_width-1||
					m_mark[(j-1)*m_width+i]==SOURCE || m_mark[j*m_width+i-1]==SOURCE||
					m_mark[j*m_width+i+1]==SOURCE || m_mark[(j+1)*m_width+i]==SOURCE)
					m_mark[j*m_width+i] = BOUNDARY;
			}
		}
	}

}

void Convert2Gray(LPBYTE lpBMP, int m_height, int m_width, double *m_gray)
{
	int x,y;
	double r,g,b;
	for(y = 0; y<m_height; y++)
		for(x = 0; x<m_width; x++)
		{
			b = lpBMP[ 3*((y*m_width) + x)];
			g = lpBMP[ 3*((y*m_width) + x)+ 1];
			r = lpBMP[ 3*((y*m_width) + x)+ 2];
			m_gray[y*m_width+x] = (double)((r*3735 + g*19267 + b*9765)/32767);
		}
}

int TargetExist(int m_width, int *m_mark)
{		
	int i, j;
	
	for(j= m_top; j<=m_bottom; j++) {
		for(i = m_left; i<= m_right; i++) {
			if(m_mark[j*m_width+i] < 0)	// if this is target
				return TRUE;	
		}
	}	
	return FALSE;
}

// find the most similar patch, according to SSD
int PatchTexture(int x, int y, int *patch_x, int *patch_y, 
				 int m_height, int m_width, int *m_source, int *m_mark,
				 double *m_r, double *m_g, double *m_b)
{
	int i, j, iter_x, iter_y;
	double temp_r;
	double temp_g;
	double temp_b;				
	double min=99999999999;
	double sum;
	int source_x, source_y;
	int target_x, target_y;
	
	for(j = 0; j<m_height; j++) {
		for(i = 0; i<m_width; i++)
		{		
			if(m_source[j*m_width+i] == FALSE)
				continue;
			sum=0;
			for(iter_y=(-1)*winsize; iter_y<=winsize; iter_y++) {
				for(iter_x=(-1)*winsize; iter_x<=winsize; iter_x++)	{
					source_x = i+iter_x;
					source_y = j+iter_y;
					target_x = x+iter_x;
					target_y = y+iter_y;
					
					if(target_x<0||target_x>=m_width||target_y<0||target_y>=m_height)
						continue;

					if(m_mark[target_y*m_width+target_x]>=0){
						temp_r = m_r[target_y*m_width+target_x]-m_r[source_y*m_width+source_x];
						temp_g = m_g[target_y*m_width+target_x]-m_g[source_y*m_width+source_x];
						temp_b = m_b[target_y*m_width+target_x]-m_b[source_y*m_width+source_x];
						sum+= temp_r*temp_r + temp_g*temp_g + temp_b*temp_b;
					}
				}				
			}			
			if(sum<min)	{			
				min=sum;
				*patch_x = i;
				*patch_y = j;
			}

		}
	}
	//	printf("patch_x is %d, patch_y is %d\n", patch_x, patch_y);				
	return TRUE;
}

int update(int target_x, int target_y, int source_x, int source_y, double confid,
		   int *m_mark, double *m_confid, LPBYTE lpBMP, LPBYTE lpBMP2, 
		   int m_height, int m_width, double *m_b, double *m_g, double *m_r,
		   double *m_gray)
{
	int iter_x, iter_y;
	int x0,y0,x1,y1;
	
	for(iter_y=(-1)*winsize; iter_y<=winsize; iter_y++) {
		for(iter_x=(-1)*winsize; iter_x<=winsize; iter_x++) {
			x0 = source_x + iter_x;
			y0 = source_y + iter_y;

			x1 = target_x + iter_x;
			y1 = target_y + iter_y;
			if( (y1*m_width+x1 < 0) || (y1*m_width+x1 > m_width*m_height))
				continue;
			if(m_mark[y1*m_width+x1] < 0 ) {
				//m_pImage->SetPixel(x1,y1,m_color[y0*m_width+x0]);// inpaint the color
				//m_color[y1*m_width+x1] = m_color[y0*m_width+x0];
				lpBMP2[3*(y1*m_width+x1)] = lpBMP[3*(y0*m_width+x0)];
				lpBMP2[3*(y1*m_width+x1)+1] = lpBMP[3*(y0*m_width+x0)+1];
				lpBMP2[3*(y1*m_width+x1)+2] = lpBMP[3*(y0*m_width+x0)+2];
				m_b[y1*m_width+x1] = m_b[y0*m_width+x0];
				m_g[y1*m_width+x1] = m_g[y0*m_width+x0];
				m_r[y1*m_width+x1] = m_r[y0*m_width+x0];
				m_gray[y1*m_width+x1] = (double)((m_r[y0*m_width+x0]*3735 + m_g[y0*m_width+x0]*19267 + m_b[y0*m_width+x0]*9765)/32767); // update gray image
				m_confid[y1*m_width+x1] = confid; // update the confidence
			}
		}
	}	
	return TRUE;
}

// just update the area near the changed patch. (+-2 pixels)
void UpdateBoundary(int i, int j, int m_height, int m_width, int *m_mark, LPBYTE lpBMP2)
{
	int x, y;

	for(y = MAX(j -winsize-(winsize-1),0); y<= MIN(j+winsize+(winsize-1),m_height-1); y++)
		for( x = MAX(i-winsize-(winsize-1),0); x<=MIN(i+winsize+(winsize-1), m_width-1); x++)
		{
			if( lpBMP2[3*(y*m_width+x)] == 0 && lpBMP2[3*(y*m_width+x)+1] == 255 && lpBMP2[3*(y*m_width+x)+2] == 0)
				m_mark[y*m_width+x] = TARGET;						
			else m_mark[y*m_width+x] = SOURCE;
		}

	for(y = MAX(j -winsize-(winsize-1),0); y<= MIN(j+winsize+(winsize-1),m_height-1); y++)
		for( x = MAX(i-winsize-(winsize-1),0); x<=MIN(i+winsize+(winsize-1), m_width-1); x++)
		{
			if(m_mark[y*m_width+x]==TARGET)
			{
				if(y==m_height-1||y==0||x==0||x==m_width-1||
					m_mark[(y-1)*m_width+x]==SOURCE||m_mark[y*m_width+x-1]==SOURCE||
					m_mark[y*m_width+x+1]==SOURCE||m_mark[(y+1)*m_width+x]==SOURCE)
					m_mark[y*m_width+x] = BOUNDARY;
			}
		}		
}

// just update the area near the changed patch. (+-3 pixels)
void UpdatePri(int i, int j, int m_height, int m_width, double *m_confid, int *m_mark, double *m_gray, double *m_pri)
{
	int x,y;
	for(y = MAX(j -winsize-(winsize-1),0); y<= MIN(j+winsize+(winsize-1),m_height-1); y++)
		for( x = MAX(i-winsize-(winsize-1),0); x<=MIN(i+winsize+(winsize-1), m_width-1); x++)
			if(m_mark[y*m_width+x] == BOUNDARY)
				m_pri[y*m_width+x] = priority(x,y, m_height, m_width, m_confid, 
				m_mark, m_gray);
}

void do_inpaint(LPBYTE lpBMP, int m_width, int m_height, LPBYTE lpBMP2) {
	int *m_mark;
	int b, g, r, mycount = 0;
	int count = 0, i, j, x, y,z;
	int pri_x, pri_y;
	int patch_x=0, patch_y =0;
	double *m_confid;
	double *m_pri;
	double *m_gray;
	double *m_r;
	double *m_g;
	double *m_b;
	double max_pri;
	int *m_source;		
	
	m_mark = (int*) calloc (m_width*m_height, sizeof(int));
	m_confid = (double*) calloc (m_width*m_height, sizeof(double));
	m_pri = (double*) calloc (m_width*m_height, sizeof(double));
	m_gray = (double*) calloc (m_width*m_height, sizeof(double));
	m_r = (double*) calloc (m_height*m_width, sizeof(double));
	m_g = (double*) calloc (m_height*m_width, sizeof(double));
	m_b = (double*) calloc (m_width*m_height, sizeof(double));
	m_source = (int*) calloc (m_width*m_height, sizeof(int));

	// Initializing
	memset(m_confid, 0, m_width*m_height*sizeof(double));
	m_top = m_height;
	m_bottom = 0;
	m_left = m_width;
	m_right = 0;

	for(y = 0; y<m_height; y++) {
		for(x = 0; x<m_width; x++)
		{
			b = lpBMP2[3*(y*m_width+x)] = lpBMP[3*(y*m_width+x)];
			g = lpBMP2[3*(y*m_width+x)+1] = lpBMP[3*(y*m_width+x)+1];
			r = lpBMP2[3*(y*m_width+x)+2] = lpBMP[3*(y*m_width+x)+2];
			m_b[y*m_width+x] = b;
			m_g[y*m_width+x] = g;
			m_r[y*m_width+x] = r;
		}
	}
	//流程
	Convert2Gray(lpBMP,m_height, m_width, m_gray);  // convert it to gray image
	DrawBoundary(lpBMP, m_width, m_height, m_mark, m_confid);  // first time draw boundary
	draw_source(lpBMP, m_width, m_height, m_source, m_mark);   // find the patches that can be used as sample texture

	memset(m_pri, 0, m_width*m_height*sizeof(double));
	for(j = m_top; j <= m_bottom; j++) {
		for(i = m_left; i <= m_right; i++) {
			if(m_mark[j*m_width+i] == BOUNDARY) {
				//if it is boundary, calculate the priority
				m_pri[j*m_width+i] = priority(i, j, m_height, m_width, m_confid, m_mark, m_gray);
			}
		}
	}
	//while(TargetExist(m_width, m_mark)) {
	for(z=0; z<1; z++){
		count++;
		max_pri = 0;
		
		for(j= m_top; j<=m_bottom; j++)	{
			for(i = m_left; i<= m_right; i++)		
			{	
				// find the boundary pixel with highest priorit		
				if(m_mark[j*m_width+i] == BOUNDARY && m_pri[j*m_width+i]>max_pri)			
				{
					pri_x = i;
					pri_y = j;
					max_pri = m_pri[j*m_width+i];
				}		
			}								
	
		}
		// find the most similar source patch
		PatchTexture(pri_x, pri_y, &patch_x, &patch_y, 
			m_height, m_width, m_source, m_mark, m_r, m_g, m_b); 
		// inpaint this area and update confidence
		update(pri_x, pri_y, patch_x,patch_y, 
			ComputeConfidence(pri_x,pri_y, m_height, m_width, m_confid), 
			   m_mark, m_confid, lpBMP, lpBMP2, m_height, m_width, 
			   m_b, m_g, m_r, m_gray);		
		// update boundary near the changed area
		UpdateBoundary(pri_x, pri_y, m_height, m_width, m_mark, lpBMP2);
		// update priority near the changed area
		UpdatePri(pri_x, pri_y, m_height, m_width, m_confid, m_mark, m_gray, m_pri);
	}

}

// 載入點陣圖
void load_lena_image(HWND hWnd, HDC hdc)
{
	static int num=0;
	HDC hmdc;
	HBITMAP hBitmap;
	BITMAP bmp;
	HINSTANCE hInst;
	int bmp_w, bmp_h;

	LPBITMAPINFO lpDIB;
	LPBYTE lpBMP, lpBMP2;
	HBITMAP hBMP, hBMP2;
	HDC hdcMem, hdcMem2;


	hInst = (HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE);
	// 將點陣圖載入到記憶體
	hBitmap =
		LoadImage(hInst, MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP, 0, 0,
				  LR_DEFAULTCOLOR);
	if (hBitmap == NULL) {
		char buf[128];
		sprintf(buf, "%d", GetLastError());
		MessageBox(hWnd, buf, "ERROR", MB_OK);
		return;
	}

	// 取得圖像的寬度和高度
	GetObject(hBitmap, sizeof(BITMAP), &bmp);
	bmp_w = (int) bmp.bmWidth;
	bmp_h = (int) bmp.bmHeight;
	hmdc = CreateCompatibleDC(hdc);

	// 使用陣列來存取螢幕(hdc)的各個像素
	lpDIB = (LPBITMAPINFO) GlobalAlloc(GPTR, sizeof(BITMAPINFO));	/* 確保DIB用的記憶體 */

	/* DIBSection用的BITMAPINFO結構設定 */
	ZeroMemory(&lpDIB->bmiHeader, sizeof(lpDIB->bmiHeader));
	lpDIB->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
	lpDIB->bmiHeader.biWidth = bmp_w;
	lpDIB->bmiHeader.biHeight = bmp_h;
	lpDIB->bmiHeader.biPlanes = 1;
	lpDIB->bmiHeader.biBitCount = 24;
	lpDIB->bmiHeader.biCompression = BI_RGB;
	lpDIB->bmiHeader.biSizeImage = 0;
	lpDIB->bmiHeader.biXPelsPerMeter = 0;
	lpDIB->bmiHeader.biYPelsPerMeter = 0;
	lpDIB->bmiHeader.biClrUsed = 0;
	lpDIB->bmiHeader.biClrImportant = 0;

	hBMP = CreateDIBSection(hdc, lpDIB, DIB_RGB_COLORS, &lpBMP, NULL, 0);
	hBMP2 = CreateDIBSection(hdc, lpDIB, DIB_RGB_COLORS, &lpBMP2, NULL, 0);
	hdcMem = CreateCompatibleDC(hdc);	/* 製作Memory device context */
	hdcMem2 = CreateCompatibleDC(hdc);	/* 製作Memory device context */
	SelectObject(hdcMem, hBMP);		/* Memory device context與DIBSection的繫結 */
	SelectObject(hdcMem2, hBMP2);	/* Memory device context與DIBSection的繫結 */

	// 將螢幕和點陣圖做繫結
	SelectObject(hmdc, hBitmap);

	//BitBlt(hdc, 0, 0, bmp_w, bmp_h, hmdc, 0, 0, SRCCOPY);	// 原圖像

//	BitBlt(hdcMem, 0, 0, bmp_w, bmp_h, hmdc, 0, 0, SRCCOPY);
//	do_rotation(lpBMP, bmp_w, bmp_h, lpBMP2, (float)(0+num), 0);
//	BitBlt(hdc, bmp_w, 0, bmp_w, bmp_h, hdcMem2, 0, 0, SRCCOPY);	//bilinear旋轉

//	BitBlt(hdcMem, 0, 0, bmp_w, bmp_h, hmdc, 0, 0, SRCCOPY);
//	do_rotation(lpBMP, bmp_w, bmp_h, lpBMP2, (float)(0+num), 1);
//	BitBlt(hdc, 0, bmp_h, bmp_w, bmp_h, hdcMem2, 0, 0, SRCCOPY);	//nn選轉

	BitBlt(hdcMem, 0, 0, bmp_w, bmp_h, hmdc, 0, 0, SRCCOPY);
	do_inpaint(lpBMP, bmp_w, bmp_h, lpBMP2);
	BitBlt(hdc, 0, 0 ,bmp_w, bmp_h, hdcMem2, 0, 0, SRCCOPY);	//inpaint

num+= DEGREE;

	// 釋放不要的資源
	DeleteDC(hmdc);
	DeleteObject(hBitmap);

	DeleteDC(hdcMem);
	DeleteObject(hBMP);
	GlobalFree(lpDIB);
}

// 視窗程序
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam,
						 LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;
	static int flag = 0;

	switch (uMsg) {
	case WM_PAINT:
		hdc = BeginPaint(hWnd, &ps);
		load_lena_image(hWnd, hdc);
		if(flag == 0) {
			InvalidateRect(hWnd, NULL, FALSE);
		}

		EndPaint(hWnd, &ps);
		break;
	case WM_LBUTTONDOWN:
		flag = (flag == 0)?1:0;
		InvalidateRect(hWnd, NULL, FALSE);
		break;

	case WM_DESTROY:
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, uMsg, wParam, lParam);
	}
	return 0;
}

// WinMain函數
int WINAPI WinMain(HINSTANCE hInstance,	// 現在的實體的標示元
				   HINSTANCE hPrevInstance,	// 以前的實體的標示元
				   LPSTR lpCmdLine,	// 命令列
				   int nCmdShow	// 顯示狀態
	)
{
	MSG msg;
	WNDCLASSEX wc;
	HWND hWnd;

	ZeroMemory(&wc, sizeof(wc));
	wc.cbSize = sizeof(WNDCLASSEX);
	wc.lpfnWndProc = (WNDPROC) WndProc;
	wc.hInstance = hInstance;
	wc.hCursor = LoadCursor(NULL, MAKEINTRESOURCE(IDC_ARROW));
	wc.hbrBackground = GetStockObject(BLACK_BRUSH);
	wc.lpszClassName = MYWNDCLASS;
	RegisterClassEx(&wc);		// 登錄視窗類別

	hWnd = CreateWindowEx(0,
						  MYWNDCLASS,
						  CAPTION,
						  WS_OVERLAPPEDWINDOW,
						  CW_USEDEFAULT, CW_USEDEFAULT,
						  WIDTH, HEIGHT, NULL, NULL, hInstance, NULL);
	ShowWindow(hWnd, nCmdShow);	// 描繪視窗
	UpdateWindow(hWnd);

	while (GetMessage(&msg, NULL, 0, 0)) {	// 訊息迴圈
		TranslateMessage(&msg);
		DispatchMessage(&msg);
	}

	return msg.wParam;
}

