///////////////////////////////////////////
// OpenTK_GLControl01.cpp
// Copyrignt (c) 2024 byYsama
///////////////////////////////////////////
using System;
using System.Drawing;
using System.Windows.Forms;
using OpenTK;						//OpenTKを使用する際に必須
using OpenTK.Graphics;				//OpenTKのグラフィックを使用する際に必須
using OpenTK.Graphics.OpenGL;		//OpenGLを使用する際に必要

namespace OpenTK_GLControl01
{
	class App
	{
		[STAThread]
		static void Main()
		{
			Application.Run(new OpenTKForm());
		}
	}

	public partial class OpenTKForm : Form
	{
		private GLControl glControl;	//GLControl
		private int angle = 0;			//画像の回転用
		private Timer renderTimer;		//再描画用タイマー

		public OpenTKForm()
		{
			this.Text = "OpenTK_GLControl01";
			this.ClientSize = new Size(640, 480);
			this.MinimumSize = new Size(480, 360);
			this.Load += new EventHandler(Form_Load);
		}

		private void Form_Load(object sender, EventArgs e)
		{
			//Formのコントロールレイアウトロジック保留
			SuspendLayout();
			//GLControl関連
			glControl = new GLControl();
			glControl.Size = new Size(this.Width, this.Height);
			glControl.Location = new System.Drawing.Point(0, 0);
			glControl.Load += new EventHandler(glControl_Load);
			glControl.Resize += new EventHandler(glControl_Resize);
			glControl.Paint += new PaintEventHandler(glControl_Paint);
			Controls.Add(glControl);
			//Timerの設定
			renderTimer = new Timer();
			renderTimer.Interval = 16; // 約120FPS (1000ms / 60 ≈ 16ms)
			renderTimer.Tick += renderTimer_Tick;
			renderTimer.Start();
			//Formのコントロールレイアウトロジック再開
			ResumeLayout();
		}

		private void glControl_Load(object sender, EventArgs e)
		{
			GL.ClearColor(Color.White);			//背景色の設定
			GL.Enable(EnableCap.DepthTest);		//デプスバッファの使用
			glControl_SetProjection();			//Projectionの設定
			glControl_SetModelView();			//ModelViewの設定
			glControl_SetLight();				//ライトの設定
			glControl.Refresh();				//再描画
		}

		private void glControl_Resize(object sender, EventArgs e)
		{
			glControl.Dock = DockStyle.Fill;	//All the control's edges are docked to the all edges of its containing control and sized appropriately.
			glControl_SetProjection();
			glControl_SetModelView();			//ModelViewの設定
			glControl_SetLight();				//ライトの設定
			glControl.Refresh();				//再描画
		}

		private void glControl_Paint(object sender, PaintEventArgs e)
		{
			//色と深度バッファーを初期化
			GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
			//モデルビューにして視点を設定
			glControl_SetModelView();
			GL.Material(MaterialFace.Front, MaterialParameter.Diffuse, Color.Red);	//質感の設定
			DrawBox();							//赤の直方体を描画
			glControl.SwapBuffers();
		}

		private void renderTimer_Tick(object sender, EventArgs e)
		{
			glControl.Refresh();	// 3次元表示を更新する
		}

		private void glControl_SetProjection()
		{
			//ビューポートの設定
			GL.Viewport(0, 0, glControl.Size.Width, glControl.Size.Height);
			//視野空間の設定
			GL.MatrixMode(MatrixMode.Projection);
			//透視投影－尚、glControl.AspectRatioは、(float)glControl.Width / (float)glControl.Heightと等価
			Matrix4 projection = Matrix4.CreatePerspectiveFieldOfView((float)Math.PI / 4, glControl.AspectRatio, 0.1f, 64.0f);
			GL.LoadMatrix(ref projection);
		}

		void glControl_SetModelView(float x = 0.0f, float y = 0.0f, float z = 5.0f)
		{
			GL.MatrixMode(MatrixMode.Modelview);	//モデルビューを選択
			//視点を設定して原点(0, 0, 0)を見る
			Vector3 eye = new Vector3(3.0f * Vector3.UnitX + 2.0f * Vector3.UnitY);
			Matrix4 modelview = Matrix4.LookAt(eye, Vector3.Zero, Vector3.UnitY);	//gluLookAt(5, 2, 0, 0, 0, 0, 0, 1, 0);
			GL.LoadMatrix(ref modelview);			//現在の変換マトリックスに設定
		}

		void glControl_SetLight(float x = 50.0f, float y = 50.0f, float z = 10.0f)
		{
			//光源の使用
			GL.Enable(EnableCap.Lighting);
			//ライト0の設定
			GL.Enable(EnableCap.Light0);
			float[] pos = new float[] {1.0f, 2.0f, 3.0f, 0.0f};
			GL.Light(LightName.Light0, LightParameter.Position, pos);
		}

		private void DrawBox()
		{
			GL.PushMatrix();
			{
				//Y軸周りに変数angleで指定した角度だけ直方体を回転
				GL.Rotate(angle, 0, 1, 0);
				angle += 2;
				double w = 0.5, h = 0.2, d = 0.7;
				//直方体の各6面を描画（面の向きと4つの頂点をGL.BeginとGL.Endで囲まれた{…}の中で指定）
				GL.Begin(PrimitiveType.TriangleStrip);
				{
					GL.Normal3(Vector3.UnitX);
					GL.Vertex3(w, h, -d);   GL.Vertex3(w, h, d);
					GL.Vertex3(w, -h, -d);  GL.Vertex3(w, -h, d);
				}
				GL.End();
				GL.Begin(PrimitiveType.TriangleStrip);
				{
					GL.Normal3(-Vector3.UnitX);
					GL.Vertex3(-w, -h, -d);  GL.Vertex3(-w, -h, d);
					GL.Vertex3(-w, h, -d);   GL.Vertex3(-w, h, d);
				}
				GL.End();
				GL.Begin(PrimitiveType.TriangleStrip);
				{
					GL.Normal3(Vector3.UnitY);
					GL.Vertex3(w, h, d);  GL.Vertex3(-w, h, d);
					GL.Vertex3(w, h, -d);  GL.Vertex3(-w, h, -d);
				}
				GL.End();
				GL.Begin(PrimitiveType.TriangleStrip);
				{
					GL.Normal3(-Vector3.UnitY);
					GL.Vertex3(w, -h, d);   GL.Vertex3(w, -h, -d);
					GL.Vertex3(-w, -h, d);  GL.Vertex3(-w, -h, -d);
				}
				GL.End();
				GL.Begin(PrimitiveType.TriangleStrip);
				{
					GL.Normal3(Vector3.UnitZ);
					GL.Vertex3(w, h, d);   GL.Vertex3(-w, h, d);
					GL.Vertex3(w, -h, d);  GL.Vertex3(-w, -h, d);
				}
				GL.End();
				GL.Begin(PrimitiveType.TriangleStrip);
				{
					GL.Normal3(-Vector3.UnitZ);
					GL.Vertex3(w, h, -d);   GL.Vertex3(-w, h, -d);
					GL.Vertex3(w, -h, -d);  GL.Vertex3(-w, -h, -d);
				}
				GL.End();
			}
			GL.PopMatrix();
		}
	}
}
