// To try a demo, uncomment the name of the demo you want and comment out all the rest.
//#define DEMO_CORNFLOWERBLUE
//#define DEMO_STRESSTEST
#define DEMO_SPRITE

#if DEMO_CORNFLOWERBLUE

using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

class CornflowerBlueGame : Game
{
	public CornflowerBlueGame()
	{
		new GraphicsDeviceManager(this);
	}

	protected override void Draw(GameTime gameTime)
	{
		GraphicsDevice.Clear(Color.CornflowerBlue);
	}

	public static int Main(string[] args)
	{
		using (CornflowerBlueGame game = new CornflowerBlueGame())
		{
			game.Run();
		}

		return 0;
	}
}

#elif DEMO_STRESSTEST

/* SpriteBatch Stress Test
 * Written by Ethan "flibitijibibo" Lee
 * http://www.flibitijibibo.com/
 *
 * Released under public domain.
 * No warranty implied; use at your own risk.
 */

using System;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

class SpriteBatchTest : Game
{
	private const int SPRITECOUNT = 2048;
	private const int TEXTURECOUNT = 2;

	private const int TEXTURESIZE = 128;
	private static readonly Color TEXTURECOLOR = Color.White;

	private SpriteSortMode mode = SpriteSortMode.Deferred;

	private Stopwatch timer;
	private Random random;
	private Vector2[] positions;
	private Color[] colors;
	private Texture2D[] boxRefs;
	private Texture2D[] boxes;
	private SpriteBatch batch;

	public SpriteBatchTest() : base()
	{
		new GraphicsDeviceManager(this);
		timer = new Stopwatch();
		random = new Random();
		positions = new Vector2[SPRITECOUNT];
		colors = new Color[SPRITECOUNT];
		boxRefs = new Texture2D[SPRITECOUNT];
	}

	protected override void Draw(GameTime gameTime)
	{
		GraphicsDevice.Clear(Color.Black);
		timer.Start();
		batch.Begin(mode, BlendState.AlphaBlend);
		for (int i = 0; i < SPRITECOUNT; i += 1)
		{
			batch.Draw(boxRefs[i], positions[i], colors[i]);
		}
		batch.End();
		timer.Stop();
		Console.WriteLine(
			"Batch took " +
			timer.ElapsedMilliseconds.ToString() +
			"ms with " +
			mode.ToString()
		);
		timer.Reset();
	}

	protected override void Update(GameTime gameTime)
	{
		if (Keyboard.GetState().IsKeyDown(Keys.D1))
		{
			mode = SpriteSortMode.Deferred;
		}
		else if (Keyboard.GetState().IsKeyDown(Keys.D2))
		{
			mode = SpriteSortMode.Immediate;
		}
		else if (Keyboard.GetState().IsKeyDown(Keys.D3))
		{
			mode = SpriteSortMode.Texture;
		}
		else if (Keyboard.GetState().IsKeyDown(Keys.D4))
		{
			mode = SpriteSortMode.BackToFront;
		}
		else if (Keyboard.GetState().IsKeyDown(Keys.D5))
		{
			mode = SpriteSortMode.FrontToBack;
		}

		for (int i = 0; i < SPRITECOUNT; i += 1)
		{
			positions[i].X = (float)(random.NextDouble() * GraphicsDeviceManager.DefaultBackBufferWidth) - (boxes[0].Width / 2);
			positions[i].Y = (float)(random.NextDouble() * GraphicsDeviceManager.DefaultBackBufferHeight) - (boxes[0].Height / 2);
			colors[i].R = (byte)(random.NextDouble() * 255);
			colors[i].G = (byte)(random.NextDouble() * 255);
			colors[i].B = (byte)(random.NextDouble() * 255);
			colors[i].A = (byte)(random.NextDouble() * 255);
			boxRefs[i] = boxes[(int)(random.NextDouble() * TEXTURECOUNT)];
		}
	}

	protected override void LoadContent()
	{
		Color[] color = new Color[TEXTURESIZE * TEXTURESIZE];
		for (int i = 0; i < color.Length; i += 1)
		{
			color[i] = TEXTURECOLOR;
		}
		boxes = new Texture2D[TEXTURECOUNT];
		for (int i = 0; i < TEXTURECOUNT; i += 1)
		{
			boxes[i] = new Texture2D(GraphicsDevice, 128, 128);
			boxes[i].SetData(color);
		}
		batch = new SpriteBatch(GraphicsDevice);
	}

	protected override void UnloadContent()
	{
		batch.Dispose();
		batch = null;
		for (int i = 0; i < TEXTURECOUNT; i += 1)
		{
			boxes[i].Dispose();
			boxes[i] = null;
		}
		boxes = null;
	}

	public static int Main(string[] args)
	{
		using (SpriteBatchTest game = new SpriteBatchTest())
		{
			game.Run();
		}

		return 0;
	}
}

#elif DEMO_SPRITE

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Input.Touch;
using System;
using System.Diagnostics;
using static DemoSpriteGame;
using static SDL2.SDL;

class DemoSpriteGame : Game
{
	GraphicsDeviceManager gdm;
	Texture2D tex;
	RenderTarget2D renderTarget;
	Vector2 texPosition;
	SpriteBatch spriteBatch;

    private DateTime startTime;

    bool bindingsReady;

    public DemoSpriteGame()
	{
        gdm = new GraphicsDeviceManager(this);

		gdm.PreferredBackBufferWidth = 1920;
		gdm.PreferredBackBufferHeight = 1080;

		IsMouseVisible = true;

		SDL2.SDL.SDL_AddEventWatch(HandleSDLEvent, IntPtr.Zero);

		startTime = DateTime.Now;
	}

    static unsafe int HandleSDLEvent(IntPtr userdata, IntPtr sdlEventPointer)
	{
		SDL_Event *sdlEvent = (SDL_Event*) sdlEventPointer;

		switch (sdlEvent->type)
		{
			case SDL_EventType.SDL_MOUSEMOTION:
				break;

			case SDL_EventType.SDL_MOUSEBUTTONUP:
                break;

            case SDL_EventType.SDL_MOUSEBUTTONDOWN:
                break;

            case SDL_EventType.SDL_MOUSEWHEEL:
			{
				break;
			}

			default:
				break;
		}

		return 0;
	}


    protected override void LoadContent()
	{
		spriteBatch = new SpriteBatch(GraphicsDevice);

        tex = Content.Load<Texture2D>("fna");
        texPosition = new Vector2(GraphicsDevice.Viewport.Bounds.Width, GraphicsDevice.Viewport.Bounds.Height)/2;

        base.LoadContent();

        Debug.Print(SDL2.SDL.SDL_GetCurrentVideoDriver());
    }

	protected override void Update(GameTime gameTime)
	{
		GamePadState state = GamePad.GetState(PlayerIndex.One);

		const float speed = 10;
		texPosition.X += speed * state.ThumbSticks.Left.X;
		texPosition.Y += -speed * state.ThumbSticks.Left.Y;

		TouchCollection touches = TouchPanel.GetState();
		if (touches.Count > 0)
		{
			texPosition.X = touches[0].Position.X;
			texPosition.Y = touches[0].Position.Y;
		}

		base.Update(gameTime);
	}

	static int count;

	protected override void Draw(GameTime gameTime)
	{
		GraphicsDevice.Clear(Color.CornflowerBlue);

        DrawTestTriangle();

        // TODO: Add your drawing code here
        spriteBatch.Begin();
        spriteBatch.Draw(tex, texPosition, null, Color.White, 0, new Vector2(tex.Width / 2f, tex.Height / 2f), 0.25f, SpriteEffects.None, 0);
		spriteBatch.End();

		count++;
		

		base.Draw(gameTime);
    }

    protected override void OnExiting(Object sender, EventArgs args)
    {
        base.OnExiting(sender, args);

        // Stop the threads
    }

    public static int Main(string[] args)
	{
		// [Support library] is currently set up for OpenGL only
		SDL2.SDL.SDL_SetHint("FNA3D_FORCE_DRIVER", "OpenGL");

		// Demands OpenGL 4.x. On Windows this is needed for RenderDoc, on Mac it is needed for [Support Library] (without this Mac vends 2.1, [Support Library] needs 3.2)
		SDL2.SDL.SDL_SetHint("FNA3D_OPENGL_FORCE_CORE_PROFILE", "1");

		// On Mac, Mojoshader needs this to coexist with OpenGL 4.x. // FIXME: Is this needed/helpful on non-Mac?
		SDL2.SDL.SDL_SetHint("FNA3D_MOJOSHADER_PROFILE", "glspirv");

        using (DemoSpriteGame game = new DemoSpriteGame())
		{
			game.Run();
		}

		return 0;
	}

    static int something;
    void DrawTestTriangle()
    {
        VertexBuffer vertexBuffer;

        BasicEffect basicEffect;
        Matrix world = Matrix.CreateFromAxisAngle(new Vector3(0f, 0f, 1f), something / 100f);
        something += 1;
        Matrix view = Matrix.CreateLookAt(new Vector3(0, 0, 3), new Vector3(0, 0, 0), new Vector3(0, 1, 0));
        Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45), 800f / 480f, 0.01f, 100f);

        basicEffect = new BasicEffect(GraphicsDevice);

        VertexPositionColor[] vertices = new VertexPositionColor[3];
        vertices[0] = new VertexPositionColor(new Vector3(0, 1, 0), Color.Red);
        vertices[1] = new VertexPositionColor(new Vector3(+0.5f, 0, 0), Color.Green);
        vertices[2] = new VertexPositionColor(new Vector3(-0.5f, 0, 0), Color.Blue);

        vertexBuffer = new VertexBuffer(GraphicsDevice, typeof(VertexPositionColor), 3, BufferUsage.WriteOnly);
        vertexBuffer.SetData<VertexPositionColor>(vertices);

        basicEffect.World = world;
        basicEffect.View = view;
        basicEffect.Projection = projection;
        basicEffect.VertexColorEnabled = true;

        GraphicsDevice.SetVertexBuffer(vertexBuffer);

        RasterizerState rasterizerState = new RasterizerState();
        rasterizerState.CullMode = CullMode.None;
        GraphicsDevice.RasterizerState = rasterizerState;

        foreach (EffectPass pass in basicEffect.CurrentTechnique.Passes)
        {
            pass.Apply();
            GraphicsDevice.DrawPrimitives(PrimitiveType.TriangleList, 0, 1);
        }
    }
}

#endif
