using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VisimBox.Renderer;
using OpenTK.Graphics.OpenGL;
using OpenTK.Graphics;
using VisimBox.Renderer.Render2D;


namespace VisimRenderGL
{
    partial class GLRenderContext : RenderContext
    {
        protected bool _IS2D = false;

        /// <summary>
        /// Sets renderer to 2d context, all 2d rendering calls should be done after this call!
        /// </summary>
        public override void Start2DRender()
        {
            if (_IS2D)
                return;

            GL.PushMatrix();
            GL.LoadIdentity();

            GL.MatrixMode(MatrixMode.Projection);
            GL.PushMatrix();

            //VisiMath.Matrix4 proj = VisiMath.Matrix4.CreateOrtographic(this.settings.Width, this.settings.Height, -1, 1);
            VisiMath.Matrix4 proj = VisiMath.Matrix4.CreateOrtographic(0,this.settings.Width, 0,this.settings.Height, -1, 1);
            LoadMatrix(ref proj);

            GL.MatrixMode(MatrixMode.Modelview);

            GL.Disable(EnableCap.Lighting);

            _IS2D = true;
        }

        /// <summary>
        /// Returns renderer to previous (3d) rendering state from the 2d renderer
        /// </summary>
        public override void Stop2DRender()
        {
            if (!_IS2D)
                return;
            GL.MatrixMode(MatrixMode.Projection);
            GL.PopMatrix();
            GL.MatrixMode(MatrixMode.Modelview);
            GL.PopMatrix();
            _IS2D = false;
            GL.Enable(EnableCap.Lighting);
        }


        /// <summary>
        /// Draw point in screen coordinates with currently selected color
        /// </summary>
        /// <param name="x">X position</param>
        /// <param name="y">Y position</param>
        public override void DrawPoint(int x, int y)        
        {
            GL.Begin(BeginMode.Points);
            GL.Vertex2(x, y);
            GL.End();
        }

        /// <summary>
        /// Draw line in screen coordinates with currently selected color
        /// </summary>
        /// <param name="x1">x of the start of the line</param>
        /// <param name="y1">y of the start of the line</param>
        /// <param name="x2">X of the end of the line</param>
        /// <param name="y2">y of the end of the line</param>
        public override void DrawLine(int x1, int y1, int x2, int y2)
        {
            GL.Begin(BeginMode.Lines);
            GL.Vertex2(x1, y1);
            GL.Vertex2(x2, y2);
            GL.End();
        }

        /// <summary>
        /// Draws outlined 2d rectangle with x1 and y1 coordinates of top left and width and height, using current color
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        public override void DrawRectangle(int x1, int y1, int width, int height)
        {
            GL.Begin(BeginMode.LineLoop);
            GL.Vertex2(x1, y1);
            GL.Vertex2(x1+width, y1);
            GL.Vertex2(x1 + width, y1+height);
            GL.Vertex2(x1, y1 + height);
            GL.End();
        }

        /// <summary>
        /// Draws filled 2d rectangle with x1 and y1 coordinates of top left and width and height, using current color
        /// </summary>
        /// <param name="x1">left upper corner</param>
        /// <param name="y1">left upper corner</param>
        /// <param name="width">width</param>
        /// <param name="height">height</param>
        public override void DrawFilledRectangle(int x1, int y1, int width, int height)
        {
            GL.Begin(BeginMode.Quads);
            GL.Vertex2(x1, y1);
            GL.Vertex2(x1 + width, y1);
            GL.Vertex2(x1 + width, y1 + height);
            GL.Vertex2(x1, y1 + height);
            GL.End();
        }

        /// <summary>
        /// Draws currently selected texture in real size to specified place on screen.
        /// NOTE - uses current color, don't forget to set it to white unless you want colored image
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        public override void DrawImage(int x, int y)
        {
            //Note!!! store data inside texture for array rendering?

            GL.PushMatrix();
            GL.Translate(x, y, 0);

            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(0.0f, 0.0f);
            GL.Vertex2(0.0f, 0.0f);

            GL.TexCoord2(1.0f, 0.0f);
            GL.Vertex2(_CurrentTexture.Width, 0.0f);

            GL.TexCoord2(1.0f, 1.0f);
            GL.Vertex2(_CurrentTexture.Width, _CurrentTexture.Height);

            GL.TexCoord2(0f, 1.0f);
            GL.Vertex2(0.0f, _CurrentTexture.Height);

            GL.End();
            GL.PopMatrix();
        }

        /// <summary>
        /// Draws currently selected texture scaled to specified width and height
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        public override void DrawImage(int x, int y, int width, int height)
        {
            //note!!! create array for faster drawing?
            GL.PushMatrix();
            GL.Translate(x, y, 0);

            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(0.0f, 0.0f);
            GL.Vertex2(0.0f, 0.0f);

            GL.TexCoord2(1.0f, 0.0f);
            GL.Vertex2(width, 0.0f);

            GL.TexCoord2(1.0f, 1.0f);
            GL.Vertex2(width, height);

            GL.TexCoord2(0f, 1.0f);
            GL.Vertex2(0.0f, height);

            GL.End();
            GL.PopMatrix();
        }


        /// <summary>
        /// Draws scaled part of the currently selected texture on the screen.
        /// </summary>
        /// <param name="x">X coordinate of top left corner</param>
        /// <param name="y">Y coordinate of top left corner</param>
        /// <param name="width">Width of the drawn image</param>
        /// <param name="height">Height of the drawn image</param>
        /// <param name="sourcex">X coordinate of top left corner inside the texture</param>
        /// <param name="sourcey">Y coordinate of top left corner inside the texture</param>
        /// <param name="sourcewidth">Width of the texture part</param>
        /// <param name="sourceheight">Height of the texture part</param>
        public override void DrawImagePart(int x, int y, int width, int height, int sourcex, int sourcey, int sourcewidth, int sourceheight)
        {
            //note!!! create array for faster drawing?
            GL.PushMatrix();
            GL.Translate(x, y, 0);

            float sx, sy, sx2, sy2;

            sx = ((float)sourcex) / _CurrentTexture.Width;
            sy = ((float)sourcey) / _CurrentTexture.Height;
            
            sx2 = ((float)(sourcex+sourcewidth)) / _CurrentTexture.Width;
            sy2 = ((float)(sourcey+sourceheight)) / _CurrentTexture.Height;


            GL.Begin(BeginMode.Quads);
            GL.TexCoord2(sx, sy);
            GL.Vertex2(0.0f, 0.0f);

            GL.TexCoord2(1.0f, 0.0f);
            GL.Vertex2(sx2, sy);

            GL.TexCoord2(1.0f, 1.0f);
            GL.Vertex2(sx2, sy2);

            GL.TexCoord2(0f, 1.0f);
            GL.Vertex2(sx, sy2);

            GL.End();
            GL.PopMatrix();
        }


        /// <summary>
        /// Draws sprite with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprite">Sprite information</param>
        public override void DrawSprite(int x, int y, ref SpriteInfo sprite)
        {
            //note!!! change sprite information for better optimalization, so it can be drawn as array!
            GL.PushMatrix();
            GL.Translate(x, y, 0);
            DrawSprite(ref sprite);
            GL.PopMatrix();
        }

        protected void DrawSprite(ref SpriteInfo sp)
        {            
            GL.Begin(BeginMode.Quads);
            for (int i = 0; i < 4; i++)
            {
                GL.TexCoord2(ref sp.Vertices[i].Tex.X);
                GL.Vertex2(ref sp.Vertices[i].Pos.X);
            }

            GL.End();
        }

        /// <summary>
        /// Draws array of sprites with currently selected texture
        /// </summary>
        /// <param name="x">X position (screen coords) for the sprite</param>
        /// <param name="y">Y position (screen coords) for the sprite</param>
        /// <param name="sprites">Sprite information</param>
        public override void DrawSprites(int x, int y, SpriteInfo[] sprites)
        {
            GL.PushMatrix();
            GL.Translate(x, y, 0);
            for (int i = 0; i < sprites.Length; i++)
                DrawSprite(ref sprites[i]);
            GL.PopMatrix();
        }

        public override void Draw2DArray(int x, int y, Vertex2D[] vertices)
        {
            GL.PushMatrix();
            GL.Translate(x, y, 0);
            GL.Begin(BeginMode.Quads);
            for (int i = 0; i < vertices.Length; i++)
            {
                GL.TexCoord2(ref vertices[i].Tex.X);
                GL.Vertex2(ref vertices[i].Pos.X);
            }
            //note optimize, draw as array!
            GL.End();
            GL.PopMatrix();
        }

    }
}
