From 5217175bab5d0d563c4d3f89df1108fed1760173 Mon Sep 17 00:00:00 2001 From: David Crawshaw Date: Mon, 29 Sep 2014 13:22:23 +1000 Subject: [PATCH] go.mobile/app: darwin window drawing support for debugging This lets you run really simple apps in a window on an OS X machine. It's not an official target, but slightly more productive than waiting for an apk install when working on the sprite package. LGTM=adg R=golang-codereviews, adg CC=golang-codereviews https://golang.org/cl/147910043 --- app/darwin.go | 110 +++++++++++++++++++++++++++++++++++++++++++ app/darwin.m | 127 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 237 insertions(+) create mode 100644 app/darwin.go create mode 100644 app/darwin.m diff --git a/app/darwin.go b/app/darwin.go new file mode 100644 index 0000000..bf62e52 --- /dev/null +++ b/app/darwin.go @@ -0,0 +1,110 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Simple on-screen app debugging for OS X. Not an officially supported +// development target for apps, as screens with mice are very different +// than screens with touch panels. + +// +build darwin + +package app + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Cocoa -framework OpenGL -framework QuartzCore +#import +#import + +void glGenVertexArrays(GLsizei n, GLuint* array); +void glBindVertexArray(GLuint array); + +void runApp(void); +void lockContext(GLintptr); +void unlockContext(GLintptr); +double backingScaleFactor(); +*/ +import "C" +import ( + "log" + "runtime" + "sync" + + "code.google.com/p/go.mobile/event" + "code.google.com/p/go.mobile/geom" + "code.google.com/p/go.mobile/gl" +) + +func init() { + runtime.LockOSThread() +} + +func run(callbacks Callbacks) { + cb = callbacks + C.runApp() +} + +//export setGeom +func setGeom(scale, width, height float64) { + // Macs default to 72 DPI, so scales are equivalent. + geom.Scale = float32(scale) + geom.Width = geom.Pt(width) + geom.Height = geom.Pt(height) + log.Printf("geom: Scale=%.2f, Width=%v, Height=%v", geom.Scale, geom.Width, geom.Height) +} + +func initGL() { + // Using attribute arrays in OpenGL 3.3 requires the use of a VBA. + // But VBAs don't exist in ES 2. So we bind one default one. + var id C.GLuint + C.glGenVertexArrays(1, &id) + C.glBindVertexArray(id) +} + +var cb Callbacks +var initGLOnce sync.Once +var events = make(chan event.Touch, 1<<6) + +func sendTouch(ty event.TouchType, x, y float32) { + events <- event.Touch{ + Type: ty, + Loc: geom.Point{ + X: geom.Pt(x), + Y: geom.Height - geom.Pt(y), + }, + } +} + +//export eventMouseDown +func eventMouseDown(x, y float32) { sendTouch(event.TouchStart, x, y) } + +//export eventMouseMove +func eventMouseMove(x, y float32) { sendTouch(event.TouchMove, x, y) } + +//export eventMouseEnd +func eventMouseEnd(x, y float32) { sendTouch(event.TouchEnd, x, y) } + +//export drawgl +func drawgl(ctx C.GLintptr) { + runtime.LockOSThread() + C.lockContext(ctx) + + initGLOnce.Do(initGL) + +loop: + for { + select { + case e := <-events: + cb.Touch(e) + default: + break loop + } + } + + gl.ClearColor(0, 0, 0, 1) + gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT) + cb.Draw() + + C.unlockContext(ctx) + runtime.UnlockOSThread() +} diff --git a/app/darwin.m b/app/darwin.m new file mode 100644 index 0000000..ab377e3 --- /dev/null +++ b/app/darwin.m @@ -0,0 +1,127 @@ +// Copyright 2014 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build darwin + +#include "_cgo_export.h" +#include + +#import +#import +#import +#import +#import + +static CVReturn displayLinkDraw(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext) +{ + NSOpenGLView* view = displayLinkContext; + NSOpenGLContext *currentContext = [view openGLContext]; + drawgl((GLintptr)currentContext); + return kCVReturnSuccess; +} + +void lockContext(GLintptr context) { + NSOpenGLContext* ctx = (NSOpenGLContext*)context; + [ctx makeCurrentContext]; + CGLLockContext([ctx CGLContextObj]); +} + +void unlockContext(GLintptr context) { + NSOpenGLContext* ctx = (NSOpenGLContext*)context; + [ctx flushBuffer]; + CGLUnlockContext([ctx CGLContextObj]); + +} + + +@interface MobileGLView : NSOpenGLView +{ + CVDisplayLinkRef displayLink; +} +@end + +@implementation MobileGLView +- (void)prepareOpenGL { + [self setWantsBestResolutionOpenGLSurface:true]; + GLint swapInt = 1; + [[self openGLContext] setValues:&swapInt forParameter:NSOpenGLCPSwapInterval]; + + CVDisplayLinkCreateWithActiveCGDisplays(&displayLink); + CVDisplayLinkSetOutputCallback(displayLink, &displayLinkDraw, self); + + CGLContextObj cglContext = [[self openGLContext] CGLContextObj]; + CGLPixelFormatObj cglPixelFormat = [[self pixelFormat] CGLPixelFormatObj]; + CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, cglContext, cglPixelFormat); + CVDisplayLinkStart(displayLink); +} + +- (void)reshape { + NSRect r = [self bounds]; + double scale = [[NSScreen mainScreen] backingScaleFactor]; + setGeom(scale, r.size.width, r.size.height); +} + +- (void)mouseDown:(NSEvent *)theEvent { + NSPoint p = [theEvent locationInWindow]; + eventMouseDown(p.x, p.y); +} + +- (void)mouseUp:(NSEvent *)theEvent { + NSPoint p = [theEvent locationInWindow]; + eventMouseEnd(p.x, p.y); +} + +- (void)mouseMoved:(NSEvent *)theEvent { + NSPoint p = [theEvent locationInWindow]; + eventMouseMove(p.x, p.y); +} +@end + +void +runApp(void) { + [NSAutoreleasePool new]; + [NSApplication sharedApplication]; + [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + + id menuBar = [[NSMenu new] autorelease]; + id menuItem = [[NSMenuItem new] autorelease]; + [menuBar addItem:menuItem]; + [NSApp setMainMenu:menuBar]; + + id menu = [[NSMenu new] autorelease]; + id name = [[NSProcessInfo processInfo] processName]; + id quitMenuItem = [[[NSMenuItem alloc] initWithTitle:@"Quit" + action:@selector(terminate:) keyEquivalent:@"q"] + autorelease]; + [menu addItem:quitMenuItem]; + [menuItem setSubmenu:menu]; + + NSRect rect = NSMakeRect(0, 0, 200, 200); + + id window = [[[NSWindow alloc] initWithContentRect:rect + styleMask:NSTitledWindowMask + backing:NSBackingStoreBuffered + defer:NO] + autorelease]; + [window setStyleMask:[window styleMask] | NSResizableWindowMask]; + [window cascadeTopLeftFromPoint:NSMakePoint(20,20)]; + [window makeKeyAndOrderFront:nil]; + [window setTitle:name]; + + NSOpenGLPixelFormatAttribute attr[] = { + NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core, + NSOpenGLPFAColorSize, 24, + NSOpenGLPFAAlphaSize, 8, + NSOpenGLPFADepthSize, 16, + NSOpenGLPFAAccelerated, + NSOpenGLPFADoubleBuffer, + 0 + }; + id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr]; + id view = [[MobileGLView alloc] initWithFrame:rect pixelFormat:pixFormat]; + [window setContentView:view]; + + [NSApp activateIgnoringOtherApps:YES]; + [NSApp run]; +}