Implement ui.cocoa

This commit is contained in:
Hajime Hoshi 2013-10-13 23:06:05 +09:00
parent 54893c3031
commit 983aeec03b
6 changed files with 171 additions and 78 deletions

View File

@ -8,8 +8,8 @@ import (
"github.com/hajimehoshi/go.ebiten/example/game/rects"
"github.com/hajimehoshi/go.ebiten/example/game/rotating"
"github.com/hajimehoshi/go.ebiten/example/game/sprites"
_ "github.com/hajimehoshi/go.ebiten/ui/cocoa"
"github.com/hajimehoshi/go.ebiten/ui/glut"
"github.com/hajimehoshi/go.ebiten/ui/cocoa"
_ "github.com/hajimehoshi/go.ebiten/ui/glut"
"os"
"runtime"
)
@ -41,5 +41,5 @@ func main() {
}
const screenScale = 2
glut.Run(game, 256, 240, screenScale, "Ebiten Demo")
cocoa.Run(game, 256, 240, screenScale, "Ebiten Demo")
}

View File

@ -10,15 +10,112 @@ package cocoa
import "C"
import (
"github.com/hajimehoshi/go.ebiten"
_ "github.com/hajimehoshi/go.ebiten/graphics"
_ "github.com/hajimehoshi/go.ebiten/graphics/opengl"
// "github.com/hajimehoshi/go.ebiten/graphics"
"github.com/hajimehoshi/go.ebiten/graphics/opengl"
"time"
"unsafe"
)
type UI struct {
game ebiten.Game
screenWidth int
screenHeight int
screenScale int
graphicsDevice *opengl.Device
inited chan bool
updating chan bool
updated chan bool
input chan ebiten.InputState
}
var currentUI *UI
//export ebiten_EbitenOpenGLView_Initialized
func ebiten_EbitenOpenGLView_Initialized() {
if currentUI.graphicsDevice != nil {
panic("The graphics device is already initialized")
}
currentUI.graphicsDevice = opengl.NewDevice(
currentUI.screenWidth,
currentUI.screenHeight,
currentUI.screenScale)
currentUI.graphicsDevice.Init()
currentUI.game.Init(currentUI.graphicsDevice.TextureFactory())
currentUI.inited <- true
}
//export ebiten_EbitenOpenGLView_Updating
func ebiten_EbitenOpenGLView_Updating() {
<-currentUI.updating
currentUI.graphicsDevice.Update(currentUI.game.Draw)
currentUI.updated <- true
}
//export ebiten_EbitenOpenGLView_InputUpdated
func ebiten_EbitenOpenGLView_InputUpdated(x, y C.int) {
currentUI.input <- ebiten.InputState{int(x), int(y)}
}
func Run(game ebiten.Game, screenWidth, screenHeight, screenScale int,
title string) {
cTitle := C.CString(title)
defer C.free(unsafe.Pointer(cTitle))
C.Run(C.size_t(screenWidth), C.size_t(screenHeight), C.size_t(screenScale), cTitle)
currentUI = &UI{
game: game,
screenWidth: screenWidth,
screenHeight: screenHeight,
screenScale: screenScale,
inited: make(chan bool),
updating: make(chan bool),
updated: make(chan bool),
input: make(chan ebiten.InputState),
}
go func() {
frameTime := time.Duration(
int64(time.Second) / int64(ebiten.FPS))
tick := time.Tick(frameTime)
gameContext := &GameContext{
screenWidth: screenWidth,
screenHeight: screenHeight,
inputState: ebiten.InputState{-1, -1},
}
<-currentUI.inited
for {
select {
case gameContext.inputState = <-currentUI.input:
case <-tick:
game.Update(gameContext)
case currentUI.updating <- true:
<-currentUI.updated
}
}
}()
C.Run(C.size_t(screenWidth),
C.size_t(screenHeight),
C.size_t(screenScale),
cTitle)
}
type GameContext struct {
screenWidth int
screenHeight int
inputState ebiten.InputState
}
func (context *GameContext) ScreenWidth() int {
return context.screenWidth
}
func (context *GameContext) ScreenHeight() int {
return context.screenHeight
}
func (context *GameContext) InputState() ebiten.InputState {
return context.inputState
}

View File

@ -2,6 +2,10 @@
#include "ebiten_opengl_view.h"
void ebiten_EbitenOpenGLView_Initialized(void);
void ebiten_EbitenOpenGLView_Updating(void);
void ebiten_EbitenOpenGLView_InputUpdated(int x, int y);
// Reference:
// http://developer.apple.com/library/mac/#qa/qa1385/_index.html
// http://www.alecjacobson.com/weblog/?p=2185
@ -28,15 +32,9 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
@implementation EbitenOpenGLView {
@private
CVDisplayLinkRef displayLink_;
updating* updating_;
//ebiten::input* input_;
}
- (id)init {
if (self = [super init]) {
self->updating_ = NULL;
}
return self;
size_t screenWidth_;
size_t screenHeight_;
size_t screenScale_;
}
- (void)dealloc {
@ -48,7 +46,7 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
[super prepareOpenGL];
NSOpenGLContext* openGLContext = [self openGLContext];
assert(openGLContext != nil);
GLint const swapInterval = 1;
GLint swapInterval = 1;
[openGLContext setValues:&swapInterval
forParameter:NSOpenGLCPSwapInterval];
CVDisplayLinkCreateWithActiveCGDisplays(&self->displayLink_);
@ -62,40 +60,24 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
cglContext,
cglPixelFormat);
CVDisplayLinkStart(self->displayLink_);
ebiten_EbitenOpenGLView_Initialized();
}
- (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_();
ebiten_EbitenOpenGLView_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;
}
@ -103,40 +85,50 @@ EbitenDisplayLinkCallback(CVDisplayLinkRef displayLink,
- (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);
}*/
int x = location.x / self->screenScale_;
int y = location.y / self->screenScale_;
if (x < 0) {
x = 0;
} else if (self->screenWidth_<= x) {
x = self->screenWidth_ - 1;
}
if (y < 0) {
y = 0;
} else if (self->screenHeight_<= y) {
y = self->screenHeight_ - 1;
}
ebiten_EbitenOpenGLView_InputUpdated(x, y);
}
- (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);
}*/
ebiten_EbitenOpenGLView_InputUpdated(-1, -1);
}
- (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);
}*/
int x = location.x / self->screenScale_;
int y = location.y / self->screenScale_;
if (x < 0) {
x = 0;
} else if (self->screenWidth_<= x) {
x = self->screenWidth_ - 1;
}
if (y < 0) {
y = 0;
} else if (self->screenHeight_<= y) {
y = self->screenHeight_ - 1;
}
ebiten_EbitenOpenGLView_InputUpdated(x, y);
}
- (void)setScreenWidth:(size_t)screenWidth
screenHeight:(size_t)screenHeight
screenScale:(size_t)screenScale {
self->screenWidth_ = screenWidth;
self->screenHeight_ = screenHeight;
self->screenScale_ = screenScale;
}
@end

View File

@ -6,12 +6,12 @@
#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)setScreenWidth:(size_t)screenWidth
screenHeight:(size_t)screenHeight
screenScale:(size_t)screenScale;
@end

View File

@ -6,12 +6,12 @@
#import "ebiten_opengl_view.h"
#import "ebiten_window.h"
static NSWindow* generateWindow(size_t width, size_t height) {
static NSWindow* generateWindow(size_t width, size_t height, size_t scale, const char* title) {
EbitenWindow* window = [[EbitenWindow alloc]
initWithSize:NSMakeSize(width, height)];
initWithSize:NSMakeSize(width * scale, height * scale)];
assert(window != nil);
NSRect const rect = NSMakeRect(0, 0, width, height);
NSRect const rect = NSMakeRect(0, 0, width * scale, height * scale);
NSOpenGLPixelFormatAttribute const attributes[] = {
NSOpenGLPFAWindow,
NSOpenGLPFADoubleBuffer,
@ -24,7 +24,11 @@ static NSWindow* generateWindow(size_t width, size_t height) {
EbitenOpenGLView* glView =
[[EbitenOpenGLView alloc] initWithFrame:rect
pixelFormat:format];
[glView setScreenWidth:width
screenHeight:height
screenScale:scale];
[window setContentView:glView];
[window setTitle: [[NSString alloc] initWithUTF8String:title]];
//[window makeFirstResponder:glView];
return window;
@ -32,7 +36,7 @@ static NSWindow* generateWindow(size_t width, size_t height) {
void Run(size_t width, size_t height, size_t scale, const char* title) {
@autoreleasepool {
NSWindow* window = generateWindow(width * scale, height * scale);
NSWindow* window = generateWindow(width, height, scale, title);
EbitenController* controller = [[EbitenController alloc]
initWithWindow:window];
NSApplication* app = [NSApplication sharedApplication];

View File

@ -78,13 +78,10 @@ func idle() {
}
func new(screenWidth, screenHeight, screenScale int, title string) *GlutUI {
graphicsDevice := opengl.NewDevice(
screenWidth, screenHeight, screenScale)
ui := &GlutUI{
glutInputting: make(chan glutInputEvent, 10),
graphicsDevice: graphicsDevice,
updating: make(chan func(graphics.Context)),
updated: make(chan bool),
glutInputting: make(chan glutInputEvent, 10),
updating: make(chan func(graphics.Context)),
updated: make(chan bool),
}
cargs := []*C.char{}
@ -109,11 +106,6 @@ func new(screenWidth, screenHeight, screenScale int, title string) *GlutUI {
defer C.free(unsafe.Pointer(cTitle))
C.glutCreateWindow(cTitle)
// Set the callbacks
C.setGlutFuncs()
graphicsDevice.Init()
return ui
}
@ -121,6 +113,11 @@ func Run(game ebiten.Game, screenWidth, screenHeight, screenScale int, title str
ui := new(screenWidth, screenHeight, screenScale, title)
currentUI = ui
graphicsDevice := opengl.NewDevice(
screenWidth, screenHeight, screenScale)
ui.graphicsDevice = graphicsDevice
graphicsDevice.Init()
game.Init(ui.graphicsDevice.TextureFactory())
input := make(chan ebiten.InputState)
@ -170,6 +167,9 @@ func Run(game ebiten.Game, screenWidth, screenHeight, screenScale int, title str
os.Exit(0)
}()
// Set the callbacks
C.setGlutFuncs()
C.glutMainLoop()
}