added a glfwcanvas subpackage

This commit is contained in:
Thomas Friedel 2018-10-20 14:42:29 +02:00
parent 32bbbdd7c8
commit 93d30a1ff7
4 changed files with 387 additions and 4 deletions

View file

@ -10,15 +10,15 @@ Whereas the Javascript API uses a context that all draw calls go to, here all dr
The library is intended to provide decent performance. Obviously it will not be able to rival hand coded OpenGL for a given purpose, but for many purposes it will be enough. It can also be combined with hand coded OpenGL. The library is intended to provide decent performance. Obviously it will not be able to rival hand coded OpenGL for a given purpose, but for many purposes it will be enough. It can also be combined with hand coded OpenGL.
# SDL convenience package # SDL/GLFW convenience packages
The sdlcanvas subpackage provides a very simple way to get started with just a few lines of code. As the name implies it is based on the SDL library. It creates a window for you and gives you a canvas to draw with. The sdlcanvas and glfwcanvas subpackages provide a very simple way to get started with just a few lines of code. As the names imply they are based on the SDL library and the GLFW library respectively. They create a window for you and give you a canvas to draw with.
# OS support # OS support
- Linux - Linux
- Windows - Windows
- OSX - macOS
- Android - Android
- iOS - iOS

View file

@ -13,7 +13,7 @@ import (
func main() { func main() {
runtime.LockOSThread() runtime.LockOSThread()
// init SDL // init GLFW
err := glfw.Init() err := glfw.Init()
if err != nil { if err != nil {
log.Fatalf("Error initializing GLFW: %v", err) log.Fatalf("Error initializing GLFW: %v", err)

167
glfwcanvas/glfwcanvas.go Normal file
View file

@ -0,0 +1,167 @@
package glfwcanvas
import (
"fmt"
_ "image/gif" // Imported here so that applications based on this package support these formats by default
_ "image/jpeg"
_ "image/png"
"log"
"math"
"runtime"
"time"
"github.com/go-gl/gl/v3.2-core/gl"
"github.com/go-gl/glfw/v3.2/glfw"
"github.com/tfriedel6/canvas"
"github.com/tfriedel6/canvas/glimpl/gogl"
)
// Window represents the opened window with GL context. The Mouse* and Key*
// functions can be set for callbacks
type Window struct {
Window *glfw.Window
canvas *canvas.Canvas
frameTimes [10]time.Time
frameIndex int
frameCount int
fps float32
close bool
MouseDown func(button, x, y int)
MouseMove func(x, y int)
MouseUp func(button, x, y int)
MouseWheel func(x, y int)
KeyDown func(scancode int, rn rune, name string)
KeyUp func(scancode int, rn rune, name string)
KeyChar func(rn rune)
SizeChange func(w, h int)
}
// CreateWindow creates a window using SDL and initializes the OpenGL context
func CreateWindow(w, h int, title string) (*Window, *canvas.Canvas, error) {
runtime.LockOSThread()
// init GLFW
err := glfw.Init()
if err != nil {
log.Fatalf("Error initializing GLFW: %v", err)
}
// the stencil size setting is required for the canvas to work
glfw.WindowHint(glfw.StencilBits, 8)
glfw.WindowHint(glfw.DepthBits, 0)
// create window
window, err := glfw.CreateWindow(w, h, title, nil, nil)
if err != nil {
log.Fatalf("Error creating window: %v", err)
}
window.MakeContextCurrent()
// init GL
err = gl.Init()
if err != nil {
log.Fatalf("Error initializing GL: %v", err)
}
// set vsync on, enable multisample (if available)
glfw.SwapInterval(1)
gl.Enable(gl.MULTISAMPLE)
// load canvas GL assets
err = canvas.LoadGL(glimplgogl.GLImpl{})
if err != nil {
log.Fatalf("Error loading canvas GL assets: %v", err)
}
err = canvas.LoadGL(glimplgogl.GLImpl{})
if err != nil {
return nil, nil, fmt.Errorf("Error loading canvas GL assets: %v", err)
}
cv := canvas.New(0, 0, w, h)
wnd := &Window{
Window: window,
canvas: cv,
}
var mx, my int
window.SetMouseButtonCallback(func(w *glfw.Window, button glfw.MouseButton, action glfw.Action, mod glfw.ModifierKey) {
if action == glfw.Press && wnd.MouseDown != nil {
wnd.MouseDown(int(button), mx, my)
} else if action == glfw.Release && wnd.MouseUp != nil {
wnd.MouseUp(int(button), mx, my)
}
})
window.SetCursorPosCallback(func(w *glfw.Window, xpos float64, ypos float64) {
mx, my = int(math.Round(xpos)), int(math.Round(ypos))
if wnd.MouseMove != nil {
wnd.MouseMove(mx, my)
}
})
window.SetScrollCallback(func(w *glfw.Window, xoff float64, yoff float64) {
if wnd.MouseWheel != nil {
wnd.MouseWheel(int(math.Round(xoff)), int(math.Round(yoff)))
}
})
window.SetKeyCallback(func(w *glfw.Window, key glfw.Key, scancode int, action glfw.Action, mods glfw.ModifierKey) {
if action == glfw.Press && wnd.KeyDown != nil {
wnd.KeyDown(scancode, keyRune(key), keyName(key))
} else if action == glfw.Release && wnd.KeyUp != nil {
wnd.KeyUp(scancode, keyRune(key), keyName(key))
}
})
window.SetCharCallback(func(w *glfw.Window, char rune) {
if wnd.KeyChar != nil {
wnd.KeyChar(char)
}
})
window.SetSizeCallback(func(w *glfw.Window, width int, height int) {
if wnd.SizeChange != nil {
wnd.SizeChange(width, height)
}
})
return wnd, cv, nil
}
// FPS returns the frames per second (averaged over 10 frames)
func (wnd *Window) FPS() float32 {
return wnd.fps
}
// Close can be used to end a call to MainLoop
func (wnd *Window) Close() {
wnd.close = true
}
// StartFrame handles events and gets the window ready for rendering
func (wnd *Window) StartFrame() {
wnd.Window.MakeContextCurrent()
glfw.PollEvents()
}
// FinishFrame updates the FPS count and displays the frame
func (wnd *Window) FinishFrame() {
now := time.Now()
wnd.frameTimes[wnd.frameIndex] = now
wnd.frameIndex++
wnd.frameIndex %= len(wnd.frameTimes)
if wnd.frameCount < len(wnd.frameTimes) {
wnd.frameCount++
} else {
diff := now.Sub(wnd.frameTimes[wnd.frameIndex]).Seconds()
wnd.fps = float32(wnd.frameCount-1) / float32(diff)
}
wnd.Window.SwapBuffers()
}
// MainLoop runs a main loop and calls run on every frame
func (wnd *Window) MainLoop(run func()) {
for !wnd.close {
wnd.StartFrame()
run()
wnd.FinishFrame()
}
}

216
glfwcanvas/keynames.go Normal file
View file

@ -0,0 +1,216 @@
package glfwcanvas
import "github.com/go-gl/glfw/v3.2/glfw"
var keyNameMap [347]string
var keyRuneMap [347]rune
func init() {
keyNameMap[glfw.KeyEscape] = "Escape"
keyNameMap[glfw.Key0] = "Digit0"
keyNameMap[glfw.Key1] = "Digit1"
keyNameMap[glfw.Key2] = "Digit2"
keyNameMap[glfw.Key3] = "Digit3"
keyNameMap[glfw.Key4] = "Digit4"
keyNameMap[glfw.Key5] = "Digit5"
keyNameMap[glfw.Key6] = "Digit6"
keyNameMap[glfw.Key7] = "Digit7"
keyNameMap[glfw.Key8] = "Digit8"
keyNameMap[glfw.Key9] = "Digit9"
keyNameMap[glfw.KeyMinus] = "Minus"
keyNameMap[glfw.KeyEqual] = "Equal"
keyNameMap[glfw.KeyBackspace] = "Backspace"
keyNameMap[glfw.KeyTab] = "Tab"
keyNameMap[glfw.KeyQ] = "KeyQ"
keyNameMap[glfw.KeyW] = "KeyW"
keyNameMap[glfw.KeyE] = "KeyE"
keyNameMap[glfw.KeyR] = "KeyR"
keyNameMap[glfw.KeyT] = "KeyT"
keyNameMap[glfw.KeyY] = "KeyY"
keyNameMap[glfw.KeyU] = "KeyU"
keyNameMap[glfw.KeyI] = "KeyI"
keyNameMap[glfw.KeyO] = "KeyO"
keyNameMap[glfw.KeyP] = "KeyP"
keyNameMap[glfw.KeyLeftBracket] = "BracketLeft"
keyNameMap[glfw.KeyRightBracket] = "BracketRight"
keyNameMap[glfw.KeyEnter] = "Enter"
keyNameMap[glfw.KeyLeftControl] = "ControlLeft"
keyNameMap[glfw.KeyA] = "KeyA"
keyNameMap[glfw.KeyS] = "KeyS"
keyNameMap[glfw.KeyD] = "KeyD"
keyNameMap[glfw.KeyF] = "KeyF"
keyNameMap[glfw.KeyG] = "KeyG"
keyNameMap[glfw.KeyH] = "KeyH"
keyNameMap[glfw.KeyJ] = "KeyJ"
keyNameMap[glfw.KeyK] = "KeyK"
keyNameMap[glfw.KeyL] = "KeyL"
keyNameMap[glfw.KeySemicolon] = "Semicolon"
keyNameMap[glfw.KeyApostrophe] = "Quote"
keyNameMap[glfw.KeyGraveAccent] = "Backquote"
keyNameMap[glfw.KeyLeftShift] = "ShiftLeft"
keyNameMap[glfw.KeyBackslash] = "Backslash"
keyNameMap[glfw.KeyZ] = "KeyZ"
keyNameMap[glfw.KeyX] = "KeyX"
keyNameMap[glfw.KeyC] = "KeyC"
keyNameMap[glfw.KeyV] = "KeyV"
keyNameMap[glfw.KeyB] = "KeyB"
keyNameMap[glfw.KeyN] = "KeyN"
keyNameMap[glfw.KeyM] = "KeyM"
keyNameMap[glfw.KeyComma] = "Comma"
keyNameMap[glfw.KeyPeriod] = "Period"
keyNameMap[glfw.KeySlash] = "Slash"
keyNameMap[glfw.KeyRightShift] = "RightShift"
keyNameMap[glfw.KeyKPMultiply] = "NumpadMultiply"
keyNameMap[glfw.KeyLeftAlt] = "AltLeft"
keyNameMap[glfw.KeySpace] = "Space"
keyNameMap[glfw.KeyCapsLock] = "CapsLock"
keyNameMap[glfw.KeyF1] = "F1"
keyNameMap[glfw.KeyF2] = "F2"
keyNameMap[glfw.KeyF3] = "F3"
keyNameMap[glfw.KeyF4] = "F4"
keyNameMap[glfw.KeyF5] = "F5"
keyNameMap[glfw.KeyF6] = "F6"
keyNameMap[glfw.KeyF7] = "F7"
keyNameMap[glfw.KeyF8] = "F8"
keyNameMap[glfw.KeyF9] = "F9"
keyNameMap[glfw.KeyF10] = "F10"
keyNameMap[glfw.KeyPause] = "Pause"
keyNameMap[glfw.KeyScrollLock] = "ScrollLock"
keyNameMap[glfw.KeyKP7] = "Numpad7"
keyNameMap[glfw.KeyKP8] = "Numpad8"
keyNameMap[glfw.KeyKP9] = "Numpad9"
keyNameMap[glfw.KeyKPSubtract] = "NumpadSubtract"
keyNameMap[glfw.KeyKP4] = "Numpad4"
keyNameMap[glfw.KeyKP5] = "Numpad5"
keyNameMap[glfw.KeyKP6] = "Numpad6"
keyNameMap[glfw.KeyKPAdd] = "NumpadAdd"
keyNameMap[glfw.KeyKP1] = "Numpad1"
keyNameMap[glfw.KeyKP2] = "Numpad2"
keyNameMap[glfw.KeyKP3] = "Numpad3"
keyNameMap[glfw.KeyKP0] = "Numpad0"
keyNameMap[glfw.KeyKPDecimal] = "NumpadDecimal"
keyNameMap[glfw.KeyPrintScreen] = "PrintScreen"
// keyNameMap[glfw.KeyNonUSBackslash] = "IntlBackslash"
keyNameMap[glfw.KeyF11] = "F11"
keyNameMap[glfw.KeyF12] = "F12"
keyNameMap[glfw.KeyKPEqual] = "NumpadEqual"
keyNameMap[glfw.KeyF13] = "F13"
keyNameMap[glfw.KeyF14] = "F14"
keyNameMap[glfw.KeyF15] = "F15"
keyNameMap[glfw.KeyF16] = "F16"
keyNameMap[glfw.KeyF17] = "F17"
keyNameMap[glfw.KeyF18] = "F18"
keyNameMap[glfw.KeyF19] = "F19"
// keyNameMap[glfw.KeyUndo] = "Undo"
// keyNameMap[glfw.KeyPaste] = "Paste"
// keyNameMap[glfw.KeyAudioNext] = "MediaTrackPrevious"
// keyNameMap[glfw.KeyCut] = "Cut"
// keyNameMap[glfw.KeyCopy] = "Copy"
// keyNameMap[glfw.KeyAudioNext] = "MediaTrackNext"
keyNameMap[glfw.KeyKPEnter] = "NumpadEnter"
keyNameMap[glfw.KeyRightControl] = "ControlRight"
// keyNameMap[glfw.KeyMute] = "AudioVolumeMute"
// keyNameMap[glfw.KeyAudioPlay] = "MediaPlayPause"
// keyNameMap[glfw.KeyAudioStop] = "MediaStop"
// keyNameMap[glfw.KeyVolumeDown] = "AudioVolumeDown"
// keyNameMap[glfw.KeyVolumeUp] = "AudioVolumeUp"
keyNameMap[glfw.KeyKPDivide] = "NumpadDivide"
keyNameMap[glfw.KeyRightAlt] = "AltRight"
// keyNameMap[glfw.KeyHelp] = "Help"
keyNameMap[glfw.KeyHome] = "Home"
keyNameMap[glfw.KeyUp] = "ArrowUp"
keyNameMap[glfw.KeyPageUp] = "PageUp"
keyNameMap[glfw.KeyLeft] = "ArrowLeft"
keyNameMap[glfw.KeyRight] = "ArrowRight"
keyNameMap[glfw.KeyEnd] = "End"
keyNameMap[glfw.KeyDown] = "ArrowDown"
keyNameMap[glfw.KeyInsert] = "Insert"
keyNameMap[glfw.KeyDelete] = "Delete"
// keyNameMap[glfw.KeyApplication] = "ContextMenu"
keyRuneMap[glfw.Key0] = '0'
keyRuneMap[glfw.Key1] = '1'
keyRuneMap[glfw.Key2] = '2'
keyRuneMap[glfw.Key3] = '3'
keyRuneMap[glfw.Key4] = '4'
keyRuneMap[glfw.Key5] = '5'
keyRuneMap[glfw.Key6] = '6'
keyRuneMap[glfw.Key7] = '7'
keyRuneMap[glfw.Key8] = '8'
keyRuneMap[glfw.Key9] = '9'
keyRuneMap[glfw.KeyMinus] = '-'
keyRuneMap[glfw.KeyEqual] = '='
keyRuneMap[glfw.KeyTab] = '\t'
keyRuneMap[glfw.KeyQ] = 'Q'
keyRuneMap[glfw.KeyW] = 'W'
keyRuneMap[glfw.KeyE] = 'E'
keyRuneMap[glfw.KeyR] = 'R'
keyRuneMap[glfw.KeyT] = 'T'
keyRuneMap[glfw.KeyY] = 'Y'
keyRuneMap[glfw.KeyU] = 'U'
keyRuneMap[glfw.KeyI] = 'I'
keyRuneMap[glfw.KeyO] = 'O'
keyRuneMap[glfw.KeyP] = 'P'
keyRuneMap[glfw.KeyLeftBracket] = '['
keyRuneMap[glfw.KeyRightBracket] = ']'
keyRuneMap[glfw.KeyEnter] = '\n'
keyRuneMap[glfw.KeyA] = 'A'
keyRuneMap[glfw.KeyS] = 'S'
keyRuneMap[glfw.KeyD] = 'D'
keyRuneMap[glfw.KeyF] = 'F'
keyRuneMap[glfw.KeyG] = 'G'
keyRuneMap[glfw.KeyH] = 'H'
keyRuneMap[glfw.KeyJ] = 'J'
keyRuneMap[glfw.KeyK] = 'K'
keyRuneMap[glfw.KeyL] = 'L'
keyRuneMap[glfw.KeySemicolon] = ';'
keyRuneMap[glfw.KeyApostrophe] = '\''
keyRuneMap[glfw.KeyGraveAccent] = '`'
keyRuneMap[glfw.KeyBackslash] = '\\'
keyRuneMap[glfw.KeyZ] = 'Z'
keyRuneMap[glfw.KeyX] = 'X'
keyRuneMap[glfw.KeyC] = 'C'
keyRuneMap[glfw.KeyV] = 'V'
keyRuneMap[glfw.KeyB] = 'B'
keyRuneMap[glfw.KeyN] = 'N'
keyRuneMap[glfw.KeyM] = 'M'
keyRuneMap[glfw.KeyComma] = ','
keyRuneMap[glfw.KeyPeriod] = '.'
keyRuneMap[glfw.KeySlash] = '/'
keyRuneMap[glfw.KeyKPMultiply] = '*'
keyRuneMap[glfw.KeySpace] = ' '
keyRuneMap[glfw.KeyKP7] = '7'
keyRuneMap[glfw.KeyKP8] = '8'
keyRuneMap[glfw.KeyKP9] = '9'
keyRuneMap[glfw.KeyKPSubtract] = '-'
keyRuneMap[glfw.KeyKP4] = '4'
keyRuneMap[glfw.KeyKP5] = '5'
keyRuneMap[glfw.KeyKP6] = '6'
keyRuneMap[glfw.KeyKPAdd] = '+'
keyRuneMap[glfw.KeyKP1] = '1'
keyRuneMap[glfw.KeyKP2] = '2'
keyRuneMap[glfw.KeyKP3] = '3'
keyRuneMap[glfw.KeyKP0] = '0'
keyRuneMap[glfw.KeyKPDecimal] = '.'
keyRuneMap[glfw.KeyKPEqual] = '='
keyRuneMap[glfw.KeyKPEnter] = '\n'
keyRuneMap[glfw.KeyKPDivide] = '/'
}
func keyName(key glfw.Key) string {
if int(key) >= len(keyNameMap) {
return "Unidentified"
}
name := keyNameMap[key]
if name == "" {
return "Unidentified"
}
return name
}
func keyRune(key glfw.Key) rune {
if int(key) >= len(keyNameMap) {
return 0
}
return keyRuneMap[key]
}