Created
February 7, 2013 13:12
-
-
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 (…
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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