mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-12-26 03:38:55 +01:00
Implement input in ui/glfw (#7)
This commit is contained in:
parent
ca97ee6961
commit
7eb6b2f51f
@ -1,12 +0,0 @@
|
||||
// -*- objc -*-
|
||||
|
||||
#ifndef GO_EBITEN_UI_COCOA_EBITEN_CONTROLLER_H_
|
||||
#define GO_EBITEN_UI_COCOA_EBITEN_CONTROLLER_H_
|
||||
|
||||
#include <Cocoa/Cocoa.h>
|
||||
|
||||
@interface EbitenController : NSObject<NSApplicationDelegate>
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
@ -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
|
@ -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 <Cocoa/Cocoa.h>
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
@interface EbitenGameContentView : NSView
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
@ -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
|
@ -1,16 +0,0 @@
|
||||
// -*- objc -*-
|
||||
|
||||
#ifndef GO_EBITEN_UI_COCOA_EBITEN_GAME_WINDOW_H_
|
||||
#define GO_EBITEN_UI_COCOA_EBITEN_GAME_WINDOW_H_
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface EbitenGameWindow : NSWindow<NSWindowDelegate>
|
||||
|
||||
- (id)initWithSize:(NSSize)size
|
||||
glContext:(NSOpenGLContext*)glContext;
|
||||
- (NSOpenGLContext*)glContext;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
@ -1,268 +0,0 @@
|
||||
package cocoa
|
||||
|
||||
// #include <stdlib.h>
|
||||
//
|
||||
// #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)
|
||||
}
|
@ -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
|
@ -1,106 +0,0 @@
|
||||
// -*- objc -*-
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <OpenGL/gl.h>
|
||||
|
||||
#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);
|
||||
}
|
@ -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
|
||||
}
|
@ -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()
|
||||
}
|
@ -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{}
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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() {
|
||||
|
Loading…
Reference in New Issue
Block a user