mirror of
https://github.com/hajimehoshi/ebiten.git
synced 2024-11-10 04:57:26 +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