// list0808win.cpp  スレッドの応用 コンソール用グラフィックウィンドウ
//	ウィンドウ側リスト
//  コンパイル設定C/C++をマルチスレッドにする

#include <Windows.h>
#include <process.h>	
#include "list0808.h"

void th_Proc( void *);
LRESULT CALLBACK grProc( HWND, UINT, WPARAM, LPARAM );

HINSTANCE	hi;
HWND		hwnd;	
HDC		mdc;				// メモリデバイスコンテキストのハンドル
int		x_size, y_size;			// グラフの大きさ
int		sw = 0;

IMG0	img00;

//	グラフィックウィンドウの生成,メッセージループ用スレッドの起動
void gr_init(int x, int y)
{
	hi = (HINSTANCE)GetWindowLong( HWND_DESKTOP, GWL_HINSTANCE ); 
	x_size = x; y_size = y;

	WNDCLASSEX	wc;				// 新しくつくるウインドクラス
	wc.cbSize        = sizeof(WNDCLASSEX);	
	wc.style	 = 0;
	wc.lpfnWndProc   = grProc;		// このクラスの持つウインドプロシージャ
	wc.cbClsExtra    = 0;
	wc.cbWndExtra    = 0;
	wc.hInstance     = hi;
	wc.hIcon         = LoadIcon( NULL, IDI_APPLICATION );
	wc.hIconSm       = LoadIcon( NULL, IDI_WINLOGO );	 
	wc.hCursor       = LoadCursor( NULL, IDC_ARROW );
	wc.hbrBackground = (HBRUSH)GetStockObject( WHITE_BRUSH );
	wc.lpszMenuName  = NULL;
	wc.lpszClassName = "GRC0";		//このクラスの名前
	if(! RegisterClassEx( &wc )) return ;	// ウィンドクラスの登録

	img00.lpbih = (BITMAPINFOHEADER *)malloc(40);
	img00.lpbi  = (BITMAPINFO *)img00.lpbih;
	_beginthread( th_Proc, 0, 0 );		// メッセージループのスレッドを起動	
	while( !sw );				// ウィンドウが表示されるのを待つ
}

// メッセージループのためのスレッド
void th_Proc( void *)
{
	MSG msg;

	int sm0 = GetSystemMetrics( SM_CYCAPTION );
	int sm1 = GetSystemMetrics( SM_CXDLGFRAME );	// WS_OVRELAPPの場合、枠の太さは
	int sm2 = GetSystemMetrics( SM_CYDLGFRAME );	// SM_C?DLGFRAMEになる
	hwnd = CreateWindow( "GRC0",				// クラスの名前
			"Windows example",
			WS_OVERLAPPED | WS_VISIBLE,		// ウィンドウの属性
			CW_USEDEFAULT, CW_USEDEFAULT,		// 位置は指定しない
			x_size + sm1 * 2,	// 描画サイズからウィンドウの大きさを計算
			y_size + sm0 + sm2 * 2,
			HWND_DESKTOP,		// 親はディスクトップ
			NULL, hi, NULL 	     );

	sw = 1;											// 表示されたことを知らせる
	while( GetMessage( &msg, NULL, 0, 0 ) ){
		TranslateMessage( &msg );
		DispatchMessage( &msg );
	}
	free(img00.lpbih);
	return ;
}

// ウィンドウプロシージャ,描画オブジェクトの準備と再描画を行う
LRESULT CALLBACK grProc( HWND hwnd, UINT msg, 
			 WPARAM wParam, LPARAM lParam )
{
	static HBITMAP hbit;
	switch(msg){
	case WM_CREATE:{
		HDC hdc = GetDC( hwnd );
		// ウィンドウと同じ仮想画面を作る
		mdc  = CreateCompatibleDC( hdc );			
		hbit = CreateCompatibleBitmap( hdc, x_size, y_size );
		SelectObject( mdc, hbit );
		PatBlt( mdc, 0, 0, x_size, y_size, WHITENESS);	// 仮想画面のクリア
		ReleaseDC( hwnd, hdc );
		break;
	}	
	case WM_PAINT:{
		PAINTSTRUCT ps;
		BeginPaint( hwnd, &ps );
		// 仮想画面からのコピー	
		BitBlt( ps.hdc, 0, 0, x_size, y_size, mdc, 0, 0, SRCCOPY);
		EndPaint( hwnd, &ps );
		break;
	}
	case WM_DESTROY:
		DeleteDC( mdc );		// メモリデバイスコンテキストの消去
		DeleteObject( hbit );		// ビットマップオブジェクトの消去
		PostQuitMessage( 0 );		// スレッドを終了させる 
		break;

	default:
		return DefWindowProc( hwnd, msg, wParam, lParam );
	}
	return 0;
}
//////////// コンソールから利用できるグラフィック関数群
void gr_clr(void)
{
	PatBlt( mdc, 0, 0, x_size, y_size, WHITENESS);	// 仮想画面のクリア
	return;
}

void gr_rect(int x, int y, int xx, int yy)			// 仮想画面の四角描画 
{
	Rectangle(mdc,x,y,xx,yy);
	return;
}

void gr_line(int x, int y, int xx, int yy)			// 仮想画面の直線描画
{
	MoveToEx( mdc, x, y, NULL);
	LineTo( mdc, xx, yy);
	return;
}

BYTE * gr_set_bmph(LPBITMAPINFOHEADER pbmph)
{
	int i;
	for(i = 0;i< 40; i++){
		((BYTE *)img00.lpbih)[i] = ((BYTE *)pbmph)[i];
	}
	return (BYTE *)pbmph + 40;
}

void gr_cp( IMG0 *p )
{	
	SetDIBitsToDevice( mdc, 0, 0,	// コピー先x,y座標
			(p -> lpbih) -> biWidth,	//DIBの幅
			(p -> lpbih) -> biHeight,// DIBの高さ
			0, 0,			// DIBの座標 
			0,				// 走査線
			(p -> lpbih) -> biHeight, // 走査線数
			p -> lpBmpData,
			p -> lpbi, //BITMAPINFO:
				   //BITMAPINFOHEADER+RGBQUAD						   
			DIB_RGB_COLORS );
	return;
}

void gr_bmp( BYTE *p )
{	
	SetDIBitsToDevice( mdc, 0, 0,	// コピー先x,y座標
			img00.lpbih -> biWidth,	//DIBの幅
			img00.lpbih -> biHeight,// DIBの高さ
			0, 0,			// DIBの座標 
			0,				// 走査線
			img00.lpbih -> biHeight, // 走査線数
			p,
			img00.lpbi, //BITMAPINFO:
				   //BITMAPINFOHEADER+RGBQUAD						   
			DIB_RGB_COLORS );
	return;
}

void gr_active()				// グラフィック画面を表に出す
{
	SetForegroundWindow( hwnd );
	return;
}

void gr_draw()					// 仮想画面をグラフィック画面にコピー
{	
	HDC hdc = GetDC( hwnd );
	BitBlt( hdc, 0, 0, x_size, y_size, mdc, 0, 0, SRCCOPY);
	ReleaseDC( hwnd, hdc);
}

void gr_quit()					// グラフィック画面の終了
{
	SendMessage( hwnd, WM_CLOSE, 0, 0 );
	return;
}
 
void gr_caption( char *p)			// キャプションのセット
{
	SetWindowText( hwnd, p );
}
//////////
char * file_open(void )
{
	OPENFILENAME fname;
	static char fn[256];
	char filename[64];
	memset(&fname, 0, sizeof(OPENFILENAME));
	fname.lStructSize    = sizeof(OPENFILENAME);
	fname.hwndOwner      = HWND_DESKTOP;
	fname.lpstrFilter    = "*.*\0*.*\0\0";
	fname.nFilterIndex   = 1;	// 1番目のファイルフィルタを使う
	fname.lpstrFile      = fn;	// 選択されたパス付きファイル名が格納されるアドレス	
	fname.nMaxFile       = sizeof(fn);
	fname.lpstrFileTitle = filename;
	fname.nMaxFileTitle  = sizeof(filename)-1;
	fname.lpstrTitle     = "AVIファイルを指定します";
	fname.Flags          = OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
	if( ! GetOpenFileName( &fname ) )	return NULL;
	return fn;
}

BYTE * swrite( BYTE * su, int n, BYTE * fp)
{
	int i;
	for( i = 0; i < n ; i++ ){
		*fp = *su;
		fp++; su++;
	}
	return fp;
}