Abstracting out drawing a box, doesn't work correctly.

main
Sean Hickey 2021-09-01 00:39:33 -07:00
parent 0ed95e851b
commit ccc61e9a07
10 changed files with 355 additions and 125 deletions

128
main.go
View File

@ -8,13 +8,13 @@ import (
"runtime"
"runtime/pprof"
"github.com/veandco/go-sdl2/sdl"
gl "github.com/go-gl/gl/v3.1/gles2"
"github.com/go-gl/mathgl/mgl32"
"github.com/veandco/go-sdl2/sdl"
"gitea.wisellama.rocks/carpy-breakout/pkg/game_window"
"gitea.wisellama.rocks/carpy-breakout/pkg/gl_helpers"
"gitea.wisellama.rocks/carpy-breakout/pkg/gl_objects"
"gitea.wisellama.rocks/carpy-breakout/pkg/game_window"
)
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
@ -23,16 +23,16 @@ const GameTitle = "Carpy Breakout"
const LogFile = "output.log"
func main() {
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
flag.Parse()
if *cpuprofile != "" {
f, err := os.Create(*cpuprofile)
if err != nil {
log.Fatal(err)
}
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()
}
setupLogging()
run()
}
@ -40,8 +40,6 @@ func main() {
func run() {
runtime.LockOSThread() // TODO can rework stuff to not need this.
log.Println(os.Environ())
err := sdl.Init(sdl.INIT_EVERYTHING)
if err != nil {
log.Fatal(err)
@ -60,8 +58,6 @@ func run() {
sdl.SetRelativeMouseMode(true)
gl.Init()
version := gl.GoStr(gl.GetString(gl.VERSION))
log.Println("OpenGL version", version)
gl.ClearColor(0.0, 0.0, 0.0, 1.0)
gameWindow, err := game_window.NewGameWindow(GameTitle)
@ -83,22 +79,31 @@ func run() {
log.Fatal(err)
}
box := gl_objects.NewBox(6.0, 4.0, 2.0, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{1, 1, 1}, true)
vertices := box.GetVertexArray()
log.Println(vertices)
var vao uint32
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
var vbo uint32
gl.GenBuffers(1, &vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.BufferData(gl.ARRAY_BUFFER, len(cubeVertices)*4, gl.Ptr(cubeVertices), gl.STATIC_DRAW)
gl.BufferData(gl.ARRAY_BUFFER, len(vertices)*4, gl.Ptr(vertices), gl.STATIC_DRAW)
vertAttrib := uint32(gl.GetAttribLocation(gameWindow.GLProgram, gl.Str("vert\x00")))
gl.EnableVertexAttribArray(vertAttrib)
gl.VertexAttribPointerWithOffset(vertAttrib, 3, gl.FLOAT, false, 5*4, 0)
gl.VertexAttribPointerWithOffset(vertAttrib, 3, gl.FLOAT, false, 8*4, 0)
vertColorAttrib := uint32(gl.GetAttribLocation(gameWindow.GLProgram, gl.Str("vertColor\x00")))
gl.EnableVertexAttribArray(vertColorAttrib)
gl.VertexAttribPointerWithOffset(vertColorAttrib, 3, gl.FLOAT, false, 8*4, 3*4)
texCoordAttrib := uint32(gl.GetAttribLocation(gameWindow.GLProgram, gl.Str("vertTexCoord\x00")))
gl.EnableVertexAttribArray(texCoordAttrib)
gl.VertexAttribPointerWithOffset(texCoordAttrib, 2, gl.FLOAT, false, 5*4, 3*4)
gl.VertexAttribPointerWithOffset(texCoordAttrib, 2, gl.FLOAT, false, 8*4, 6*4)
// Configure global settings
gl.Enable(gl.DEPTH_TEST)
@ -110,30 +115,29 @@ func run() {
running := true
var angle float32 = 0.0
var move float32 = 0.0
for running {
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
model = mgl32.Ident4()
move += 0.01
camera.Update()
camera.Draw(gameWindow.GLProgram)
angle += 0.00
angle += 0.01
model = mgl32.HomogRotate3D(angle, mgl32.Vec3{0, 1, 0})
gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])
// I think this is what I might need to abstract out into each Draw()
gl.BindVertexArray(vao)
gl.ActiveTexture(gl.TEXTURE0)
gl.BindTexture(gl.TEXTURE_2D, texture)
gl.DrawArrays(gl.TRIANGLES, 0, 6 * 2 * 3) // 6 sides, 2 triangles, 3 points each
gl.DrawArrays(gl.TRIANGLES, 0, 6*2*3) // 6 sides, 2 triangles, 3 points each
// end Draw()
gameWindow.SDLWindow.GLSwap()
running = handleEvents(running, gameWindow, &camera)
sdl.Delay(16)
}
@ -149,19 +153,6 @@ func setupLogging() {
log.Println("=== START ===")
}
func drawSDLRenderer(renderer *sdl.Renderer) {
renderer.SetDrawColor(0, 0, 0, 255)
renderer.Clear()
rect := sdl.Rect{0, 0, 100, 100}
renderer.SetDrawColor(0, 0, 255, 255)
renderer.DrawRect(&rect)
renderer.Present()
}
func handleEvents(running bool, gameWindow *game_window.GameWindow, camera *gl_objects.Camera) bool {
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
switch t := event.(type) {
@ -172,7 +163,7 @@ func handleEvents(running bool, gameWindow *game_window.GameWindow, camera *gl_o
running = false
case *sdl.MouseMotionEvent:
if t.XRel != 0 || t.YRel != 0 {
camera.Rotate(t.XRel, t.YRel)
camera.RotateInput(t.XRel, t.YRel)
}
case *sdl.MouseButtonEvent:
fmt.Printf("[%d ms] MouseButton\ttype:%d\tid:%d\tx:%d\ty:%d\tbutton:%d\tstate:%d\n",
@ -209,7 +200,8 @@ func handleEvents(running bool, gameWindow *game_window.GameWindow, camera *gl_o
camera.SetZVelocity(-1)
} else if t.Type == sdl.KEYUP {
camera.SetZVelocity(0)
} }
}
}
if t.Keysym.Sym == sdl.K_d {
if t.Type == sdl.KEYDOWN {
camera.SetXVelocity(1)
@ -250,55 +242,3 @@ func handleEvents(running bool, gameWindow *game_window.GameWindow, camera *gl_o
return running
}
var cubeVertices = []float32{
// X, Y, Z, texture U, V
// Bottom
-1.0, -1.0, -1.0, 0.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 1.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
// Top
-1.0, 1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0, 1.0,
// Front
-1.0, -1.0, 1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0, 0.0,
-1.0, 1.0, 1.0, 1.0, 1.0,
1.0, -1.0, 1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 1.0, 1.0,
// Back
-1.0, -1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, -1.0, 0.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0,
1.0, -1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, -1.0, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 1.0,
// Left
-1.0, -1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.0,
-1.0, -1.0, -1.0, 0.0, 0.0,
-1.0, -1.0, 1.0, 0.0, 1.0,
-1.0, 1.0, 1.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.0,
// Right
1.0, -1.0, 1.0, 1.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.0,
1.0, 1.0, -1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 1.0, 1.0,
1.0, 1.0, -1.0, 0.0, 0.0,
1.0, 1.0, 1.0, 0.0, 1.0,
}

View File

@ -2,10 +2,10 @@ package game_window
import (
"log"
"github.com/veandco/go-sdl2/sdl"
gl "github.com/go-gl/gl/v3.1/gles2"
"github.com/go-gl/mathgl/mgl32"
"github.com/veandco/go-sdl2/sdl"
"gitea.wisellama.rocks/carpy-breakout/pkg/gl_helpers"
)
@ -19,7 +19,7 @@ type GameWindow struct {
SDLWindow *sdl.Window
GLContext *sdl.GLContext
GLProgram uint32
fullscreen bool
}
@ -37,7 +37,7 @@ func NewGameWindow(title string) (*GameWindow, error) {
log.Println("Failed creating SDL window")
return nil, err
}
context, err := window.GLCreateContext()
if err != nil {
log.Println("Failed Creating GL context.")
@ -51,7 +51,6 @@ func NewGameWindow(title string) (*GameWindow, error) {
}
gl.UseProgram(program)
gameWindow.SDLWindow = window
gameWindow.GLProgram = program
gameWindow.fullscreen = false
@ -91,9 +90,12 @@ uniform mat4 projection;
uniform mat4 camera;
uniform mat4 model;
in vec3 vert;
in vec3 vertColor;
in vec2 vertTexCoord;
out vec3 outColor;
out vec2 fragTexCoord;
void main() {
outColor = vertColor;
fragTexCoord = vertTexCoord;
gl_Position = projection * camera * model * vec4(vert, 1);
}
@ -103,8 +105,11 @@ var fragmentShader = `
#version 330
uniform sampler2D tex;
in vec2 fragTexCoord;
in vec3 inColor;
out vec4 outputColor;
void main() {
outputColor = texture(tex, fragTexCoord);
outputColor = vec4(inColor, 1);
}
` + "\x00"
// outputColor = texture(tex, fragTexCoord) * vec4(inColor, 1);

View File

@ -3,11 +3,11 @@ package gl_helpers
// https://github.com/go-gl/example
import (
"os"
"fmt"
"image"
"image/draw"
_ "image/png"
"fmt"
"os"
"strings"
gl "github.com/go-gl/gl/v3.1/gles2"
@ -62,7 +62,7 @@ func compileShader(source string, shaderType uint32) (uint32, error) {
var logLength int32
gl.GetShaderiv(shader, gl.INFO_LOG_LENGTH, &logLength)
log := strings.Repeat("\x00", int(logLength + 1))
log := strings.Repeat("\x00", int(logLength+1))
gl.GetShaderInfoLog(shader, logLength, nil, gl.Str(log))
return 0, fmt.Errorf("failed to compile %v: %v", source, log)
@ -76,7 +76,7 @@ func NewTexture(file string) (uint32, error) {
if err != nil {
return 0, fmt.Errorf("texture %q file not found found: %v", file, err)
}
img, _, err := image.Decode(imgFile)
if err != nil {
return 0, err
@ -86,7 +86,7 @@ func NewTexture(file string) (uint32, error) {
if rgba.Stride != rgba.Rect.Size().X*4 {
return 0, fmt.Errorf("unsupported stride")
}
draw.Draw(rgba, rgba.Bounds(), img, image.Point{0, 0}, draw.Src)
var texture uint32

75
pkg/gl_objects/box.go Normal file
View File

@ -0,0 +1,75 @@
package gl_objects
import (
"github.com/go-gl/mathgl/mgl32"
)
type Box struct {
Size int32
Faces []*Face
Color mgl32.Vec3
Position mgl32.Vec3
TextureOn bool
}
func NewBox(
length, width, depth float32,
position, color mgl32.Vec3, textureOn bool) *Box {
// length = z axis (towards)
// width = x axis (right)
// depth = y axis (up)
box := Box{}
box.Color = color
box.Size = 6
topPos := mgl32.Vec3{position.X(), position.Y() + depth/2.0, position.Z()}
top := NewFace(width, length, topPos, mgl32.Vec3{0, 1, 0}, color, textureOn)
bottomPos := mgl32.Vec3{position.X(), position.Y() - depth/2.0, position.Z()}
bottom := NewFace(width, length, bottomPos, mgl32.Vec3{0, -1, 0}, color, textureOn)
frontPos := mgl32.Vec3{position.X(), position.Y(), position.Z() + length/2.0}
front := NewFace(width, depth, frontPos, mgl32.Vec3{0, 0, 1}, color, textureOn)
backPos := mgl32.Vec3{position.X(), position.Y(), position.Z() - length/2.0}
back := NewFace(width, depth, backPos, mgl32.Vec3{0, 0, -1}, color, textureOn)
rightPos := mgl32.Vec3{position.X() + width/2.0, position.Y(), position.Z()}
right := NewFace(length, depth, rightPos, mgl32.Vec3{1, 0, 0}, color, textureOn)
leftPos := mgl32.Vec3{position.X() - width/2.0, position.Y(), position.Z()}
left := NewFace(length, depth, leftPos, mgl32.Vec3{-1, 0, 0}, color, textureOn)
box.Faces = []*Face{
top,
bottom,
front,
back,
right,
left,
}
return &box
}
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
}

View File

@ -10,30 +10,30 @@ import (
Positive Y = up
Positive Z = backward (outward, towards you)
Negative Z = forwards (inward)
*/
*/
type Camera struct {
Position mgl32.Vec3
Direction mgl32.Vec3
Position mgl32.Vec3
Direction mgl32.Vec3
OriginalDirection mgl32.Vec3
Up mgl32.Vec3
OriginalUp mgl32.Vec3
Velocity mgl32.Vec3
MoveStep float32
RotationVelocity float32
RotateStep float32
MouseSensitivity float32
Up mgl32.Vec3
OriginalUp mgl32.Vec3
Velocity mgl32.Vec3
MoveStep float32
RotationVelocity float32
RotateStep float32
MouseSensitivity float32
}
func NewCamera() (Camera) {
func NewCamera() Camera {
camera := Camera{}
camera.Up = mgl32.Vec3{0, 1, 0}
camera.OriginalUp = mgl32.Vec3{0, 1, 0}
camera.Direction = mgl32.Vec3{0, 0, -1}
camera.OriginalDirection = mgl32.Vec3{0, 0, -1}
camera.MoveStep = 0.1
camera.RotateStep = 0.02
camera.MouseSensitivity = 0.02
camera.RotateStep = 0.01
camera.MouseSensitivity = 0.06
return camera
}
@ -48,11 +48,15 @@ func (c *Camera) Draw(program uint32) {
}
func (c *Camera) Update() {
c.Rotate(0, 0)
c.Rotate()
c.Move(c.Velocity)
}
func (c *Camera) Rotate(mouseX, mouseY int32) {
func (c *Camera) Rotate() {
c.RotateInput(0, 0)
}
func (c *Camera) RotateInput(mouseX, mouseY int32) {
angle := mgl32.Vec3{}
// X Rotation (pitch) - mouse up/down
angle[0] = -1 * float32(mouseY) * c.MouseSensitivity
@ -69,7 +73,7 @@ func (c *Camera) Rotate(mouseX, mouseY int32) {
relativeY := c.Up
relativeZ := c.Direction
relativeX := relativeZ.Cross(relativeY)
quatX := mgl32.QuatRotate(angle.X(), relativeX)
c.Up = quatX.Rotate(c.Up)
c.Direction = quatX.Rotate(c.Direction)
@ -90,11 +94,11 @@ func (c *Camera) Move(vec mgl32.Vec3) {
vec = vec.Normalize()
vec = vec.Mul(c.MoveStep)
perp := c.Direction.Cross(c.Up)
relativeY := c.Up.Mul(vec.Y())
relativeZ := c.Direction.Mul(vec.Z())
relativeX := perp.Mul(vec.X())
relativeY := c.Up.Mul(vec.Y())
relativeZ := c.Direction.Mul(vec.Z())
relativeX := perp.Mul(vec.X())
relativeMove := mgl32.Vec3{}
relativeMove = relativeMove.Add(relativeX)

116
pkg/gl_objects/face.go Normal file
View File

@ -0,0 +1,116 @@
package gl_objects
import (
"log"
"github.com/go-gl/mathgl/mgl32"
"gitea.wisellama.rocks/carpy-breakout/pkg/math_helpers"
)
type Face struct {
Triangles []*Triangle
}
func NewFace(
width, height float32,
center, normal mgl32.Vec3,
color mgl32.Vec3, textureOn bool) *Face {
// TODO texture
texture := mgl32.Vec2{0, 0}
// top left
v1 := newFaceVertex(
height/2.0,
-1*width/2.0,
center,
normal,
color,
texture)
// bottom left
v2 := newFaceVertex(
-1*height/2.0,
-1*width/2.0,
center,
normal,
color,
texture)
// bottom right
v3 := newFaceVertex(
-1*height/2.0,
width/2.0,
center,
normal,
color,
texture)
// top right
v4 := newFaceVertex(
height/2.0,
width/2.0,
center,
normal,
color,
texture)
t1 := NewTriangle(v1, v2, v3)
t2 := NewTriangle(v3, v4, v1)
face := Face{}
face.Triangles = []*Triangle{t1, t2}
return &face
}
func newFaceVertex(
xoffset, zoffset float32,
center, normal mgl32.Vec3,
color mgl32.Vec3, texture mgl32.Vec2) *Vertex {
// We'll create the face as though the normal were simply upward
// {0, 1, 0} and then rotate all the points to fit the actual
// normal.
// Create the vertex offset from the center
v := mgl32.Vec3{center.X() + xoffset, center.Y(), center.Z() + zoffset}
// Subtract the center to create a vector pointing out so we can rotate it
v = v.Sub(center)
up := mgl32.Vec3{0, 1, 0}
angle, err := math_helpers.AngleBetweenVectors(up, normal)
if err != nil {
log.Println(err)
return nil
}
rotationAxis := up.Cross(normal)
// rotate
quat := mgl32.QuatRotate(angle, rotationAxis)
v = quat.Rotate(v)
// add back the center so we get the correct absolute position
v = v.Add(center)
log.Println(v)
vertex := NewVertex(
v.X(), v.Y(), v.Z(),
color[0], color[1], color[2],
texture[0], texture[1])
return vertex
}
func (f *Face) GetVertexArray() []float32 {
a := make([]float32, 2*3*VertexSize)
for _, triangle := range f.Triangles {
for _, vertex := range triangle.Vertices {
a = append(a, vertex.GetVertexArray()...)
}
}
return a
}

View File

@ -1,5 +1,6 @@
package gl_objects
type globject interface {
Update()
Draw(uint32)
}

View File

@ -0,0 +1,22 @@
package gl_objects
type Triangle struct {
Vertices []*Vertex
}
func NewTriangle(a, b, c *Vertex) *Triangle {
triangle := Triangle{}
triangle.Vertices = []*Vertex{a, b, c}
return &triangle
}
func (t *Triangle) GetVertexArray() []float32 {
a := make([]float32, 3*VertexSize)
for _, vertex := range t.Vertices {
a = append(a, vertex.GetVertexArray()...)
}
return a
}

38
pkg/gl_objects/vertex.go Normal file
View File

@ -0,0 +1,38 @@
package gl_objects
import (
"github.com/go-gl/mathgl/mgl32"
)
const VertexSize int32 = 8
type Vertex struct {
Position mgl32.Vec3
Color mgl32.Vec3
Texture mgl32.Vec2
}
func NewVertex(x, y, z, r, g, b, u, v float32) *Vertex {
vertex := Vertex{}
vertex.Position = mgl32.Vec3{x, y, z}
vertex.Color = mgl32.Vec3{r, g, b}
vertex.Texture = mgl32.Vec2{u, v}
return &vertex
}
func (v *Vertex) GetVertexArray() []float32 {
a := make([]float32, VertexSize)
a[0] = v.Position[0]
a[1] = v.Position[1]
a[2] = v.Position[2]
a[3] = v.Color[0]
a[4] = v.Color[1]
a[5] = v.Color[2]
a[6] = v.Texture[0]
a[7] = v.Texture[1]
return a
}

View File

@ -0,0 +1,29 @@
package math_helpers
import (
"fmt"
"math"
"github.com/go-gl/mathgl/mgl32"
)
func AngleBetweenVectors(v1, v2 mgl32.Vec3) (float32, error) {
len1 := v1.LenSqr()
len2 := v2.LenSqr()
if len1 == 0 || len2 == 0 {
return 0.0, fmt.Errorf("AngleBetweenVectors given zero length vector")
}
if len1 != 1 {
v1 = v1.Normalize()
}
if len2 != 1 {
v2 = v2.Normalize()
}
dotProd := v1.Dot(v2)
angle := math.Acos(float64(dotProd))
return float32(angle), nil
}