Ejemplo n.º 1
0
func windowDraw(w *C.ANativeWindow, queue *C.AInputQueue, donec chan struct{}) (done bool) {
	// Android can send a windowRedrawNeeded event any time, including
	// in the middle of a paint cycle. The redraw event may have changed
	// the size of the screen, so any partial painting is now invalidated.
	// We must also not return to Android (via sending on windowRedrawDone)
	// until a complete paint with the new configuration is complete.
	//
	// When a windowRedrawNeeded request comes in, we increment redrawGen
	// (Gen is short for generation number), and do not make a paint cycle
	// visible on <-endPaint unless paintGen agrees. If possible,
	// windowRedrawDone is signalled, allowing onNativeWindowRedrawNeeded
	// to return.
	var redrawGen, paintGen uint32
	for {
		processEvents(queue)
		select {
		case <-donec:
			return true
		case cfg := <-windowConfigChange:
			// TODO save orientation
			pixelsPerPt = cfg.pixelsPerPt
		case w := <-windowRedrawNeeded:
			sendLifecycle(lifecycle.StageFocused)
			widthPx := int(C.ANativeWindow_getWidth(w))
			heightPx := int(C.ANativeWindow_getHeight(w))
			eventsIn <- config.Event{
				WidthPx:     widthPx,
				HeightPx:    heightPx,
				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
				PixelsPerPt: pixelsPerPt,
			}
			if paintGen == 0 {
				paintGen++
				C.createEGLWindow(w)
				eventsIn <- paint.Event{}
			}
			redrawGen++
		case <-windowDestroyed:
			sendLifecycle(lifecycle.StageAlive)
			return false
		case <-gl.WorkAvailable:
			gl.DoWork()
		case <-endPaint:
			if paintGen == redrawGen {
				// eglSwapBuffers blocks until vsync.
				C.eglSwapBuffers(C.display, C.surface)
				select {
				case windowRedrawDone <- struct{}{}:
				default:
				}
			}
			paintGen = redrawGen
			eventsIn <- paint.Event{}
		}
	}
}
Ejemplo n.º 2
0
func Initialize(win unsafe.Pointer, configAttr, contextAttr []int32) *platform.EGLState {
	eglState := new(platform.EGLState)
	eglState.Display = getEGLDisp(egl.DEFAULT_DISPLAY)
	eglState.Config = chooseEGLConfig(eglState.Display, configAttr)
	eglState.VisualId = getEGLNativeVisualId(eglState.Display, eglState.Config)
	C.ANativeWindow_setBuffersGeometry((*[0]byte)(win), 0, 0, C.int32_t(eglState.VisualId))
	eglState.Surface = EGLCreateWindowSurface(eglState.Display, eglState.Config, egl.NativeWindowType(win))

	egl.BindAPI(egl.OPENGL_ES_API)
	eglState.Context = egl.CreateContext(eglState.Display, eglState.Config, egl.NO_CONTEXT, &contextAttr[0])

	eglState.SurfaceWidth = int(C.ANativeWindow_getWidth((*C.ANativeWindow)(win)))
	eglState.SurfaceHeight = int(C.ANativeWindow_getHeight((*C.ANativeWindow)(win)))

	return eglState
}
Ejemplo n.º 3
0
func mainUI(vm, jniEnv, ctx uintptr) error {
	env := (*C.JNIEnv)(unsafe.Pointer(jniEnv)) // not a Go heap pointer

	donec := make(chan struct{})
	go func() {
		mainUserFn(app{})
		close(donec)
	}()

	var q *C.AInputQueue
	var pixelsPerPt float32
	var orientation size.Orientation

	// Android can send a windowRedrawNeeded event any time, including
	// in the middle of a paint cycle. The redraw event may have changed
	// the size of the screen, so any partial painting is now invalidated.
	// We must also not return to Android (via sending on windowRedrawDone)
	// until a complete paint with the new configuration is complete.
	//
	// When a windowRedrawNeeded request comes in, we increment redrawGen
	// (Gen is short for generation number), and do not make a paint cycle
	// visible on <-endPaint unless Generation agrees. If possible,
	// windowRedrawDone is signalled, allowing onNativeWindowRedrawNeeded
	// to return.
	var redrawGen uint32

	for {
		if q != nil {
			processEvents(env, q)
		}
		select {
		case <-windowCreated:
		case q = <-inputQueue:
		case <-donec:
			return nil
		case cfg := <-windowConfigChange:
			pixelsPerPt = cfg.pixelsPerPt
			orientation = cfg.orientation
		case w := <-windowRedrawNeeded:
			if C.surface == nil {
				if errStr := C.createEGLSurface(w); errStr != nil {
					return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
				}
			}
			sendLifecycle(lifecycle.StageFocused)
			widthPx := int(C.ANativeWindow_getWidth(w))
			heightPx := int(C.ANativeWindow_getHeight(w))
			eventsIn <- size.Event{
				WidthPx:     widthPx,
				HeightPx:    heightPx,
				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
				PixelsPerPt: pixelsPerPt,
				Orientation: orientation,
			}
			redrawGen++
			eventsIn <- paint.Event{redrawGen}
		case <-windowDestroyed:
			if C.surface != nil {
				if errStr := C.destroyEGLSurface(); errStr != nil {
					return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
				}
			}
			C.surface = nil
			sendLifecycle(lifecycle.StageAlive)
		case <-gl.WorkAvailable:
			gl.DoWork()
		case p := <-endPaint:
			if p.Generation != redrawGen {
				continue
			}
			if C.surface != nil {
				// eglSwapBuffers blocks until vsync.
				if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
					log.Printf("app: failed to swap buffers (%s)", eglGetError())
				}
			}
			select {
			case windowRedrawDone <- struct{}{}:
			default:
			}
			if C.surface != nil {
				redrawGen++
				eventsIn <- paint.Event{redrawGen}
			}
		}
	}
}
Ejemplo n.º 4
0
func main(f func(App)) {
	// Preserve this OS thread for the GL context created below.
	runtime.LockOSThread()

	donec := make(chan struct{})
	go func() {
		f(app{})
		close(donec)
	}()

	var q *C.AInputQueue

	// Android can send a windowRedrawNeeded event any time, including
	// in the middle of a paint cycle. The redraw event may have changed
	// the size of the screen, so any partial painting is now invalidated.
	// We must also not return to Android (via sending on windowRedrawDone)
	// until a complete paint with the new configuration is complete.
	//
	// When a windowRedrawNeeded request comes in, we increment redrawGen
	// (Gen is short for generation number), and do not make a paint cycle
	// visible on <-endPaint unless Generation agrees. If possible,
	// windowRedrawDone is signalled, allowing onNativeWindowRedrawNeeded
	// to return.
	var redrawGen uint32

	for {
		if q != nil {
			processEvents(q)
		}
		select {
		case <-windowCreated:
		case q = <-inputQueue:
		case <-donec:
			return
		case cfg := <-windowConfigChange:
			// TODO save orientation
			pixelsPerPt = cfg.pixelsPerPt
		case w := <-windowRedrawNeeded:
			newWindow := C.surface == nil
			if newWindow {
				if errStr := C.createEGLSurface(w); errStr != nil {
					log.Printf("app: %s (%s)", C.GoString(errStr), eglGetError())
					return
				}
			}
			sendLifecycle(lifecycle.StageFocused)
			widthPx := int(C.ANativeWindow_getWidth(w))
			heightPx := int(C.ANativeWindow_getHeight(w))
			eventsIn <- config.Event{
				WidthPx:     widthPx,
				HeightPx:    heightPx,
				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
				PixelsPerPt: pixelsPerPt,
			}
			redrawGen++
			if newWindow {
				// New window, begin paint loop.
				eventsIn <- paint.Event{redrawGen}
			}
		case <-windowDestroyed:
			if C.surface != nil {
				if errStr := C.destroyEGLSurface(); errStr != nil {
					log.Printf("app: %s (%s)", C.GoString(errStr), eglGetError())
					return
				}
			}
			C.surface = nil
			sendLifecycle(lifecycle.StageAlive)
		case <-gl.WorkAvailable:
			gl.DoWork()
		case p := <-endPaint:
			if p.Generation != redrawGen {
				continue
			}
			if C.surface != nil {
				// eglSwapBuffers blocks until vsync.
				if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
					log.Printf("app: failed to swap buffers (%s)", eglGetError())
				}
			}
			select {
			case windowRedrawDone <- struct{}{}:
			default:
			}
			if C.surface != nil {
				redrawGen++
				eventsIn <- paint.Event{redrawGen}
			}
		}
	}
}
Ejemplo n.º 5
0
func mainUI(vm, jniEnv, ctx uintptr) error {
	workAvailable := theApp.worker.WorkAvailable()

	donec := make(chan struct{})
	go func() {
		mainUserFn(theApp)
		close(donec)
	}()

	var pixelsPerPt float32
	var orientation size.Orientation

	for {
		select {
		case <-donec:
			return nil
		case cfg := <-windowConfigChange:
			pixelsPerPt = cfg.pixelsPerPt
			orientation = cfg.orientation
		case w := <-windowRedrawNeeded:
			if C.surface == nil {
				if errStr := C.createEGLSurface(w); errStr != nil {
					return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
				}
			}
			theApp.sendLifecycle(lifecycle.StageFocused)
			widthPx := int(C.ANativeWindow_getWidth(w))
			heightPx := int(C.ANativeWindow_getHeight(w))
			theApp.eventsIn <- size.Event{
				WidthPx:     widthPx,
				HeightPx:    heightPx,
				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
				PixelsPerPt: pixelsPerPt,
				Orientation: orientation,
			}
			theApp.eventsIn <- paint.Event{External: true}
		case <-windowDestroyed:
			if C.surface != nil {
				if errStr := C.destroyEGLSurface(); errStr != nil {
					return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
				}
			}
			C.surface = nil
			theApp.sendLifecycle(lifecycle.StageAlive)
		case <-workAvailable:
			theApp.worker.DoWork()
		case <-theApp.publish:
			// TODO: compare a generation number to redrawGen for stale paints?
			if C.surface != nil {
				// eglSwapBuffers blocks until vsync.
				if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
					log.Printf("app: failed to swap buffers (%s)", eglGetError())
				}
			}
			select {
			case windowRedrawDone <- struct{}{}:
			default:
			}
			theApp.publishResult <- PublishResult{}
		}
	}
}
Ejemplo n.º 6
0
func mainUI(vm, jniEnv, ctx uintptr) error {
	var worker gl.Worker
	glctx, worker = gl.NewContext()
	workAvailable := worker.WorkAvailable()

	donec := make(chan struct{})
	go func() {
		mainUserFn(theApp)
		close(donec)
	}()

	var pixelsPerPt float32
	var orientation size.Orientation

	// Android can send a windowRedrawNeeded event any time, including
	// in the middle of a paint cycle. The redraw event may have changed
	// the size of the screen, so any partial painting is now invalidated.
	// We must also not return to Android (via sending on windowRedrawDone)
	// until a complete paint with the new configuration is complete.
	//
	// When a windowRedrawNeeded request comes in, we increment redrawGen
	// (Gen is short for generation number), and do not make a paint cycle
	// visible on <-endPaint unless Generation agrees. If possible,
	// windowRedrawDone is signalled, allowing onNativeWindowRedrawNeeded
	// to return.
	//
	// TODO: is this still needed?
	var redrawGen uint32

	for {
		select {
		case <-donec:
			return nil
		case cfg := <-windowConfigChange:
			pixelsPerPt = cfg.pixelsPerPt
			orientation = cfg.orientation
		case w := <-windowRedrawNeeded:
			if C.surface == nil {
				if errStr := C.createEGLSurface(w); errStr != nil {
					return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
				}
			}
			theApp.sendLifecycle(lifecycle.StageFocused)
			widthPx := int(C.ANativeWindow_getWidth(w))
			heightPx := int(C.ANativeWindow_getHeight(w))
			theApp.eventsIn <- size.Event{
				WidthPx:     widthPx,
				HeightPx:    heightPx,
				WidthPt:     geom.Pt(float32(widthPx) / pixelsPerPt),
				HeightPt:    geom.Pt(float32(heightPx) / pixelsPerPt),
				PixelsPerPt: pixelsPerPt,
				Orientation: orientation,
			}
			redrawGen++
			theApp.eventsIn <- paint.Event{redrawGen}
		case <-windowDestroyed:
			if C.surface != nil {
				if errStr := C.destroyEGLSurface(); errStr != nil {
					return fmt.Errorf("%s (%s)", C.GoString(errStr), eglGetError())
				}
			}
			C.surface = nil
			theApp.sendLifecycle(lifecycle.StageAlive)
		case <-workAvailable:
			worker.DoWork()
		case <-theApp.publish:
			// TODO: compare a generation number to redrawGen for stale paints?
			if C.surface != nil {
				// eglSwapBuffers blocks until vsync.
				if C.eglSwapBuffers(C.display, C.surface) == C.EGL_FALSE {
					log.Printf("app: failed to swap buffers (%s)", eglGetError())
				}
			}
			select {
			case windowRedrawDone <- struct{}{}:
			default:
			}
			theApp.publishResult <- PublishResult{}
		}
	}
}
Ejemplo n.º 7
0
func (win *window) resize(androidWin unsafe.Pointer) {
	width := int(C.ANativeWindow_getWidth((*C.ANativeWindow)(androidWin)))
	height := int(C.ANativeWindow_getHeight((*C.ANativeWindow)(androidWin)))
	win.eglState.SurfaceWidth = width
	win.eglState.SurfaceHeight = height
}
Ejemplo n.º 8
0
// GetSize returns the dimension of the rendering surface.
func (win *window) GetSize() (int, int) {
	win.eglState.SurfaceWidth = int(C.ANativeWindow_getWidth((*C.ANativeWindow)(win.window)))
	win.eglState.SurfaceHeight = int(C.ANativeWindow_getHeight((*C.ANativeWindow)(win.window)))
	return win.eglState.SurfaceWidth, win.eglState.SurfaceHeight
}