From 7eb6b2f51fecf5f5df0dd28ba16a0ef7ec308d42 Mon Sep 17 00:00:00 2001 From: Hajime Hoshi Date: Sat, 6 Dec 2014 03:10:17 +0900 Subject: [PATCH] Implement input in ui/glfw (#7) --- ui/cocoa/ebiten_controller.h | 12 -- ui/cocoa/ebiten_game_content_view.c | 54 ------ ui/cocoa/ebiten_game_content_view.h | 13 -- ui/cocoa/ebiten_game_window.c | 88 --------- ui/cocoa/ebiten_game_window.h | 16 -- ui/cocoa/game_window.go | 268 ---------------------------- ui/cocoa/input.h | 10 -- ui/cocoa/mainloop.c | 106 ----------- ui/cocoa/shared_context.go | 96 ---------- ui/cocoa/ui.go | 57 ------ ui/dummy/dummy.go | 65 ------- ui/glfw/canvas.go | 25 +-- ui/glfw/inputstate.go | 35 +++- ui/glfw/ui.go | 4 +- 14 files changed, 44 insertions(+), 805 deletions(-) delete mode 100644 ui/cocoa/ebiten_controller.h delete mode 100644 ui/cocoa/ebiten_game_content_view.c delete mode 100644 ui/cocoa/ebiten_game_content_view.h delete mode 100644 ui/cocoa/ebiten_game_window.c delete mode 100644 ui/cocoa/ebiten_game_window.h delete mode 100644 ui/cocoa/game_window.go delete mode 100644 ui/cocoa/input.h delete mode 100644 ui/cocoa/mainloop.c delete mode 100644 ui/cocoa/shared_context.go delete mode 100644 ui/cocoa/ui.go delete mode 100644 ui/dummy/dummy.go diff --git a/ui/cocoa/ebiten_controller.h b/ui/cocoa/ebiten_controller.h deleted file mode 100644 index 888341848..000000000 --- a/ui/cocoa/ebiten_controller.h +++ /dev/null @@ -1,12 +0,0 @@ -// -*- objc -*- - -#ifndef GO_EBITEN_UI_COCOA_EBITEN_CONTROLLER_H_ -#define GO_EBITEN_UI_COCOA_EBITEN_CONTROLLER_H_ - -#include - -@interface EbitenController : NSObject - -@end - -#endif diff --git a/ui/cocoa/ebiten_game_content_view.c b/ui/cocoa/ebiten_game_content_view.c deleted file mode 100644 index 846d10851..000000000 --- a/ui/cocoa/ebiten_game_content_view.c +++ /dev/null @@ -1,54 +0,0 @@ -// -*- objc -*- - -#include "ebiten_game_content_view.h" -#include "input.h" - -void ebiten_KeyDown(NSWindow* nativeWindow, int keyCode); -void ebiten_KeyUp(NSWindow* nativeWindow, int keyCode); -void ebiten_MouseStateUpdated(NSWindow* nativeWindow, InputType inputType, int x, int y); - -@implementation EbitenGameContentView { -} - -- (BOOL)acceptsFirstResponder { - return YES; -} - -- (BOOL)isFlipped { - return YES; -} - -- (void)keyDown:(NSEvent*)theEvent { - ebiten_KeyDown([self window], [theEvent keyCode]); -} - -- (void)keyUp:(NSEvent*)theEvent { - ebiten_KeyUp([self window], [theEvent keyCode]); -} - -- (void)mouseDown:(NSEvent*)theEvent { - NSPoint location = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - int x = location.x; - int y = location.y; - ebiten_MouseStateUpdated([self window], InputTypeMouseDown, x, y); -} - -- (void)mouseUp:(NSEvent*)theEvent { - (void)theEvent; - NSPoint location = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - int x = location.x; - int y = location.y; - ebiten_MouseStateUpdated([self window], InputTypeMouseUp, x, y); -} - -- (void)mouseDragged:(NSEvent*)theEvent { - NSPoint location = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - int x = location.x; - int y = location.y; - ebiten_MouseStateUpdated([self window], InputTypeMouseDragged, x, y); -} - -@end diff --git a/ui/cocoa/ebiten_game_content_view.h b/ui/cocoa/ebiten_game_content_view.h deleted file mode 100644 index a14ac37f8..000000000 --- a/ui/cocoa/ebiten_game_content_view.h +++ /dev/null @@ -1,13 +0,0 @@ -// -*- objc -*- - -#ifndef GO_EBITEN_UI_COCOA_EBITEN_GAME_CONTENT_VIEW_H_ -#define GO_EBITEN_UI_COCOA_EBITEN_GAME_CONTENT_VIEW_H_ - -#import -#import - -@interface EbitenGameContentView : NSView - -@end - -#endif diff --git a/ui/cocoa/ebiten_game_window.c b/ui/cocoa/ebiten_game_window.c deleted file mode 100644 index 868f7742e..000000000 --- a/ui/cocoa/ebiten_game_window.c +++ /dev/null @@ -1,88 +0,0 @@ -// -*- objc -*- - -#import "ebiten_game_window.h" - -#import "ebiten_game_content_view.h" - -@class NSOpenGLContext; - -void ebiten_WindowClosed(void* nativeWindow); - -@implementation EbitenGameWindow { -@private - NSOpenGLContext* glContext_; -} - -- (id)initWithSize:(NSSize)size - glContext:(NSOpenGLContext*)glContext { - self->glContext_ = glContext; - [self->glContext_ retain]; - - NSUInteger style = (NSTitledWindowMask | NSClosableWindowMask | - NSMiniaturizableWindowMask); - NSRect windowRect = - [NSWindow frameRectForContentRect:NSMakeRect(0, 0, size.width, size.height) - styleMask:style]; - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - NSSize screenSize = [screen visibleFrame].size; - NSRect contentRect = NSMakeRect(0, 0, size.width, size.height); - self = [super initWithContentRect:contentRect - styleMask:style - backing:NSBackingStoreBuffered - defer:YES]; - if (self != nil) { - [self center]; - [self setReleasedWhenClosed:YES]; - [self setDelegate:self]; - [self setDocumentEdited:YES]; - - NSRect rect = NSMakeRect(0, 0, size.width, size.height); - NSView* contentView = [[EbitenGameContentView alloc] initWithFrame:rect]; - [self setContentView:contentView]; - [contentView release]; - } - - return self; -} - -- (void)dealloc { - [self->glContext_ release]; - [super dealloc]; -} - -- (NSOpenGLContext*)glContext { - return self->glContext_; -} - -- (BOOL)windowShouldClose:(id)sender { - if ([sender isDocumentEdited]) { - // TODO: add the application's name - NSAlert* alert = [NSAlert new]; - [alert setMessageText:@"Quit the game?"]; - [alert addButtonWithTitle:@"Quit"]; - [alert addButtonWithTitle:@"Cancel"]; - [alert setAlertStyle:NSWarningAlertStyle]; - SEL selector = @selector(alertDidEnd:returnCode:contextInfo:); - [alert beginSheetModalForWindow:sender - modalDelegate:self - didEndSelector:selector - contextInfo:nil]; - [alert release]; - } - return NO; -} - -- (void)alertDidEnd:(NSAlert*)alert - returnCode:(NSInteger)returnCode - contextInfo:(void*)contextInfo { - if (returnCode == NSAlertFirstButtonReturn) { - [self close]; - ebiten_WindowClosed(self); - } -} - -- (BOOL)canBecomeMainWindow { - return YES; -} - -@end diff --git a/ui/cocoa/ebiten_game_window.h b/ui/cocoa/ebiten_game_window.h deleted file mode 100644 index 0fd755bb7..000000000 --- a/ui/cocoa/ebiten_game_window.h +++ /dev/null @@ -1,16 +0,0 @@ -// -*- objc -*- - -#ifndef GO_EBITEN_UI_COCOA_EBITEN_GAME_WINDOW_H_ -#define GO_EBITEN_UI_COCOA_EBITEN_GAME_WINDOW_H_ - -#import - -@interface EbitenGameWindow : NSWindow - -- (id)initWithSize:(NSSize)size - glContext:(NSOpenGLContext*)glContext; -- (NSOpenGLContext*)glContext; - -@end - -#endif diff --git a/ui/cocoa/game_window.go b/ui/cocoa/game_window.go deleted file mode 100644 index 620e1c3e9..000000000 --- a/ui/cocoa/game_window.go +++ /dev/null @@ -1,268 +0,0 @@ -package cocoa - -// #include -// -// #include "input.h" -// -// @class EbitenGameWindow; -// @class NSOpenGLContext; -// -// typedef EbitenGameWindow* EbitenGameWindowPtr; -// -// EbitenGameWindow* CreateGameWindow(size_t width, size_t height, const char* title, NSOpenGLContext* glContext); -// NSOpenGLContext* CreateGLContext(NSOpenGLContext* sharedGLContext); -// -// void UseGLContext(NSOpenGLContext* glContext); -// void UnuseGLContext(void); -// -import "C" -import ( - "github.com/hajimehoshi/ebiten/graphics" - "github.com/hajimehoshi/ebiten/graphics/opengl" - "github.com/hajimehoshi/ebiten/ui" - "runtime" - "sync" - "time" - "unsafe" -) - -type Keys map[ui.Key]struct{} - -func newKeys() Keys { - return Keys(map[ui.Key]struct{}{}) -} - -func (k Keys) clone() Keys { - n := newKeys() - for key, value := range k { - n[key] = value - } - return n -} - -func (k Keys) add(key ui.Key) { - k[key] = struct{}{} -} - -func (k Keys) remove(key ui.Key) { - delete(k, key) -} - -func (k Keys) Includes(key ui.Key) bool { - _, ok := k[key] - return ok -} - -type InputState struct { - pressedKeys Keys - mouseX int - mouseY int -} - -func (i *InputState) PressedKeys() ui.Keys { - return i.pressedKeys -} - -func (i *InputState) MouseX() int { - return i.mouseX -} - -func (i *InputState) MouseY() int { - return i.mouseY -} - -func (i *InputState) setMouseXY(x, y int) { - i.mouseX = x - i.mouseY = y -} - -type GameWindow struct { - width int - height int - scale int - isClosed bool - inputState *InputState - title string - native *C.EbitenGameWindow - funcs chan func(*opengl.Context) - funcsDone chan struct{} - closed chan struct{} - sync.RWMutex -} - -var windows = map[*C.EbitenGameWindow]*GameWindow{} - -func newGameWindow(width, height, scale int, title string) *GameWindow { - inputState := &InputState{ - pressedKeys: newKeys(), - mouseX: -1, - mouseY: -1, - } - return &GameWindow{ - width: width, - height: height, - scale: scale, - inputState: inputState, - title: title, - funcs: make(chan func(*opengl.Context)), - funcsDone: make(chan struct{}), - closed: make(chan struct{}), - } -} - -func (w *GameWindow) IsClosed() bool { - w.RLock() - defer w.RUnlock() - return w.isClosed -} - -func (w *GameWindow) run(sharedGLContext *C.NSOpenGLContext) { - cTitle := C.CString(w.title) - defer C.free(unsafe.Pointer(cTitle)) - - ch := make(chan struct{}) - go func() { - runtime.LockOSThread() - glContext := C.CreateGLContext(sharedGLContext) - w.native = C.CreateGameWindow( - C.size_t(w.width*w.scale), - C.size_t(w.height*w.scale), - cTitle, - glContext) - windows[w.native] = w - close(ch) - - C.UseGLContext(glContext) - context := opengl.NewContext( - w.width, w.height, w.scale) - C.UnuseGLContext() - - defer func() { - C.UseGLContext(glContext) - context.Dispose() - C.UnuseGLContext() - }() - - w.loop(context, glContext) - }() - <-ch -} - -func (w *GameWindow) loop(context *opengl.Context, glContext *C.NSOpenGLContext) { - for { - select { - case <-w.closed: - return - case f := <-w.funcs: - // Wait 10 millisecond at least to avoid busy loop. - after := time.After(time.Duration(int64(time.Millisecond) * 10)) - C.UseGLContext(glContext) - f(context) - C.UnuseGLContext() - <-after - w.funcsDone <- struct{}{} - } - } -} - -func (w *GameWindow) Draw(f func(graphics.Context)) { - select { - case <-w.closed: - return - default: - } - w.useGLContext(func(context *opengl.Context) { - context.Update(f) - }) -} - -func (w *GameWindow) useGLContext(f func(*opengl.Context)) { - w.funcs <- f - <-w.funcsDone -} - -func (w *GameWindow) InputState() ui.InputState { - w.RLock() - defer w.RUnlock() - return &InputState{ - pressedKeys: w.inputState.pressedKeys.clone(), - mouseX: w.inputState.mouseX, - mouseY: w.inputState.mouseY, - } -} - -var cocoaKeyCodeToKey = map[int]ui.Key{ - 49: ui.KeySpace, - 123: ui.KeyLeft, - 124: ui.KeyRight, - 125: ui.KeyDown, - 126: ui.KeyUp, -} - -//export ebiten_KeyDown -func ebiten_KeyDown(nativeWindow C.EbitenGameWindowPtr, keyCode int) { - key, ok := cocoaKeyCodeToKey[keyCode] - if !ok { - return - } - w := windows[nativeWindow] - - w.Lock() - defer w.Unlock() - w.inputState.pressedKeys.add(key) -} - -//export ebiten_KeyUp -func ebiten_KeyUp(nativeWindow C.EbitenGameWindowPtr, keyCode int) { - key, ok := cocoaKeyCodeToKey[keyCode] - if !ok { - return - } - w := windows[nativeWindow] - - w.Lock() - defer w.Unlock() - w.inputState.pressedKeys.remove(key) -} - -//export ebiten_MouseStateUpdated -func ebiten_MouseStateUpdated(nativeWindow C.EbitenGameWindowPtr, inputType C.InputType, cx, cy C.int) { - w := windows[nativeWindow] - - if inputType == C.InputTypeMouseUp { - w.Lock() - defer w.Unlock() - w.inputState.setMouseXY(-1, -1) - return - } - - x, y := int(cx), int(cy) - x /= w.scale - y /= w.scale - if x < 0 { - x = 0 - } else if w.width <= x { - x = w.width - 1 - } - if y < 0 { - y = 0 - } else if w.height <= y { - y = w.height - 1 - } - - w.Lock() - defer w.Unlock() - w.inputState.setMouseXY(x, y) -} - -//export ebiten_WindowClosed -func ebiten_WindowClosed(nativeWindow C.EbitenGameWindowPtr) { - w := windows[nativeWindow] - close(w.closed) - - w.Lock() - defer w.Unlock() - w.isClosed = true - - delete(windows, nativeWindow) -} diff --git a/ui/cocoa/input.h b/ui/cocoa/input.h deleted file mode 100644 index 88f7246d5..000000000 --- a/ui/cocoa/input.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef GO_EBITEN_UI_COCOA_INPUT_H_ -#define GO_EBITEN_UI_COCOA_INPUT_H_ - -typedef enum { - InputTypeMouseUp, - InputTypeMouseDragged, - InputTypeMouseDown, -} InputType; - -#endif diff --git a/ui/cocoa/mainloop.c b/ui/cocoa/mainloop.c deleted file mode 100644 index 78343d4ea..000000000 --- a/ui/cocoa/mainloop.c +++ /dev/null @@ -1,106 +0,0 @@ -// -*- objc -*- - -#include -#include - -#import "ebiten_game_window.h" - -static NSAutoreleasePool* pool = NULL; - -void initMenu(void) { - NSString* processName = [[NSProcessInfo processInfo] processName]; - - NSMenu* menuBar = [NSMenu new]; - [NSApp setMainMenu: menuBar]; - [menuBar release]; - - NSMenuItem* rootMenuItem = [NSMenuItem new]; - [menuBar addItem:rootMenuItem]; - [rootMenuItem release]; - - NSMenu* appMenu = [NSMenu new]; - [rootMenuItem setSubmenu:appMenu]; - [appMenu release]; - - [appMenu addItemWithTitle:[@"Quit " stringByAppendingString:processName] - action:@selector(performClose:) - keyEquivalent:@"q"]; -} - -void StartApplication(void) { - pool = [NSAutoreleasePool new]; - - NSApplication* app = [NSApplication sharedApplication]; - [app setActivationPolicy:NSApplicationActivationPolicyRegular]; - initMenu(); - [app finishLaunching]; - [NSApp activateIgnoringOtherApps:YES]; -} - -void DoEvents(void) { - for (;;) { - NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask - untilDate:[NSDate distantPast] - inMode:NSDefaultRunLoopMode - dequeue:YES]; - if (event == nil) { - break; - } - [NSApp sendEvent:event]; - } - - [pool drain]; - pool = [NSAutoreleasePool new]; -} - -void TerminateApplication(void) { - [pool drain]; -} - -NSOpenGLContext* CreateGLContext(NSOpenGLContext* sharedGLContext) { - NSOpenGLPixelFormatAttribute attributes[] = { - NSOpenGLPFAWindow, - NSOpenGLPFADoubleBuffer, - NSOpenGLPFAAccelerated, - NSOpenGLPFADepthSize, 32, - 0, - }; - NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc] - initWithAttributes:attributes]; - NSOpenGLContext* glContext = - [[NSOpenGLContext alloc] initWithFormat:format - shareContext:sharedGLContext]; - [format release]; - return glContext; -} - -EbitenGameWindow* CreateGameWindow(size_t width, size_t height, const char* title, NSOpenGLContext* glContext) { - NSSize size = NSMakeSize(width, height); - EbitenGameWindow* window = [[EbitenGameWindow alloc] - initWithSize:size - glContext:glContext]; - [glContext release]; - - NSString* nsTitle = [[NSString alloc] - initWithUTF8String:title]; - [window setTitle: nsTitle]; - [nsTitle release]; - - [window makeKeyAndOrderFront:nil]; - [glContext setView:[window contentView]]; - return window; -} - -void UseGLContext(NSOpenGLContext* glContext) { - CGLContextObj cglContext = [glContext CGLContextObj]; - CGLLockContext(cglContext); - [glContext makeCurrentContext]; -} - -void UnuseGLContext(void) { - NSOpenGLContext* glContext = [NSOpenGLContext currentContext]; - [glContext flushBuffer]; - [NSOpenGLContext clearCurrentContext]; - CGLContextObj cglContext = [glContext CGLContextObj]; - CGLUnlockContext(cglContext); -} diff --git a/ui/cocoa/shared_context.go b/ui/cocoa/shared_context.go deleted file mode 100644 index 8e404ac07..000000000 --- a/ui/cocoa/shared_context.go +++ /dev/null @@ -1,96 +0,0 @@ -package cocoa - -// @class NSOpenGLContext; -// -// NSOpenGLContext* CreateGLContext(NSOpenGLContext* sharedGLContext); -// void UseGLContext(NSOpenGLContext* glContext); -// void UnuseGLContext(void); -// -import "C" -import ( - "github.com/hajimehoshi/ebiten/graphics" - "github.com/hajimehoshi/ebiten/graphics/opengl" - "image" - "runtime" -) - -type sharedContext struct { - inited chan struct{} - funcs chan func() - funcsDone chan struct{} - gameWindows chan *GameWindow -} - -func newSharedContext() *sharedContext { - return &sharedContext{ - inited: make(chan struct{}), - funcs: make(chan func()), - funcsDone: make(chan struct{}), - gameWindows: make(chan *GameWindow), - } -} - -func (t *sharedContext) run() { - var sharedGLContext *C.NSOpenGLContext - go func() { - runtime.LockOSThread() - sharedGLContext = C.CreateGLContext(nil) - close(t.inited) - t.loop(sharedGLContext) - }() - <-t.inited - go func() { - for w := range t.gameWindows { - w.run(sharedGLContext) - } - }() -} - -func (t *sharedContext) loop(sharedGLContext *C.NSOpenGLContext) { - for { - select { - case f := <-t.funcs: - C.UseGLContext(sharedGLContext) - f() - C.UnuseGLContext() - t.funcsDone <- struct{}{} - } - } -} - -func (t *sharedContext) useGLContext(f func()) { - t.funcs <- f - <-t.funcsDone -} - -func (t *sharedContext) createGameWindow(width, height, scale int, title string) *GameWindow { - w := newGameWindow(width, height, scale, title) - go func() { - t.gameWindows <- w - }() - return w -} - -func (t *sharedContext) CreateTexture( - img image.Image, - filter graphics.Filter) (graphics.TextureId, error) { - <-t.inited - var id graphics.TextureId - var err error - t.useGLContext(func() { - id, err = opengl.CreateTexture(img, filter) - }) - return id, err -} - -func (t *sharedContext) CreateRenderTarget( - width, height int, - filter graphics.Filter) (graphics.RenderTargetId, error) { - <-t.inited - var id graphics.RenderTargetId - var err error - t.useGLContext(func() { - id, err = opengl.CreateRenderTarget(width, height, filter) - }) - return id, err -} diff --git a/ui/cocoa/ui.go b/ui/cocoa/ui.go deleted file mode 100644 index d31da9748..000000000 --- a/ui/cocoa/ui.go +++ /dev/null @@ -1,57 +0,0 @@ -package cocoa - -// #cgo CFLAGS: -x objective-c -// #cgo LDFLAGS: -framework Cocoa -framework OpenGL -// -// void StartApplication(void); -// void DoEvents(void); -// void TerminateApplication(void); -// -import "C" -import ( - "github.com/hajimehoshi/ebiten/graphics" - "github.com/hajimehoshi/ebiten/ui" -) - -type cocoaUI struct { - sharedContext *sharedContext -} - -var currentUI *cocoaUI - -func getCurrentUI() *cocoaUI { - if currentUI != nil { - return currentUI - } - - currentUI = &cocoaUI{} - currentUI.sharedContext = newSharedContext() - - return currentUI -} - -func UI() ui.UI { - return getCurrentUI() -} - -func TextureFactory() graphics.TextureFactory { - return getCurrentUI().sharedContext -} - -func (u *cocoaUI) CreateCanvas(width, height, scale int, title string) ui.Canvas { - return u.sharedContext.createGameWindow(width, height, scale, title) -} - -func (u *cocoaUI) DoEvents() { - C.DoEvents() -} - -func (u *cocoaUI) Start() { - C.StartApplication() - currentUI.sharedContext.run() -} - -func (u *cocoaUI) Terminate() { - // TODO: Close existing windows - C.TerminateApplication() -} diff --git a/ui/dummy/dummy.go b/ui/dummy/dummy.go deleted file mode 100644 index f48273a24..000000000 --- a/ui/dummy/dummy.go +++ /dev/null @@ -1,65 +0,0 @@ -package dummy - -import ( - "github.com/hajimehoshi/ebiten/graphics" - "github.com/hajimehoshi/ebiten/ui" - "image" -) - -type TextureFactory struct{} - -func (t *TextureFactory) CreateRenderTarget(width, height int, filter graphics.Filter) (graphics.RenderTargetId, error) { - return 0, nil -} - -func (t *TextureFactory) CreateTexture(img image.Image, filter graphics.Filter) (graphics.TextureId, error) { - return 0, nil -} - -type UI struct{} - -func (u *UI) CreateCanvas(widht, height, scale int, title string) ui.Canvas { - return &Canvas{} -} - -func (u *UI) Start() { -} - -func (u *UI) DoEvents() { -} - -func (u *UI)Terminate() { -} - -type Keys struct{} - -func (k *Keys) Includes(key ui.Key) bool { - return false -} - -type InputState struct{} - -func (i *InputState) PressedKeys() ui.Keys { - return &Keys{} -} - -func (i *InputState) MouseX() int { - return -1 -} - -func (i *InputState) MouseY() int { - return -1 -} - -type Canvas struct{} - -func (c *Canvas) Draw(func(graphics.Context)) { -} - -func (c *Canvas) IsClosed() bool { - return true -} - -func (c *Canvas) InputState() ui.InputState { - return &InputState{} -} diff --git a/ui/glfw/canvas.go b/ui/glfw/canvas.go index 136e2c5ce..9790d88e5 100644 --- a/ui/glfw/canvas.go +++ b/ui/glfw/canvas.go @@ -10,10 +10,11 @@ import ( ) type Canvas struct { - window *glfw.Window - context *opengl.Context - funcs chan func() - funcsDone chan struct{} + window *glfw.Window + inputState *InputState + context *opengl.Context + funcs chan func() + funcsDone chan struct{} } func NewCanvas(width, height, scale int, title string) *Canvas { @@ -22,15 +23,15 @@ func NewCanvas(width, height, scale int, title string) *Canvas { panic(err) } canvas := &Canvas{ - window: window, - funcs: make(chan func()), - funcsDone: make(chan struct{}), + window: window, + inputState: newInputState(), + funcs: make(chan func()), + funcsDone: make(chan struct{}), } // For retina displays, recalculate the scale with the framebuffer size. - windowWidth, windowHeight := window.GetFramebufferSize() + windowWidth, _ := window.GetFramebufferSize() realScale := windowWidth / width - _ = windowHeight canvas.run() canvas.use(func() { @@ -51,7 +52,7 @@ func (c *Canvas) IsClosed() bool { } func (c *Canvas) InputState() ui.InputState { - return &InputState{newKeys(), -1, -1} + return c.inputState } func (c *Canvas) CreateTexture(img image.Image, filter graphics.Filter) (graphics.TextureId, error) { @@ -89,3 +90,7 @@ func (c *Canvas) use(f func()) { c.funcs <- f <-c.funcsDone } + +func (c *Canvas) update() { + c.inputState.update(c.window) +} diff --git a/ui/glfw/inputstate.go b/ui/glfw/inputstate.go index 5f5dfce42..10af80d94 100644 --- a/ui/glfw/inputstate.go +++ b/ui/glfw/inputstate.go @@ -1,6 +1,7 @@ package glfw import ( + glfw "github.com/go-gl/glfw3" "github.com/hajimehoshi/ebiten/ui" ) @@ -10,14 +11,6 @@ func newKeys() Keys { return Keys(map[ui.Key]struct{}{}) } -func (k Keys) clone() Keys { - n := newKeys() - for key, value := range k { - n[key] = value - } - return n -} - func (k Keys) add(key ui.Key) { k[key] = struct{}{} } @@ -37,6 +30,14 @@ type InputState struct { mouseY int } +func newInputState() *InputState { + return &InputState{ + pressedKeys: newKeys(), + mouseX: -1, + mouseY: -1, + } +} + func (i *InputState) PressedKeys() ui.Keys { return i.pressedKeys } @@ -48,3 +49,21 @@ func (i *InputState) MouseX() int { func (i *InputState) MouseY() int { return i.mouseY } + +var glfwKeyCodeToKey = map[glfw.Key]ui.Key{ + glfw.KeySpace: ui.KeySpace, + glfw.KeyLeft: ui.KeyLeft, + glfw.KeyRight: ui.KeyRight, + glfw.KeyUp: ui.KeyUp, + glfw.KeyDown: ui.KeyDown, +} + +func (i *InputState) update(window *glfw.Window) { + for g, u := range glfwKeyCodeToKey { + if window.GetKey(g) == glfw.Press { + i.pressedKeys.add(u) + } else { + i.pressedKeys.remove(u) + } + } +} diff --git a/ui/glfw/ui.go b/ui/glfw/ui.go index 81fe67dc7..5079a32dd 100644 --- a/ui/glfw/ui.go +++ b/ui/glfw/ui.go @@ -22,7 +22,6 @@ func (u *UI) CreateCanvas(width, height, scale int, title string) ui.Canvas { panic("glfw.Init() fails") } glfw.WindowHint(glfw.Resizable, glfw.False) - //glfw.WindowHint(glfw.ClientAPI, glfw.OpenGLESAPI) u.canvas = NewCanvas(width, height, scale, title) return u.canvas } @@ -31,7 +30,8 @@ func (u *UI) Start() { } func (u *UI) DoEvents() { - glfw.PollEvents() + glfw.PollEvents() + u.canvas.update() } func (u *UI) Terminate() {