'
'
'	EZ GL2D For NET (C#, VB, C++/CLI, F#, ironPython, etc.) 
'
'	Relminator 2014
'	Richard Eric M. Lope BSN RN
'
'	http://rel.phatcode.net
'
'    License:
'
'    Copyright (c) 2010 - 2014 
'
'    Source is released under the LGPL license with these additional provisions:
' 
'        Permission is granted, free of charge, for anyone(without restrictions).. 
'        1. To use the source in any way as long as it does not harm someone else. 
'        2. To edit/modify the source in any way they want.
'        3. To distribute the source along with its accompanying files.
'
'    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
'    EXPRESS OR IMPLIED.
'    IN NO EVENT SHALL THE AUTHOR OR COPYRIGHT HOLDER BE LIABLE FOR
'    ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 
'    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 
'    OTHER DEALINGS IN THE SOFTWARE.
'
'


'!
' \mainpage EZ GL2D Documentation
'
' \section author Author
' 
'    EZ GL2D For NET (C#, VB, C++/CLI, F#, ironPython, etc.) 
'
'	Relminator 2014
' 
'	Richard Eric M. Lope BSN RN
' 
' \section features Features
' 
' - Very easy to use
' - Lightweight
' - Fast
' - Portable
' - Can be used alongside 3D scenes
' - 1:1 screen to coordinate ratio
' - Shared across modules
' - Easy sprite atlas support
' - Automatic texture binding
' - Automatic texture cleanup
' - Full hardware acceleration
' 
' \section api Library API
' - \ref EZGL2D.cs "Reference"
' 
' \section intro Official Site
' - <a href="http://rel.phatcode.net">Genso's Junkyard</a> 
' 
' \section download Download
'  - <a href="http://www.opentk.com/">OpenTK(EZGL2D uses this as a backend)</a>
'  - <a href="http://rel.phatcode.net/junk.php?id=117">Easy GL2D for Nintendo DS</a> 
'  - <a href="http://rel.phatcode.net/junk.php?id=121">Easy GL2D for C++</a> 
'
' \section games Example Games
' - PC
' - <a href="http://rel.phatcode.net/index.php?action=contents&item=Pyromax-Dax">Pyromax Dax</a> 
' - <a href="http://rel.phatcode.net/index.php?action=contents&item=ConvexWars-FB">Convex Wars</a> 
' <br>
' <br>
' - Nintendo DS
' - <a href="http://rel.phatcode.net/index.php?action=contents&item=Fuzed-DS">Fuzed DS</a> 
' - <a href="http://rel.phatcode.net/index.php?action=contents&item=Space-Impakto-DS">Space Impakto DS</a> 
' - <a href="http://rel.phatcode.net/index.php?action=contents&item=Bubble_Fight_EX_DS">Bubble Fight EX</a> 
' 
' \section tools Misc. Tools
' - <a href="http://rel.phatcode.net/junk.php?id=106">Rel's Texture Packer</a> 
' 
' \section external_links Useful links
' - <a href="http://www.devkitpro.org/">devkitPro</a>
' - <a href="http://www.freebasic.net">Freebasic</a>
' - <a href="https://www.facebook.com/groups/ProgramersDevelopers/">Programmers, Developers</a>
' 
'




'! \file EZGL2D.cs
'	\brief A very small and simple NET-based PC/MAC/DS/Mobile hardware accelerated rendering lib OpenGL(via OpenTK) to render 2D stuff.
'

Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Imports System.Threading
Imports System.Drawing
Imports System.Drawing.Imaging
Imports System.IO

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


Namespace EZGL2D
	'! \brief GL2D Static Class. 
	Public Class GL2D




		'! \brief Enums for controlling how blending works. 
		Public Enum BLEND_MODE

			GL2D_TRANS = 0 '!< Transparent blit
			GL2D_SOLID '!< Solid blit
			GL2D_BLENDED '!< Alpha Blended blit
			GL2D_GLOW '!< Additive Blended blit
			GL2D_ALPHA '!< Alpha Transparent blit
		End Enum


'        ! \brief Struct for our GL-Based Images<BR>
'        This is our struct to hold our image
'	    attributes. You don't need to worry about this 
'	    most of the time. 
		Public Class SpriteGL

'            ! \brief Constants to select flipping mode.
'            *
'            *	These enums are bits for flipping the sprites. <Br>
'            *	You can <b>"|"</b> (or) GL_FLIP_V and GL_FLIP_H to flip 
'            *	both ways. <Br><Br>
'            *  <ul>
'            *	<li> Related functions:
'            * 		<ol>
'            *	 	<li>Sprite()
'            *	 	<li>SpriteRotateScale()
'            * 		</ol>
'            * 	</ul>	
'            

			Public Shared FLIP_NONE As Integer = 1 << 0 '!< No flip
			Public Shared FLIP_V As Integer = 1 << 1 '!< Vertical flip
			Public Shared FLIP_H As Integer = 1 << 2 '!< Horizontal flip

			Public width As Integer '!< Width of the sprite
			Public height As Integer '!< Height of the sprite
			Public u_off As Single '!< Horizontal texture offset of the sprite
			Public v_off As Single '!< Vertical texture offset of the sprite
			Public u_width As Single '!< Horizontal texture offset width of the sprite
			Public v_height As Single '!< Vertical texture offset height of the sprite

			Public textureID As Integer '!< OpenGL generated texture ID of the sprite

'            ! \brief SpriteGL constructor. <Br> 
'	            Use this constructor to instantiate a SpriteGL object.
'             
			Public Sub New()

			End Sub

		End Class


		Private Shared textureIDs As IList(Of Integer) = New List(Of Integer)()

		Private Shared currentTexture As Integer = 0
		Private Shared screenWidth As Integer = 640
		Private Shared screenHeight As Integer = 480

'        ! \brief Sets up OpenGL for 2d rendering. <Br> 
'            Call this before drawing any of GL2D's drawing or sprite functions.
'         
		Public Shared Sub Begin2D()
			'currentTexture = 0;
			GL.Disable(EnableCap.DepthTest)
			GL.Disable(EnableCap.CullFace)

			GL.Enable(EnableCap.Blend)
			GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha)

			GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill)

			GL.Enable(EnableCap.ColorMaterial)

			GL.Enable(EnableCap.Texture2D)

			GL.Disable(EnableCap.StencilTest)
			GL.Disable(EnableCap.Texture1D)
			GL.Disable(EnableCap.Lighting)
			GL.Disable(EnableCap.Fog)
			GL.Disable(EnableCap.Dither)

			GL.Disable(EnableCap.ColorLogicOp)

			GL.PointSize(1.0F)
			GL.LineWidth(1.0F)

			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest)
			GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest)

			GL.MatrixMode(MatrixMode.Projection)
			GL.PushMatrix()
			GL.LoadIdentity()
			GL.Ortho(0, screenWidth, screenHeight, 0, -1, 1)
			GL.MatrixMode(MatrixMode.Modelview)
			GL.PushMatrix()
			GL.LoadIdentity()
			GL.Translate(0.375F, 0.375F, 0.0F)

			GL.ClearColor(0, 0, 0, 0)
			GL.Color4(1.0F, 1.0F, 1.0F, 1.0F)

		End Sub


'        ! \brief Issue this after drawing 2d so that we don't mess the matrix stack. <Br> 
'    	    The compliment of glBegin2D().
'        
		Public Shared Sub End2D()
			GL.MatrixMode(MatrixMode.Modelview)
			GL.PopMatrix()
			GL.MatrixMode(MatrixMode.Projection)
			GL.PopMatrix()
			GL.MatrixMode(MatrixMode.Modelview)
		End Sub

'        ! \brief Initializes GL in 2D mode
'            \param width width of the window.
'            \param height height of the window.
'        
		Public Shared Sub Screen2D(ByVal width As Integer, ByVal height As Integer)

			screenWidth = width
			screenHeight = height

			GL.Viewport(0, 0, screenWidth, screenHeight)

			GL.MatrixMode(MatrixMode.Projection)
			GL.LoadIdentity()

			Dim aspect_ratio As Double = screenWidth / CDbl(screenHeight)

			Dim perspective As OpenTK.Matrix4 = OpenTK.Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, CSng(aspect_ratio), 1, 500)
			GL.MatrixMode(MatrixMode.Projection)
			GL.LoadMatrix(perspective)

			GL.MatrixMode(MatrixMode.Modelview)

			GL.LoadIdentity()

			Dim lookat As Matrix4 = Matrix4.LookAt(0, 5, 5, 0, 0, 0, 0, 1, 0)
			GL.MatrixMode(MatrixMode.Modelview)
			GL.LoadMatrix(lookat)


			GL.ShadeModel(ShadingModel.Smooth)
			GL.ClearColor(0, 0, 0, 1.0F)
			GL.DepthFunc(DepthFunction.Lequal)

			GL.Disable(EnableCap.DepthTest)
			GL.Disable(EnableCap.CullFace)

			GL.Enable(EnableCap.Blend)
			GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha)

			GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill)

			GL.Enable(EnableCap.ColorMaterial)

			GL.Enable(EnableCap.Texture2D)

			GL.Disable(EnableCap.StencilTest)
			GL.Disable(EnableCap.Texture1D)
			GL.Disable(EnableCap.Lighting)
			GL.Disable(EnableCap.Fog)
			GL.Disable(EnableCap.Dither)

			GL.Disable(EnableCap.ColorLogicOp)

			GL.PointSize(1.0F)
			GL.LineWidth(1.0F)

			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest)
			GL.Hint(HintTarget.LineSmoothHint, HintMode.Nicest)



		End Sub

'        ! \brief Cleans up EZGL2D. Call this at program end.
'	        Automatic texture management.

		Public Shared Sub Close()
			Dim textures() As Integer = textureIDs.ToArray()
			GL.DeleteTextures(textures.Length, textures)

		End Sub

'        ! \brief Sets the default blending/blitting mode
'        \param mode enums for blending see example files.
'        
		Public Shared Sub BlendMode(ByVal mode As BLEND_MODE)
			Select Case mode
				Case BLEND_MODE.GL2D_TRANS, BLEND_MODE.GL2D_ALPHA
					GL.Enable(EnableCap.Blend)
					GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha)
				Case BLEND_MODE.GL2D_SOLID
					GL.Disable(EnableCap.Blend)
				Case BLEND_MODE.GL2D_BLENDED
					GL.Enable(EnableCap.Blend)
					GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.One)
				Case BLEND_MODE.GL2D_GLOW
					GL.Enable(EnableCap.Blend)
					GL.BlendFunc(BlendingFactorSrc.One, BlendingFactorDest.One)
				Case Else
			End Select

		End Sub

		'! \brief Clears the GL2D screen buffer
		Public Shared Sub ClearScreen()

			GL.ClearColor(0.0F, 0.0F, 0.0F, 0.0F)
			GL.Clear(ClearBufferMask.ColorBufferBit Or ClearBufferMask.DepthBufferBit)

		End Sub

'        ! \brief Draws a Pixel
'            \param r Red channel of the color.
'            \param g Green channel of the color.
'            \param b Blue channel of the color.
'            \param a Alpha channel of the color.
'        
		Public Shared Sub SetColor(ByVal r As Single, ByVal g As Single, ByVal b As Single, ByVal a As Single)
			GL.Color4(r, g, b, a)
		End Sub

'        ! \brief Enables or disables AA depending on the switch
'            \param flag true == enable; false(0) == disable.
'        
		Public Shared Sub EnableAntialias(ByVal flag As Boolean)
			If flag Then
				GL.Enable(EnableCap.PointSmooth)
				GL.Enable(EnableCap.LineSmooth)
			Else
				GL.Disable(EnableCap.PointSmooth)
				GL.Disable(EnableCap.LineSmooth)
			End If

		End Sub

'        ! \brief Draws a Pixel
'        \param x X position of the pixel.
'        \param y Y position of the pixel.
'        
		Public Shared Sub PutPixel(ByVal x As Integer, ByVal y As Integer)
			GL.Disable(EnableCap.Texture2D)
			GL.Begin(PrimitiveType.Points)
			GL.Vertex2(x, y)
			GL.End()
			GL.Enable(EnableCap.Texture2D)

		End Sub

'        ! \brief Draws a Line
'          \param x1,y1 Start point of the line.
'          \param y2,y2 End point of the line.
'        
		Public Shared Sub Line(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer)

			GL.Disable(EnableCap.Texture2D)
			GL.Begin(PrimitiveType.Lines)
			GL.Vertex2(x1, y1)
			GL.Vertex2(x2, y2)
			GL.End()
			GL.Enable(EnableCap.Texture2D)

		End Sub

'        ! \brief Draws a Box
'            \param x1,y1 Top-Left coordinate of the box.
'            \param x2,y2 Bottom-Right coordinate of the box.
'        
		Public Shared Sub Box(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer)
			GL.Disable(EnableCap.Texture2D)

			GL.Begin(PrimitiveType.LineStrip)
			GL.Vertex2(x1, y1)
			GL.Vertex2(x2, y1)
			GL.Vertex2(x2, y2)
			GL.Vertex2(x1, y2)
			GL.Vertex2(x1, y1)
			GL.End()

			GL.Enable(EnableCap.Texture2D)

		End Sub

'        ! \brief Draws a Box filled with a single color
'         \param x1,y1 Top-Left coordinate of the box.
'         \param x2,y2 Bottom-Right coordinate of the box.
'        
		Public Shared Sub BoxFilled(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer)
			x2 += 1
			y2 += 1

			GL.Disable(EnableCap.Texture2D)
			GL.Begin(PrimitiveType.Quads)
			GL.Vertex2(x1, y1)
			GL.Vertex2(x1, y2)
			GL.Vertex2(x2, y2)
			GL.Vertex2(x2, y1)
			GL.End()
			GL.Enable(EnableCap.Texture2D)

		End Sub

'        ! \brief Draws a Triangle
'        \param x1,y1 Vertex 1 of the triangle.
'        \param x2,y2 Vertex 2 of the triangle.
'        \param x3,y3 Vertex 3 of the triangle.
'        
		Public Shared Sub Triangle(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer, ByVal x3 As Integer, ByVal y3 As Integer)
			GL.Disable(EnableCap.Texture2D)
			GL.Begin(PrimitiveType.LineStrip)
			GL.Vertex2(x1, y1)
			GL.Vertex2(x2, y2)
			GL.Vertex2(x3, y3)
			GL.Vertex2(x1, y1)
			GL.End()
			GL.Enable(EnableCap.Texture2D)
		End Sub

'        ! \brief Draws a filled Triangle
'            \param x1,y1 Vertex 1 of the triangle.
'            \param x2,y2 Vertex 2 of the triangle.
'            \param x3,y3 Vertex 3 of the triangle.
'        
		Public Shared Sub TriangleFilled(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer, ByVal x3 As Integer, ByVal y3 As Integer)
			GL.Disable(EnableCap.Texture2D)
			GL.Begin(PrimitiveType.Triangles)
			GL.Vertex2(x1, y1)
			GL.Vertex2(x2, y2)
			GL.Vertex2(x3, y3)
			GL.End()
			GL.Enable(EnableCap.Texture2D)
		End Sub


'        ! \brief Draws a Sprite
'        \param x X position of the sprite.
'        \param y Y position of the sprite.
'        \param flipmode mode for flipping (see FLIP_MODE constants).
'        \param sprite a glImage. 
'        
		Public Shared Sub Sprite(ByVal x As Integer, ByVal y As Integer, ByVal flipmode As Integer, ByVal sprite As SpriteGL)
			Dim x1 As Integer = x
			Dim y1 As Integer = y
			Dim x2 As Integer = x + sprite.width
			Dim y2 As Integer = y + sprite.height

			Dim u1 As Single = If((flipmode And SpriteGL.FLIP_H) <> 0, sprite.u_off + sprite.u_width, sprite.u_off)
			Dim u2 As Single = If((flipmode And SpriteGL.FLIP_H) <> 0, sprite.u_off, sprite.u_off + sprite.u_width)
			Dim v1 As Single = If((flipmode And SpriteGL.FLIP_V) <> 0, sprite.v_off + sprite.v_height, sprite.v_off)
			Dim v2 As Single = If((flipmode And SpriteGL.FLIP_V) <> 0, sprite.v_off, sprite.v_off + sprite.v_height)


			If sprite.textureID <> currentTexture Then
				GL.BindTexture(TextureTarget.Texture2D, sprite.textureID)
				currentTexture = sprite.textureID
			End If

			GL.Begin(PrimitiveType.Quads)

			GL.TexCoord2(u1, v1)
			GL.Vertex2(x1, y1)
			GL.TexCoord2(u1, v2)
			GL.Vertex2(x1, y2)
			GL.TexCoord2(u2, v2)
			GL.Vertex2(x2, y2)
			GL.TexCoord2(u2, v1)
			GL.Vertex2(x2, y1)

			GL.End()


		End Sub

'        ! \brief Draws a Center Rotated Axis-Exclusive Scaled Sprite
'            \param x X position of the sprite center.
'            \param y Y position of the sprite center.
'            \param angle Angle(in degrees) to rotate the sprite.
'            \param scaleX X-Axis scale value (1.0f is normal).
'            \param scaleY Y-Axis scale value (1.0f is normal).
'            \param flipmode mode for flipping (see FLIP_MODE constants).
'            \param sprite a glImage. 
'        
		Public Shared Sub SpriteRotateScale(ByVal x As Integer, ByVal y As Integer, ByVal angle As Single, ByVal scaleX As Single, ByVal scaleY As Single, ByVal flipmode As Integer, ByVal sprite As SpriteGL)

			Dim hx As Single = (sprite.width \ 2) * scaleX
			Dim hy As Single = (sprite.height \ 2) * scaleY

			Dim hx1 As Single = -hx ' top left
			Dim hy1 As Single = -hy
			Dim hx2 As Single = -hx ' bottom left
			Dim hy2 As Single = hy
			Dim hx3 As Single = hx ' bottom right
			Dim hy3 As Single = hy
			Dim hx4 As Single = hx ' top right
			Dim hy4 As Single = -hy

			Dim a As Double = angle * Math.PI / 180
			Dim cz As Single = CSng(Math.Cos(a))
			Dim sz As Single = CSng(Math.Sin(a))

			Dim x1 As Single = cz * hx1 - sz * hy1
			Dim y1 As Single = sz * hx1 + cz * hy1
			Dim x2 As Single = cz * hx2 - sz * hy2
			Dim y2 As Single = sz * hx2 + cz * hy2
			Dim x3 As Single = cz * hx3 - sz * hy3
			Dim y3 As Single = sz * hx3 + cz * hy3
			Dim x4 As Single = cz * hx4 - sz * hy4
			Dim y4 As Single = sz * hx4 + cz * hy4

			Dim u1 As Single = If((flipmode And SpriteGL.FLIP_H) <> 0, sprite.u_off + sprite.u_width, sprite.u_off)
			Dim u2 As Single = If((flipmode And SpriteGL.FLIP_H) <> 0, sprite.u_off, sprite.u_off + sprite.u_width)
			Dim v1 As Single = If((flipmode And SpriteGL.FLIP_V) <> 0, sprite.v_off + sprite.v_height, sprite.v_off)
			Dim v2 As Single = If((flipmode And SpriteGL.FLIP_V) <> 0, sprite.v_off, sprite.v_off + sprite.v_height)

			If sprite.textureID <> currentTexture Then
				GL.BindTexture(TextureTarget.Texture2D, sprite.textureID)
				currentTexture = sprite.textureID
			End If

			GL.Begin(PrimitiveType.Quads)

			GL.TexCoord2(u1, v1)
			GL.Vertex2(x + x1, y + y1)
			GL.TexCoord2(u1, v2)
			GL.Vertex2(x + x2, y + y2)
			GL.TexCoord2(u2, v2)
			GL.Vertex2(x + x3, y + y3)
			GL.TexCoord2(u2, v1)
			GL.Vertex2(x + x4, y + y4)

			GL.End()

		End Sub


'        ! \brief Draws a textured line
'            \param x1,y1 Start point of the line.
'            \param x2,y2 End point of the line.
'            \param thickness Thickness of the line.
'            \param sprite a glImage used to texture the line.
'        
		Public Shared Sub SpriteOnLine(ByVal x1 As Integer, ByVal y1 As Integer, ByVal x2 As Integer, ByVal y2 As Integer, ByVal thickness As Integer, ByVal sprite As SpriteGL)


			' Only change active texture when there is a need
			' Speeds up the rendering by batching textures
			If sprite.textureID <> currentTexture Then
				GL.BindTexture(TextureTarget.Texture2D, sprite.textureID)
				currentTexture = sprite.textureID
			End If


			Dim nx As Single = -(y2 - y1)
			Dim ny As Single = (x2 - x1)

			Dim invLength As Single = 1 / CSng(Math.Sqrt(nx * nx + ny * ny))

			nx *= invLength
			ny *= invLength

			nx *= thickness / 2.0F
			ny *= thickness / 2.0F

			Dim vx As Single = (x2 - x1)
			Dim vy As Single = (y2 - y1)
			invLength = 1 / CSng(Math.Sqrt(vx * vx + vy * vy))
			vx *= invLength
			vy *= invLength

			vx *= thickness / 2.0F
			vy *= thickness / 2.0F


			Dim lx1 As Single = x2 + nx
			Dim ly1 As Single = y2 + ny
			Dim lx2 As Single = x2 - nx
			Dim ly2 As Single = y2 - ny
			Dim lx3 As Single = x1 - nx
			Dim ly3 As Single = y1 - ny
			Dim lx4 As Single = x1 + nx
			Dim ly4 As Single = y1 + ny
			Dim lx5 As Single = lx1 + vx
			Dim ly5 As Single = ly1 + vy
			Dim lx6 As Single = lx2 + vx
			Dim ly6 As Single = ly2 + vy
			Dim lx7 As Single = lx4 - vx
			Dim ly7 As Single = ly4 - vy
			Dim lx8 As Single = lx3 - vx
			Dim ly8 As Single = ly3 - vy

			Dim u1 As Single = sprite.u_off
			Dim v1 As Single = sprite.v_off
			Dim u2 As Single = sprite.u_off + sprite.u_width
			Dim v2 As Single = sprite.v_off + sprite.v_height
			Dim su As Single = (u1 + u2) / 2.0F

			' center
			spriteOnQuad(lx1, ly1, lx2, ly2, lx3, ly3, lx4, ly4, su, v2, su, v1)

			' right
			spriteOnQuad(lx5, ly5, lx6, ly6, lx2, ly2, lx1, ly1, u2, v2, su, v1)

			' left
			spriteOnQuad(lx8, ly8, lx7, ly7, lx4, ly4, lx3, ly3, u1, v1, su, v2)

		End Sub



'        ! \brief Loads an image file(prefer PNGs) directly to a SpriteGL object <Br>
'            Image file needs to be have power of 2 dimension(2, 4, 8,.... 2048,...) 
'            \param filename filename of the TGA file to load ie. "ships.png".
'            \param filtermode TextureMinFilter.Linear, TextureMinFilter.Nearest, etc.
'            \return SpriteGL that can be directly used by the sprite routines.
'        
		Public Shared Function LoadSprite(ByVal filename As String, ByVal filtermode As Integer) As SpriteGL

			Dim bitmap As New Bitmap(filename)

			Dim textureID As Integer

			GL.Enable(EnableCap.Texture2D)

			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest)

			GL.GenTextures(1, textureID)
			GL.BindTexture(TextureTarget.Texture2D, textureID)

			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, CInt(TextureWrapMode.Repeat))
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, CInt(TextureWrapMode.Repeat))
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filtermode)
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, filtermode)

			Dim data As BitmapData = bitmap.LockBits(New System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

			GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)

			bitmap.UnlockBits(data)


'INSTANT VB NOTE: The variable sprite was renamed since Visual Basic does not handle local variables named the same as class members well:
			Dim sprite_Renamed As New SpriteGL()

			sprite_Renamed.textureID = textureID
			sprite_Renamed.width = bitmap.Width
			sprite_Renamed.height = bitmap.Height
			sprite_Renamed.u_off = 0.0F ' set x-coord
			sprite_Renamed.v_off = 0.0F ' y-coord
			sprite_Renamed.u_width = 1.0F ' set x-coord
			sprite_Renamed.v_height = 1.0F ' y-coord

			GL.BindTexture(TextureTarget.Texture2D, 0)

			bitmap.Dispose()

			textureIDs.Add(textureID)

			Return sprite_Renamed

		End Function


'        ! \brief Initializes our spriteset with Texture Packer generated UV coordinates <Br>
'	         Very safe and easy to use..
'            Image file needs to be have power of 2 dimension(2, 4, 8,.... 2048,...) 
'            \param filename filename of the image file to load ie. "ships.png".
'            \param numframes number of frames in a spriteset.
'            \param texcoords Texture Packer auto-generated array of UV coords.
'            \param filtermode TextureMinFilter.Linear, TextureMinFilter.Nearest, etc.
'            \return SpriteGL array that can be directly used by the sprite routines.
'        
		Public Shared Function LoadSpriteSet(ByVal filename As String, ByVal numframes As Integer, ByVal texcoords() As Integer, ByVal filtermode As Integer) As SpriteGL()

			Dim tileSet As IList(Of GL2D.SpriteGL) = New List(Of GL2D.SpriteGL)()

			Dim bitmap As New Bitmap(filename)

			Dim textureID As Integer

			GL.Enable(EnableCap.Texture2D)

			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest)

			GL.GenTextures(1, textureID)
			GL.BindTexture(TextureTarget.Texture2D, textureID)

			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, CInt(TextureWrapMode.Repeat))
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, CInt(TextureWrapMode.Repeat))
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filtermode)
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, filtermode)

			Dim data As BitmapData = bitmap.LockBits(New System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

			GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)

			Dim width As Integer = bitmap.Width
			Dim height As Integer = bitmap.Height

			bitmap.UnlockBits(data)

			GL.BindTexture(TextureTarget.Texture2D, 0)

			' init sprites texture coords and texture ID
			For i As Integer = 0 To numframes - 1
				Dim j As Integer = i * 4 ' texcoords array is u_off, wid, hei
'INSTANT VB NOTE: The variable sprite was renamed since Visual Basic does not handle local variables named the same as class members well:
				Dim sprite_Renamed As New SpriteGL()
				sprite_Renamed.textureID = textureID
				sprite_Renamed.width = texcoords(j + 2)
				sprite_Renamed.height = texcoords(j + 3)
				sprite_Renamed.u_off = texcoords(j) / CSng(width) ' set x-coord
				sprite_Renamed.v_off = texcoords(j + 1) / CSng(height) ' y-coord
				sprite_Renamed.u_width = texcoords(j + 2) / CSng(width) ' set x-coord
				sprite_Renamed.v_height = texcoords(j + 3) / CSng(height) ' y-coord
				tileSet.Add(sprite_Renamed)
			Next i

			textureIDs.Add(textureID)

			bitmap.Dispose()

			Return tileSet.ToArray()

		End Function


'        ! \brief Initializes our Tileset. <Br>
'	        Can only be used when tiles in a tilset are of the same dimensions.
'            Image file needs to be have power of 2 dimension(2, 4, 8,.... 2048,...) 
'            \param filename filename of the image file to load ie. "ships.png".
'            \param tileWidth Width of each tile in the texture.
'            \param tileHeight Height of each tile in the texture.
'            \param filtermode TextureMinFilter.Linear, TextureMinFilter.Nearest, etc.
'            \return SpriteGL array that can be directly used by the sprite routines.
'        
		Public Shared Function LoadTileSet(ByVal filename As String, ByVal tileWidth As Integer, ByVal tileHeight As Integer, ByVal filtermode As Integer) As SpriteGL()

			Dim tileSet As IList(Of GL2D.SpriteGL) = New List(Of GL2D.SpriteGL)()

			Dim bitmap As New Bitmap(filename)

			Dim textureID As Integer

			GL.Enable(EnableCap.Texture2D)

			GL.Hint(HintTarget.PerspectiveCorrectionHint, HintMode.Nicest)

			GL.GenTextures(1, textureID)
			GL.BindTexture(TextureTarget.Texture2D, textureID)

			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapS, CInt(TextureWrapMode.Repeat))
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureWrapT, CInt(TextureWrapMode.Repeat))
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, filtermode)
			GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, filtermode)

			Dim data As BitmapData = bitmap.LockBits(New System.Drawing.Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb)

			GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, data.Width, data.Height, 0, OpenTK.Graphics.OpenGL.PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0)


			bitmap.UnlockBits(data)

			GL.BindTexture(TextureTarget.Texture2D, 0)

			Dim textureWidth As Integer = bitmap.Width
			Dim textureHeight As Integer = bitmap.Height

			' init sprites texture coords and texture ID
			For y As Integer = 0 To (textureHeight \ tileHeight) - 1
				For x As Integer = 0 To (textureWidth \ tileWidth) - 1
'INSTANT VB NOTE: The variable sprite was renamed since Visual Basic does not handle local variables named the same as class members well:
					Dim sprite_Renamed As New SpriteGL()
					sprite_Renamed.width = tileWidth
					sprite_Renamed.height = tileHeight
					sprite_Renamed.u_off = (x * tileWidth) / CSng(textureWidth)
					sprite_Renamed.v_off = (y * tileHeight) / CSng(textureHeight)
					sprite_Renamed.u_width = tileWidth / CSng(textureWidth)
					sprite_Renamed.v_height = tileHeight / CSng(textureHeight)
					sprite_Renamed.textureID = textureID
					tileSet.Add(sprite_Renamed)
				Next x
			Next y

			textureIDs.Add(textureID)

			Return tileSet.ToArray()
		End Function

		Private Shared Sub spriteOnQuad(ByVal x1 As Single, ByVal y1 As Single, ByVal x2 As Single, ByVal y2 As Single, ByVal x3 As Single, ByVal y3 As Single, ByVal x4 As Single, ByVal y4 As Single, ByVal u1 As Single, ByVal v1 As Single, ByVal u2 As Single, ByVal v2 As Single)


			GL.Begin(PrimitiveType.Quads)

			GL.TexCoord2(u1, v1)
			GL.Vertex2(x1, y1)
			GL.TexCoord2(u1, v2)
			GL.Vertex2(x2, y2)
			GL.TexCoord2(u2, v2)
			GL.Vertex2(x3, y3)
			GL.TexCoord2(u2, v1)
			GL.Vertex2(x4, y4)

			GL.End()
		End Sub


	End Class ' GL2D

End Namespace ' namespace
