func ScreenToGLCoords(x, y int, screenWidth, screenHeight int) (xOut, yOut float32) {
	xOut = 2.0*float32(x)/float32(screenWidth-1) - 1.0
	yOut = -2.0*float32(y)/float32(screenHeight-1) + 1.0
	return
}
ScreenToGLCoords transforms from pixel coordinates to GL coordinates.

This assumes that your pixel coordinate system considers its origin to be in the top left corner (GL's is in the bottom left).
The coordinates x and y may be out of the range [0,screenWidth-1] and [0,screeneHeight-1].

GL's coordinate system maps [screenWidth-1,0] to [1.0,1.0] and [0,screenHeight-1] to [-1.0,-1.0]. If x and y are out of the range, they'll still
be mapped correctly, just off the screen. (e.g. if y = 2*(screenHeight-1) you'll get -3.0 for yOut)

This is similar to Unproject, except for 2D cases and much simpler (especially since an inverse may always be found)
package mgl32
import (
	"fmt"
	"math"
)
func Circle(radiusX, radiusY float32, numSlices int) []Vec2 {
	twoPi := float32(2.0 * math.Pi)
	circlePoints := make([]Vec2, 0, numSlices*3)
	center := Vec2{0.0, 0.0}
	previous := Vec2{radiusX, 0.0}
	for theta := twoPi / float32(numSlices); !FloatEqual(theta, twoPi); theta = Clamp(theta+twoPi/float32(numSlices), 0.0, twoPi) {
		sin, cos := math.Sincos(float64(theta))
		curr := Vec2{float32(cos) * radiusX, float32(sin) * radiusY}
		circlePoints = append(circlePoints, center, previous, curr)
		previous = curr
	}
	circlePoints = append(circlePoints, center, previous, Vec2{radiusX, 0.0})
	return circlePoints
}
func Rect(width, height float32) []Vec2 {
	return []Vec2{
		{0.0, 0.0},
		{0.0, -height},
		{width, -height},
		{0.0, 0.0},
		{width, -height},
		{width, 0.0},
	}
}
func QuadraticBezierCurve2D(t float32, cPoint1, cPoint2, cPoint3 Vec2) Vec2 {
	if t < 0.0 || t > 1.0 {
		panic("Can't interpolate on bezier curve with t out of range [0.0,1.0]")
	}
	return cPoint1.Mul((1.0 - t) * (1.0 - t)).Add(cPoint2.Mul(2 * (1 - t) * t)).Add(cPoint3.Mul(t * t))
}
func QuadraticBezierCurve3D(t float32, cPoint1, cPoint2, cPoint3 Vec3) Vec3 {
	if t < 0.0 || t > 1.0 {
		panic("Can't interpolate on bezier curve with t out of range [0.0,1.0]")
	}
	return cPoint1.Mul((1.0 - t) * (1.0 - t)).Add(cPoint2.Mul(2 * (1 - t) * t)).Add(cPoint3.Mul(t * t))
}
func CubicBezierCurve2D(t float32, cPoint1, cPoint2, cPoint3, cPoint4 Vec2) Vec2 {
	if t < 0.0 || t > 1.0 {
		panic("Can't interpolate on bezier curve with t out of range [0.0,1.0]")
	}
	return cPoint1.Mul((1 - t) * (1 - t) * (1 - t)).Add(cPoint2.Mul(3 * (1 - t) * (1 - t) * t)).Add(cPoint3.Mul(3 * (1 - t) * t * t)).Add(cPoint4.Mul(t * t * t))
}
func CubicBezierCurve3D(t float32, cPoint1, cPoint2, cPoint3, cPoint4 Vec3) Vec3 {
	if t < 0.0 || t > 1.0 {
		panic("Can't interpolate on bezier curve with t out of range [0.0,1.0]")
	}
	return cPoint1.Mul((1 - t) * (1 - t) * (1 - t)).Add(cPoint2.Mul(3 * (1 - t) * (1 - t) * t)).Add(cPoint3.Mul(3 * (1 - t) * t * t)).Add(cPoint4.Mul(t * t * t))
}
func BezierCurve2D(t float32, cPoints []Vec2) Vec2 {
	if t < 0.0 || t > 1.0 {
		panic("Input to bezier has t not in range [0,1]. If you think this is a precision error, use mathgl.Clamp[f|d] before calling this function")
	}
	n := len(cPoints) - 1
	point := cPoints[0].Mul(float32(math.Pow(float64(1.0-t), float64(n))))
	for i := 1; i <= n; i++ {
		point = point.Add(cPoints[i].Mul(float32(float64(choose(n, i)) * math.Pow(float64(1-t), float64(n-i)) * math.Pow(float64(t), float64(i)))))  
	}
	return point
}
func BezierCurve3D(t float32, cPoints []Vec3) Vec3 {
	if t < 0.0 || t > 1.0 {
		panic("Input to bezier has t not in range [0,1]. If you think this is a precision error, use mathgl.Clamp[f|d] before calling this function")
	}
	n := len(cPoints) - 1
	point := cPoints[0].Mul(float32(math.Pow(float64(1.0-t), float64(n))))
	for i := 1; i <= n; i++ {
		point = point.Add(cPoints[i].Mul(float32(float64(choose(n, i)) * math.Pow(float64(1-t), float64(n-i)) * math.Pow(float64(t), float64(i)))))  
	}
	return point
}
func MakeBezierCurve2D(numPoints int, cPoints []Vec2) (line []Vec2) {
	line = make([]Vec2, numPoints)
	if numPoints == 0 {
		return
	} else if numPoints == 1 {
		line[0] = cPoints[0]
		return
	} else if numPoints == 2 {
		line[0] = cPoints[0]
		line[1] = cPoints[len(cPoints)-1]
		return
	}
	line[0] = cPoints[0]
	for i := 1; i < numPoints-1; i++ {
		line[i] = BezierCurve2D(Clamp(float32(i)/float32(numPoints-1), 0.0, 1.0), cPoints)
	}
	line[numPoints-1] = cPoints[len(cPoints)-1]
	return
}
func MakeBezierCurve3D(numPoints int, cPoints []Vec3) (line []Vec3) {
	line = make([]Vec3, numPoints)
	if numPoints == 0 {
		return
	} else if numPoints == 1 {
		line[0] = cPoints[0]
		return
	} else if numPoints == 2 {
		line[0] = cPoints[0]
		line[1] = cPoints[len(cPoints)-1]
		return
	}
	line[0] = cPoints[0]
	for i := 1; i < numPoints-1; i++ {
		line[i] = BezierCurve3D(Clamp(float32(i)/float32(numPoints-1), 0.0, 1.0), cPoints)
	}
	line[numPoints-1] = cPoints[len(cPoints)-1]
	return
}
func BezierSurface(u, v float32, cPoints [][]Vec3) Vec3 {
	if u < 0.0 || u > 1.0 || v < 1.0 || v > 1.0 {
		panic("u or v not in range [0.0,1.0] in BezierSurface")
	}
	n := len(cPoints) - 1
	m := len(cPoints[0]) - 1
	point := cPoints[0][0].Mul(float32(math.Pow(float64(1.0-u), float64(n)) * math.Pow(float64(1.0-v), float64(m))))
	for i := 0; i <= n; i++ {
		for j := 0; j <= m; j++ {
			if i == 0 && j == 0 {
				continue
			}
			point = point.Add(cPoints[i][j].Mul(float32(float64(choose(n, i)) * math.Pow(float64(u), float64(i)) * math.Pow(float64(1.0-u), float64(n-i)) * float64(choose(m, j)) * math.Pow(float64(v), float64(j)) * math.Pow(float64(1.0-v), float64(m-j)))))
		}
	}
	return point
}
func BezierSplineInterpolate2D(t float32, ranges [][2]float32, cPoints [][]Vec2) Vec2 {
	if len(ranges) != len(cPoints) {
		panic("Each bezier curve needs a range")
	}
	for i, curveRange := range ranges {
		if t >= curveRange[0] && t <= curveRange[1] {
			return BezierCurve2D((t-curveRange[0])/(curveRange[1]-curveRange[0]), cPoints[i])
		}
	}
	panic("t is out of the range of all bezier curves in this spline")
}
func BezierSplineInterpolate3D(t float32, ranges [][2]float32, cPoints [][]Vec3) Vec3 {
	if len(ranges) != len(cPoints) {
		panic("Each bezier curve needs a range")
	}
	for i, curveRange := range ranges {
		if t >= curveRange[0] && t <= curveRange[1] {
			return BezierCurve3D((t-curveRange[0])/(curveRange[1]-curveRange[0]), cPoints[i])
		}
	}
	panic("t is out of the range of all bezier curves in this spline")
}
func ReticulateSplines(ranges [][][2]float32, cPoints [][][]Vec2, withLlamas bool) {
	if !withLlamas {
		fmt.Println("You can't reticulate splines without llamas, silly.")
	} else {
		fmt.Println("Actually, you can't even reticulate splines WITH llamas")
	}
}