You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

216 lines
5.4 KiB

// SPDX-License-Identifier: Unlicense OR MIT
// GLFW doesn't build on OpenBSD and FreeBSD.
//go:build !openbsd && !freebsd && !android && !ios && !js
// +build !openbsd,!freebsd,!android,!ios,!js
// The glfw example demonstrates integration of Gio into a foreign
// windowing and rendering library, in this case GLFW
// (https://www.glfw.org).
//
// See the go-glfw package for installation of the native
// dependencies:
//
// https://github.com/go-gl/glfw
package main
import (
"image"
"log"
"math"
"runtime"
"time"
"gioui.org/f32"
"gioui.org/font/gofont"
"gioui.org/gpu"
"gioui.org/io/pointer"
"gioui.org/io/router"
"gioui.org/layout"
"gioui.org/op"
"gioui.org/unit"
"gioui.org/widget"
"gioui.org/widget/material"
"github.com/go-gl/gl/v3.1/gles2"
"github.com/go-gl/gl/v3.3-core/gl"
"github.com/go-gl/glfw/v3.3/glfw"
)
// desktopGL is true when the (core, desktop) OpenGL should
// be used, false for OpenGL ES.
const desktopGL = runtime.GOOS == "darwin"
func main() {
// Required by the OpenGL threading model.
runtime.LockOSThread()
err := glfw.Init()
if err != nil {
log.Fatal(err)
}
defer glfw.Terminate()
// Gio assumes a sRGB backbuffer.
glfw.WindowHint(glfw.SRGBCapable, glfw.True)
glfw.WindowHint(glfw.ScaleToMonitor, glfw.True)
glfw.WindowHint(glfw.CocoaRetinaFramebuffer, glfw.True)
if desktopGL {
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 3)
glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile)
glfw.WindowHint(glfw.OpenGLForwardCompatible, glfw.True)
} else {
glfw.WindowHint(glfw.ContextCreationAPI, glfw.EGLContextAPI)
glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLESAPI)
glfw.WindowHint(glfw.ContextVersionMajor, 3)
glfw.WindowHint(glfw.ContextVersionMinor, 0)
}
window, err := glfw.CreateWindow(800, 600, "Gio + GLFW", nil, nil)
if err != nil {
log.Fatal(err)
}
window.MakeContextCurrent()
if desktopGL {
err = gl.Init()
} else {
err = gles2.Init()
}
if err != nil {
log.Fatalf("gl.Init failed: %v", err)
}
if desktopGL {
// Enable sRGB.
gl.Enable(gl.FRAMEBUFFER_SRGB)
// Set up default VBA, required for the forward-compatible core profile.
var defVBA uint32
gl.GenVertexArrays(1, &defVBA)
gl.BindVertexArray(defVBA)
}
var queue router.Router
var ops op.Ops
th := material.NewTheme(gofont.Collection())
gpuCtx, err := gpu.New(gpu.OpenGL{ES: !desktopGL, Shared: true})
if err != nil {
log.Fatal(err)
}
defer gpuCtx.Release()
registerCallbacks(window, &queue)
for !window.ShouldClose() {
glfw.PollEvents()
scale, _ := window.GetContentScale()
width, height := window.GetFramebufferSize()
sz := image.Point{X: width, Y: height}
ops.Reset()
gtx := layout.Context{
Ops: &ops,
Now: time.Now(),
Queue: &queue,
Metric: unit.Metric{
PxPerDp: scale,
PxPerSp: scale,
},
Constraints: layout.Exact(sz),
}
drawOpenGL()
draw(gtx, th)
gpuCtx.Frame(gtx.Ops, gpu.OpenGLRenderTarget{}, sz)
queue.Frame(gtx.Ops)
window.SwapBuffers()
}
}
var (
button widget.Clickable
green float64 = 0.2
)
// drawOpenGL demonstrates the direct use of OpenGL commands
// to draw non-Gio content below the Gio UI.
func drawOpenGL() {
if desktopGL {
gl.ClearColor(0, float32(green), 0, 1)
gl.Clear(gl.COLOR_BUFFER_BIT)
} else {
gles2.ClearColor(0, float32(green), 0, 1)
gles2.Clear(gl.COLOR_BUFFER_BIT)
}
}
// handleCursorEvent handles cursor events not processed by Gio.
func handleCursorEvent(xpos, ypos float64) {
log.Printf("mouse cursor: (%f,%f)", xpos, ypos)
}
// handleMouseButtonEvent handles mouse button events not processed by Gio.
func handleMouseButtonEvent(button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
if action == glfw.Press {
green += 0.1
green, _ = math.Frexp(green)
}
log.Printf("mouse button: %v action %v mods %v", button, action, mods)
}
func draw(gtx layout.Context, th *material.Theme) layout.Dimensions {
return layout.Center.Layout(gtx,
material.Button(th, &button, "Button").Layout,
)
}
func registerCallbacks(window *glfw.Window, q *router.Router) {
var btns pointer.Buttons
beginning := time.Now()
var lastPos f32.Point
window.SetCursorPosCallback(func(w *glfw.Window, xpos float64, ypos float64) {
scale := float32(1)
if runtime.GOOS == "darwin" {
// macOS cursor positions are not scaled to the underlying framebuffer
// size when CocoaRetinaFramebuffer is true.
scale, _ = w.GetContentScale()
}
lastPos = f32.Point{X: float32(xpos) * scale, Y: float32(ypos) * scale}
e := pointer.Event{
Type: pointer.Move,
Position: lastPos,
Source: pointer.Mouse,
Time: time.Since(beginning),
Buttons: btns,
}
if !q.Queue(e) {
handleCursorEvent(xpos, ypos)
}
})
window.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mods glfw.ModifierKey) {
var btn pointer.Buttons
switch button {
case glfw.MouseButton1:
btn = pointer.ButtonPrimary
case glfw.MouseButton2:
btn = pointer.ButtonSecondary
case glfw.MouseButton3:
btn = pointer.ButtonTertiary
}
var typ pointer.Type
switch action {
case glfw.Release:
typ = pointer.Release
btns &^= btn
case glfw.Press:
typ = pointer.Press
btns |= btn
}
e := pointer.Event{
Type: typ,
Source: pointer.Mouse,
Time: time.Since(beginning),
Position: lastPos,
Buttons: btns,
}
if !q.Queue(e) {
handleMouseButtonEvent(button, action, mods)
}
})
}