Following a couple different tutorials, got a rotating cube
commit
21f16bf5c3
|
@ -0,0 +1,4 @@
|
|||
*~
|
||||
|
||||
carpy-breakout
|
||||
output.log
|
|
@ -0,0 +1,7 @@
|
|||
all: dependencies build
|
||||
|
||||
dependencies:
|
||||
go mod tidy
|
||||
|
||||
build:
|
||||
go build
|
|
@ -0,0 +1,113 @@
|
|||
package glhelpers
|
||||
|
||||
// https://github.com/go-gl/example
|
||||
|
||||
import (
|
||||
"os"
|
||||
"image"
|
||||
"image/draw"
|
||||
_ "image/png"
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
gl "github.com/go-gl/gl/v3.1/gles2"
|
||||
)
|
||||
|
||||
func NewProgram(vertexShaderSource string, fragmentShaderSource string) (uint32, error) {
|
||||
vertexShader, err := compileShader(vertexShaderSource, gl.VERTEX_SHADER)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
fragmentShader, err := compileShader(fragmentShaderSource, gl.FRAGMENT_SHADER)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
program := gl.CreateProgram()
|
||||
|
||||
gl.AttachShader(program, vertexShader)
|
||||
gl.AttachShader(program, fragmentShader)
|
||||
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 0, fmt.Errorf("failed to link program: %v", log)
|
||||
}
|
||||
|
||||
gl.DeleteShader(vertexShader)
|
||||
gl.DeleteShader(fragmentShader)
|
||||
|
||||
return program, nil
|
||||
}
|
||||
|
||||
func compileShader(source string, shaderType uint32) (uint32, error) {
|
||||
shader := gl.CreateShader(shaderType)
|
||||
|
||||
csources, free := gl.Strs(source)
|
||||
gl.ShaderSource(shader, 1, csources, nil)
|
||||
free()
|
||||
gl.CompileShader(shader)
|
||||
|
||||
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 0, fmt.Errorf("failed to compile %v: %v", source, log)
|
||||
}
|
||||
|
||||
return shader, nil
|
||||
}
|
||||
|
||||
func NewTexture(file string) (uint32, error) {
|
||||
imgFile, err := os.Open(file)
|
||||
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
|
||||
}
|
||||
|
||||
rgba := image.NewRGBA(img.Bounds())
|
||||
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
|
||||
gl.GenTextures(1, &texture)
|
||||
gl.ActiveTexture(gl.TEXTURE0)
|
||||
gl.BindTexture(gl.TEXTURE_2D, texture)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE)
|
||||
gl.TexParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE)
|
||||
gl.TexImage2D(
|
||||
gl.TEXTURE_2D,
|
||||
0,
|
||||
gl.RGBA,
|
||||
int32(rgba.Rect.Size().X),
|
||||
int32(rgba.Rect.Size().Y),
|
||||
0,
|
||||
gl.RGBA,
|
||||
gl.UNSIGNED_BYTE,
|
||||
gl.Ptr(rgba.Pix),
|
||||
)
|
||||
|
||||
return texture, nil
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
module gitea.wisellama.rocks/carpy-breakout
|
||||
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f
|
||||
github.com/go-gl/mathgl v1.0.0
|
||||
github.com/veandco/go-sdl2 v0.4.9
|
||||
)
|
||||
|
||||
require golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f // indirect
|
|
@ -0,0 +1,9 @@
|
|||
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f h1:s0O46d8fPwk9kU4k1jj76wBquMVETx7uveQD9MCIQoU=
|
||||
github.com/go-gl/gl v0.0.0-20210813123233-e4099ee2221f/go.mod h1:wjpnOv6ONl2SuJSxqCPVaPZibGFdSci9HFocT9qtVYM=
|
||||
github.com/go-gl/mathgl v1.0.0 h1:t9DznWJlXxxjeeKLIdovCOVJQk/GzDEL7h/h+Ro2B68=
|
||||
github.com/go-gl/mathgl v1.0.0/go.mod h1:yhpkQzEiH9yPyxDUGzkmgScbaBVlhC06qodikEM0ZwQ=
|
||||
github.com/veandco/go-sdl2 v0.4.9 h1:Fc0/Xj8JToXO7qia77Vc1M6bP7iufE+vzsLNah70Y6M=
|
||||
github.com/veandco/go-sdl2 v0.4.9/go.mod h1:OROqMhHD43nT4/i9crJukyVecjPNYYuCofep6SNiAjY=
|
||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f h1:FO4MZ3N56GnxbqxGKqh+YTzUWQ2sDwtFQEZgLOxh9Jc=
|
||||
golang.org/x/image v0.0.0-20190321063152-3fc05d484e9f/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
@ -0,0 +1,289 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
"runtime/pprof"
|
||||
|
||||
"github.com/veandco/go-sdl2/sdl"
|
||||
gl "github.com/go-gl/gl/v3.1/gles2"
|
||||
"github.com/go-gl/mathgl/mgl32"
|
||||
|
||||
"gitea.wisellama.rocks/carpy-breakout/glhelpers"
|
||||
)
|
||||
|
||||
var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
|
||||
|
||||
const GameTitle = "Carpy Breakout"
|
||||
const DefaultWindowWidth int32 = 800
|
||||
const DefaultWindowHeight int32 = 600
|
||||
const DefaultWindowFlags uint32 = sdl.WINDOW_SHOWN | sdl.WINDOW_RESIZABLE | sdl.WINDOW_OPENGL
|
||||
const FullscreenWindowFlags uint32 = DefaultWindowFlags | sdl.WINDOW_FULLSCREEN_DESKTOP
|
||||
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()
|
||||
}
|
||||
|
||||
setupLogging()
|
||||
run()
|
||||
}
|
||||
|
||||
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 {
|
||||
panic(err)
|
||||
}
|
||||
defer sdl.Quit()
|
||||
|
||||
// Disable the Linux compositor flicker.
|
||||
// https://github.com/mosra/magnum/issues/184#issuecomment-425952900
|
||||
sdl.SetHint(sdl.HINT_VIDEO_X11_NET_WM_BYPASS_COMPOSITOR, "0")
|
||||
|
||||
sdl.DisableScreenSaver()
|
||||
|
||||
//sdl.GLSetAttribute(sdl.GL_MULTISAMPLESAMPLES, 4) // Smooth
|
||||
|
||||
window, err := sdl.CreateWindow(
|
||||
GameTitle,
|
||||
sdl.WINDOWPOS_UNDEFINED,
|
||||
sdl.WINDOWPOS_UNDEFINED,
|
||||
DefaultWindowWidth,
|
||||
DefaultWindowHeight,
|
||||
DefaultWindowFlags)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer window.Destroy()
|
||||
|
||||
context, err := window.GLCreateContext()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer sdl.GLDeleteContext(context)
|
||||
|
||||
width, height := window.GetSize()
|
||||
|
||||
gl.Init()
|
||||
version := gl.GoStr(gl.GetString(gl.VERSION))
|
||||
log.Println("OpenGL version", version)
|
||||
|
||||
gl.Viewport(0, 0, width, height)
|
||||
gl.ClearColor(0.0, 0.0, 0.0, 1.0)
|
||||
|
||||
program, err := glhelpers.NewProgram(vertexShader, fragmentShader)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
gl.UseProgram(program)
|
||||
|
||||
projection := mgl32.Perspective(mgl32.DegToRad(45.0), float32(width)/float32(height), 0.1, 10.0)
|
||||
projectionUniform := gl.GetUniformLocation(program, gl.Str("projection\x00"))
|
||||
gl.UniformMatrix4fv(projectionUniform, 1, false, &projection[0])
|
||||
|
||||
camera := mgl32.LookAtV(mgl32.Vec3{3, 3, 3}, mgl32.Vec3{0, 0, 0}, mgl32.Vec3{0, 1, 0})
|
||||
cameraUniform := gl.GetUniformLocation(program, gl.Str("camera\x00"))
|
||||
gl.UniformMatrix4fv(cameraUniform, 1, false, &camera[0])
|
||||
|
||||
model := mgl32.Ident4()
|
||||
modelUniform := gl.GetUniformLocation(program, gl.Str("model\x00"))
|
||||
gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])
|
||||
|
||||
textureUniform := gl.GetUniformLocation(program, gl.Str("tex\x00"))
|
||||
gl.Uniform1i(textureUniform, 0)
|
||||
|
||||
//gl.BindFragDataLocation(program, 0, gl.Str("outputColor\x00"))
|
||||
|
||||
texture, err := glhelpers.NewTexture("square.png")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
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)
|
||||
|
||||
vertAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vert\x00")))
|
||||
gl.EnableVertexAttribArray(vertAttrib)
|
||||
gl.VertexAttribPointerWithOffset(vertAttrib, 3, gl.FLOAT, false, 5*4, 0)
|
||||
|
||||
texCoordAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vertTexCoord\x00")))
|
||||
gl.EnableVertexAttribArray(texCoordAttrib)
|
||||
gl.VertexAttribPointerWithOffset(texCoordAttrib, 2, gl.FLOAT, false, 5*4, 3*4)
|
||||
|
||||
// Configure global settings
|
||||
gl.Enable(gl.DEPTH_TEST)
|
||||
gl.DepthFunc(gl.LESS)
|
||||
gl.ClearColor(1.0, 1.0, 1.0, 1.0)
|
||||
|
||||
running := true
|
||||
angle := 0.0
|
||||
for running {
|
||||
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
||||
|
||||
angle += 0.01
|
||||
model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0})
|
||||
|
||||
gl.UseProgram(program)
|
||||
gl.UniformMatrix4fv(modelUniform, 1, false, &model[0])
|
||||
|
||||
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
|
||||
|
||||
window.GLSwap()
|
||||
|
||||
running = handleEvents(running, window)
|
||||
sdl.Delay(16)
|
||||
}
|
||||
}
|
||||
|
||||
func setupLogging() {
|
||||
file, err := os.OpenFile(LogFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
log.SetOutput(file)
|
||||
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, window *sdl.Window) bool {
|
||||
for event := sdl.PollEvent(); event != nil; event = sdl.PollEvent() {
|
||||
switch t := event.(type) {
|
||||
case *sdl.QuitEvent:
|
||||
fmt.Printf("Quit")
|
||||
running = false
|
||||
case *sdl.MouseMotionEvent:
|
||||
fmt.Printf("[%d ms] MouseMotion\ttype:%d\tid:%d\tx:%d\ty:%d\txrel:%d\tyrel:%d\n",
|
||||
t.Timestamp, t.Type, t.Which, t.X, t.Y, 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",
|
||||
t.Timestamp, t.Type, t.Which, t.X, t.Y, t.Button, t.State)
|
||||
case *sdl.MouseWheelEvent:
|
||||
fmt.Printf("[%d ms] MouseWheel\ttype:%d\tid:%d\tx:%d\ty:%d\n",
|
||||
t.Timestamp, t.Type, t.Which, t.X, t.Y)
|
||||
case *sdl.KeyboardEvent:
|
||||
if t.Keysym.Sym == sdl.K_ESCAPE {
|
||||
fmt.Print("Esc quitting\n")
|
||||
running = false
|
||||
}
|
||||
if t.Keysym.Sym == sdl.K_f {
|
||||
window.SetFullscreen(FullscreenWindowFlags)
|
||||
}
|
||||
if t.Keysym.Sym == sdl.K_g {
|
||||
window.SetFullscreen(DefaultWindowFlags)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
var vertexShader = `
|
||||
#version 330
|
||||
uniform mat4 projection;
|
||||
uniform mat4 camera;
|
||||
uniform mat4 model;
|
||||
in vec3 vert;
|
||||
in vec2 vertTexCoord;
|
||||
out vec2 fragTexCoord;
|
||||
void main() {
|
||||
fragTexCoord = vertTexCoord;
|
||||
gl_Position = projection * camera * model * vec4(vert, 1);
|
||||
}
|
||||
` + "\x00"
|
||||
|
||||
var fragmentShader = `
|
||||
#version 330
|
||||
uniform sampler2D tex;
|
||||
in vec2 fragTexCoord;
|
||||
out vec4 outputColor;
|
||||
void main() {
|
||||
outputColor = texture(tex, fragTexCoord);
|
||||
}
|
||||
` + "\x00"
|
Loading…
Reference in New Issue