tofu.go (3910B)
1 package tofu 2 3 import ( 4 "errors" 5 "fmt" 6 "log" 7 "unsafe" 8 9 "github.com/go-gl/gl/v3.3-core/gl" 10 "github.com/go-gl/glfw/v3.3/glfw" 11 ) 12 13 type App interface { 14 Update() error 15 } 16 17 type Cursor struct { 18 X, Y int 19 } 20 21 type CursorApp interface { 22 App 23 CursorChan() chan<- Cursor 24 } 25 26 func watchCursor(c chan<- Cursor) { 27 callback := func(w *glfw.Window, x, y float64) { 28 c <- Cursor{X: int(x), Y: int(y)} 29 } 30 window.SetCursorPosCallback(callback) 31 } 32 33 type Scroll struct { 34 Dx, Dy float32 35 } 36 37 type ScrollApp interface { 38 App 39 ScrollChan() chan<- Scroll 40 } 41 42 func watchScroll(c chan<- Scroll) { 43 callback := func(w *glfw.Window, dx, dy float64) { 44 c <- Scroll{Dx: float32(dx), Dy: float32(dy)} 45 } 46 window.SetScrollCallback(callback) 47 } 48 49 var ( 50 window *glfw.Window 51 winW, winH int = 800, 600 52 winTitle string = "Tofu" 53 keyCallback func(*glfw.Window) 54 ) 55 56 func Init() error { 57 err := glfw.Init() 58 if err != nil { 59 return fmt.Errorf("init glfw: %v", err) 60 } 61 glfw.WindowHint(glfw.ContextVersionMajor, 3) 62 glfw.WindowHint(glfw.ContextVersionMinor, 3) 63 glfw.WindowHint(glfw.OpenGLProfile, glfw.OpenGLCoreProfile) 64 65 window, err = glfw.CreateWindow(winW, winH, winTitle, nil, nil) 66 if err != nil { 67 return fmt.Errorf("create window: %v", err) 68 } 69 window.MakeContextCurrent() 70 if err = gl.Init(); err != nil { 71 return fmt.Errorf("init gl: %v", err) 72 } 73 gl.Viewport(0, 0, int32(winW), int32(winH)) 74 gl.Enable(gl.DEBUG_OUTPUT) 75 gl.DebugMessageCallback(messageCallback, nil) 76 window.SetFramebufferSizeCallback(framebufferSizeCallback) 77 78 gl.Enable(gl.DEPTH_TEST) 79 80 window.SetInputMode(glfw.CursorMode, glfw.CursorDisabled) 81 return nil 82 } 83 84 func Run(app App) error { 85 if app, ok := app.(CursorApp); ok { 86 c := app.CursorChan() 87 watchCursor(c) 88 defer close(c) 89 } 90 if app, ok := app.(ScrollApp); ok { 91 c := app.ScrollChan() 92 watchScroll(c) 93 defer close(c) 94 } 95 96 for !window.ShouldClose() { 97 gl.ClearColor(0.3, 0.3, 0, 1.0) 98 gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) 99 err := app.Update() 100 if err == Termination { 101 break 102 } 103 window.SwapBuffers() 104 glfw.PollEvents() 105 } 106 glfw.Terminate() 107 return nil 108 } 109 110 func messageCallback(source, gltype, id, severity uint32, length int32, message string, userProgram unsafe.Pointer) { 111 log.Printf("debug: type = 0x%x, severity = 0x%x, message = %s", gltype, severity, message) 112 } 113 114 func framebufferSizeCallback(w *glfw.Window, width int, height int) { 115 gl.Viewport(0, 0, int32(width), int32(height)) 116 } 117 118 func SetFramebufferSizeCallback(f glfw.FramebufferSizeCallback) { 119 } 120 121 func SetWindowSize(w, h int) { 122 winW, winH = w, h 123 } 124 125 func SetWindowTitle(t string) { 126 winTitle = t 127 } 128 129 type Key int 130 131 const ( 132 KeyA Key = Key(glfw.KeyA) 133 KeyB = Key(glfw.KeyB) 134 KeyC = Key(glfw.KeyC) 135 KeyD = Key(glfw.KeyD) 136 KeyE = Key(glfw.KeyE) 137 KeyF = Key(glfw.KeyF) 138 KeyG = Key(glfw.KeyG) 139 KeyH = Key(glfw.KeyH) 140 KeyI = Key(glfw.KeyI) 141 KeyJ = Key(glfw.KeyJ) 142 KeyK = Key(glfw.KeyK) 143 KeyL = Key(glfw.KeyL) 144 KeyM = Key(glfw.KeyM) 145 KeyN = Key(glfw.KeyN) 146 KeyO = Key(glfw.KeyO) 147 KeyP = Key(glfw.KeyP) 148 KeyQ = Key(glfw.KeyQ) 149 KeyR = Key(glfw.KeyR) 150 KeyS = Key(glfw.KeyS) 151 KeyT = Key(glfw.KeyT) 152 KeyU = Key(glfw.KeyU) 153 KeyV = Key(glfw.KeyV) 154 KeyW = Key(glfw.KeyW) 155 KeyX = Key(glfw.KeyX) 156 KeyY = Key(glfw.KeyY) 157 KeyZ = Key(glfw.KeyZ) 158 KeySpace = Key(glfw.KeySpace) 159 KeyLeftShift = Key(glfw.KeyLeftShift) 160 KeyUp = Key(glfw.KeyUp) 161 KeyDown = Key(glfw.KeyDown) 162 KeyRight = Key(glfw.KeyRight) 163 KeyLeft = Key(glfw.KeyLeft) 164 ) 165 166 var Termination error = errors.New("Termination") 167 168 func IsKeyPressed(key Key) bool { 169 return window.GetKey(glfw.Key(key)) == glfw.Press 170 }