carpy-breakout/pkg/globject/box.go

210 lines
4.9 KiB
Go

package globject
import (
"git.wisellama.rocks/Wisellama/carpy-breakout/pkg/glshader"
gl "github.com/go-gl/gl/v3.1/gles2"
"github.com/go-gl/mathgl/mgl32"
)
type Box struct {
baseAABB *AABB
Material *Material
Faces []*Face
VertexArray []float32
Translation mgl32.Vec3
Velocity mgl32.Vec3
Rotation mgl32.Vec3
RotationVelocity mgl32.Vec3
Size int32
Width float32
Height float32
Depth float32
GLProgram uint32
GLVertexArrayID uint32
GLVertexBufferID uint32
Wireframe bool
}
func NewBox(
width, height, depth float32,
position mgl32.Vec3, material *Material) *Box {
// depth = z axis (towards)
// width = x axis (right)
// height = y axis (up)
box := Box{
Size: 6,
Width: width,
Depth: depth,
Height: height,
Translation: position,
Material: material,
RotationVelocity: mgl32.Vec3{0, 0, 0},
}
topPos := mgl32.Vec3{0, height / 2.0, 0}
top := NewFace(width, depth, topPos, mgl32.Vec3{0, 1, 0}, material)
bottomPos := mgl32.Vec3{0, -height / 2.0, 0}
bottom := NewFace(width, depth, bottomPos, mgl32.Vec3{0, -1, 0}, material)
frontPos := mgl32.Vec3{0, 0, depth / 2.0}
front := NewFace(width, height, frontPos, mgl32.Vec3{0, 0, 1}, material)
backPos := mgl32.Vec3{0, 0, -depth / 2.0}
back := NewFace(width, height, backPos, mgl32.Vec3{0, 0, -1}, material)
rightPos := mgl32.Vec3{width / 2.0, 0, 0}
right := NewFace(height, depth, rightPos, mgl32.Vec3{1, 0, 0}, material)
leftPos := mgl32.Vec3{-width / 2.0, 0, 0}
left := NewFace(height, depth, leftPos, mgl32.Vec3{-1, 0, 0}, material)
box.Faces = []*Face{
top,
bottom,
front,
back,
right,
left,
}
box.VertexArray = box.GetVertexArray()
box.baseAABB = NewAABBFromBox(&box)
return &box
}
func (b *Box) GLInit(glProgram uint32) {
b.GLProgram = glProgram
gl.GenVertexArrays(1, &b.GLVertexArrayID)
gl.BindVertexArray(b.GLVertexArrayID)
gl.GenBuffers(1, &b.GLVertexBufferID)
gl.BindBuffer(gl.ARRAY_BUFFER, b.GLVertexBufferID)
sizeOfFloat := 4
gl.BufferData(gl.ARRAY_BUFFER, len(b.VertexArray)*sizeOfFloat, gl.Ptr(b.VertexArray), gl.STATIC_DRAW)
for _, face := range b.Faces {
face.GLInit(b.GLProgram)
}
}
func (b *Box) Update() {
b.Rotation = b.Rotation.Add(b.RotationVelocity)
b.Translation = b.Translation.Add(b.Velocity)
}
// GetModelMatrix applies the current rotation and translation to give you a model matrix.
// Multiplying the original positions by this matrix will give you the new position.
// It is also used in the OpenGL shaders directly.
func (b *Box) GetModelMatrix() *mgl32.Mat4 {
if b.Rotation.LenSqr() == 0 && b.Translation.LenSqr() == 0 {
model := mgl32.Ident4()
return &model
}
// Apply rotation
rotate := b.GetRotationMatrix()
// Apply translation
translate := mgl32.Translate3D(b.Translation.X(), b.Translation.Y(), b.Translation.Z())
model := translate.Mul4(*rotate)
return &model
}
func (b *Box) GetRotationMatrix() *mgl32.Mat4 {
rotateX := mgl32.HomogRotate3D(b.Rotation.X(), mgl32.Vec3{1, 0, 0})
rotateY := mgl32.HomogRotate3D(b.Rotation.Y(), mgl32.Vec3{0, 1, 0})
rotateZ := mgl32.HomogRotate3D(b.Rotation.Z(), mgl32.Vec3{0, 0, 1})
rotate := rotateX.Mul4(rotateY)
rotate = rotate.Mul4(rotateZ)
return &rotate
}
func (b *Box) GLDraw() {
model := b.GetModelMatrix()
glshader.SetUniformMatrix4f(b.GLProgram, "model", model)
b.Material.GLDraw(b.GLProgram)
if b.Wireframe {
b.glDrawLineLoop()
} else {
b.glDrawTriangles()
}
}
func (b *Box) glDrawTriangles() {
glshader.SetUniformInt(b.GLProgram, "lightsOn", 1)
gl.BindVertexArray(b.GLVertexArrayID)
gl.BindBuffer(gl.ARRAY_BUFFER, b.GLVertexBufferID)
if b.Material.TextureOn {
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, b.Material.TextureID)
}
glshader.UpdateVertexAttribs(b.GLProgram, VertexSize)
gl.DrawArrays(gl.TRIANGLES, 0, 6*2*3) // 6 sides, 2 triangles, 3 points each
}
func (b *Box) glDrawLineLoop() {
glshader.SetUniformInt(b.GLProgram, "lightsOn", 0)
for _, face := range b.Faces {
face.GLDrawLineLoop(b.GLProgram)
}
}
func (b *Box) GetVertexArray() []float32 {
// Boxes have 6 faces, 2 triangles per face, 3 vertices per triangle
// (technically 2 vertices overlap in a face, but ignore that for now)
totalVertices := 6 * 2 * 3 * VertexSize
a := make([]float32, totalVertices)
i := 0
for _, face := range b.Faces {
for _, triangle := range face.Triangles {
for _, vertex := range triangle.Vertices {
for _, elem := range vertex.GetVertexArray() {
a[i] = elem
i++
}
}
}
}
return a
}
func (b *Box) ToggleWireframe() {
b.Wireframe = !b.Wireframe
}
func (b *Box) SetXVelocity(v float32) {
b.Velocity[0] = v
}
func (b *Box) SetYVelocity(v float32) {
b.Velocity[1] = v
}
func (b *Box) SetZVelocity(v float32) {
b.Velocity[2] = v
}
func (b *Box) SetYRotationVelocity(v float32) {
b.RotationVelocity[1] = v
}
func (b *Box) GetAABB() *AABB {
return NewAABBFromBox(b)
}