//////////////////////////////////////////
// Glut_BCCProc.h
// Copyright (c) 10/26/2021 by BCCSkelton
//////////////////////////////////////////

/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//ウィンドウメッセージ関数
/////////////////////////////////
bool CMyWnd::OnInit(WPARAM wParam, LPARAM lParam) {

	//IDC_SELOBJの初期化
	for(int i = 0; i < 18; i++)
		SendItemMsg(IDC_SELOBJ, CB_ADDSTRING, 0, (LPARAM)g_ObjName[i]);
	SendItemMsg(IDC_SELOBJ, CB_SETCURSEL, 0, (LPARAM)0);
	//IDC_SELPROJの初期化
	for(int i = 0; i < 3; i++)
		SendItemMsg(IDC_SELPROJ, CB_ADDSTRING, 0, (LPARAM)g_ProjName[i]);
	SendItemMsg(IDC_SELPROJ, CB_SETCURSEL, 0, (LPARAM)0);
	//IDC_SELLIGHTの初期化
	for(int i = 0; i < 3; i++)
		SendItemMsg(IDC_SELLIGHT, CB_ADDSTRING, 0, (LPARAM)g_LightName[i]);
	SendItemMsg(IDC_SELLIGHT, CB_SETCURSEL, 0, (LPARAM)0);
	//チェックボックスの初期設定
	SendItemMsg(IDC_ROTATE, BM_SETCHECK, BST_CHECKED, (LPARAM)0);
	//スライダーの範囲設定
	SendItemMsg(IDC_ANGLE, TBM_SETRANGE, TRUE, (LPARAM)MAKELONG(0, 360));
	//ページサイズ（マウスクリック時の移動量）設定
	SendItemMsg(IDC_ANGLE, TBM_SETPAGESIZE, 0, (LPARAM)30);
	//ラインサイズ（矢印キーによる移動量）設定
	SendItemMsg(IDC_ANGLE, TBM_SETLINESIZE, 0, (LPARAM)10);
	//ポジションの設定
	SendItemMsg(IDC_ANGLE, TBM_SETPOS, TRUE, (LPARAM)0);
	//目盛りサイズの設定
	SendItemMsg(IDC_ANGLE, TBM_SETTICFREQ, 10, 0);
	return TRUE;
}

bool CMyWnd::OnHScroll(WPARAM wParam, LPARAM lParam) {

	if(!g_rotate && (HWND)lParam == GetDlgItem(m_hWnd, IDC_ANGLE)) {	//常時回転の場合、何もしない
		if(LOWORD(wParam) == TB_THUMBPOSITION || LOWORD(wParam) == TB_THUMBTRACK)
			g_r = (GLdouble)HIWORD(wParam);
		else
			g_r = (GLdouble)SendItemMsg(IDC_ANGLE, TBM_GETPOS, 0, (LPARAM)0);
	}
	return FALSE;	//アプリケーションでこのメッセージを処理する場合は、0 を返す必要があります。(MSDN)
}

bool CMyWnd::OnClose(WPARAM wParam, LPARAM lParam) {

	if(MessageBox(m_hWnd, "終了しますか", "終了確認",
					MB_YESNO | MB_ICONINFORMATION) == IDYES)
		//処理をするとDestroyWindow、PostQuitMessageが呼ばれる
		return TRUE;
	else
		//そうでなければウィンドウではDefWindowProc関数をreturn、ダイアログではreturn FALSEとなる。
		return FALSE;
}

//ダイアログベースの場合はこれが必要
bool CMyWnd::OnDestroy(WPARAM wPram, LPARAM lParam) {

	PostQuitMessage(0);
	return TRUE;
}

/////////////////////////////////
//主ウィンドウCMyWndの関数の定義
//メニュー項目、コントロール関数
/////////////////////////////////
bool CMyWnd::OnSelected(WPARAM wParam) {

	if(HIWORD(wParam) == CBN_SELCHANGE) {	//アイテムが選択された場合
		//IDC_SELOBJの選択内容を確認し、glにセットする
		int sel = SendItemMsg(IDC_SELOBJ, CB_GETCURSEL, 0, (LPARAM)0);
		gl.m_Obj = sel / 2;
		gl.m_sw = (sel % 2 == 1);	//Solid（TRUE）か否か（WireはFALSE）
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnSelCol() {

	CMNDLG cmndlg;
	COLORREF col = cmndlg.GetColor(m_hWnd);
	if(col) {
		g_Red = (GLdouble)GetRValue(col) / 255.0;
		g_Green = (GLdouble)GetGValue(col) / 255.0;
		g_Blue = (GLdouble)GetBValue(col) / 255.0;
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnCreate() {

	//テキストボックスの状態を変更する
	for(int i = 0; i < 9; i++)
		EnableWindow(GetDlgItem(m_hWnd, IDC_EYEX + i), TRUE);
	for(int i = 0; i < 4; i++)
		EnableWindow(GetDlgItem(m_hWnd, IDC_FOV + i), TRUE);
	//コンボボックスの状態を変更する
	EnableWindow(GetDlgItem(m_hWnd, IDC_SELPROJ), TRUE);
	//ラジオボタンの状態を変更する
	EnableWindow(GetDlgItem(m_hWnd, IDC_ROTATE), TRUE);
	EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHT), TRUE);
	//プッシュボタンの状態を変更する
	EnableWindow(GetDlgItem(m_hWnd, IDC_CREATE), FALSE);
	EnableWindow(GetDlgItem(m_hWnd, IDC_SETLA), TRUE);
	EnableWindow(GetDlgItem(m_hWnd, IDC_SETPROJ), TRUE);
	//CGLUTクラスインスタンスの初期設定
	gl.SetPos(100, 100);					//CGLUTの初期値
	gl.SetSize(640, 480);					//CGLUTの初期値
	gl.SetTitle("Glut Window");				//GLUTウィンドウタイトル
	//CGLUTクラスインスタンスの生成
	gl.Create();							//引数でウィンドウタイトル設定可
 	glClearColor(0.0, 0.0, 0.0, 0.0);		//黒で画面クリア
	glShadeModel(GL_SMOOTH);				//既定値の滑らかな網かけ（他の選択肢としてフラットシェーディング−GL_FLATがある）
	glEnable(GL_DEPTH_TEST);				//描画オブジェクトの陰面消去を行う為の深度処理
	gl.SetMode(GLUT_DOUBLE | GLUT_RGBA);	//CGLUTの初期値（ダブルバッファリング vs. GLUT_SINGLE）
  	//CGLUTコールバック関数の設定
	gl.Idle(gl_Idle);
	gl.Display(gl_Display);
	gl.Reshape(gl_Resize);
	gl.Loop();
	return TRUE;
}

bool CMyWnd::OnSetLA() {

	GLdouble val[9];
	for(int i = 0; i < 9; i++)
		val[i] = GetDouble(IDC_EYEX + i);
	gl.SetLA(	val[0], val[1], val[2],		//視点のポイント			(GLdouble) eyex, eyey, eyez,
				val[3], val[4], val[5],		//クリップシーンの中心点	(GLdouble) centerx, centery, centerz,
				val[6], val[7], val[8]);	//アップベクター			(GLdouble) upx, upy, upz
	gl.Refresh();
	return TRUE;
}

bool CMyWnd::OnSelProj(WPARAM wParam) {

	if(HIWORD(wParam) == CBN_SELCHANGE) {	//アイテムが選択された場合
		//IDC_SELPROJの選択内容を確認し、glにセットする
		gl.m_proj = SendItemMsg(IDC_SELPROJ, CB_GETCURSEL, 0, (LPARAM)0);	//投影法式変更
		SetControlState(gl.m_proj);			//投影法式に合わせたコントロールを有効化
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnSetProj() {

	switch(gl.m_proj) {
	default:
	case 0:
		//gluPerspective関数
		gl.m_fov = GetDouble(IDC_FOV);			//視野（Fiield of view）で単位は度
		gl.m_aspect = GetDouble(IDC_ASPECT);	//縦横比（幅 / 高さ）
		gl.m_near = GetDouble(IDC_NEAR);		//視点から近クリップ平面までの距離（正）
		gl.m_far = GetDouble(IDC_FAR);			//視点から遠クリップ平面までの距離（正）
		break;
	case 1:
		//glFrustum関数
		gl.m_left = GetDouble(IDC_LEFT);		//クリップ平面左座標
		gl.m_right = GetDouble(IDC_RIGHT);		//クリップ平面右座標
		gl.m_bottom = GetDouble(IDC_BOTTOM);	//クリップ平面下座標
		gl.m_top = GetDouble(IDC_TOP);			//クリップ平面上座標
		gl.m_near = GetDouble(IDC_NEAR);		//視点から近クリップ平面までの距離（正）
		gl.m_far = GetDouble(IDC_FAR);			//視点から遠クリップ平面までの距離（正）
		break;
	case 2:
		//glOrtho関数
		gl.m_left = GetDouble(IDC_LEFT);		//クリップ平面左座標
		gl.m_right = GetDouble(IDC_RIGHT);		//クリップ平面右座標
		gl.m_bottom = GetDouble(IDC_BOTTOM);	//クリップ平面下座標
		gl.m_top = GetDouble(IDC_TOP);			//クリップ平面上座標
		gl.m_front = GetDouble(IDC_BACK);		//手前クリップ平面座標
		gl.m_back = GetDouble(IDC_FRONT);		//奥クリップ平面座標
		break;
	}
	gl.Refresh();
	return TRUE;
}

bool CMyWnd::OnRotate() {

	if(SendItemMsg(IDC_ROTATE, BM_GETCHECK, 0, (LPARAM)0) == BST_CHECKED) {	//チェックボックスの状態確認
		SendItemMsg(IDC_ROTATE, BM_SETCHECK, BST_UNCHECKED, (LPARAM)0);
		g_rotate = FALSE;
		//テキストボックスを有効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_ENDX), TRUE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_ENDY), TRUE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_ENDZ), TRUE);
		//スライダーを有効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_ANGLE), TRUE);
	}
	else {
		SendItemMsg(IDC_ROTATE, BM_SETCHECK, BST_CHECKED, (LPARAM)0);
		g_rotate = TRUE;
		//テキストボックスを無効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_ENDX), FALSE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_ENDY), FALSE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_ENDZ), FALSE);
		//スライダーを無効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_ANGLE), FALSE);
	}
	return TRUE;
}

bool CMyWnd::OnEndXChanged(WPARAM wParam) {

	if(!g_rotate && HIWORD(wParam) == EN_CHANGE) {	//常時回転以外で、データが変更された場合
		g_x = GetDouble(IDC_ENDX);
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnEndYChanged(WPARAM wParam) {

	if(!g_rotate && HIWORD(wParam) == EN_CHANGE) {	//常時回転以外で、データが変更された場合
		g_y = GetDouble(IDC_ENDY);
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnEndZChanged(WPARAM wParam) {

	if(!g_rotate && HIWORD(wParam) == EN_CHANGE) {	//常時回転以外で、データが変更された場合
		g_z = GetDouble(IDC_ENDZ);
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnLight() {

	if(SendItemMsg(IDC_LIGHT, BM_GETCHECK, 0, (LPARAM)0) == BST_UNCHECKED) {	//チェックボックスの状態確認
		SendItemMsg(IDC_LIGHT, BM_SETCHECK, BST_CHECKED, (LPARAM)0);
		g_light = TRUE;
		//「色」ボタンを無効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_COLOR), FALSE);
		//テキストボックスを有効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHTX), TRUE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHTY), TRUE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHTZ), TRUE);
		//コンボボックスを有効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_SELLIGHT), TRUE);
		//光源を有効にする
		gl.Enable(GL_LIGHTING);
		//選択された光源(光源は8個まで設定可能)を有効にする
		gl.Enable(g_lightno[g_selected]);
		//物体の質感を有効にする設定を解除する
		gl.Disable(GL_COLOR_MATERIAL);
	}
	else {
		SendItemMsg(IDC_LIGHT, BM_SETCHECK, BST_UNCHECKED, (LPARAM)0);
		g_light = FALSE;
		//「色」ボタンを有効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_COLOR), TRUE);
		//テキストボックスを無効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHTX), FALSE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHTY), FALSE);
		EnableWindow(GetDlgItem(m_hWnd, IDC_LIGHTZ), FALSE);
		//コンボボックスを無効化する
		EnableWindow(GetDlgItem(m_hWnd, IDC_SELLIGHT), FALSE);
		//光源を無効にする
		gl.Disable(GL_LIGHTING);
		//現在選択されている光源を無効にする
		gl.Disable(g_lightno[g_selected]);
		//物体の質感を有効にする設定
		gl.Enable(GL_COLOR_MATERIAL);
	}
	return TRUE;
}

bool CMyWnd::OnLightXChanged(WPARAM wParam) {

	if(g_light && HIWORD(wParam) == EN_CHANGE) {	//照光効果が有効で、データが変更された場合
		g_lightpos[0] = GetDouble(IDC_LIGHTX);
		gl_Display();
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnLightYChanged(WPARAM wParam) {

	if(g_light && HIWORD(wParam) == EN_CHANGE) {	//照光効果が有効で、データが変更された場合
		g_lightpos[1] = GetDouble(IDC_LIGHTY);
		gl_Display();
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnLightZChanged(WPARAM wParam) {

	if(g_light && HIWORD(wParam) == EN_CHANGE) {	//照光効果が有効で、データが変更された場合
		g_lightpos[2] = GetDouble(IDC_LIGHTZ);
		gl_Display();
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnSelLight(WPARAM wParam) {

	if(HIWORD(wParam) == CBN_SELCHANGE) {	//アイテムが選択された場合
		//現在選択されている光源を無効にする
		gl.Disable(g_lightno[g_selected]);
		//IDC_SELLIGHTの選択内容を確認し、glにセットする
		g_selected = SendItemMsg(IDC_SELLIGHT, CB_GETCURSEL, 0, (LPARAM)0);	//投影法式変更
		//選択された光源を有効にする
		gl.Enable(g_lightno[g_selected]);
		gl_Display();
		return TRUE;
	}
	else
		return FALSE;
}

bool CMyWnd::OnIdok() {

	SendMsg(WM_CLOSE, 0, 0);
	return TRUE;
}

///////////////////
//ユーザー定義関数
///////////////////
//テキストボックスからGLDouble値を取得する
GLdouble CMyWnd::GetDouble(UINT id) {

	char buff[MAX_PATH];
	SendItemMsg(id, WM_GETTEXT, MAX_PATH, (LPARAM)buff);
	double res = strtod(buff, NULL);	//変換に失敗した場合は0.0を返す筈
	return (GLdouble)res;
}

void CMyWnd::SetControlState(int pattern = 0) {

	bool tof[10] = {FALSE};
	switch(pattern) {
	case 0:
		tof[0] = tof[1] = tof[2] = tof[3] = TRUE;
		break;
	case 1:
		tof[2] = tof[3] = tof[4] = tof[5] = tof[6] = tof[7] = TRUE;
		break;
	case 2:
		tof[4] = tof[5] = tof[6] = tof[7] = tof[8] = tof[9] = TRUE;
		break;
	default:
		break;
	}
	EnableWindow(GetDlgItem(m_hWnd, IDC_FOV), tof[0]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_ASPECT), tof[1]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_NEAR), tof[2]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_FAR), tof[3]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_LEFT), tof[4]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_RIGHT), tof[5]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_BOTTOM), tof[6]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_TOP), tof[7]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_BACK), tof[8]);
	EnableWindow(GetDlgItem(m_hWnd, IDC_FRONT), tof[9]);
}
