Imports System
Imports System.Collections.Generic
Imports System.Threading
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO
Imports System.Diagnostics

Imports OpenTK
Imports OpenTK.Graphics
Imports OpenTK.Graphics.OpenGL
Imports EZGL2D

Namespace EZGL2Dexample2Dwith3D
	Public Class GL2Dexample ' inherit the GameWindow class
		Inherits GameWindow

		Private Const SCREEN_WIDTH As Integer = 800 ' screen dimension
		Private Const SCREEN_HEIGHT As Integer = 600

		Private cubeDisplayList As Integer ' out display list

		Private timer As New Stopwatch() ' timer used for animation
		Private frame As Integer ' frame counter
		Private magicSprite As GL2D.SpriteGL ' our sprite


		' Init screen
		Public Sub New()
			MyBase.New(SCREEN_WIDTH, SCREEN_HEIGHT)

		End Sub

		' this is where you would initialize everything
		' like loading textures, setting up OpenGL screen, etc.
		Protected Overrides Sub OnLoad(ByVal e As EventArgs)
			MyBase.OnLoad(e)
			timer.Start()

			VSync = VSyncMode.On ' force vertical synching
			Title = "EZGL2D is too easy to use it hurts!" ' set the title
			'WindowBorder = WindowBorder.Hidden;           // hide the window

			' Load our sprite
			magicSprite = GL2D.LoadSprite("data/EZGL2Dexample2Dwith3D/magic.png", CInt(TextureMinFilter.Linear))

			initCubeDisplayList() ' initialize our display list

		End Sub

		Protected Overrides Sub OnResize(ByVal e As EventArgs)
			MyBase.OnResize(e)
			GL2D.Screen2D(Width, Height) ' reset the screen every resize
		End Sub

		' this is where all your game logic
		' should be done. (Input, Entity movement, collisions, etc)
		Protected Overrides Sub OnUpdateFrame(ByVal e As FrameEventArgs)
			MyBase.OnUpdateFrame(e)


			' get input
			If Keyboard(OpenTK.Input.Key.Escape) Then
				GL.DeleteLists(cubeDisplayList, 1)
				Me.Exit()
				'Console.WriteLine("FPS = {0}", frame / (timer.ElapsedMilliseconds / 1000));
				Return
			End If
		End Sub

		' This is where all rendering/drawing should be done
		Protected Overrides Sub OnRenderFrame(ByVal e As FrameEventArgs)
			MyBase.OnRenderFrame(e)

			frame += 1

			Dim time As Double = timer.ElapsedMilliseconds * 0.001 ' get timer in seconds

			GL2D.ClearScreen() ' clear the screen

			GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Line) ' draw only lines

			GL.Disable(EnableCap.Texture2D) ' disable texturing so we see lines
			GL.Enable(EnableCap.Blend) ' blend 'em
			GL2D.BlendMode(GL2D.BLEND_MODE.GL2D_GLOW) ' glow it

			' 3D mode is active when we don't call GL2D.Begin2D()

			' Draw the single moving cube
            GL.Color4(1, 1, 1, 1.0)
			GL.PushMatrix()
				GL.Translate(Math.Sin(time * 0.2), Math.Cos(time * 0.7), Math.Cos(time) + Math.Sin(time))
				GL.Rotate(time * 100, 1, 0, 0)
				GL.Rotate(time * 100, 0, 1, 0)
				GL.Rotate(time * 100, 0, 0, 1)
				DrawCube()
			GL.PopMatrix()


			' do some crazy math in preparation for drawing multicubes
			Dim ti As Double = time * 0.002208
			Dim t As Double = ti * 180.5 * (Math.Sin(time / 1150.0) + 360 * Math.Cos(time / 2250.0) + 90 * Math.Sin(time / 1540.0))
			Dim dt As Double = 0.80130 + 2.0124 * (Math.Sin(time / 30.0) * Math.Sin(time / 140.0) * Math.Cos(time / 340.0))

			' draw the multicube
			GL.PushMatrix()
				GL.Scale(10, 10, 10) ' make the next linecube bigger
				' Do some pseudo Inverse Kinematics
				Dim color As Single = 0.0001F
				For i As Integer = 0 To 511
					t += dt
					GL.Color4(color, color * 0.7, color * 0.3, color)
					' Rotate and draw
					GL.PushMatrix()
						GL.Rotate(t * 1, 1, 0, 0)
						GL.Rotate(t * 2, 0, 1, 0)
						GL.Rotate(t * 3, 0, 0, 1)
						DrawCube()
					GL.PopMatrix()

					' Increase color
					color += (0.0005232151F * ((i * i * i) * 0.00000012F))
					' decrease the size of each succeedinng linecube
					GL.Scale(0.98899999, 0.98899999, 0.98899999)
				Next i
			GL.PopMatrix()

			' End of 3D mode


			GL2D.Begin2D() ' start 2D drawing mode

				' draw four timer animated sprites
				GL.Color4(1.0F, 1.0F, 1.0F, 1.0F)
				GL2D.BlendMode(GL2D.BLEND_MODE.GL2D_ALPHA)
				Dim dx As Single = (CSng(Math.Cos(time * 2.0R)) + CSng(Math.Cos(time * 4.0R))) * 180
				Dim dy As Single = (CSng(Math.Sin(time * 3.0R)) + CSng(Math.Cos(time * 1.0R))) * 120
				Dim cx As Single = Width \ 2
				Dim cy As Single = Height \ 2
				GL2D.SpriteRotateScale(CInt(Math.Truncate(cx + dx)), CInt(Math.Truncate(cy + dy)), CSng(time) * 500, 1, 1, GL2D.SpriteGL.FLIP_NONE, magicSprite)
				GL2D.SpriteRotateScale(CInt(Math.Truncate(cx - dx)), CInt(Math.Truncate(cy - dy)), CSng(time) * -500, 1, 1, GL2D.SpriteGL.FLIP_NONE, magicSprite)
				GL2D.SpriteRotateScale(CInt(Math.Truncate(cx + dx)), CInt(Math.Truncate(cy - dy)), CSng(time) * 500, 1, 1, GL2D.SpriteGL.FLIP_NONE, magicSprite)
				GL2D.SpriteRotateScale(CInt(Math.Truncate(cx - dx)), CInt(Math.Truncate(cy + dy)), CSng(time) * -500, 1, 1, GL2D.SpriteGL.FLIP_NONE, magicSprite)

			GL2D.End2D()


			Me.SwapBuffers() ' copy what we draw to screen

			Thread.Sleep(1) ' sleep so that we don't hog CPU

		End Sub

		' Draws a single cube
		Private Sub DrawCube()
			GL.CallList(cubeDisplayList)
		End Sub

		' initializes our display list
		Private Sub initCubeDisplayList()
			cubeDisplayList = GL.GenLists(1)
			GL.NewList(cubeDisplayList, ListMode.Compile)

			GL.Begin(PrimitiveType.Quads)

			GL.Vertex3(-1.0F, -1.0F, -1.0F)
			GL.Vertex3(-1.0F, 1.0F, -1.0F)
			GL.Vertex3(1.0F, 1.0F, -1.0F)
			GL.Vertex3(1.0F, -1.0F, -1.0F)

			GL.Vertex3(-1.0F, -1.0F, -1.0F)
			GL.Vertex3(1.0F, -1.0F, -1.0F)
			GL.Vertex3(1.0F, -1.0F, 1.0F)
			GL.Vertex3(-1.0F, -1.0F, 1.0F)

			GL.Vertex3(-1.0F, -1.0F, -1.0F)
			GL.Vertex3(-1.0F, -1.0F, 1.0F)
			GL.Vertex3(-1.0F, 1.0F, 1.0F)
			GL.Vertex3(-1.0F, 1.0F, -1.0F)

			GL.Vertex3(-1.0F, -1.0F, 1.0F)
			GL.Vertex3(1.0F, -1.0F, 1.0F)
			GL.Vertex3(1.0F, 1.0F, 1.0F)
			GL.Vertex3(-1.0F, 1.0F, 1.0F)

			GL.Vertex3(-1.0F, 1.0F, -1.0F)
			GL.Vertex3(-1.0F, 1.0F, 1.0F)
			GL.Vertex3(1.0F, 1.0F, 1.0F)
			GL.Vertex3(1.0F, 1.0F, -1.0F)

			GL.Vertex3(1.0F, -1.0F, -1.0F)
			GL.Vertex3(1.0F, 1.0F, -1.0F)
			GL.Vertex3(1.0F, 1.0F, 1.0F)
			GL.Vertex3(1.0F, -1.0F, 1.0F)

			GL.End()

			GL.EndList()

		End Sub

        <STAThread()> _
  Public Shared Sub Main()
            Using example As New GL2Dexample()
                example.Run(60) ' run the game at 60 frames per second\
            End Using
        End Sub

	End Class
End Namespace
