using System;
using System.Windows.Forms;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics;

namespace EditedTriangle
{
    public partial class Form1 : Form
    {
        private int _shaderProgram;
        private int _uColorLocation;

        private string _vertexShaderSource =
            "#version 140\n" +
            "in vec2 aPosition;" +
            "void main()" +
            "{" +
            "    gl_Position = vec4(aPosition, 1.0, 1.0);"+
            "}";

        private string _fragmentShaderSource =
            "#version 140\n" +
            "out vec4 fragColor;" +
            "uniform vec3 uColor;" +
            "void main()" +
            "{" +
            "    fragColor = vec4(uColor, 1.0);" +
            "}";

        public Form1()
        {
            InitializeComponent();
            CenterToScreen();
        }

        private int InitShaders()
        {
            // Vertex Shader
            int vShader = GL.CreateShader(ShaderType.VertexShader);
            GL.ShaderSource(vShader, _vertexShaderSource);
            GL.CompileShader(vShader);
            // Check compilation
            int ok;
            GL.GetShader(vShader, ShaderParameter.CompileStatus, out ok);
            if (ok == 0)
            {
                string vShaderInfo = GL.GetShaderInfoLog(vShader);
                MessageBox.Show("Error in the vertex shader:\n" + vShaderInfo);
                return -1;
            }

            // Fragment Shader
            int fShader = GL.CreateShader(ShaderType.FragmentShader);
            GL.ShaderSource(fShader, _fragmentShaderSource);
            GL.CompileShader(fShader);
            GL.GetShader(fShader, ShaderParameter.CompileStatus, out ok);
            if (ok == 0)
            {
                string fShaderInfo = GL.GetShaderInfoLog(fShader);
                MessageBox.Show("Error in the fragment shader:\n" + fShaderInfo);
                return -1;
            }

            int program = GL.CreateProgram();
            GL.AttachShader(program, vShader);
            GL.AttachShader(program, fShader);
            GL.LinkProgram(program);
            GL.UseProgram(program);

            return program;
        }

        private void InitVertexBuffers()
        {
            float[] vertices = new float[]
            {
                0.0f, 0.5f,
                -0.5f, -0.5f,
                0.5f, -0.5f
            };

            int vbo;
            GL.GenBuffers(1, out vbo);

            GL.BindBuffer(BufferTarget.ArrayBuffer, vbo);
            // Get an array size in bytes
            int sizeInBytes = vertices.Length * sizeof(float);
            // Send the vertex array to a video card memory
            GL.BufferData(BufferTarget.ArrayBuffer, sizeInBytes, vertices, BufferUsageHint.StaticDraw);
            // Config
            GL.VertexAttribPointer(0, 2, VertexAttribPointerType.Float, false, 0, 0);
            GL.EnableVertexAttribArray(0);
        }

        private void glControl_Load(object sender, EventArgs e)
        {
            // Initialize shaders and get a shader program
            _shaderProgram = InitShaders();
            if (_shaderProgram < 0) return;

            // Initialize vertex buffers
            InitVertexBuffers();

            _uColorLocation = GL.GetUniformLocation(_shaderProgram, "uColor");
            if (_uColorLocation < 0)
            {
                MessageBox.Show("Failed to get uColorLocation variable");
                return;
            }

            // Set a triangle color
            GL.Uniform3(_uColorLocation, 0.1f, 0.8f, 0.3f);

            GL.ClearColor(Color4.Wheat);
        }

        private void glControl_Paint(object sender, PaintEventArgs e)
        {
            GL.Clear(ClearBufferMask.ColorBufferBit);
            GL.DrawArrays(PrimitiveType.Triangles, 0, 3);
            glControl.SwapBuffers();
        }

        private void btnBGColor_Click(object sender, EventArgs e)
        {
            if (bgColorDialog.ShowDialog() == DialogResult.OK)
            {
                GL.ClearColor(bgColorDialog.Color);
                glControl.Invalidate();
            }
        }

        private void btnTriangleColor_Click(object sender, EventArgs e)
        {
            if (triColorDialog.ShowDialog() == DialogResult.OK)
            {
                float r = triColorDialog.Color.R / 255f;
                float g = triColorDialog.Color.G / 255f;
                float b = triColorDialog.Color.B / 255f;
                GL.Uniform3(_uColorLocation, r, g, b);
                glControl.Invalidate();
            }
        }
    }
}
