using System;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.DirectX;
using Microsoft.DirectX.Direct3D;
using Microsoft.DirectX.DirectInput;

namespace DirectXEksempel03
{
    public abstract class Model
    {
        private Vector3 position;   // X, Y, Z
        private int color;          // System.Drawing.Color
        private float size;         // Scale factor
        private float pitch = 0;    // Radianer
        private float yaw = 0;      // Radianer
        private float roll = 0;     // Radianer

        public Model(Vector3 aPosition, int aColor, float aSize)
        {
            position = aPosition;
            color = aColor;
            size = aSize;
        }

        public int Color 
        {
            get { return color; }
            set { color = value; }
        }

        public Vector3 Position
        {
            get { return position; }
            set { position = value; }
        }

        public float Size
        {
            get { return size; }
            set { size = value; }
        }

        public float Pitch 
        {
            get { return pitch; }
            set { pitch = value; }
        }

        public float Yaw
        {
            get { return yaw; }
            set { yaw = value; }
        }

        public float Roll
        {
            get { return roll; }
            set { roll = value; }
        }
    }

    public class Terning : Model
    {
        private CustomVertex.PositionColored[] vb1 = null;
        private CustomVertex.PositionColored[] vb2 = null;
        private CustomVertex.PositionColored[] vb3 = null;
        private CustomVertex.PositionColored[] vb4 = null;
        private CustomVertex.PositionColored[] vb5 = null;
        private CustomVertex.PositionColored[] vb6 = null;

        public Terning(Vector3 aPosition, int aColor, float aSize)
            : base(aPosition, aColor, aSize)
        {
            int i;
            // Forside
            vb1 = new CustomVertex.PositionColored[4];
            i = 0;
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, -0.5F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.5F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.5F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, -0.5F, -0.5F), Color);
            // Højre
            vb2 = new CustomVertex.PositionColored[4];
            i = 0;
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, -0.5F, -0.5F), Color);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.5F, -0.5F), Color);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.5F, 0.5F), Color);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, -0.5F, 0.5F), Color);
            // Venstre
            vb3 = new CustomVertex.PositionColored[4];
            i = 0;
            vb3[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.5F, 0.5F), Color);
            vb3[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.5F, -0.5F), Color);
            vb3[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, -0.5F, -0.5F), Color);
            vb3[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, -0.5F, 0.5F), Color);
            // Bagside
            vb4 = new CustomVertex.PositionColored[4];
            i = 0;
            vb4[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.5F, 0.5F), Color);
            vb4[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.5F, 0.5F), Color);
            vb4[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, -0.5F, 0.5F), Color);
            vb4[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, -0.5F, 0.5F), Color);
            // Top
            vb5 = new CustomVertex.PositionColored[4];
            i = 0;
            vb5[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.5F, -0.5F), Color);
            vb5[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.5F, 0.5F), Color);
            vb5[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.5F, 0.5F), Color);
            vb5[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.5F, -0.5F), Color);
            // Bund
            vb6 = new CustomVertex.PositionColored[4];
            i = 0;
            vb6[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, -0.5F, -0.5F), Color);
            vb6[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, -0.5F, -0.5F), Color);
            vb6[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, -0.5F, 0.5F), Color);
            vb6[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, -0.5F, 0.5F), Color);
        }

        public void Render(Microsoft.DirectX.Direct3D.Device device, Matrix m)
        {
            device.Transform.World = Matrix.Scaling(Size, Size, Size) * m *
                Matrix.Translation(Position);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vb1);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vb2);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vb3);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vb4);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vb5);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 2, vb6);
        }

    }

    public class PaperPlane : Model
    {
        private CustomVertex.PositionColored[] vb1 = null;
        private CustomVertex.PositionColored[] vb2 = null;
        private int secondColor;
        private float speed;
        private bool animate;
        private float yawIncrement;

        public int SecondColor 
        {
            get { return secondColor; }
        }

        public float Speed
        {
            get { return speed; }
            set { speed = value; }
        }

        public bool Animate
        {
            get { return animate; }
            set { animate = value; }
        }

        public float YawIncrement
        {
            get { return yawIncrement; }
            set { yawIncrement = value; }
        }

        public PaperPlane(Vector3 aPosition, int aColor, int aSecondColor, float aSize)
            : base(aPosition, aColor, aSize)
        {
            secondColor = aSecondColor;
            speed = 1F;
            yawIncrement = 0F;
            int i;
            // Overside
            vb1 = new CustomVertex.PositionColored[6];
            i = 0;
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(0.0F, 0.0F, 0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.0F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(0.2F, 0.0F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(0.0F, -0.5F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(-0.2F, 0.0F, -0.5F), Color);
            vb1[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.0F, -0.5F), Color);
            // Underside
            vb2 = new CustomVertex.PositionColored[6];
            i = 0;
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.0F, 0.0F, 0.5F), SecondColor);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(-0.5F, 0.0F, -0.5F), SecondColor);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(-0.2F, 0.0F, -0.5F), SecondColor);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.0F, -0.5F, -0.5F), SecondColor);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.2F, 0.0F, -0.5F), SecondColor);
            vb2[i++] = new CustomVertex.PositionColored(new Vector3(0.5F, 0.0F, -0.5F), SecondColor);
        }

        private void ReadUserInput(Microsoft.DirectX.DirectInput.Device keyb)
        {
            KeyboardState keys = keyb.GetCurrentKeyboardState();

            if (keys[Key.Right])
            { // Flyet drejer og krænger til højre
                YawIncrement += 0.001f;
                Roll -= 0.01f;
            }

            if (keys[Key.Left])
            { // Flyet drejer og krænger til venstre
                YawIncrement -= 0.001f;
                Roll += 0.01f;
            }

            if (keys[Key.Down])
            { // Styrepind tilbage - flyet hæver næsen
                Pitch -= 0.01f;
            }

            if (keys[Key.Up])
            { // Styrepind fremad - flyet sænker næsen
                Pitch += 0.01f;
            }
        }

        public void Render(Microsoft.DirectX.Direct3D.Device device, 
            Microsoft.DirectX.DirectInput.Device keyb, Matrix m)
        {
            this.ReadUserInput(keyb);
            device.Transform.World = Matrix.Scaling(Size, Size, Size) * 
                Matrix.RotationYawPitchRoll(Yaw, Pitch, Roll) *
                m * Matrix.Translation(Position);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 4, vb1);
            device.DrawUserPrimitives(PrimitiveType.TriangleFan, 4, vb2);
            if (Animate)
            {
                // Beregning af næste position
                Vector3 v = new Vector3(0, 0, 0);
                v.TransformCoordinate(
                    Matrix.Translation(new Vector3(0, 0, Speed))
                    * Matrix.RotationYawPitchRoll(Yaw, Pitch, Roll));
                Position += v;
                Yaw += YawIncrement;
            }
        }
    }

    public partial class Form1 : Form
    {
        // Global variables for this project
        private Microsoft.DirectX.Direct3D.Device device = null; // Rendering device
        private Microsoft.DirectX.DirectInput.Device keyb = null; // Keyboard device
        private Terning t1 = new Terning(new Vector3(100F, 100F, 0F), System.Drawing.Color.Red.ToArgb(), 100F);
        private Terning t2 = new Terning(new Vector3(-100F, 100F, 50F), System.Drawing.Color.Green.ToArgb(), 50F);

        private PaperPlane p1 = new PaperPlane(new Vector3(-150, 150, 0), 
            System.Drawing.Color.Beige.ToArgb(), System.Drawing.Color.Gray.ToArgb(), 20F);
                        
        private float angle1 = 0F;
        private float angle2 = 0F;
        private bool pause = false;

        private CustomVertex.PositionColored[] v = new CustomVertex.PositionColored[10];

        

        public Form1() // Constructor
        {
            // Set the initial size of the form
            this.ClientSize = new System.Drawing.Size(800, 600);
            // And its caption
            this.Text = "DirectX Eksempel 3";
        }

        public void Render()
        {
            if (device == null)
                return;

            //Clear the backbuffer to a blue color 
            device.Clear(ClearFlags.ZBuffer | ClearFlags.Target, System.Drawing.Color.MidnightBlue, 1.0f, 0);
            //Begin the scene
            device.BeginScene();
            device.VertexFormat = CustomVertex.PositionColored.Format;
            device.DrawUserPrimitives(PrimitiveType.LineList, 2, v);
            p1.Render(device, keyb, Matrix.Identity);
            t1.Render(device, Matrix.RotationY(angle1));
            t2.Render(device, Matrix.RotationZ(angle2));
            //End the scene
            device.EndScene();
            device.Present();
            angle1 += 0.01f; // Ny linie
            angle2 -= 0.02f; // Ny linie
        }

        public void InitializeKeyboard()
        {
            keyb = new Microsoft.DirectX.DirectInput.Device(SystemGuid.Keyboard);
            keyb.SetCooperativeLevel(this, CooperativeLevelFlags.Background | CooperativeLevelFlags.NonExclusive);
            keyb.Acquire();
        }
        
        public void InitializeGraphics()
        {
            // Definering af device til DirectX Rendering
            PresentParameters presentParams = new PresentParameters();
            presentParams.Windowed = true;
            presentParams.SwapEffect = SwapEffect.Discard;
            presentParams.AutoDepthStencilFormat = DepthFormat.D16;
            presentParams.EnableAutoDepthStencil = true;
            device = new Microsoft.DirectX.Direct3D.Device
                (0, Microsoft.DirectX.Direct3D.DeviceType.Hardware, this,
                CreateFlags.SoftwareVertexProcessing, presentParams);

            //Placering af kameraet
            device.Transform.Projection = Matrix.PerspectiveFovLH((float)Math.PI / 4,
                this.Width / this.Height, 0f, 50f);
            device.Transform.View = Matrix.LookAtLH(new Vector3(0, 0, -500),
                new Vector3(0, 0, 0), new Vector3(0, 1, 0));
            //device.RenderState.CullMode = Cull.None;
            device.RenderState.ZBufferEnable = true;
            device.RenderState.ZBufferWriteEnable = true;
            device.RenderState.Lighting = false;
            // Papirflyverens orientering i rummet:
            p1.Yaw = (float)(2F * Math.PI / 360F) * 0F;
            p1.Pitch = (float)(2F * Math.PI / 360F) * 0F;
            p1.Roll = (float)(2F * Math.PI / 360F) * 0F;
            p1.Animate = true;
            v[0].X = 0; v[0].Y = 0; v[0].Z = 0;
            v[1].X = 20; v[1].Y = 0; v[1].Z = 0;
        }

        protected override void OnResize(EventArgs e)
        {
            pause = ((this.WindowState == FormWindowState.Minimized) ||
                (this.WindowState == FormWindowState.Maximized) ||
                !this.Visible);
        }

        static void Main() // Entry point
        {
            using (Form1 engine = new Form1())
            {
                engine.InitializeGraphics();
                engine.InitializeKeyboard();
                engine.Show();

                // While the form is still valid, render and process messages
                while (engine.Created) // Pulsen
                {
                    engine.Render();
                    Application.DoEvents();
                }
            }
        }
    }
}