// vim: shiftwidth=4 tabstop=4 noexpandtab package main import ( "fmt" "log" "strings" "github.com/go-gl/gl/v4.6-core/gl" "github.com/go-gl/glfw/v3.3/glfw" ) var ( // a single triangle triangle = []float32{ 0.0, 0.5, 0.0, -0.5, -0.5, 0.0, 0.5, -0.5, 0.0, } ) const ( WINDOW_WIDTH = 500 WINDOW_HEIGHT = 500 WINDOW_TITLE = "stlscope" // vertex shader to draw points VERTEX_SHADER = ` #version 410 in vec3 vp; void main() { gl_Position = vec4(vp, 1.0); } ` + "\x00" // fragment shader to draw surfaces FRAGMENT_SHADER = ` #version 410 out vec4 frag_colour; void main() { frag_colour = vec4(0, 0, 1, 1); // RGBA color format } ` + "\x00" ) func initGlfw() *glfw.Window { log.Println("GLFW init") if err := glfw.Init(); err != nil { panic(err) } glfw.WindowHint(glfw.Resizable, glfw.False) glfw.WindowHint(glfw.ContextVersionMajor, 4) glfw.WindowHint(glfw.ContextVersionMinor, 6) glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True) glfw.WindowHint(glfw.Samples, 16) // anti-aliasing window, err := glfw.CreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() return window } // initOpenGL initializes OpenGL and returns an intiialized program func initOpenGL() uint32 { log.Println("OpenGL init") if err := gl.Init(); err != nil { panic(err) } version := gl.GoStr(gl.GetString(gl.VERSION)) log.Println("OpenGL version", version) vertexShader, err := compileShader(VERTEX_SHADER, gl.VERTEX_SHADER) if err != nil { panic(err) } fragmentShader, err := compileShader(FRAGMENT_SHADER, gl.FRAGMENT_SHADER) if err != nil { panic(err) } prog := gl.CreateProgram() gl.AttachShader(prog, vertexShader) gl.AttachShader(prog, fragmentShader) gl.LinkProgram(prog) return prog } func draw(vao uint32, window *glfw.Window, program uint32) { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) gl.UseProgram(program) gl.BindVertexArray(vao) gl.DrawArrays(gl.TRIANGLES, 0, int32(len(triangle)/3)) glfw.PollEvents() window.SwapBuffers() } // makeVao initializes and returns a vertex array from the points provided. func makeVao(points []float32) uint32 { log.Println("Creating VAO") // start with vertex buffer object (VBO): var vbo uint32 // VBO ID gl.GenBuffers(1, &vbo) gl.BindBuffer(gl.ARRAY_BUFFER, vbo) gl.BufferData(gl.ARRAY_BUFFER, 4*len(points), gl.Ptr(points), gl.STATIC_DRAW) // vertex array objects (VAO) are a feature of newer GL implementations: var vao uint32 // VAO ID gl.GenVertexArrays(1, &vao) gl.BindVertexArray(vao) gl.EnableVertexAttribArray(0) gl.BindBuffer(gl.ARRAY_BUFFER, vbo) gl.VertexAttribPointer(0, 3, gl.FLOAT, false, 0, nil) // tell GL to use 3D float vectors return vao } func compileShader(source string, shaderType uint32) (uint32, error) { log.Println("Compiling shader") 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 }