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
This commit is contained in:
parent
659ad767f0
commit
5217175bab
110
app/darwin.go
Normal file
110
app/darwin.go
Normal file
@ -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 <Cocoa/Cocoa.h>
|
||||
#import <OpenGL/gl.h>
|
||||
|
||||
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()
|
||||
}
|
127
app/darwin.m
Normal file
127
app/darwin.m
Normal file
@ -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 <stdio.h>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <OpenGL/gl.h>
|
||||
#import <QuartzCore/CVReturn.h>
|
||||
#import <QuartzCore/CVBase.h>
|
||||
|
||||
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];
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user