public
Created

Simple OpenGL 2D drawing

  • Download Gist
main.go
Go
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145
package main
 
import (
"fmt"
"strings"
gl "github.com/chsc/gogl/gl42"
glfw "github.com/go-gl/glfw"
glutil "github.com/go3d/go-util/gl"
)
 
type tGeometry struct {
glVerts []gl.Float
glNumVerts gl.Sizei
glMode gl.Enum
glVertBuf gl.Uint
}
 
var (
faceTri, faceQuad = &tGeometry {}, &tGeometry {}
useStrictCoreProfile = false // set this to true to see the problem...
isFirstLoop = true // only output glLastError in the loop's first iteration
lastErr error
shaderProg *glutil.TShaderProgram
srcVertShader = "in vec3 aPos; void main () { gl_Position = vec4(aPos, 1.0); }"
srcFragShader = "out vec4 oColor; void main () { oColor = vec4(0.0, 0.6, 0.9, 1.0); }"
)
 
func compileShaders () (err error) {
var glStatus gl.Int
var glFrag = gl.CreateShader(gl.FRAGMENT_SHADER)
var glVert = gl.CreateShader(gl.VERTEX_SHADER)
glutil.ShaderSource("test", glFrag, srcFragShader, nil, false, "150")
gl.CompileShader(glFrag)
if gl.GetShaderiv(glFrag, gl.COMPILE_STATUS, &glStatus); glStatus == 0 {
err = fmt.Errorf("SHADER %s: %s\n", "Frag", glutil.ShaderInfoLog(glFrag, true)); return
}
glutil.ShaderSource("test", glVert, srcVertShader, nil, false, "150")
gl.CompileShader(glVert)
if gl.GetShaderiv(glVert, gl.COMPILE_STATUS, &glStatus); glStatus == 0 {
err = fmt.Errorf("SHADER %s: %s\n", "Vert", glutil.ShaderInfoLog(glVert, true)); return
}
if shaderProg, err = glutil.NewShaderProgram("test", 0, glFrag, 0, 0, 0, glVert); err == nil {
err = shaderProg.SetAttrLocations("aPos")
}
return
}
 
func deleteGeometry () {
gl.DeleteBuffers(1, &faceTri.glVertBuf)
gl.DeleteBuffers(1, &faceQuad.glVertBuf)
}
 
func renderGeometry (mesh *tGeometry) {
gl.BindBuffer(gl.ARRAY_BUFFER, mesh.glVertBuf)
if isFirstLoop { logLastGlError("render.BindBuffer(buf)") }
 
gl.VertexAttribPointer(shaderProg.AttrLocs["aPos"], 3, gl.FLOAT, gl.FALSE, 0, gl.Pointer(nil))
if isFirstLoop { logLastGlError("render.VertexAttribPointer()") }
 
gl.DrawArrays(mesh.glMode, 0, mesh.glNumVerts)
if isFirstLoop { logLastGlError("render.DrawArrays()") }
 
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
if isFirstLoop { logLastGlError("render.BindBuffer(0)") }
}
 
func setupGeometry () {
var z gl.Float = -1
faceTri.glMode, faceTri.glNumVerts, faceTri.glVerts = gl.TRIANGLES, 3, []gl.Float {
0, 1, z,
-1, -1, z,
1, -1, z,
}
uploadGeometry(faceTri)
faceQuad.glMode, faceQuad.glNumVerts, faceQuad.glVerts = gl.TRIANGLE_STRIP, 4, []gl.Float {
0.5, 0.5, z,
-0.5, 0.5, z,
0.5, -0.5, z,
-0.5, -0.5, z,
}
uploadGeometry(faceQuad)
}
 
func uploadGeometry (mesh *tGeometry) {
gl.GenBuffers(1, &mesh.glVertBuf)
gl.BindBuffer(gl.ARRAY_BUFFER, mesh.glVertBuf)
gl.BufferData(gl.ARRAY_BUFFER, gl.Sizeiptr(4 * len(mesh.glVerts)), gl.Pointer(&mesh.glVerts[0]), gl.STATIC_DRAW)
gl.BindBuffer(gl.ARRAY_BUFFER, 0)
}
 
func logLastGlError (step string) {
if lastErr = glutil.LastError(step); lastErr != nil { fmt.Printf("LASTERR: %v\n", lastErr) }
}
 
func main () {
var err error
var looping = true
defer fmt.Println("EXIT")
if err = glfw.Init(); err != nil { panic(err) }
defer glfw.Terminate()
glfw.OpenWindowHint(glfw.FsaaSamples, 0)
if useStrictCoreProfile {
glfw.OpenWindowHint(glfw.OpenGLVersionMajor, 3)
glfw.OpenWindowHint(glfw.OpenGLVersionMinor, 2)
glfw.OpenWindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
// if runtime.GOOS == "darwin" { glfw.OpenWindowHint(glfw.OpenGLForwardCompat, 1) }
}
 
if err = glfw.OpenWindow(1280, 720, 8, 8, 8, 0, 24, 8, glfw.Windowed); err != nil { panic(err) }
defer glfw.CloseWindow()
glfw.Enable(glfw.StickyKeys)
if err = gl.Init(); (err != nil) && (strings.Index(err.Error(), "VERSION_") < 0) { panic(err) }
defer logLastGlError("(post loop)")
glutil.SetVersion()
fmt.Printf("GLCONN: %v\n", glutil.GlConnInfo())
gl.ClearColor(0.3, 0.1, 0.0, 1.0)
gl.Enable(gl.DEPTH_TEST)
gl.FrontFace(gl.CCW)
gl.CullFace(gl.BACK)
gl.Disable(gl.CULL_FACE)
if err = compileShaders(); err != nil { panic(err) }
setupGeometry()
logLastGlError("(pre loop)")
 
for looping {
gl.UseProgram(shaderProg.Program)
if isFirstLoop { logLastGlError("gl.UseProgram") }
 
gl.Viewport(0, 0, 1280, 720)
if isFirstLoop { logLastGlError("gl.ViewPort") }
 
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
if isFirstLoop { logLastGlError("gl.Clear") }
 
renderGeometry(faceTri)
renderGeometry(faceQuad)
if (glfw.WindowParam(glfw.Opened) != 1) || (glfw.Key(glfw.KeyEsc) == glfw.KeyPress) {
looping = false
} else {
glfw.SwapBuffers()
}
isFirstLoop = false
}
 
}

With useStrictCoreProfile set to false, the program outputs no error messages to the console and draws a quad and a triangle: http://dl.dropbox.com/u/136375/gl-quad-tri.png

With useStrictCoreProfile set to true, it clears the background color but does not draw the tri & quad, console output is this:

GLCONN: OpenGL 3.2.0 @ NVIDIA Corporation GeForce GT 640M LE/PCIe/SSE2 (GLSL: 1.50 NVIDIA via Cg compiler)
LASTERR: OpenGL error at step 'render.VertexAttribPointer()':   GL_INVALID_OPERATION
LASTERR: OpenGL error at step 'render.DrawArrays()':    GL_INVALID_OPERATION
LASTERR: OpenGL error at step 'render.VertexAttribPointer()':   GL_INVALID_OPERATION
LASTERR: OpenGL error at step 'render.DrawArrays()':    GL_INVALID_OPERATION
LASTERR: OpenGL error at step '(post loop)':    GL_INVALID_OPERATION
EXIT

... if a 4.2 strict core profile is requested instead of 3.2, same issue. Applies to 3 different nvidia GPUs so I assume I'm not conforming to the strict core profile properly.

Note, you won't find a glEnableVertexAttribArray call in the above Gist, as it's inside the glutil package I'm importing -- but this does get called as the last step in this Gist's compileShaders() func.

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.