Added geo and gl packages from gogeline and improved documentation.

This commit is contained in:
Marvin Blum
2016-05-03 21:23:50 +02:00
parent 05013370fd
commit 19731dc0e5
15 changed files with 1388 additions and 3 deletions

View File

@@ -67,6 +67,7 @@ func Run(game Game, options *RunOptions) {
for running {
if exitOnClose && wnd.ShouldClose() {
cleanup()
return
}
@@ -87,3 +88,9 @@ func Run(game Game, options *RunOptions) {
func Stop() {
running = false
}
func cleanup() {
for _, system := range systems {
system.Cleanup()
}
}

171
geo/mat3.go Normal file
View File

@@ -0,0 +1,171 @@
package geo
import (
"math"
)
// 3x3 column major matrix.
type Mat3 struct {
Values [9]float64
}
// Creates a new 3x3 matrix with initial values.
func NewMat3(m00, m10, m20, m01, m11, m21, m02, m12, m22 float64) *Mat3 {
return &Mat3{[9]float64{m00, m10, m20, m01, m11, m21, m02, m12, m22}}
}
// Creates a copy of actual matrix.
func (m *Mat3) Copy() *Mat3 {
return &Mat3{m.Values}
}
// Sets the matrix to zeros.
func (m *Mat3) Clear() {
for i := range m.Values {
m.Values[i] = 0
}
}
// Sets the matrix to identity matrix.
func (m *Mat3) Identity() {
m.Clear()
m.Values[0] = 1
m.Values[4] = 1
m.Values[8] = 1
}
// Multiplies actual matrix with given matrix and saves result.
func (m *Mat3) Mult(mat *Mat3) {
this := m.Copy()
m.Values[0] = mat.Values[0]*this.Values[0] + mat.Values[1]*this.Values[3] + mat.Values[2]*this.Values[6]
m.Values[1] = mat.Values[0]*this.Values[1] + mat.Values[1]*this.Values[4] + mat.Values[2]*this.Values[7]
m.Values[2] = mat.Values[0]*this.Values[2] + mat.Values[1]*this.Values[5] + mat.Values[2]*this.Values[8]
m.Values[3] = mat.Values[3]*this.Values[0] + mat.Values[4]*this.Values[3] + mat.Values[5]*this.Values[6]
m.Values[4] = mat.Values[3]*this.Values[1] + mat.Values[4]*this.Values[4] + mat.Values[5]*this.Values[7]
m.Values[5] = mat.Values[3]*this.Values[2] + mat.Values[4]*this.Values[5] + mat.Values[5]*this.Values[8]
m.Values[6] = mat.Values[6]*this.Values[0] + mat.Values[7]*this.Values[3] + mat.Values[8]*this.Values[6]
m.Values[7] = mat.Values[6]*this.Values[1] + mat.Values[7]*this.Values[4] + mat.Values[8]*this.Values[7]
m.Values[8] = mat.Values[6]*this.Values[2] + mat.Values[7]*this.Values[5] + mat.Values[8]*this.Values[8]
}
// Multiplies given vector with actual matrix and returns result.
func (m *Mat3) MultVec(v Vec3) Vec3 {
vec := Vec3{}
vec.X = m.Values[0]*v.X + m.Values[3]*v.X + m.Values[6]*v.X
vec.Y = m.Values[1]*v.Y + m.Values[4]*v.Y + m.Values[7]*v.Y
vec.Z = m.Values[2]*v.Z + m.Values[5]*v.Z + m.Values[8]*v.Z
return vec
}
// Returns the determinate of actual matrix.
func (m *Mat3) Determinate() float64 {
var d float64
d = m.Values[0]*m.Values[4]*m.Values[8] + m.Values[3]*m.Values[7]*m.Values[2] + m.Values[6]*m.Values[1]*m.Values[5]
d -= m.Values[2]*m.Values[4]*m.Values[6] - m.Values[5]*m.Values[7]*m.Values[0] - m.Values[8]*m.Values[1]*m.Values[3]
return d
}
// Sets the inverse of actual matrix.
func (m *Mat3) Inverse() {
d := 1 / m.Determinate()
mat := m.Copy()
m.Values[0] = (mat.Values[4]*mat.Values[8] - mat.Values[7]*mat.Values[5]) * d
m.Values[1] = (mat.Values[7]*mat.Values[2] - mat.Values[1]*mat.Values[8]) * d
m.Values[2] = (mat.Values[1]*mat.Values[5] - mat.Values[4]*mat.Values[2]) * d
m.Values[3] = (mat.Values[6]*mat.Values[5] - mat.Values[3]*mat.Values[8]) * d
m.Values[4] = (mat.Values[0]*mat.Values[8] - mat.Values[6]*mat.Values[2]) * d
m.Values[5] = (mat.Values[3]*mat.Values[2] - mat.Values[0]*mat.Values[5]) * d
m.Values[6] = (mat.Values[3]*mat.Values[7] - mat.Values[6]*mat.Values[4]) * d
m.Values[7] = (mat.Values[6]*mat.Values[1] - mat.Values[0]*mat.Values[7]) * d
m.Values[8] = (mat.Values[0]*mat.Values[4] - mat.Values[3]*mat.Values[1]) * d
}
// Calculates and saves the transpose of actual matrix.
func (m *Mat3) Transpose() {
mat := m.Copy()
m.Values[1] = mat.Values[3]
m.Values[2] = mat.Values[6]
m.Values[3] = mat.Values[1]
m.Values[5] = mat.Values[7]
m.Values[6] = mat.Values[2]
m.Values[7] = mat.Values[5]
}
// Translates and saves actual matrix by given vector.
func (m *Mat3) Translate(v Vec2) {
mat := &Mat3{}
mat.Identity()
mat.Values[6] = v.X
mat.Values[7] = v.Y
m.Mult(mat)
}
// Scales and saves actual matrix by given vector.
func (m *Mat3) Scale(v Vec2) {
mat := &Mat3{}
mat.Identity()
mat.Values[0] = v.X
mat.Values[4] = v.Y
m.Mult(mat)
}
// Rotates and saves actual matrix by given vector.
func (m *Mat3) Rotate(angle float64) {
mat := &Mat3{}
var co, si float64
angle = angle * (math.Pi / 180)
si = math.Sin(angle)
co = math.Cos(angle)
mat.Values[0] = co
mat.Values[1] = si
mat.Values[2] = 0
mat.Values[3] = -si
mat.Values[4] = co
mat.Values[5] = 0
mat.Values[6] = 0
mat.Values[7] = 0
mat.Values[8] = 1
m.Mult(mat)
}
// Sets actual matrix to orthogonal projection with given viewport.
func (m *Mat3) Ortho(viewport Vec4) {
if viewport.X != viewport.Z && viewport.Y != viewport.W {
m.Identity()
m.Values[0] = 2 / (viewport.Z - viewport.X)
m.Values[4] = 2 / (viewport.W - viewport.Y)
m.Values[6] = -(viewport.Z + viewport.X) / (viewport.Z - viewport.X)
m.Values[7] = -(viewport.W + viewport.Y) / (viewport.W - viewport.Y)
m.Values[8] = 1
}
}
// Multiplies both matrices and returns a new Mat3.
func MultMat3(a, b *Mat3) *Mat3 {
c := a.Copy()
c.Mult(b)
return c
}

255
geo/mat4.go Normal file
View File

@@ -0,0 +1,255 @@
package geo
import (
"math"
)
// 4x4 column major matrix.
type Mat4 struct {
Values [16]float64
}
// Creates a new 4x4 matrix with initial values.
func NewMat4(m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33 float64) *Mat4 {
return &Mat4{[16]float64{m00, m10, m20, m30, m01, m11, m21, m31, m02, m12, m22, m32, m03, m13, m23, m33}}
}
// Creates a copy of actual matrix.
func (m *Mat4) Copy() *Mat4 {
return &Mat4{m.Values}
}
// Sets the matrix to zeros.
func (m *Mat4) Clear() {
for i := range m.Values {
m.Values[i] = 0
}
}
// Sets the matrix to identity matrix.
func (m *Mat4) Identity() {
m.Clear()
m.Values[0] = 1
m.Values[5] = 1
m.Values[10] = 1
m.Values[15] = 1
}
// Multiplies actual matrix with given matrix and saves result.
func (m *Mat4) Mult(mat *Mat4) {
this := m.Copy()
m.Values[0] = mat.Values[0]*this.Values[0] + mat.Values[1]*this.Values[4] + mat.Values[2]*this.Values[8] + mat.Values[3]*this.Values[12]
m.Values[1] = mat.Values[0]*this.Values[1] + mat.Values[1]*this.Values[5] + mat.Values[2]*this.Values[9] + mat.Values[3]*this.Values[13]
m.Values[2] = mat.Values[0]*this.Values[2] + mat.Values[1]*this.Values[6] + mat.Values[2]*this.Values[10] + mat.Values[3]*this.Values[14]
m.Values[3] = mat.Values[0]*this.Values[3] + mat.Values[1]*this.Values[7] + mat.Values[2]*this.Values[11] + mat.Values[3]*this.Values[15]
m.Values[4] = mat.Values[4]*this.Values[0] + mat.Values[5]*this.Values[4] + mat.Values[6]*this.Values[8] + mat.Values[7]*this.Values[12]
m.Values[5] = mat.Values[4]*this.Values[1] + mat.Values[5]*this.Values[5] + mat.Values[6]*this.Values[9] + mat.Values[7]*this.Values[13]
m.Values[6] = mat.Values[4]*this.Values[2] + mat.Values[5]*this.Values[6] + mat.Values[6]*this.Values[10] + mat.Values[7]*this.Values[14]
m.Values[7] = mat.Values[4]*this.Values[3] + mat.Values[5]*this.Values[7] + mat.Values[6]*this.Values[11] + mat.Values[7]*this.Values[15]
m.Values[8] = mat.Values[8]*this.Values[0] + mat.Values[9]*this.Values[4] + mat.Values[10]*this.Values[8] + mat.Values[11]*this.Values[12]
m.Values[9] = mat.Values[8]*this.Values[1] + mat.Values[9]*this.Values[5] + mat.Values[10]*this.Values[9] + mat.Values[11]*this.Values[13]
m.Values[10] = mat.Values[8]*this.Values[2] + mat.Values[9]*this.Values[6] + mat.Values[10]*this.Values[10] + mat.Values[11]*this.Values[14]
m.Values[11] = mat.Values[8]*this.Values[3] + mat.Values[9]*this.Values[7] + mat.Values[10]*this.Values[11] + mat.Values[11]*this.Values[15]
m.Values[12] = mat.Values[12]*this.Values[0] + mat.Values[13]*this.Values[4] + mat.Values[14]*this.Values[8] + mat.Values[15]*this.Values[12]
m.Values[13] = mat.Values[12]*this.Values[1] + mat.Values[13]*this.Values[5] + mat.Values[14]*this.Values[9] + mat.Values[15]*this.Values[13]
m.Values[14] = mat.Values[12]*this.Values[2] + mat.Values[13]*this.Values[6] + mat.Values[14]*this.Values[10] + mat.Values[15]*this.Values[14]
m.Values[15] = mat.Values[12]*this.Values[3] + mat.Values[13]*this.Values[7] + mat.Values[14]*this.Values[11] + mat.Values[15]*this.Values[15]
}
// Multiplies given vector with actual matrix and returns result.
func (m *Mat4) MultVec(v Vec3) Vec3 {
vec := Vec3{}
vec.X = m.Values[0]*v.X + m.Values[4]*v.X + m.Values[8]*v.X + m.Values[12]*v.X
vec.Y = m.Values[1]*v.Y + m.Values[5]*v.Y + m.Values[9]*v.Y + m.Values[13]*v.Y
vec.Z = m.Values[2]*v.Z + m.Values[6]*v.Z + m.Values[10]*v.Z + m.Values[14]*v.Z
return vec
}
// Returns the determinate of actual matrix.
func (m *Mat4) Determinate() float64 {
var d float64
d = m.Values[0]*m.Values[4]*m.Values[8] + m.Values[1]*m.Values[5]*m.Values[6] + m.Values[2]*m.Values[3]*m.Values[7]
d -= m.Values[2]*m.Values[4]*m.Values[6] + m.Values[0]*m.Values[5]*m.Values[7] + m.Values[1]*m.Values[3]*m.Values[8]
return d
}
// Sets the inverse of actual matrix.
func (m *Mat4) Inverse() {
mat := m.Copy()
m.Values[0] = mat.Values[0]
m.Values[1] = mat.Values[4]
m.Values[2] = mat.Values[8]
m.Values[4] = mat.Values[1]
m.Values[6] = mat.Values[9]
m.Values[8] = mat.Values[2]
m.Values[9] = mat.Values[6]
m.Values[12] = m.Values[0]*-mat.Values[12] + m.Values[4]*-mat.Values[13] + m.Values[8]*-mat.Values[14]
m.Values[13] = m.Values[1]*-mat.Values[12] + m.Values[5]*-mat.Values[13] + m.Values[9]*-mat.Values[14]
m.Values[14] = m.Values[2]*-mat.Values[12] + m.Values[6]*-mat.Values[13] + m.Values[10]*-mat.Values[14]
m.Values[3] = 0
m.Values[7] = 0
m.Values[11] = 0
m.Values[15] = 1
}
// Calculates and saves the transpose of actual matrix.
func (m *Mat4) Transpose() {
mat := m.Copy()
m.Values[1] = mat.Values[4]
m.Values[2] = mat.Values[8]
m.Values[3] = mat.Values[12]
m.Values[4] = mat.Values[1]
m.Values[6] = mat.Values[9]
m.Values[7] = mat.Values[13]
m.Values[8] = mat.Values[2]
m.Values[9] = mat.Values[6]
m.Values[11] = mat.Values[14]
m.Values[12] = mat.Values[3]
m.Values[13] = mat.Values[2]
m.Values[14] = mat.Values[11]
}
// Translates and saves actual matrix by given vector.
func (m *Mat4) Translate(v Vec3) {
mat := Mat4{}
mat.Identity()
mat.Values[12] = v.X
mat.Values[13] = v.Y
mat.Values[14] = v.Z
m.Mult(&mat)
}
// Scales and saves actual matrix by given vector.
func (m *Mat4) Scale(v Vec3) {
mat := Mat4{}
mat.Identity()
mat.Values[0] = v.X
mat.Values[5] = v.Y
mat.Values[10] = v.Z
m.Mult(&mat)
}
// Rotates and saves actual matrix by given vector.
func (m *Mat4) Rotate(angle float64, axis Vec3) {
mat := Mat4{}
var co, si float64
axis.Normalize()
angle = angle * (math.Pi / 180)
si = float64(math.Sin(float64(angle)))
co = float64(math.Cos(float64(angle)))
mat.Values[0] = axis.X*axis.X*(1-co) + co
mat.Values[1] = axis.Y*axis.X*(1-co) + axis.Z*si
mat.Values[2] = axis.X*axis.Z*(1-co) - axis.Y*si
mat.Values[3] = 0
mat.Values[4] = axis.X*axis.Y*(1-co) - axis.Z*si
mat.Values[5] = axis.Y*axis.Y*(1-co) + co
mat.Values[6] = axis.Y*axis.Z*(1-co) + axis.X*si
mat.Values[7] = 0
mat.Values[8] = axis.X*axis.Z*(1-co) + axis.Y*si
mat.Values[9] = axis.Y*axis.Z*(1-co) - axis.X*si
mat.Values[10] = axis.Z*axis.Z*(1-co) + co
mat.Values[11] = 0
mat.Values[12] = 0
mat.Values[13] = 0
mat.Values[14] = 0
mat.Values[15] = 1
m.Mult(&mat)
}
// Sets actual matrix to orthogonal projection with given viewport.
func (m *Mat4) Ortho(viewport Vec4, znear, zfar float64) {
if viewport.X != viewport.Z && viewport.Y != viewport.W && znear != zfar {
m.Identity()
m.Values[0] = 2 / (viewport.Z - viewport.X)
m.Values[5] = 2 / (viewport.W - viewport.Y)
m.Values[10] = -2 / (zfar - znear)
m.Values[12] = -(viewport.Z + viewport.X) / (viewport.Z - viewport.X)
m.Values[13] = -(viewport.W + viewport.Y) / (viewport.W - viewport.Y)
m.Values[14] = -(zfar + znear) / (zfar - znear)
m.Values[15] = 1
}
}
// Sets actual matrix to project to specified locations with given upper axis.
func (m *Mat4) LookAt(pos, lookAt, up Vec3) {
dir := lookAt.Copy()
dir.Sub(pos)
dir.Normalize()
right := CrossVec3(dir, up)
right.Normalize()
up = CrossVec3(right, dir)
up.Normalize()
mat := Mat4{}
mat.Values[0] = right.X
mat.Values[4] = right.Y
mat.Values[8] = right.Z
mat.Values[12] = -right.DotVec(pos)
mat.Values[1] = up.X
mat.Values[5] = up.Y
mat.Values[9] = up.Z
mat.Values[13] = -up.DotVec(pos)
mat.Values[2] = -dir.X
mat.Values[6] = -dir.Y
mat.Values[10] = -dir.Z
mat.Values[14] = dir.DotVec(pos)
mat.Values[3] = 0
mat.Values[7] = 0
mat.Values[11] = 0
mat.Values[15] = 1
m.Mult(&mat)
}
// Sets actual matrix to perspective projection with given viewport.
func (m *Mat4) Perspective(fov, ratio, znear, zfar float64) {
f := 1 / math.Tan(float64(fov*(math.Pi/360)))
m.Identity()
m.Values[0] = f / ratio
m.Values[5] = f
m.Values[10] = (zfar + znear) / (znear - zfar)
m.Values[11] = -1
m.Values[14] = (2 * zfar * znear) / (znear - zfar)
m.Values[15] = 0
}
// Multiplies both matrices and returns a new Mat4.
func MultMat4(a, b *Mat4) *Mat4 {
c := a.Copy()
c.Mult(b)
return c
}

20
geo/util.go Normal file
View File

@@ -0,0 +1,20 @@
package geo
import (
"math"
)
// Returns the distance between two 2D vectors.
func DistanceVec2(a, b Vec2) float64 {
return math.Sqrt(float64((a.X-b.X)*(a.X-b.X) + (a.Y-b.Y)*(a.Y-b.Y)))
}
// Returns the distance between two 3D vectors.
func DistanceVec3(a, b Vec3) float64 {
return math.Sqrt(float64((a.X-b.X)*(a.X-b.X) + (a.Y-b.Y)*(a.Y-b.Y) + (a.Z-b.Z)*(a.Z-b.Z)))
}
// Returns the distance between two 4D vectors.
func DistanceVec4(a, b Vec4) float64 {
return math.Sqrt(float64((a.X-b.X)*(a.X-b.X) + (a.Y-b.Y)*(a.Y-b.Y) + (a.Z-b.Z)*(a.Z-b.Z) + (a.W-b.W)*(a.W-b.W)))
}

62
geo/vec2.go Normal file
View File

@@ -0,0 +1,62 @@
package geo
import (
"math"
)
// A 2D vector.
type Vec2 struct {
X, Y float64
}
// Creates a copy of actual vector.
func (v *Vec2) Copy() Vec2 {
return Vec2{v.X, v.Y}
}
// Adds and saves the given vector to actual vector.
func (v *Vec2) Add(vec Vec2) {
v.X += vec.X
v.Y += vec.Y
}
// Subtracts and saves the given vector to actual vector.
func (v *Vec2) Sub(vec Vec2) {
v.X -= vec.X
v.Y -= vec.Y
}
// Multiplies and saves the given vector to actual vector.
func (v *Vec2) Mult(vec Vec2) {
v.X *= vec.X
v.Y *= vec.Y
}
// Divides and saves the given vector to actual vector.
func (v *Vec2) Div(vec Vec2) {
v.X /= vec.X
v.Y /= vec.Y
}
// Calculates and returns the dot product of actual vector.
func (v *Vec2) Dot() float64 {
return v.X*v.X + v.Y*v.Y
}
// Calculates and returns the dot product of combination of given vector and actual vector.
func (v *Vec2) DotVec(vec Vec2) float64 {
return v.X*vec.X + v.Y*vec.Y
}
// Returns the length of actual vector.
func (v *Vec2) Length() float64 {
return float64(math.Sqrt(float64(v.Dot())))
}
// Normalizes actual vector to length 1.
func (v *Vec2) Normalize() {
l := v.Length()
v.X /= l
v.Y /= l
}

87
geo/vec3.go Normal file
View File

@@ -0,0 +1,87 @@
package geo
import (
"math"
)
// A 3D vector.
type Vec3 struct {
X, Y, Z float64
}
// Creates a copy of actual vector.
func (v *Vec3) Copy() Vec3 {
return Vec3{v.X, v.Y, v.Z}
}
// Adds and saves the given vector to actual vector.
func (v *Vec3) Add(vec Vec3) {
v.X += vec.X
v.Y += vec.Y
v.Z += vec.Z
}
// Subtracts and saves the given vector to actual vector.
func (v *Vec3) Sub(vec Vec3) {
v.X -= vec.X
v.Y -= vec.Y
v.Z -= vec.Z
}
// Multiplies and saves the given vector to actual vector.
func (v *Vec3) Mult(vec Vec3) {
v.X *= vec.X
v.Y *= vec.Y
v.Z *= vec.Z
}
// Divides and saves the given vector to actual vector.
func (v *Vec3) Div(vec Vec3) {
v.X /= vec.X
v.Y /= vec.Y
v.Z /= vec.Z
}
// Calculates and returns the dot product of actual vector.
func (v *Vec3) Dot() float64 {
return v.X*v.X + v.Y*v.Y + v.Z*v.Z
}
// Calculates and returns the dot product of combination of given vector and actual vector.
func (v *Vec3) DotVec(vec Vec3) float64 {
return v.X*vec.X + v.Y*vec.Y + v.Z*vec.Z
}
// Returns the length of actual vector.
func (v *Vec3) Length() float64 {
return math.Sqrt(v.Dot())
}
// Normalizes actual vector to length 1.
func (v *Vec3) Normalize() {
l := v.Length()
v.X /= l
v.Y /= l
v.Z /= l
}
// Calculates and saves cross product of given and actual vector.
func (v *Vec3) Cross(vec Vec3) {
this := Vec3{v.X, v.Y, v.Z}
v.X = this.Y*vec.Z - this.Z*vec.Y
v.Y = this.Z*vec.X - this.X*vec.Z
v.Z = this.X*vec.Y - this.Y*vec.X
}
// Calulates the cross product of given vectors and returns result as a new vector.
func CrossVec3(a, b Vec3) Vec3 {
vec := Vec3{}
vec.X = (a.Y * b.Z) - (a.Z * b.Y)
vec.Y = (a.Z * b.X) - (a.X * b.Z)
vec.Z = (a.X * b.Y) - (a.Y * b.X)
return vec
}

72
geo/vec4.go Normal file
View File

@@ -0,0 +1,72 @@
package geo
import (
"math"
)
// A 4D vector.
type Vec4 struct {
X, Y, Z, W float64
}
// Creates a copy of actual vector.
func (v *Vec4) Copy() Vec4 {
return Vec4{v.X, v.Y, v.Z, v.W}
}
// Adds and saves the given vector to actual vector.
func (v *Vec4) Add(vec Vec4) {
v.X += vec.X
v.Y += vec.Y
v.Z += vec.Z
v.W += vec.W
}
// Subracts and saves the given vector to actual vector.
func (v *Vec4) Sub(vec Vec4) {
v.X -= vec.X
v.Y -= vec.Y
v.Z -= vec.Z
v.W -= vec.W
}
// Multiplies and saves the given vector to actual vector.
func (v *Vec4) Mult(vec Vec4) {
v.X *= vec.X
v.Y *= vec.Y
v.Z *= vec.Z
v.W *= vec.W
}
// Divides and saves the given vector to actual vector.
func (v *Vec4) Div(vec Vec4) {
v.X /= vec.X
v.Y /= vec.Y
v.Z /= vec.Z
v.W /= vec.W
}
// Calculates and returns the dot product of actual vector.
func (v *Vec4) Dot() float64 {
return v.X*v.X + v.Y*v.Y + v.Z*v.Z + v.W*v.W
}
// Calculates and returns the dot product of combination of given vector and actual vector.
func (v *Vec4) DotVec(vec Vec4) float64 {
return v.X*vec.X + v.Y*vec.Y + v.Z*vec.Z + v.W*vec.W
}
// Returns the length of actual vector.
func (v *Vec4) Length() float64 {
return math.Sqrt(v.Dot())
}
// Normalizes actual vector to length 1.
func (v *Vec4) Normalize() {
l := v.Length()
v.X /= l
v.Y /= l
v.Z /= l
v.W /= l
}

15
gl/drop.go Normal file
View File

@@ -0,0 +1,15 @@
package gl
// The dropable interface is used to clean up GL objects.
// Use the Drop() function to drop a range of objects.
type Dropable interface {
Drop()
}
// Drops given GL objects.
// Objects must implement the Dropable inteface.
func Drop(objects []Dropable) {
for _, obj := range objects {
obj.Drop()
}
}

123
gl/fbo.go Normal file
View File

@@ -0,0 +1,123 @@
package gl
import (
"github.com/go-gl/gl/v4.5-core/gl"
)
// Frame Buffer Object.
type FBO struct {
id uint32
target uint32
attachments []uint32
}
// Creates a new FBO with given target.
func NewFBO(target uint32) *FBO {
fbo := &FBO{}
gl.GenFramebuffers(1, &fbo.id)
fbo.target = target
fbo.attachments = make([]uint32, 0)
return fbo
}
// Creates a new FBO with given target and 2D texture.
// Used to render to texture.
func NewFBOWithTex2D(width, height, filter int32) (*FBO, *Tex) {
tex := NewTex(gl.TEXTURE_2D)
tex.Bind()
tex.SetDefaultParams(filter)
tex.Texture2D(0,
gl.RGBA,
width,
height,
gl.RGBA,
gl.UNSIGNED_BYTE,
nil)
tex.Unbind()
fbo := NewFBO(gl.FRAMEBUFFER)
fbo.Bind()
fbo.Texture2D(gl.COLOR_ATTACHMENT0, tex.GetId(), 0)
fbo.Unbind()
return fbo, tex
}
// Drops the FBO.
func (f *FBO) Drop() {
gl.DeleteFramebuffers(1, &f.id)
}
// Binds the FBO for usage (rendered on).
func (f *FBO) Bind() {
gl.BindFramebuffer(f.target, f.id)
}
// Unbinds.
func (f *FBO) Unbind() {
gl.BindFramebuffer(f.target, 0)
}
// Sets draw buffer.
func (f *FBO) DrawBuffer(mode uint32) {
gl.DrawBuffer(mode)
}
// Sets read buffer.
func (f *FBO) ReadBuffer(mode uint32) {
gl.ReadBuffer(mode)
}
func (f *FBO) DrawBuffers(mode uint32) {
gl.DrawBuffers(int32(len(f.attachments)), &f.attachments[0])
}
// Removes all attached textures from FBO.
func (f *FBO) ClearAttachments() {
f.attachments = make([]uint32, 0)
}
// Attaches a texture.
func (f *FBO) Texture(attachment, texId uint32, level int32) {
f.attachments = append(f.attachments, attachment)
gl.FramebufferTexture(f.target, attachment, texId, level)
}
// Attaches a 1D texture.
func (f *FBO) Texture1D(attachment, texId uint32, level int32) {
f.attachments = append(f.attachments, attachment)
gl.FramebufferTexture1D(f.target, attachment, gl.TEXTURE_1D, texId, level)
}
// Attaches a 2D texture.
func (f *FBO) Texture2D(attachment, texId uint32, level int32) {
f.attachments = append(f.attachments, attachment)
gl.FramebufferTexture2D(f.target, attachment, gl.TEXTURE_2D, texId, level)
}
// Attaches a 3D texture.
func (f *FBO) Texture3D(attachment, texId uint32, level, layer int32) {
f.attachments = append(f.attachments, attachment)
gl.FramebufferTexture3D(f.target, attachment, gl.TEXTURE_3D, texId, level, layer)
}
// Returns the status of the FBO.
func (f *FBO) GetStatus() uint32 {
return gl.CheckFramebufferStatus(f.target)
}
// Returns true if FBO is complete, else false.
func (f *FBO) Complete() bool {
return f.GetStatus() == gl.FRAMEBUFFER_COMPLETE
}
// Returns the GL ID.
func (f *FBO) GetId() uint32 {
return f.id
}
// Returns the target.
func (f *FBO) GetTarget() uint32 {
return f.target
}

313
gl/shader.go Normal file
View File

@@ -0,0 +1,313 @@
package gl
import (
"errors"
"geo"
"github.com/go-gl/gl/v4.5-core/gl"
"strings"
)
// Combination of shaders and shader program.
type Shader struct {
program, vertex, fragment uint32
attrIndex uint32
attributes []uint32
uniformMap map[string]int32
attrMap map[string]int32
}
// Creates a new shader program by given vertex and fragment shader source code.
// The shaders itself will be deleted when compiled, only the program ID will be kept.
func NewShader(vertexShader, fragmentShader string) (*Shader, error) {
shader := &Shader{}
shader.attributes = make([]uint32, 0)
shader.uniformMap = make(map[string]int32)
shader.attrMap = make(map[string]int32)
shader.program = gl.CreateProgram()
shader.vertex = gl.CreateShader(gl.VERTEX_SHADER)
shader.fragment = gl.CreateShader(gl.FRAGMENT_SHADER)
if err := compileShader(&shader.vertex, vertexShader+NullTerminator); err != nil {
gl.DeleteShader(shader.vertex)
gl.DeleteShader(shader.fragment)
shader.Drop()
return nil, err
}
if err := compileShader(&shader.fragment, fragmentShader+NullTerminator); err != nil {
gl.DeleteShader(shader.vertex)
gl.DeleteShader(shader.fragment)
shader.Drop()
return nil, err
}
gl.AttachShader(shader.program, shader.vertex)
gl.AttachShader(shader.program, shader.fragment)
if err := linkProgram(shader.program); err != nil {
gl.DeleteShader(shader.vertex)
gl.DeleteShader(shader.fragment)
shader.Drop()
return nil, err
}
// we don't need to keep them in memory
gl.DetachShader(shader.program, shader.vertex)
gl.DetachShader(shader.program, shader.fragment)
gl.DeleteShader(shader.vertex)
gl.DeleteShader(shader.fragment)
return shader, nil
}
func compileShader(shader *uint32, source string) error {
csrc := gl.Str(source)
gl.ShaderSource(*shader, 1, &csrc, nil)
gl.CompileShader(*shader)
if err := shaderCheckError(*shader); err != nil {
return err
}
return nil
}
func shaderCheckError(shader uint32) error {
var status int32
gl.GetShaderiv(shader, gl.COMPILE_STATUS, &status)
if status == gl.FALSE {
var logLength int32
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength+1))
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
return errors.New("compiler error:\r\n" + log)
}
return nil
}
func linkProgram(program uint32) error {
gl.LinkProgram(program)
var status int32
gl.GetProgramiv(program, gl.LINK_STATUS, &status)
if status == gl.FALSE {
var logLength int32
gl.GetProgramiv(program, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength+1))
gl.GetProgramInfoLog(program, logLength, nil, gl.Str(log))
return errors.New("linker error:\r\n" + log)
}
return nil
}
// Deletes the GL program object.
func (s *Shader) Drop() {
gl.DeleteProgram(s.program)
}
// Binds the shader for usage.
func (s *Shader) Bind() {
gl.UseProgram(s.program)
}
// Unbinds shader.
func (s *Shader) Unbind() {
gl.UseProgram(0)
}
// Binds an attribute to this shader, name must be present in shader source.
func (s *Shader) BindAttribIndex(name string, index uint32) {
gl.BindAttribLocation(s.program, index, gl.Str(name+NullTerminator))
s.attributes = append(s.attributes, index)
}
// Binds an attribute to this shader (with default index), name must be present in shader source.
func (s *Shader) BindAttrib(name string) {
s.BindAttribIndex(name, s.attrIndex)
s.attrIndex++
}
// Enables all bound attributes.
func (s *Shader) EnableVertexAttribArrays() {
for i := range s.attributes {
gl.EnableVertexAttribArray(s.attributes[i])
}
}
// Disables all bound attributes.
func (s *Shader) DisableVertexAttribArrays() {
for i := range s.attributes {
gl.DisableVertexAttribArray(s.attributes[i])
}
}
// Returns the uniform location of a variable.
// The name must be present in the shader source.
func (s *Shader) GetUniformLocation(name string) int32 {
_, exists := s.uniformMap[name]
if !exists {
s.uniformMap[name] = gl.GetUniformLocation(s.program, gl.Str(name+NullTerminator))
}
return s.uniformMap[name]
}
// Returns the location of an attribute.
// The name must be present in the shader source.
func (s *Shader) GetAttribLocation(name string) int32 {
_, exists := s.attrMap[name]
if !exists {
s.attrMap[name] = gl.GetAttribLocation(s.program, gl.Str(name+NullTerminator))
}
return s.attrMap[name]
}
func (s *Shader) SendUniform1i(name string, v int32) {
gl.Uniform1i(s.GetUniformLocation(name), v)
}
func (s *Shader) SendUniform2i(name string, v0, v1 int32) {
gl.Uniform2i(s.GetUniformLocation(name), v0, v1)
}
func (s *Shader) SendUniform3i(name string, v0, v1, v2 int32) {
gl.Uniform3i(s.GetUniformLocation(name), v0, v1, v2)
}
func (s *Shader) SendUniform4i(name string, v0, v1, v2, v3 int32) {
gl.Uniform4i(s.GetUniformLocation(name), v0, v1, v2, v3)
}
func (s *Shader) SendUniform1f(name string, v float32) {
gl.Uniform1f(s.GetUniformLocation(name), v)
}
func (s *Shader) SendUniform2f(name string, v0, v1 float32) {
gl.Uniform2f(s.GetUniformLocation(name), v0, v1)
}
func (s *Shader) SendUniform3f(name string, v0, v1, v2 float32) {
gl.Uniform3f(s.GetUniformLocation(name), v0, v1, v2)
}
func (s *Shader) SendUniform4f(name string, v0, v1, v2, v3 float32) {
gl.Uniform4f(s.GetUniformLocation(name), v0, v1, v2, v3)
}
func (s *Shader) SendUniform1iv(name string, count int32, data *int32) {
gl.Uniform1iv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform2iv(name string, count int32, data *int32) {
gl.Uniform2iv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform3iv(name string, count int32, data *int32) {
gl.Uniform3iv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform4iv(name string, count int32, data *int32) {
gl.Uniform4iv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform1fv(name string, count int32, data *float32) {
gl.Uniform1fv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform2fv(name string, count int32, data *float32) {
gl.Uniform2fv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform3fv(name string, count int32, data *float32) {
gl.Uniform3fv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform4fv(name string, count int32, data *float32) {
gl.Uniform4fv(s.GetUniformLocation(name), count, data)
}
func (s *Shader) SendUniform2x2(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix2fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform3x3(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix3fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform4x4(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix4fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform2x3(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix2x3fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform3x2(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix3x2fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform2x4(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix2x4fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform4x2(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix4x2fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform3x4(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix3x4fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendUniform4x3(name string, data *float32, count int32, transpose bool) {
gl.UniformMatrix4x3fv(s.GetUniformLocation(name), count, transpose, data)
}
func (s *Shader) SendMat3(name string, m geo.Mat3) {
var data [9]float32
for i := 0; i < 9; i++ {
data[i] = float32(m.Values[i])
}
gl.UniformMatrix3fv(s.GetUniformLocation(name), 1, false, &data[0])
}
func (s *Shader) SendMat4(name string, m geo.Mat4) {
var data [16]float32
for i := 0; i < 16; i++ {
data[i] = float32(m.Values[i])
}
gl.UniformMatrix4fv(s.GetUniformLocation(name), 1, false, &data[0])
}
// Retuns the program GL ID.
func (s *Shader) GetProgramId() uint32 {
return s.program
}
// Returns the vertex shader GL ID.
func (s *Shader) GetVertexId() uint32 {
return s.vertex
}
// Returns the fragment shader GL ID.
func (s *Shader) GetFragmentId() uint32 {
return s.fragment
}

132
gl/tex.go Normal file
View File

@@ -0,0 +1,132 @@
package gl
import (
"geo"
"github.com/go-gl/gl/v4.5-core/gl"
"image"
)
// Texture object.
type Tex struct {
id uint32
target uint32
activeTexture uint32
size geo.Vec3
rgba *image.RGBA // optional, most of the time nil
}
// Creates a new texture for given target (e.g. GL_TEXTURE_2D).
func NewTex(target uint32) *Tex {
tex := &Tex{}
tex.target = target
tex.activeTexture = gl.TEXTURE0
gl.GenTextures(1, &tex.id)
return tex
}
// Drops the texture.
func (t *Tex) Drop() {
gl.DeleteBuffers(1, &t.id)
}
// Binds the texture for rendering.
func (t *Tex) Bind() {
gl.ActiveTexture(t.activeTexture)
gl.BindTexture(t.target, t.id)
}
// Unbinds.
func (t *Tex) Unbind() {
gl.BindTexture(t.target, 0)
}
// Sets the default parameters, which are passed filter and CLAMP_TO_EDGE.
func (t *Tex) SetDefaultParams(filter int32) {
t.Parameteri(gl.TEXTURE_MIN_FILTER, filter)
t.Parameteri(gl.TEXTURE_MAG_FILTER, filter)
t.Parameteri(gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
t.Parameteri(gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
}
// Creates a new 1D texture.
func (t *Tex) Texture1D(level, internalFormat, width int32, format, ttype uint32, data []uint8) {
t.size = geo.Vec3{float64(width), 0, 0}
t.Bind()
if data != nil {
gl.TexImage1D(t.target, level, internalFormat, width, 0, format, ttype, gl.Ptr(data))
} else {
gl.TexImage1D(t.target, level, internalFormat, width, 0, format, ttype, nil)
}
}
// Creates a new 2D texture.
func (t *Tex) Texture2D(level, internalFormat, width, height int32, format, ttype uint32, data []uint8) {
t.size = geo.Vec3{float64(width), float64(height), 0}
t.Bind()
if data != nil {
gl.TexImage2D(t.target, level, internalFormat, width, height, 0, format, ttype, gl.Ptr(data))
} else {
gl.TexImage2D(t.target, level, internalFormat, width, height, 0, format, ttype, nil)
}
}
// Creates a new 3D texture.
func (t *Tex) Texture3D(level, internalFormat, width, height, depth int32, format, ttype uint32, data []uint8) {
t.size = geo.Vec3{float64(width), float64(height), float64(depth)}
t.Bind()
if data != nil {
gl.TexImage3D(t.target, level, internalFormat, width, height, depth, 0, format, ttype, gl.Ptr(data))
} else {
gl.TexImage3D(t.target, level, internalFormat, width, height, depth, 0, format, ttype, nil)
}
}
// Sets integer parameter.
func (t *Tex) Parameteri(name uint32, param int32) {
gl.TexParameteri(t.target, name, param)
}
// Sets float parameter.
func (t *Tex) Parameterf(name uint32, param float32) {
gl.TexParameterf(t.target, name, param)
}
// Sets which texture boundary is used when bound for rendering.
// Can be GL_TEXTURE0, GL_TEXTURE1, ... GL_TEXTUREn.
func (t *Tex) SetActiveTexture(activeTexture uint32) {
t.activeTexture = activeTexture
}
// Sets pixel data.
func (t *Tex) SetRGBA(rgba *image.RGBA) {
t.rgba = rgba
}
// Returns the GL ID.
func (t *Tex) GetId() uint32 {
return t.id
}
// Returns the texture target
func (t *Tex) GetTarget() uint32 {
return t.target
}
// Returns the active texture used when bound for rendering.
func (t *Tex) getActiveTexture() uint32 {
return t.activeTexture
}
// Returns the size of this texture.
func (t *Tex) GetSize() geo.Vec3 {
return t.size
}
// Returns the pixel data.
func (t *Tex) GetRGBA() *image.RGBA {
return t.rgba
}

3
gl/types.go Normal file
View File

@@ -0,0 +1,3 @@
package gl
const NullTerminator = "\x00"

39
gl/vao.go Normal file
View File

@@ -0,0 +1,39 @@
package gl
import (
"github.com/go-gl/gl/v4.5-core/gl"
)
// Vertex Array Object.
type VAO struct {
id uint32
}
// Creates a new VAO.
// Bind and use VBOs for rendering later.
func NewVAO() *VAO {
vao := &VAO{}
gl.GenVertexArrays(1, &vao.id)
return vao
}
// Drops this VAO.
func (v *VAO) Drop() {
gl.DeleteVertexArrays(1, &v.id)
}
// Binds VAO for rendering.
func (v *VAO) Bind() {
gl.BindVertexArray(v.id)
}
// Unbinds.
func (v *VAO) Unbind() {
gl.BindVertexArray(0)
}
// Returns the GL ID.
func (v *VAO) GetId() uint32 {
return v.id
}

77
gl/vbo.go Normal file
View File

@@ -0,0 +1,77 @@
package gl
import (
"github.com/go-gl/gl/v4.5-core/gl"
"unsafe"
)
// Vertex Buffer Object.
type VBO struct {
id uint32
target uint32
size int32
}
// Creates a new VBO with given target.
func NewVBO(target uint32) *VBO {
vbo := &VBO{target: target}
gl.GenBuffers(1, &vbo.id)
return vbo
}
// Drops this VBO.
func (v *VBO) Drop() {
gl.DeleteBuffers(1, &v.id)
}
// Binds VBO for rendering.
func (v *VBO) Bind() {
gl.BindBuffer(v.target, v.id)
}
// Unbinds.
func (v *VBO) Unbind() {
gl.BindBuffer(v.target, 0)
}
// Fills VBO with data.
// An unsafe pointer must be used out of Gos unsafe package.
func (v *VBO) Fill(data unsafe.Pointer, elements, size int, use uint32) {
v.size = int32(size)
v.Bind()
gl.BufferData(v.target, elements*size, data, use)
v.Unbind()
}
// Updates data or part of data.
// An unsafe pointer must be used out of Gos unsafe package.
func (v *VBO) Update(data unsafe.Pointer, elements, offset, size int) {
v.size = int32(size)
v.Bind()
gl.BufferSubData(v.target, offset, elements*size, data)
v.Unbind()
}
// Sets the attribute pointer for rendering.
// Used together with shader.
func (v *VBO) AttribPointer(attribLocation int32, size int32, btype uint32, normalized bool, stride int32) {
gl.VertexAttribPointer(uint32(attribLocation), size, btype, normalized, stride, nil)
}
// Returns the GL ID.
func (v *VBO) GetId() uint32 {
return v.id
}
// Returns the target.
func (v *VBO) GetTarget() uint32 {
return v.target
}
// Returns the number of elements within this VBO.
func (v *VBO) Size() int32 {
return v.size
}

View File

@@ -4,11 +4,15 @@ import ()
// A system provides logic for actors satisfying required components.
// They are automatically updated on each frame.
// When a system is removed from systems, the Cleanup() method will be called.
// This will also happen on program stop. This can be used to cleanup open resources
// (like GL objects).
type System interface {
Update(float64)
Add(actor *Actor) bool
Remove(actor *Actor) bool
RemoveById(id ActorId) bool
Cleanup()
Add(*Actor) bool
Remove(*Actor) bool
RemoveById(ActorId) bool
RemoveAll()
Len() int
GetName() string
@@ -37,6 +41,7 @@ func AddSystem(system System) bool {
func RemoveSystem(system System) bool {
for i, sys := range systems {
if sys == system {
sys.Cleanup()
systems = append(systems[:i], systems[i+1:]...)
return true
}
@@ -47,6 +52,10 @@ func RemoveSystem(system System) bool {
// Removes all systems.
func RemoveAllSystems() {
for _, system := range systems {
system.Cleanup()
}
systems = make([]System, 0)
}