Skip to content

Instantly share code, notes, and snippets.

@Niriel
Created February 7, 2013 13:12
Show Gist options
  • Save Niriel/4730812 to your computer and use it in GitHub Desktop.
Save Niriel/4730812 to your computer and use it in GitHub Desktop.
OpenGl stops working properly as soon as I try to use goroutines. This piece of code rotates triangle on the screen with OpenGl. I wrote several main loops: * one that uses time.Ticker to control the framerate, * one that listens to SDL events through a channel to know when to stop the program, * one that does both, * and one that does neither (…
package main
import (
"fmt"
"github.com/0xe2-0x9a-0x9b/Go-SDL/sdl"
gl "github.com/chsc/gogl/gl33"
"math"
"runtime"
"time"
"unsafe"
)
const DEG_TO_RAD = math.Pi / 180
type GoMatrix [16]float64
type GlMatrix [16]gl.Float
var good_frames, bad_frames, sdl_events int
func main() {
runtime.GOMAXPROCS(1)
//=========================================================================
// Just opening a window, skip to the next part.
if status := sdl.Init(sdl.INIT_VIDEO); status != 0 {
panic("Could not initialize SDL: " + sdl.GetError())
}
defer sdl.Quit()
sdl.GL_SetAttribute(sdl.GL_DOUBLEBUFFER, 1)
const FLAGS = sdl.OPENGL
if screen := sdl.SetVideoMode(640, 480, 32, FLAGS); screen == nil {
panic("Could not open SDL window: " + sdl.GetError())
}
if err := gl.Init(); err != nil {
panic(err)
}
gl.Viewport(0, 0, 640, 480)
gl.ClearColor(.5, .5, .5, 1)
renderer := gl.GetString(gl.RENDERER)
fmt.Println(gl.GoStringUb(renderer))
//=========================================================================
// Simplest shaders ever.
// A matrix to move the model, nothing else.
vertex_code := gl.GLString(`
#version 330 core
in vec3 vpos;
uniform mat4 MVP;
void main() {
gl_Position = MVP * vec4(vpos, 1);
}
`)
// Everything is red.
fragment_code := gl.GLString(`
#version 330 core
void main(){
gl_FragColor = vec4(1,0,0,1);
}
`)
vs := gl.CreateShader(gl.VERTEX_SHADER)
fs := gl.CreateShader(gl.FRAGMENT_SHADER)
gl.ShaderSource(vs, 1, &vertex_code, nil)
gl.ShaderSource(fs, 1, &fragment_code, nil)
gl.CompileShader(vs)
gl.CompileShader(fs)
prog := gl.CreateProgram()
gl.AttachShader(prog, vs)
gl.AttachShader(prog, fs)
gl.LinkProgram(prog)
// Did it compile?
var link_status gl.Int
gl.GetProgramiv(prog, gl.LINK_STATUS, &link_status)
if link_status == gl.FALSE {
var info_log_length gl.Int
gl.GetProgramiv(prog, gl.INFO_LOG_LENGTH, &info_log_length)
if info_log_length == 0 {
panic("Program linking failed but OpenGL has no log about it.")
} else {
info_log_gl := gl.GLStringAlloc(gl.Sizei(info_log_length))
defer gl.GLStringFree(info_log_gl)
gl.GetProgramInfoLog(prog, gl.Sizei(info_log_length), nil, info_log_gl)
info_log := gl.GoString(info_log_gl)
panic(info_log)
}
}
gl.UseProgram(prog)
attrib_vpos := gl.Uint(gl.GetAttribLocation(prog, gl.GLString("vpos")))
//=========================================================================
// One triangle.
positions := [...]gl.Float{-.5, -.5, 0, .5, -.5, 0, 0, .5, 0}
var vao gl.Uint
gl.GenVertexArrays(1, &vao)
gl.BindVertexArray(vao)
var vbo gl.Uint
gl.GenBuffers(1, &vbo)
gl.BindBuffer(gl.ARRAY_BUFFER, vbo)
gl.BufferData(gl.ARRAY_BUFFER,
gl.Sizeiptr(unsafe.Sizeof(positions)),
gl.Pointer(&positions[0]),
gl.STATIC_DRAW)
gl.EnableVertexAttribArray(attrib_vpos)
gl.VertexAttribPointer(attrib_vpos, 3, gl.FLOAT, gl.FALSE, 0, gl.Pointer(nil))
//=========================================================================
gl.Finish()
LoopNothing(prog)
fmt.Println("Good frames", good_frames)
fmt.Println("Bad frames", bad_frames)
fmt.Println("sdl events", sdl_events)
}
func LoopSdlTick(program gl.Uint) {
start_time := time.Now()
ticker := time.NewTicker(1000 * time.Millisecond)
defer ticker.Stop()
running := true
for running {
select {
case tick_time := <-ticker.C:
OnTick(start_time, tick_time, program)
case event := <-sdl.Events:
running = OnSdlEvent(event)
}
}
}
func DummyFeeder(dummy_chan chan int) {
for {
dummy_chan <- 0
// time.Sleep(1 * time.Millisecond)
// runtime.Gosched()
}
}
func LoopNothing(program gl.Uint) {
start_time := time.Now()
stop_time := start_time.Add(time.Duration(10 * time.Second))
// dummy_chan := make(chan int)
// go DummyFeeder(dummy_chan)
running := true
for running {
// select {
// case <-dummy_chan:
// default:
// break
// }
tick_time := time.Now()
OnTick(start_time, tick_time, program)
time.Sleep(20 * time.Millisecond)
if tick_time.After(stop_time) {
running = false
}
}
}
func LoopTick(program gl.Uint) {
start_time := time.Now()
stop_time := start_time.Add(time.Duration(10 * time.Second))
ticker := time.NewTicker(20 * time.Millisecond)
defer ticker.Stop()
running := true
for running {
select {
case tick_time := <-ticker.C:
{
OnTick(start_time, tick_time, program)
tick_time := time.Now()
if tick_time.After(stop_time) {
running = false
}
}
default:
runtime.Gosched()
}
}
}
func LoopSdl(program gl.Uint) {
var now time.Time
start_time := time.Now()
time_next := start_time.Add(time.Duration(20 * time.Millisecond))
running := true
for running {
select {
case e := <-sdl.Events:
running = OnSdlEvent(e)
default:
break
}
now = time.Now()
if now.After(time_next) {
OnTick(start_time, now, program)
time_next = now.Add(time.Duration(20 * time.Millisecond))
} else {
time.Sleep(1 * time.Millisecond)
}
}
}
func OnSdlEvent(event interface{}) bool {
sdl_events++
switch event.(type) {
case sdl.QuitEvent:
return false // Stop the main loop.
}
return true // Do not stop the main loop.
}
func OnTick(start_time, tick_time time.Time, program gl.Uint) {
duration := tick_time.Sub(start_time).Seconds()
speed := 10.
angle := math.Mod(duration*speed, 360)
gom := RotZ(angle)
MVP := ToGlMatrix(gom)
matrix_loc := gl.GetUniformLocation(program, gl.GLString("MVP"))
dummy_matrix_loc := gl.GetUniformLocation(program, gl.GLString("dummy"))
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error get location") // Never happens.
}
if dummy_matrix_loc == -1 {
good_frames++ // Because it SHOULD fail.
} else {
bad_frames++ // That's not normal.
}
gl.UniformMatrix4fv(matrix_loc, 16, gl.TRUE, &MVP[0])
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error send matrix") // Never happens.
}
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error clearing") // Never happens.
}
gl.DrawArrays(gl.TRIANGLES, 0, 3)
if gl.GetError() != gl.NO_ERROR {
fmt.Println("Error drawing") // Never happens.
}
sdl.GL_SwapBuffers()
}
func RotZ(angle float64) GoMatrix {
var gom GoMatrix
a := angle * DEG_TO_RAD
c := math.Cos(a)
s := math.Sin(a)
gom[0] = c
gom[1] = s
gom[4] = -s
gom[5] = c
gom[10] = 1
gom[15] = 1
return gom
}
func ToGlMatrix(gom GoMatrix) GlMatrix {
var glm GlMatrix
glm[0] = gl.Float(gom[0])
glm[1] = gl.Float(gom[1])
glm[2] = gl.Float(gom[2])
glm[3] = gl.Float(gom[3])
glm[4] = gl.Float(gom[4])
glm[5] = gl.Float(gom[5])
glm[6] = gl.Float(gom[6])
glm[7] = gl.Float(gom[7])
glm[8] = gl.Float(gom[8])
glm[9] = gl.Float(gom[9])
glm[10] = gl.Float(gom[10])
glm[11] = gl.Float(gom[11])
glm[12] = gl.Float(gom[12])
glm[13] = gl.Float(gom[13])
glm[14] = gl.Float(gom[14])
glm[15] = gl.Float(gom[15])
return glm
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment