forked from go/golangs_learn
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
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)
|
|
}
|
|
})
|
|
}
|
|
|