2014-09-29 03:22:23 +00:00
|
|
|
// 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
|
|
|
|
|
|
|
|
package app
|
|
|
|
|
2014-10-12 22:24:05 +00:00
|
|
|
// 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.
|
|
|
|
|
2014-09-29 03:22:23 +00:00
|
|
|
/*
|
|
|
|
#cgo CFLAGS: -x objective-c
|
|
|
|
#cgo LDFLAGS: -framework Cocoa -framework OpenGL -framework QuartzCore
|
|
|
|
#import <Cocoa/Cocoa.h>
|
|
|
|
#import <OpenGL/gl.h>
|
2014-10-23 00:24:05 +00:00
|
|
|
#include <pthread.h>
|
2014-09-29 03:22:23 +00:00
|
|
|
|
|
|
|
void glGenVertexArrays(GLsizei n, GLuint* array);
|
|
|
|
void glBindVertexArray(GLuint array);
|
|
|
|
|
|
|
|
void runApp(void);
|
2015-05-28 10:08:52 +00:00
|
|
|
void makeCurrentContext(GLintptr);
|
2014-09-29 03:22:23 +00:00
|
|
|
double backingScaleFactor();
|
2014-10-23 00:24:05 +00:00
|
|
|
uint64 threadID();
|
|
|
|
|
2014-09-29 03:22:23 +00:00
|
|
|
*/
|
|
|
|
import "C"
|
|
|
|
import (
|
2014-10-23 00:24:05 +00:00
|
|
|
"log"
|
2014-09-29 03:22:23 +00:00
|
|
|
"runtime"
|
|
|
|
"sync"
|
|
|
|
|
2014-11-09 21:55:57 +00:00
|
|
|
"golang.org/x/mobile/event"
|
|
|
|
"golang.org/x/mobile/geom"
|
|
|
|
"golang.org/x/mobile/gl"
|
2014-09-29 03:22:23 +00:00
|
|
|
)
|
|
|
|
|
2014-10-23 00:24:05 +00:00
|
|
|
var initThreadID uint64
|
|
|
|
|
2014-09-29 03:22:23 +00:00
|
|
|
func init() {
|
2014-10-23 00:24:05 +00:00
|
|
|
// Lock the goroutine responsible for initialization to an OS thread.
|
|
|
|
// This means the goroutine running main (and calling the run function
|
|
|
|
// below) is locked to the OS thread that started the program. This is
|
|
|
|
// necessary for the correct delivery of Cocoa events to the process.
|
|
|
|
//
|
|
|
|
// A discussion on this topic:
|
|
|
|
// https://groups.google.com/forum/#!msg/golang-nuts/IiWZ2hUuLDA/SNKYYZBelsYJ
|
2014-09-29 03:22:23 +00:00
|
|
|
runtime.LockOSThread()
|
2014-10-23 00:24:05 +00:00
|
|
|
initThreadID = uint64(C.threadID())
|
2014-09-29 03:22:23 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 11:44:56 +00:00
|
|
|
func main(f func(App) error) error {
|
2014-10-23 00:24:05 +00:00
|
|
|
if tid := uint64(C.threadID()); tid != initThreadID {
|
2015-06-27 11:44:56 +00:00
|
|
|
log.Fatalf("app.Main called on thread %d, but app.init ran on %d", tid, initThreadID)
|
2014-10-23 00:24:05 +00:00
|
|
|
}
|
2015-06-27 11:44:56 +00:00
|
|
|
|
|
|
|
var err error
|
|
|
|
go func() {
|
|
|
|
err = f(app{})
|
|
|
|
// TODO(crawshaw): trigger runApp to return
|
|
|
|
}()
|
|
|
|
|
2014-09-29 03:22:23 +00:00
|
|
|
C.runApp()
|
2015-06-27 11:44:56 +00:00
|
|
|
return err
|
2014-09-29 03:22:23 +00:00
|
|
|
}
|
|
|
|
|
2015-06-27 11:44:56 +00:00
|
|
|
var windowHeight geom.Pt
|
|
|
|
|
2014-09-29 03:22:23 +00:00
|
|
|
//export setGeom
|
2015-06-27 11:44:56 +00:00
|
|
|
func setGeom(ppp float32, width, height int) {
|
|
|
|
pixelsPerPt = ppp
|
|
|
|
windowHeight = geom.Pt(float32(height) / pixelsPerPt)
|
|
|
|
eventsIn <- event.Config{
|
|
|
|
Width: geom.Pt(float32(width) / pixelsPerPt),
|
|
|
|
Height: windowHeight,
|
|
|
|
PixelsPerPt: pixelsPerPt,
|
2015-05-05 13:52:19 +00:00
|
|
|
}
|
2014-09-29 03:22:23 +00:00
|
|
|
}
|
|
|
|
|
2014-12-21 17:00:15 +00:00
|
|
|
var touchEvents struct {
|
2014-10-23 00:24:05 +00:00
|
|
|
sync.Mutex
|
|
|
|
pending []event.Touch
|
|
|
|
}
|
2014-09-29 03:22:23 +00:00
|
|
|
|
|
|
|
func sendTouch(ty event.TouchType, x, y float32) {
|
2015-06-27 11:44:56 +00:00
|
|
|
eventsIn <- event.Touch{
|
2014-12-21 17:00:15 +00:00
|
|
|
ID: 0,
|
2014-09-29 03:22:23 +00:00
|
|
|
Type: ty,
|
|
|
|
Loc: geom.Point{
|
2015-06-27 11:44:56 +00:00
|
|
|
X: geom.Pt(x / pixelsPerPt),
|
|
|
|
Y: windowHeight - geom.Pt(y/pixelsPerPt),
|
2014-09-29 03:22:23 +00:00
|
|
|
},
|
2015-06-27 11:44:56 +00:00
|
|
|
}
|
2014-09-29 03:22:23 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//export eventMouseDown
|
|
|
|
func eventMouseDown(x, y float32) { sendTouch(event.TouchStart, x, y) }
|
|
|
|
|
2014-10-23 00:24:05 +00:00
|
|
|
//export eventMouseDragged
|
|
|
|
func eventMouseDragged(x, y float32) { sendTouch(event.TouchMove, x, y) }
|
2014-09-29 03:22:23 +00:00
|
|
|
|
|
|
|
//export eventMouseEnd
|
|
|
|
func eventMouseEnd(x, y float32) { sendTouch(event.TouchEnd, x, y) }
|
|
|
|
|
2015-05-28 10:08:52 +00:00
|
|
|
var startedgl = false
|
|
|
|
|
2014-09-29 03:22:23 +00:00
|
|
|
//export drawgl
|
|
|
|
func drawgl(ctx C.GLintptr) {
|
2015-05-28 10:08:52 +00:00
|
|
|
if !startedgl {
|
|
|
|
startedgl = true
|
2015-06-27 11:44:56 +00:00
|
|
|
C.makeCurrentContext(ctx)
|
2014-09-29 03:22:23 +00:00
|
|
|
|
2015-06-27 11:44:56 +00:00
|
|
|
// Using attribute arrays in OpenGL 3.3 requires the use of a VBA.
|
|
|
|
// But VBAs don't exist in ES 2. So we bind a default one.
|
|
|
|
var id C.GLuint
|
|
|
|
C.glGenVertexArrays(1, &id)
|
|
|
|
C.glBindVertexArray(id)
|
2015-05-28 10:08:52 +00:00
|
|
|
|
2015-06-27 11:44:56 +00:00
|
|
|
sendLifecycle(event.LifecycleStageFocused)
|
2014-09-29 03:22:23 +00:00
|
|
|
}
|
|
|
|
|
2014-10-12 22:24:05 +00:00
|
|
|
// TODO: is the library or the app responsible for clearing the buffers?
|
2014-09-29 03:22:23 +00:00
|
|
|
gl.ClearColor(0, 0, 0, 1)
|
|
|
|
gl.Clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)
|
2015-06-27 11:44:56 +00:00
|
|
|
|
|
|
|
eventsIn <- event.Draw{}
|
|
|
|
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-gl.WorkAvailable:
|
|
|
|
gl.DoWork()
|
|
|
|
case <-endDraw:
|
|
|
|
C.CGLFlushDrawable(C.CGLGetCurrentContext())
|
|
|
|
return
|
2015-05-05 13:52:19 +00:00
|
|
|
}
|
2014-10-12 22:24:05 +00:00
|
|
|
}
|
2014-09-29 03:22:23 +00:00
|
|
|
}
|