go.mobile/app: an exceedingly simple display loop
Missing many features (like event processing). This is just enough to get example/basic working. LGTM=nigeltao R=golang-codereviews, capnm9, bryanturley, nigeltao, crawshaw CC=golang-codereviews https://golang.org/cl/131030043
This commit is contained in:
Родитель
1d1714ebe9
Коммит
e27dbf7bf9
|
@ -30,7 +30,10 @@ int go_started;
|
|||
JavaVM* current_vm;
|
||||
*/
|
||||
import "C"
|
||||
import "unsafe"
|
||||
import (
|
||||
"runtime"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
//export onStart
|
||||
func onStart(activity *C.ANativeActivity) {
|
||||
|
@ -63,6 +66,7 @@ func onWindowFocusChanged(activity *C.ANativeActivity, hasFocus int) {
|
|||
|
||||
//export onNativeWindowCreated
|
||||
func onNativeWindowCreated(activity *C.ANativeActivity, w *C.ANativeWindow) {
|
||||
windowCreated <- w
|
||||
}
|
||||
|
||||
//export onNativeWindowResized
|
||||
|
@ -75,6 +79,7 @@ func onNativeWindowRedrawNeeded(activity *C.ANativeActivity, window *C.ANativeWi
|
|||
|
||||
//export onNativeWindowDestroyed
|
||||
func onNativeWindowDestroyed(activity *C.ANativeActivity, window *C.ANativeWindow) {
|
||||
windowDestroyed <- true
|
||||
}
|
||||
|
||||
//export onInputQueueCreated
|
||||
|
@ -102,7 +107,15 @@ func onLowMemory(activity *C.ANativeActivity) {
|
|||
// bindings access to the JNI *JavaVM object.
|
||||
var JavaInit func(javaVM uintptr)
|
||||
|
||||
func run() {
|
||||
var (
|
||||
windowDestroyed = make(chan bool)
|
||||
windowCreated = make(chan *C.ANativeWindow)
|
||||
)
|
||||
|
||||
func run(cb Callbacks) {
|
||||
// We want to keep the event loop on a consistent OS thread.
|
||||
runtime.LockOSThread()
|
||||
|
||||
ctag := C.CString("Go")
|
||||
cstr := C.CString("app.Run")
|
||||
C.__android_log_write(C.ANDROID_LOG_INFO, ctag, cstr)
|
||||
|
@ -119,5 +132,10 @@ func run() {
|
|||
C.pthread_cond_signal(&C.go_started_cond)
|
||||
C.pthread_mutex_unlock(&C.go_started_mu)
|
||||
|
||||
select {}
|
||||
for {
|
||||
select {
|
||||
case w := <-windowCreated:
|
||||
windowDrawLoop(cb, w)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
22
app/app.go
22
app/app.go
|
@ -4,16 +4,22 @@
|
|||
|
||||
package app
|
||||
|
||||
// Run starts the process.
|
||||
func Run() {
|
||||
run()
|
||||
// Run starts the app.
|
||||
//
|
||||
// It must be called directly from from the main function and will
|
||||
// block until the app exits.
|
||||
func Run(cb Callbacks) {
|
||||
run(cb)
|
||||
}
|
||||
|
||||
// Draw is called by the render loop to draw the screen.
|
||||
//
|
||||
// Drawing is done into a framebuffer, which is then swapped onto the
|
||||
// screen when Draw returns. It is called 60 times a second.
|
||||
var Draw func()
|
||||
// Callbacks is the set of functions called by the app.
|
||||
type Callbacks struct {
|
||||
// Draw is called by the render loop to draw the screen.
|
||||
//
|
||||
// Drawing is done into a framebuffer, which is then swapped onto the
|
||||
// screen when Draw returns. It is called 60 times a second.
|
||||
Draw func()
|
||||
}
|
||||
|
||||
/*
|
||||
TODO(crawshaw): Implement.
|
||||
|
|
|
@ -61,8 +61,9 @@ function exits, the app exits.
|
|||
)
|
||||
|
||||
func main() {
|
||||
app.Draw = draw
|
||||
app.Run()
|
||||
app.Run(app.Callbacks{
|
||||
Draw: draw,
|
||||
})
|
||||
}
|
||||
|
||||
func draw() {
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
// 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.
|
||||
|
||||
package app
|
||||
|
||||
/*
|
||||
#cgo android LDFLAGS: -llog -landroid -lEGL -lGLESv2
|
||||
#include <android/log.h>
|
||||
#include <android/native_activity.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <GLES/gl.h>
|
||||
|
||||
// TODO(crawshaw): Test configuration on more devices.
|
||||
const EGLint RGB_888[] = {
|
||||
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||||
EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
|
||||
EGL_BLUE_SIZE, 8,
|
||||
EGL_GREEN_SIZE, 8,
|
||||
EGL_RED_SIZE, 8,
|
||||
EGL_DEPTH_SIZE, 16,
|
||||
EGL_CONFIG_CAVEAT, EGL_NONE,
|
||||
EGL_NONE
|
||||
};
|
||||
|
||||
EGLint windowWidth;
|
||||
EGLint windowHeight;
|
||||
EGLDisplay display;
|
||||
EGLSurface surface;
|
||||
|
||||
#define LOG_ERROR(...) __android_log_print(ANDROID_LOG_ERROR, "Go", __VA_ARGS__)
|
||||
|
||||
void createEGLWindow(ANativeWindow* window) {
|
||||
EGLint numConfigs, format;
|
||||
EGLConfig config;
|
||||
EGLContext context;
|
||||
|
||||
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
|
||||
if (!eglInitialize(display, 0, 0)) {
|
||||
LOG_ERROR("EGL initialize failed");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!eglChooseConfig(display, RGB_888, &config, 1, &numConfigs)) {
|
||||
LOG_ERROR("EGL choose RGB_888 config failed");
|
||||
return;
|
||||
}
|
||||
if (numConfigs <= 0) {
|
||||
LOG_ERROR("EGL no config found");
|
||||
return;
|
||||
}
|
||||
|
||||
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);
|
||||
if (ANativeWindow_setBuffersGeometry(window, 0, 0, format) != 0) {
|
||||
LOG_ERROR("EGL set buffers geometry failed");
|
||||
return;
|
||||
}
|
||||
|
||||
surface = eglCreateWindowSurface(display, config, window, NULL);
|
||||
if (surface == EGL_NO_SURFACE) {
|
||||
LOG_ERROR("EGL create surface failed");
|
||||
return;
|
||||
}
|
||||
|
||||
const EGLint contextAttribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
|
||||
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
|
||||
|
||||
if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
|
||||
LOG_ERROR("eglMakeCurrent failed");
|
||||
return;
|
||||
}
|
||||
|
||||
eglQuerySurface(display, surface, EGL_WIDTH, &windowWidth);
|
||||
eglQuerySurface(display, surface, EGL_HEIGHT, &windowHeight);
|
||||
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glViewport(0, 0, windowWidth, windowHeight);
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
eglSwapBuffers(display, surface);
|
||||
|
||||
GLenum err;
|
||||
if ((err = glGetError()) != GL_NO_ERROR) {
|
||||
LOG_ERROR("GL error in createEGLWindow: 0x%x", err);
|
||||
}
|
||||
}
|
||||
|
||||
#undef LOG_ERROR
|
||||
*/
|
||||
import "C"
|
||||
|
||||
// windowDrawLoop calls Draw at 60 FPS processes input queue events.
|
||||
func windowDrawLoop(cb Callbacks, window *C.ANativeWindow) {
|
||||
C.createEGLWindow(window)
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-windowDestroyed:
|
||||
return
|
||||
// TODO(crawshaw): Event processing goes here.
|
||||
default:
|
||||
cb.Draw()
|
||||
C.eglSwapBuffers(C.display, C.surface)
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче