func main() { // Initialize GLFW for window management glfw.SetErrorCallback(glfwErrorCallback) if !glfw.Init() { panic("failed to initialize glfw") } defer glfw.Terminate() glfw.WindowHint(glfw.Resizable, glfw.False) glfw.WindowHint(glfw.ContextVersionMajor, 3) glfw.WindowHint(glfw.ContextVersionMinor, 3) glfw.WindowHint(glfw.OpenglForwardCompatible, glfw.True) // Necessary for OS X glfw.WindowHint(glfw.OpenglProfile, glfw.OpenglCoreProfile) // Necessary for OS X glfw.WindowHint(glfw.OpenglDebugContext, glfw.True) window, err := glfw.CreateWindow(WindowWidth, WindowHeight, "Cube", nil, nil) if err != nil { panic(err) } window.MakeContextCurrent() // Initialize Glow if err := gl.Init(); err != nil { panic(err) } // Note that it is possible to use GL functions spanning multiple versions if err := gl4.Init(); err != nil { fmt.Printf("Could not initialize GL 4.4 (non-fatal)") } if gl.ARB_debug_output { gl.Enable(gl.DEBUG_OUTPUT_SYNCHRONOUS_ARB) gl.DebugMessageCallbackARB(gl.DebugProc(glDebugCallback), gl.Ptr(nil)) // Trigger an error to demonstrate debug output gl.Enable(gl.CONTEXT_FLAGS) } version := gl.GoStr(gl.GetString(gl.VERSION)) fmt.Println("OpenGL version", version) // Configure the vertex and fragment shaders program, err := newProgram(vertexShader, fragmentShader) if err != nil { panic(err) } gl.UseProgram(program) projection := mgl32.Perspective(70.0, float32(WindowWidth)/WindowHeight, 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")) // Load the texture texture, err := newTexture("square.png") if err != nil { panic(err) } // Configure the vertex data 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.VertexAttribPointer(vertAttrib, 3, gl.FLOAT, false, 5*4, gl.PtrOffset(0)) texCoordAttrib := uint32(gl.GetAttribLocation(program, gl.Str("vertTexCoord\x00"))) gl.EnableVertexAttribArray(texCoordAttrib) gl.VertexAttribPointer(texCoordAttrib, 2, gl.FLOAT, false, 5*4, gl.PtrOffset(3*4)) // Configure global settings gl.Enable(gl.DEPTH_TEST) gl.DepthFunc(gl.LESS) gl.ClearColor(1.0, 1.0, 1.0, 1.0) angle := 0.0 previousTime := glfw.GetTime() for !window.ShouldClose() { gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) // Update time := glfw.GetTime() elapsed := time - previousTime previousTime = time angle += elapsed model = mgl32.HomogRotate3D(float32(angle), mgl32.Vec3{0, 1, 0}) // Render 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) // Maintenance window.SwapBuffers() glfw.PollEvents() } }
// RenderString must be called on the render thread. x and y are the initial position of the pen, // in screen coordinates, and height is the height of a full line of text, in screen coordinates. func (d *Dictionary) RenderString(str string, x, y, height float64) { if str == "" { return } // No synchronization necessary because everything is run serially on the render thread anyway. if d.strs == nil { d.strs = make(map[string]strData) } data, ok := d.strs[str] if !ok { data = d.bindString(str) d.strs[str] = data } render.EnableShader("glop.font") defer render.EnableShader("") gl.ActiveTexture(gl.TEXTURE0) gl.BindTexture(gl.TEXTURE_2D, d.atlas.texture) location, _ := render.GetUniformLocation("glop.font", "tex") gl.Uniform1i(location, 0) gl.BindSampler(0, d.atlas.sampler) location, _ = render.GetUniformLocation("glop.font", "height") gl.Uniform1f(location, float32(height)) var viewport [4]int32 gl.GetIntegerv(gl.VIEWPORT, &viewport[0]) location, _ = render.GetUniformLocation("glop.font", "screen") gl.Uniform2f(location, float32(viewport[2]), float32(viewport[3])) location, _ = render.GetUniformLocation("glop.font", "pen") gl.Uniform2f(location, float32(x)+float32(viewport[0]), float32(y)+float32(viewport[1])) location, _ = render.GetUniformLocation("glop.font", "textColor") gl.Uniform3f(location, d.color[0], d.color[1], d.color[2]) gl.Enable(gl.BLEND) gl.BlendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA) gl.BindVertexArray(data.varrays[0]) gl.DrawArrays(gl.TRIANGLES, 0, data.count) }
// bindString generates all of the vertex buffers and vertex arrays for a single constant line of // text. No error checking is done. func (d *Dictionary) bindString(str string) strData { var data strData gl.GenVertexArrays(1, &data.varrays[0]) gl.BindVertexArray(data.varrays[0]) gl.GenBuffers(2, &data.vbuffers[0]) var positions, texcoords []float32 var pen pos var prev rune for _, r := range str { ri := d.Runes[r] var scale float32 = 1.0 / float32(d.GlyphMax.Dy()) var posMin, posMax pos posMin.x = pen.x + float32(ri.GlyphBounds.Min.X)*scale posMin.y = pen.y + float32(ri.GlyphBounds.Min.Y)*scale posMax.x = pen.x + float32(ri.GlyphBounds.Max.X)*scale posMax.y = pen.y + float32(ri.GlyphBounds.Max.Y)*scale var texMin, texMax pos texMin.x = float32(ri.PixBounds.Min.X) / float32(d.Dx) texMin.y = float32(ri.PixBounds.Min.Y) / float32(d.Dy) texMax.x = float32(ri.PixBounds.Max.X) / float32(d.Dx) texMax.y = float32(ri.PixBounds.Max.Y) / float32(d.Dy) pen.x += float32(ri.AdvanceWidth) * scale pen.x += float32(d.Kerning[RunePair{prev, r}]) * scale // pen.x -= float32(d.Kerning[RunePair{prev, r}]) * scale positions = append(positions, posMin.x) // lower left positions = append(positions, posMin.y) positions = append(positions, posMin.x) // upper left positions = append(positions, posMax.y) positions = append(positions, posMax.x) // upper right positions = append(positions, posMax.y) positions = append(positions, posMin.x) // lower left positions = append(positions, posMin.y) positions = append(positions, posMax.x) // upper right positions = append(positions, posMax.y) positions = append(positions, posMax.x) // lower right positions = append(positions, posMin.y) texcoords = append(texcoords, texMin.x) // lower left texcoords = append(texcoords, texMax.y) texcoords = append(texcoords, texMin.x) // upper left texcoords = append(texcoords, texMin.y) texcoords = append(texcoords, texMax.x) // upper right texcoords = append(texcoords, texMin.y) texcoords = append(texcoords, texMin.x) // lower left texcoords = append(texcoords, texMax.y) texcoords = append(texcoords, texMax.x) // upper right texcoords = append(texcoords, texMin.y) texcoords = append(texcoords, texMax.x) // lower right texcoords = append(texcoords, texMax.y) prev = r } data.count = int32(len(positions)) gl.BindBuffer(gl.ARRAY_BUFFER, data.vbuffers[0]) gl.BufferData(gl.ARRAY_BUFFER, len(positions)*int(unsafe.Sizeof(positions[0])), gl.Ptr(&positions[0]), gl.STATIC_DRAW) location, _ := render.GetAttribLocation("glop.font", "position") gl.EnableVertexAttribArray(uint32(location)) gl.VertexAttribPointer(uint32(location), 2, gl.FLOAT, false, 0, gl.PtrOffset(0)) gl.BindBuffer(gl.ARRAY_BUFFER, data.vbuffers[1]) gl.BufferData(gl.ARRAY_BUFFER, len(texcoords)*int(unsafe.Sizeof(texcoords[0])), gl.Ptr(&texcoords[0]), gl.STATIC_DRAW) location, _ = render.GetAttribLocation("glop.font", "texCoord") gl.EnableVertexAttribArray(uint32(location)) gl.VertexAttribPointer(uint32(location), 2, gl.FLOAT, false, 0, gl.PtrOffset(0)) return data }