Add ui/cocoa

This commit is contained in:
Hajime Hoshi 2013-10-13 03:17:51 +09:00
parent 38af973461
commit e8a4bdcef2
8 changed files with 379 additions and 0 deletions

20
ui/cocoa/cocoa.go Normal file
View 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))
}

View 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

View 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

View 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

View 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
View 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
View 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
View 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];
}
}