mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2025-01-12 12:08:58 +01:00
Add ui/cocoa
This commit is contained in:
parent
38af973461
commit
e8a4bdcef2
20
ui/cocoa/cocoa.go
Normal file
20
ui/cocoa/cocoa.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
package cocoa
|
||||||
|
|
||||||
|
// #cgo CFLAGS: -x objective-c -fobjc-arc
|
||||||
|
// #cgo LDFLAGS: -framework Cocoa -framework OpenGL -framework QuartzCore
|
||||||
|
//
|
||||||
|
// #include <stdlib.h>
|
||||||
|
//
|
||||||
|
// void Run(size_t width, size_t height, size_t scale);
|
||||||
|
//
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"github.com/hajimehoshi/go.ebiten"
|
||||||
|
_ "github.com/hajimehoshi/go.ebiten/graphics"
|
||||||
|
_ "github.com/hajimehoshi/go.ebiten/graphics/opengl"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Run(game ebiten.Game, screenWidth, screenHeight, screenScale int,
|
||||||
|
title string) {
|
||||||
|
C.Run(C.size_t(screenWidth), C.size_t(screenHeight), C.size_t(screenScale))
|
||||||
|
}
|
48
ui/cocoa/ebiten_controller.c
Normal file
48
ui/cocoa/ebiten_controller.c
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
// -*- objc -*-
|
||||||
|
|
||||||
|
#import "ebiten_controller.h"
|
||||||
|
|
||||||
|
@implementation EbitenController {
|
||||||
|
@private
|
||||||
|
NSWindow* window_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)initWithWindow:(NSWindow*)window {
|
||||||
|
self = [super init];
|
||||||
|
if (self != nil) {
|
||||||
|
self->window_ = window;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)initMenu {
|
||||||
|
NSString* processName = [[NSProcessInfo processInfo] processName];
|
||||||
|
|
||||||
|
NSMenu* menuBar = [NSMenu new];
|
||||||
|
NSMenuItem* rootMenu = [NSMenuItem new];
|
||||||
|
[menuBar addItem:rootMenu];
|
||||||
|
|
||||||
|
NSMenu* appMenu = [NSMenu new];
|
||||||
|
[appMenu addItemWithTitle:[@"Quit " stringByAppendingString:processName]
|
||||||
|
action:@selector(performClose:)
|
||||||
|
keyEquivalent:@"q"];
|
||||||
|
|
||||||
|
[rootMenu setSubmenu:appMenu];
|
||||||
|
[NSApp setMainMenu: menuBar];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification {
|
||||||
|
(void)aNotification;
|
||||||
|
NSWindow* window = self->window_;
|
||||||
|
assert(window);
|
||||||
|
[window makeKeyAndOrderFront:nil];
|
||||||
|
[self initMenu];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:
|
||||||
|
(NSApplication*)theApplication {
|
||||||
|
(void)theApplication;
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
15
ui/cocoa/ebiten_controller.h
Normal file
15
ui/cocoa/ebiten_controller.h
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
// -*- 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>
|
||||||
|
|
||||||
|
- (id)initWithWindow:(NSWindow*)window;
|
||||||
|
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
152
ui/cocoa/ebiten_opengl_view.c
Normal file
152
ui/cocoa/ebiten_opengl_view.c
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
// -*- objc -*-
|
||||||
|
|
||||||
|
#include "ebiten_opengl_view.h"
|
||||||
|
|
||||||
|
// Reference:
|
||||||
|
// http://developer.apple.com/library/mac/#qa/qa1385/_index.html
|
||||||
|
// http://www.alecjacobson.com/weblog/?p=2185
|
||||||
|
|
||||||
|
// TODO: Use NSViewController?
|
||||||
|
|
||||||
|
static CVReturn
|
||||||
|
EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
|
||||||
|
CVTimeStamp const* now,
|
||||||
|
CVTimeStamp const* outputTime,
|
||||||
|
CVOptionFlags flagsIn,
|
||||||
|
CVOptionFlags* flagsOut,
|
||||||
|
void* displayLinkContext) {
|
||||||
|
(void)displayLink;
|
||||||
|
(void)now;
|
||||||
|
(void)flagsIn;
|
||||||
|
(void)flagsOut;
|
||||||
|
@autoreleasepool {
|
||||||
|
EbitenOpenGLView* view = (__bridge EbitenOpenGLView*)displayLinkContext;
|
||||||
|
return [view getFrameForTime:outputTime];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@implementation EbitenOpenGLView {
|
||||||
|
@private
|
||||||
|
CVDisplayLinkRef displayLink_;
|
||||||
|
updating* updating_;
|
||||||
|
//ebiten::input* input_;
|
||||||
|
bool isTerminated_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (id)init {
|
||||||
|
if (self = [super init]) {
|
||||||
|
self->updating_ = NULL;
|
||||||
|
}
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)dealloc {
|
||||||
|
CVDisplayLinkRelease(self->displayLink_);
|
||||||
|
// Do not call [super dealloc] because of ARC.
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)prepareOpenGL {
|
||||||
|
[super prepareOpenGL];
|
||||||
|
self->isTerminated_ = false;
|
||||||
|
NSOpenGLContext* openGLContext = [self openGLContext];
|
||||||
|
assert(openGLContext != nil);
|
||||||
|
GLint const swapInterval = 1;
|
||||||
|
[openGLContext setValues:&swapInterval
|
||||||
|
forParameter:NSOpenGLCPSwapInterval];
|
||||||
|
CVDisplayLinkCreateWithActiveCGDisplays(&self->displayLink_);
|
||||||
|
CVDisplayLinkSetOutputCallback(self->displayLink_,
|
||||||
|
&EbitenDisplayLinkCallback,
|
||||||
|
(__bridge void*)self);
|
||||||
|
CGLContextObj cglContext = (CGLContextObj)[openGLContext CGLContextObj];
|
||||||
|
CGLPixelFormatObj cglPixelFormat =
|
||||||
|
(CGLPixelFormatObj)[[self pixelFormat] CGLPixelFormatObj];
|
||||||
|
CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(self->displayLink_,
|
||||||
|
cglContext,
|
||||||
|
cglPixelFormat);
|
||||||
|
CVDisplayLinkStart(self->displayLink_);
|
||||||
|
}
|
||||||
|
|
||||||
|
- (CVReturn)getFrameForTime:(CVTimeStamp const*)outputTime {
|
||||||
|
(void)outputTime;
|
||||||
|
if (!self->updating_) {
|
||||||
|
return kCVReturnSuccess;
|
||||||
|
}
|
||||||
|
NSOpenGLContext* context = [self openGLContext];
|
||||||
|
assert(context != nil);
|
||||||
|
[context makeCurrentContext];
|
||||||
|
bool terminated = false;
|
||||||
|
{
|
||||||
|
CGLLockContext((CGLContextObj)[context CGLContextObj]);
|
||||||
|
terminated = self->updating_();
|
||||||
|
[context flushBuffer];
|
||||||
|
CGLUnlockContext((CGLContextObj)[context CGLContextObj]);
|
||||||
|
}
|
||||||
|
if (terminated) {
|
||||||
|
//CVDisplayLinkStop(self->displayLink_);
|
||||||
|
[NSApp terminate:nil];
|
||||||
|
return kCVReturnSuccess;
|
||||||
|
}
|
||||||
|
return kCVReturnSuccess;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)setUpdatingFunc:(updating*)func {
|
||||||
|
self->updating_ = func;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
// - (void)setInput:(ebiten::input&)input {
|
||||||
|
// self->input_ = &input;
|
||||||
|
// }
|
||||||
|
|
||||||
|
- (BOOL)isFlipped {
|
||||||
|
return YES;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDown:(NSEvent*)theEvent {
|
||||||
|
NSPoint location = [self convertPoint:[theEvent locationInWindow]
|
||||||
|
fromView:nil];
|
||||||
|
// TODO
|
||||||
|
/*
|
||||||
|
if (self->input_) {
|
||||||
|
int x = location.x;
|
||||||
|
int y = location.y;
|
||||||
|
// TODO: Screen size
|
||||||
|
self->input_->set_touches_real_location(0,
|
||||||
|
static_cast<int>(x),
|
||||||
|
static_cast<int>(y));
|
||||||
|
self->input_->set_touched(0, true);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseUp:(NSEvent*)theEvent {
|
||||||
|
(void)theEvent;
|
||||||
|
// TODO
|
||||||
|
/*if (self->input_) {
|
||||||
|
self->input_->set_touches_real_location(0, -1, -1);
|
||||||
|
self->input_->set_touched(0, false);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)mouseDragged:(NSEvent*)theEvent {
|
||||||
|
NSPoint location = [self convertPoint:[theEvent locationInWindow]
|
||||||
|
fromView:nil];
|
||||||
|
// TODO
|
||||||
|
/*if (self->input_) {
|
||||||
|
int x = location.x;
|
||||||
|
int y = location.y;
|
||||||
|
self->input_->set_touches_real_location(0,
|
||||||
|
static_cast<int>(x),
|
||||||
|
static_cast<int>(y));
|
||||||
|
self->input_->set_touched(0, true);
|
||||||
|
}*/
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)terminate {
|
||||||
|
self->isTerminated_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (bool)isTerminated {
|
||||||
|
return self->isTerminated_;
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
20
ui/cocoa/ebiten_opengl_view.h
Normal file
20
ui/cocoa/ebiten_opengl_view.h
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// -*- objc -*-
|
||||||
|
|
||||||
|
#ifndef GO_EBITEN_UI_COCOA_EBITEN_OPENGL_VIEW_H_
|
||||||
|
#define GO_EBITEN_UI_COCOA_EBITEN_OPENGL_VIEW_H_
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
#import <QuartzCore/QuartzCore.h>
|
||||||
|
|
||||||
|
typedef bool updating(void);
|
||||||
|
|
||||||
|
@interface EbitenOpenGLView : NSOpenGLView
|
||||||
|
|
||||||
|
- (CVReturn)getFrameForTime:(CVTimeStamp const*)outputTime;
|
||||||
|
- (void)setUpdatingFunc:(updating*)updatingFunc;
|
||||||
|
- (void)terminate;
|
||||||
|
- (bool)isTerminated;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
61
ui/cocoa/ebiten_window.c
Normal file
61
ui/cocoa/ebiten_window.c
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
// -*- objc -*-
|
||||||
|
|
||||||
|
#import "ebiten_opengl_view.h"
|
||||||
|
#import "ebiten_window.h"
|
||||||
|
|
||||||
|
@implementation EbitenWindow
|
||||||
|
|
||||||
|
- (id)initWithSize:(NSSize)size {
|
||||||
|
[NSApplication sharedApplication];
|
||||||
|
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;
|
||||||
|
// Reference: Mac OS X Human Interface Guidelines: UI Element Guidelines: Windows
|
||||||
|
// http://developer.apple.com/library/mac/#documentation/UserExperience/Conceptual/AppleHIGuidelines/Windows/Windows.html
|
||||||
|
NSRect contentRect = NSMakeRect((screenSize.width - windowRect.size.width) / 2,
|
||||||
|
(screenSize.height - windowRect.size.height) * 2 / 3,
|
||||||
|
size.width, size.height);
|
||||||
|
self = [super initWithContentRect:contentRect
|
||||||
|
styleMask:style
|
||||||
|
backing:NSBackingStoreBuffered
|
||||||
|
defer:YES];
|
||||||
|
assert(self != nil);
|
||||||
|
[self setReleasedWhenClosed:YES];
|
||||||
|
[self setDelegate:self];
|
||||||
|
[self setDocumentEdited:YES];
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (BOOL)windowShouldClose:(id)sender {
|
||||||
|
if ([sender isDocumentEdited]) {
|
||||||
|
// TODO: add the application's name
|
||||||
|
NSAlert* alert = [NSAlert alertWithMessageText:@"Quit the game?"
|
||||||
|
defaultButton:@"Quit"
|
||||||
|
alternateButton:nil
|
||||||
|
otherButton:@"Cancel"
|
||||||
|
informativeTextWithFormat:@""];
|
||||||
|
[alert beginSheetModalForWindow:sender
|
||||||
|
modalDelegate:self
|
||||||
|
didEndSelector:@selector(alertDidEnd:returnCode:contextInfo:)
|
||||||
|
contextInfo:nil];
|
||||||
|
}
|
||||||
|
return NO;
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)alertDidEnd:(NSAlert*)alert
|
||||||
|
returnCode:(NSInteger)returnCode
|
||||||
|
contextInfo:(void*)contextInfo {
|
||||||
|
(void)alert;
|
||||||
|
(void)contextInfo;
|
||||||
|
if (returnCode == NSAlertDefaultReturn) {
|
||||||
|
EbitenOpenGLView* glView = [self contentView];
|
||||||
|
[glView terminate];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
18
ui/cocoa/ebiten_window.h
Normal file
18
ui/cocoa/ebiten_window.h
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
// -*- objc -*-
|
||||||
|
|
||||||
|
#ifndef GO_EBITEN_UI_COCOA_EBITEN_WINDOW_H_
|
||||||
|
#define GO_EBITEN_UI_COCOA_EBITEN_WINDOW_H_
|
||||||
|
|
||||||
|
#import <Cocoa/Cocoa.h>
|
||||||
|
|
||||||
|
@interface EbitenWindow : NSWindow<NSWindowDelegate>
|
||||||
|
|
||||||
|
- (id)initWithSize:(NSSize)size;
|
||||||
|
- (void)alertDidEnd:(NSAlert*)alert
|
||||||
|
returnCode:(NSInteger)returnCode
|
||||||
|
contextInfo:(void*)contextInfo;
|
||||||
|
- (BOOL)windowShouldClose:(id)sender;
|
||||||
|
|
||||||
|
@end
|
||||||
|
|
||||||
|
#endif
|
45
ui/cocoa/run.c
Normal file
45
ui/cocoa/run.c
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
// -*- objc -*-
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#import "ebiten_controller.h"
|
||||||
|
#import "ebiten_opengl_view.h"
|
||||||
|
#import "ebiten_window.h"
|
||||||
|
|
||||||
|
static NSWindow* generateWindow(size_t width, size_t height) {
|
||||||
|
EbitenWindow* window = [[EbitenWindow alloc]
|
||||||
|
initWithSize:NSMakeSize(width, height)];
|
||||||
|
assert(window != nil);
|
||||||
|
|
||||||
|
NSRect const rect = NSMakeRect(0, 0, width, height);
|
||||||
|
NSOpenGLPixelFormatAttribute const attributes[] = {
|
||||||
|
NSOpenGLPFAWindow,
|
||||||
|
NSOpenGLPFADoubleBuffer,
|
||||||
|
NSOpenGLPFAAccelerated,
|
||||||
|
NSOpenGLPFADepthSize, 32,
|
||||||
|
0,
|
||||||
|
};
|
||||||
|
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
|
||||||
|
initWithAttributes:attributes];
|
||||||
|
EbitenOpenGLView* glView =
|
||||||
|
[[EbitenOpenGLView alloc] initWithFrame:rect
|
||||||
|
pixelFormat:format];
|
||||||
|
[window setContentView:glView];
|
||||||
|
//[window makeFirstResponder:glView];
|
||||||
|
|
||||||
|
return window;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Run(size_t width, size_t height, size_t scale) {
|
||||||
|
@autoreleasepool {
|
||||||
|
NSWindow* window = generateWindow(width * scale, height * scale);
|
||||||
|
EbitenController* controller = [[EbitenController alloc]
|
||||||
|
initWithWindow:window];
|
||||||
|
NSApplication* app = [NSApplication sharedApplication];
|
||||||
|
[app setActivationPolicy:NSApplicationActivationPolicyRegular];
|
||||||
|
[app setDelegate:controller];
|
||||||
|
[app finishLaunching];
|
||||||
|
[app activateIgnoringOtherApps:YES];
|
||||||
|
[app run];
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user