Stop using [NSApp run]

This commit is contained in:
Hajime Hoshi 2013-11-23 02:56:18 +09:00
parent 2bc4d6bf14
commit 170ed689fa
10 changed files with 165 additions and 123 deletions

View File

@ -9,9 +9,7 @@ import (
"github.com/hajimehoshi/go-ebiten/example/game/rotating"
"github.com/hajimehoshi/go-ebiten/example/game/sprites"
"github.com/hajimehoshi/go-ebiten/example/game/testpattern"
"github.com/hajimehoshi/go-ebiten/ui"
"github.com/hajimehoshi/go-ebiten/ui/cocoa"
// "github.com/hajimehoshi/go-ebiten/ui/glut"
"os"
"runtime"
)
@ -23,10 +21,6 @@ func main() {
if 2 <= len(os.Args) {
gameName = os.Args[1]
}
uiName := "cocoa"
if 3 <= len(os.Args) {
uiName = os.Args[2]
}
var game ebiten.Game
switch gameName {
@ -52,12 +46,11 @@ func main() {
const screenHeight = 240
const screenScale = 2
const title = "Ebiten Demo"
var u ui.UI
switch uiName {
default:
fallthrough
case "cocoa":
u = cocoa.New(screenWidth, screenHeight, screenScale, title)
ui := cocoa.New(screenWidth, screenHeight, screenScale, title)
ui.Start(game)
ui.InitTextures(game)
for {
ui.WaitEvents()
ui.Draw(game.Draw)
}
u.Run(game)
}

View File

@ -6,13 +6,13 @@ import (
)
type Device struct {
context *Context
context *Context
}
func NewDevice(screenWidth, screenHeight, screenScale int) *Device {
graphicsContext := newContext(screenWidth, screenHeight, screenScale)
context := newContext(screenWidth, screenHeight, screenScale)
return &Device{
context: graphicsContext,
context: context,
}
}

View File

@ -1,20 +1,24 @@
package cocoa
// #cgo CFLAGS: -x objective-c -fobjc-arc
// #cgo CFLAGS: -x objective-c
// #cgo LDFLAGS: -framework Cocoa -framework OpenGL -framework QuartzCore
//
//
// #include <stdlib.h>
// #include "input.h"
//
// void Run(size_t width, size_t height, size_t scale, const char* title);
// void Start(size_t width, size_t height, size_t scale, const char* title);
// void WaitEvents(void);
// void BeginDrawing(void);
// void EndDrawing(void);
//
import "C"
import (
"github.com/hajimehoshi/go-ebiten"
"github.com/hajimehoshi/go-ebiten/graphics"
"github.com/hajimehoshi/go-ebiten/graphics/opengl"
"runtime"
"sync"
"time"
"runtime"
"unsafe"
)
@ -41,16 +45,16 @@ func (context *GameContext) InputState() ebiten.InputState {
}
type UI struct {
screenWidth int
screenHeight int
screenScale int
title string
updating chan ebiten.Game
updated chan ebiten.Game
input chan ebiten.InputState
graphicsDevice *opengl.Device
funcsExecutedOnMainThread []func() // TODO: map?
lock sync.Mutex
screenWidth int
screenHeight int
screenScale int
title string
updating chan struct{}
updated chan struct{}
input chan ebiten.InputState
graphicsDevice *opengl.Device
lock sync.Mutex
gameContext *GameContext
}
var currentUI *UI
@ -60,14 +64,18 @@ func New(screenWidth, screenHeight, screenScale int, title string) *UI {
panic("UI can't be duplicated.")
}
ui := &UI{
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
title: title,
updating: make(chan ebiten.Game),
updated: make(chan ebiten.Game),
input: make(chan ebiten.InputState),
funcsExecutedOnMainThread: []func(){},
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
title: title,
updating: make(chan struct{}),
updated: make(chan struct{}),
input: make(chan ebiten.InputState),
gameContext: &GameContext{
screenWidth: screenWidth,
screenHeight: screenHeight,
inputState: ebiten.InputState{-1, -1},
},
}
currentUI = ui
return ui
@ -76,50 +84,45 @@ func New(screenWidth, screenHeight, screenScale int, title string) *UI {
func (ui *UI) gameMainLoop(game ebiten.Game) {
frameTime := time.Duration(int64(time.Second) / int64(ebiten.FPS))
tick := time.Tick(frameTime)
gameContext := &GameContext{
screenWidth: ui.screenWidth,
screenHeight: ui.screenHeight,
inputState: ebiten.InputState{-1, -1},
}
ui.InitializeGame(game)
for {
select {
case gameContext.inputState = <-ui.input:
case ui.gameContext.inputState = <-ui.input:
case <-tick:
game.Update(gameContext)
case ui.updating <- game:
game = <-ui.updated
game.Update(ui.gameContext)
case ui.updating <- struct{}{}:
//ui.DrawGame(game)
<-ui.updated
}
}
}
func (ui *UI) Run(game ebiten.Game) {
func (ui *UI) Start(game ebiten.Game) {
go ui.gameMainLoop(game)
runtime.LockOSThread()
cTitle := C.CString(ui.title)
defer C.free(unsafe.Pointer(cTitle))
C.Run(C.size_t(ui.screenWidth),
C.Start(C.size_t(ui.screenWidth),
C.size_t(ui.screenHeight),
C.size_t(ui.screenScale),
cTitle)
C.WaitEvents()
}
func (ui *UI) InitializeGame(game ebiten.Game) {
ui.lock.Lock()
defer ui.lock.Unlock()
ui.funcsExecutedOnMainThread = append(ui.funcsExecutedOnMainThread, func() {
game.InitTextures(ui.graphicsDevice.TextureFactory())
})
func (ui *UI) WaitEvents() {
C.WaitEvents()
}
func (ui *UI) DrawGame(game ebiten.Game) {
ui.lock.Lock()
defer ui.lock.Unlock()
ui.funcsExecutedOnMainThread = append(ui.funcsExecutedOnMainThread, func() {
ui.graphicsDevice.Update(game.Draw)
})
func (ui *UI) InitTextures(game ebiten.Game) {
C.BeginDrawing()
game.InitTextures(ui.graphicsDevice.TextureFactory())
C.EndDrawing()
}
func (ui *UI) Draw(f func(graphics.Context)) {
C.BeginDrawing()
ui.graphicsDevice.Update(f)
C.EndDrawing()
}
//export ebiten_EbitenOpenGLView_Initialized
@ -127,7 +130,6 @@ func ebiten_EbitenOpenGLView_Initialized() {
if currentUI.graphicsDevice != nil {
panic("The graphics device is already initialized")
}
currentUI.graphicsDevice = opengl.NewDevice(
currentUI.screenWidth,
currentUI.screenHeight,
@ -136,16 +138,6 @@ func ebiten_EbitenOpenGLView_Initialized() {
//export ebiten_EbitenOpenGLView_Updating
func ebiten_EbitenOpenGLView_Updating() {
currentUI.lock.Lock()
defer currentUI.lock.Unlock()
for _, f := range currentUI.funcsExecutedOnMainThread {
f()
}
currentUI.funcsExecutedOnMainThread = currentUI.funcsExecutedOnMainThread[0:0]
game := <-currentUI.updating
currentUI.graphicsDevice.Update(game.Draw)
currentUI.updated <- game
}
//export ebiten_EbitenOpenGLView_InputUpdated

View File

@ -13,7 +13,7 @@ void ebiten_EbitenOpenGLView_InputUpdated(InputType inputType, int x, int y);
// TODO: Use NSViewController?
static CVReturn
/*static CVReturn
EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
CVTimeStamp const* now,
CVTimeStamp const* outputTime,
@ -28,19 +28,26 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
EbitenOpenGLView* view = (__bridge EbitenOpenGLView*)displayLinkContext;
return [view getFrameForTime:outputTime];
}
}
}*/
@implementation EbitenOpenGLView {
@private
CVDisplayLinkRef displayLink_;
/*@private
CVDisplayLinkRef displayLink_;*/
}
- (void)dealloc {
/*- (void)dealloc {
CVDisplayLinkRelease(self->displayLink_);
// Do not call [super dealloc] because of ARC.
}
#if !__has_feature(objc_arc)
[super dealloc];
#endif
}*/
- (void)prepareOpenGL {
/*- (void)prepareOpenGL {
[super prepareOpenGL];
ebiten_EbitenOpenGLView_Initialized();
}*/
/*- (void)prepareOpenGL {
[super prepareOpenGL];
NSOpenGLContext* openGLContext = [self openGLContext];
assert(openGLContext != nil);
@ -60,9 +67,9 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
CVDisplayLinkStart(self->displayLink_);
ebiten_EbitenOpenGLView_Initialized();
}
}*/
- (CVReturn)getFrameForTime:(CVTimeStamp const*)outputTime {
/*- (CVReturn)getFrameForTime:(CVTimeStamp const*)outputTime {
(void)outputTime;
NSOpenGLContext* context = [self openGLContext];
assert(context != nil);
@ -74,7 +81,7 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
CGLUnlockContext((CGLContextObj)[context CGLContextObj]);
}
return kCVReturnSuccess;
}
}*/
- (BOOL)isFlipped {
return YES;

View File

@ -8,7 +8,7 @@
@interface EbitenOpenGLView : NSOpenGLView
- (CVReturn)getFrameForTime:(CVTimeStamp const*)outputTime;
//- (CVReturn)getFrameForTime:(CVTimeStamp const*)outputTime;
@end

View File

@ -2,9 +2,16 @@
#import "ebiten_window.h"
#include <OpenGL/gl.h>
#import "ebiten_opengl_view.h"
void ebiten_EbitenOpenGLView_Initialized(void);
@implementation EbitenWindow
{
NSOpenGLContext* glContext_;
}
- (id)initWithSize:(NSSize)size {
NSUInteger style = (NSTitledWindowMask | NSClosableWindowMask |
@ -31,6 +38,20 @@
[self setDocumentEdited:YES];
NSRect rect = NSMakeRect(0, 0, size.width, size.height);
NSView* contentView = [[NSView alloc] initWithFrame:rect];
[self setContentView:contentView];
return self;
/*EbitenOpenGLView* contentView =
[[EbitenOpenGLView alloc] initWithFrame:rect
pixelFormat:format];*/
}
- (NSOpenGLContext*)glContext {
if (self->glContext_ != nil)
return self->glContext_;
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFAWindow,
NSOpenGLPFADoubleBuffer,
@ -40,11 +61,15 @@
};
NSOpenGLPixelFormat* format = [[NSOpenGLPixelFormat alloc]
initWithAttributes:attributes];
EbitenOpenGLView* glView =
[[EbitenOpenGLView alloc] initWithFrame:rect
pixelFormat:format];
[self setContentView:glView];
return self;
self->glContext_ = [[NSOpenGLContext alloc] initWithFormat:format
shareContext:nil];
[self->glContext_ setView:[self contentView]];
[self->glContext_ makeCurrentContext];
ebiten_EbitenOpenGLView_Initialized();
[format release];
return self->glContext_;
}
- (BOOL)windowShouldClose:(id)sender {
@ -60,6 +85,7 @@
modalDelegate:self
didEndSelector:selector
contextInfo:nil];
[alert release];
}
return NO;
}
@ -74,5 +100,13 @@
}
}
@end
- (void)beginDrawing {
[[self glContext] makeCurrentContext];
glClear(GL_COLOR_BUFFER_BIT);
}
- (void)endDrawing {
[[self glContext] flushBuffer];
}
@end

View File

@ -12,6 +12,8 @@
returnCode:(NSInteger)returnCode
contextInfo:(void*)contextInfo;
- (BOOL)windowShouldClose:(id)sender;
- (void)beginDrawing;
- (void)endDrawing;
@end

45
ui/cocoa/mainloop.c Normal file
View File

@ -0,0 +1,45 @@
// -*- objc -*-
#include <stdlib.h>
#import "ebiten_controller.h"
#import "ebiten_window.h"
static EbitenWindow* currentWindow = 0;
void Start(size_t width, size_t height, size_t scale, const char* title) {
NSSize size = NSMakeSize(width * scale, height * scale);
EbitenWindow* window = [[EbitenWindow alloc]
initWithSize:size];
[window setTitle: [[NSString alloc] initWithUTF8String:title]];
EbitenController* controller = [[EbitenController alloc]
initWithWindow:window];
NSApplication* app = [NSApplication sharedApplication];
[app setActivationPolicy:NSApplicationActivationPolicyRegular];
[app setDelegate:controller];
[app finishLaunching];
[app activateIgnoringOtherApps:YES];
currentWindow = window;
}
void WaitEvents(void) {
for (;;) {
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask
untilDate:[NSDate distantPast]
inMode:NSDefaultRunLoopMode
dequeue:YES];
if (event == nil) {
break;
}
[NSApp sendEvent:event];
}
}
void BeginDrawing(void) {
[currentWindow beginDrawing];
}
void EndDrawing(void) {
[currentWindow endDrawing];
}

View File

@ -1,23 +0,0 @@
// -*- objc -*-
#include <stdlib.h>
#import "ebiten_controller.h"
#import "ebiten_window.h"
void Run(size_t width, size_t height, size_t scale, const char* title) {
@autoreleasepool {
NSSize size = NSMakeSize(width * scale, height * scale);
EbitenWindow* window = [[EbitenWindow alloc]
initWithSize:size];
[window setTitle: [[NSString alloc] initWithUTF8String:title]];
EbitenController* controller = [[EbitenController alloc]
initWithWindow:window];
NSApplication* app = [NSApplication sharedApplication];
[app setActivationPolicy:NSApplicationActivationPolicyRegular];
[app setDelegate:controller];
[app finishLaunching];
[app activateIgnoringOtherApps:YES];
[app run];
}
}

View File

@ -1,9 +1 @@
package ui
import (
"github.com/hajimehoshi/go-ebiten"
)
type UI interface {
Run(game ebiten.Game)
}