3dphotoshoot

changeset 0:a4bf2687e406

3d photoshoot initial commit
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 12 May 2015 05:31:21 +0300
parents
children 7eb73ce46dd0
files .hgignore android/Makefile android/manifest.xml.in proj.mk src/android/MainActivity.java src/android/amain.c src/android/android_native_app_glue.c src/android/android_native_app_glue.h src/android/logger.c src/android/logger.h src/game.c src/game.h src/opengl.h src/timer.c src/timer.h
diffstat 15 files changed, 1467 insertions(+), 0 deletions(-) [+]
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/.hgignore	Tue May 12 05:31:21 2015 +0300
     1.3 @@ -0,0 +1,13 @@
     1.4 +\.o$
     1.5 +\.d$
     1.6 +\.swp$
     1.7 +^3dphotoshoot$
     1.8 +^android/bin/
     1.9 +^android/src/
    1.10 +^android/libs/
    1.11 +^android/res/
    1.12 +^android/gen/
    1.13 +\.properties$
    1.14 +\.apk$
    1.15 +^android/proguard-project\.txt
    1.16 +\.xml$
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/android/Makefile	Tue May 12 05:31:21 2015 +0300
     2.3 @@ -0,0 +1,88 @@
     2.4 +root = ..
     2.5 +include $(root)/proj.mk
     2.6 +
     2.7 +# --- android settings ---
     2.8 +android_platform = android-22
     2.9 +name = $(bin)
    2.10 +pkgprefix = com.mutantstargoat
    2.11 +# ------------------------
    2.12 +
    2.13 +src += $(wildcard $(root)/src/android/*.c)
    2.14 +
    2.15 +obj = $(src:.c=.o) $(ccsrc:.cc=.o)
    2.16 +lib = libs/armeabi/lib$(name).so
    2.17 +apk-release = bin/$(name).apk
    2.18 +apk-debug = bin/$(name)-debug.apk
    2.19 +
    2.20 +pkg = $(pkgprefix).$(name)
    2.21 +act = $(pkg).MainActivity
    2.22 +
    2.23 +CC = arm-linux-androideabi-gcc
    2.24 +CXX = arm-linux-androideabi-g++
    2.25 +
    2.26 +android_usr = $(NDK)/platforms/$(android_platform)/arch-arm/usr
    2.27 +android_inc = -I$(native_app_glue_dir)
    2.28 +android_libs = -llog -landroid -lEGL -lGLESv1_CM
    2.29 +
    2.30 +CFLAGS = -std=c99 -Wall -g -DAPP_NAME=\"$(name)\" -march=armv7-a -mfloat-abi=softfp \
    2.31 +		 $(android_inc) -I$(root)/src/android -I$(root)/src/gles $(incpaths)
    2.32 +LDFLAGS = -Wl,--fix-cortex-a8 -Wl,-z,defs $(android_libs) $(libpaths) -lm
    2.33 +
    2.34 +.PHONY: debug
    2.35 +debug: $(apk-debug)
    2.36 +
    2.37 +.PHONY: release
    2.38 +release: $(apk-release)
    2.39 +
    2.40 +$(apk-debug): $(lib) AndroidManifest.xml
    2.41 +	ant debug
    2.42 +
    2.43 +$(apk-release): $(lib) AndroidManifest.xml
    2.44 +	ant release
    2.45 +
    2.46 +.PHONY: lib
    2.47 +lib: $(lib)
    2.48 +
    2.49 +$(lib): $(obj)
    2.50 +	@mkdir -p libs/armeabi
    2.51 +	$(CC) -o $@ -shared $(obj) $(LDFLAGS)
    2.52 +
    2.53 +ant_files = *.xml *.properties proguard-project.txt
    2.54 +ant_dirs = bin libs res obj src gen
    2.55 +
    2.56 +.PHONY: clean
    2.57 +clean:
    2.58 +	rm -f $(obj) $(lib) $(apk-release) $(apk-debug) $(ant_files)
    2.59 +	rm -rf $(ant_dirs)
    2.60 +
    2.61 +.PHONY: install
    2.62 +install: install-debug
    2.63 +
    2.64 +.PHONY: install-debug
    2.65 +install-debug:
    2.66 +	adb install -r $(apk-debug)
    2.67 +
    2.68 +.PHONY: install-release
    2.69 +install-release:
    2.70 +	adb install -r $(apk-release)
    2.71 +
    2.72 +.PHONY: uninstall
    2.73 +uninstall:
    2.74 +	adb uninstall $(pkg)
    2.75 +
    2.76 +.PHONY: run
    2.77 +run:
    2.78 +	adb shell am start -n $(pkg)/$(act)
    2.79 +
    2.80 +.PHONY: stop
    2.81 +stop:
    2.82 +	adb shell am force-stop $(pkg)
    2.83 +
    2.84 +AndroidManifest.xml:
    2.85 +	android create project -p . -t $(android_platform) -k $(pkg) -a NativeActivity -n $(name)
    2.86 +	cat manifest.xml.in | sed 's/$$APPNAME/$(name)/g' | sed 's/$$APPTITLE/$(title)/g' >$@
    2.87 +	cd src && rm -f *.java && ln -s ../../src/android/*.java .
    2.88 +
    2.89 +.PHONY: update-project
    2.90 +update-project: build.xml
    2.91 +	android update project -p . -t $(android_platform)
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/android/manifest.xml.in	Tue May 12 05:31:21 2015 +0300
     3.3 @@ -0,0 +1,22 @@
     3.4 +<?xml version="1.0" encoding="utf-8"?>
     3.5 +<manifest xmlns:android="http://schemas.android.com/apk/res/android"
     3.6 +	package="com.mutantstargoat.$APPNAME"
     3.7 +	android:versionCode="1"
     3.8 +	android:versionName="1.0">
     3.9 +
    3.10 +	<uses-sdk android:minSdkVersion="9"/>
    3.11 +
    3.12 +	<application android:label="$APPNAME" android:debuggable="true">
    3.13 +			<!-- android:icon="@drawable/ic_launcher" -->
    3.14 +
    3.15 +		<activity android:name="MainActivity" android:label="$APPTITLE">
    3.16 +
    3.17 +			<meta-data android:name="android.app.lib_name" android:value="$APPNAME"/>
    3.18 +
    3.19 +			<intent-filter>
    3.20 +				<action android:name="android.intent.action.MAIN" />
    3.21 +				<category android:name="android.intent.category.LAUNCHER" />
    3.22 +			</intent-filter>
    3.23 +		</activity>
    3.24 +	</application>
    3.25 +</manifest>
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/proj.mk	Tue May 12 05:31:21 2015 +0300
     4.3 @@ -0,0 +1,8 @@
     4.4 +root ?= $(shell pwd)
     4.5 +
     4.6 +src = $(wildcard $(root)/src/*.c)
     4.7 +bin = photoshoot3d
     4.8 +title = 3D Photo Shoot
     4.9 +
    4.10 +incpaths = -I$(root)/src
    4.11 +libpaths =
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/android/MainActivity.java	Tue May 12 05:31:21 2015 +0300
     5.3 @@ -0,0 +1,11 @@
     5.4 +package com.mutantstargoat.photoshoot3d;
     5.5 +
     5.6 +import android.app.NativeActivity;
     5.7 +import android.util.Log;
     5.8 +
     5.9 +public class MainActivity extends NativeActivity {
    5.10 +	final public void foo(String s, int n)
    5.11 +	{
    5.12 +		Log.i("3DPS", s + ": " + n);
    5.13 +	}
    5.14 +}
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/src/android/amain.c	Tue May 12 05:31:21 2015 +0300
     6.3 @@ -0,0 +1,257 @@
     6.4 +#include <stdio.h>
     6.5 +#include <stdlib.h>
     6.6 +#include <EGL/egl.h>
     6.7 +#include "android_native_app_glue.h"
     6.8 +#include "logger.h"
     6.9 +#include "game.h"
    6.10 +#include "timer.h"
    6.11 +
    6.12 +
    6.13 +static void handle_command(struct android_app *app, int32_t cmd);
    6.14 +static int handle_input(struct android_app *app, AInputEvent *ev);
    6.15 +static int handle_touch_input(struct android_app *app, AInputEvent *ev);
    6.16 +static int init_gl(void);
    6.17 +static void destroy_gl(void);
    6.18 +
    6.19 +static EGLDisplay dpy;
    6.20 +static EGLSurface surf;
    6.21 +static EGLContext ctx;
    6.22 +
    6.23 +static struct android_app *app;
    6.24 +static int win_width, win_height;
    6.25 +static int init_done;
    6.26 +
    6.27 +void android_main(struct android_app *app_ptr)
    6.28 +{
    6.29 +	app_dummy();
    6.30 +	app = app_ptr;
    6.31 +
    6.32 +	app->onAppCmd = handle_command;
    6.33 +	app->onInputEvent = handle_input;
    6.34 +
    6.35 +	start_logger();
    6.36 +
    6.37 +	for(;;) {
    6.38 +		int num_events;
    6.39 +		struct android_poll_source *pollsrc;
    6.40 +
    6.41 +		while(ALooper_pollAll(0, 0, &num_events, (void**)&pollsrc) >= 0) {
    6.42 +			if(pollsrc) {
    6.43 +				pollsrc->process(app, pollsrc);
    6.44 +			}
    6.45 +		}
    6.46 +
    6.47 +		if(app->destroyRequested) {
    6.48 +			return;
    6.49 +		}
    6.50 +
    6.51 +		if(init_done) {
    6.52 +			game_display(get_time_msec());
    6.53 +			eglSwapBuffers(dpy, surf);
    6.54 +		}
    6.55 +	}
    6.56 +}
    6.57 +
    6.58 +void set_mouse_pos(int x, int y)
    6.59 +{
    6.60 +}
    6.61 +
    6.62 +void set_mouse_cursor(int enable)
    6.63 +{
    6.64 +}
    6.65 +
    6.66 +static void handle_command(struct android_app *app, int32_t cmd)
    6.67 +{
    6.68 +	switch(cmd) {
    6.69 +	case APP_CMD_SAVE_STATE:
    6.70 +		/* save the application state to be reloaded on restart if needed */
    6.71 +		break;
    6.72 +
    6.73 +	case APP_CMD_INIT_WINDOW:
    6.74 +		if(init_gl() == -1) {
    6.75 +			exit(1);
    6.76 +		}
    6.77 +		/* initialize the application */
    6.78 +		if(game_init() == -1) {
    6.79 +			exit(1);	/* initialization failed, quit */
    6.80 +		}
    6.81 +		init_done = 1;
    6.82 +		break;
    6.83 +
    6.84 +	case APP_CMD_TERM_WINDOW:
    6.85 +		/* cleanup */
    6.86 +		init_done = 0;
    6.87 +		game_shutdown();
    6.88 +		destroy_gl();
    6.89 +		break;
    6.90 +
    6.91 +	case APP_CMD_GAINED_FOCUS:
    6.92 +		/* app focused */
    6.93 +		break;
    6.94 +
    6.95 +	case APP_CMD_LOST_FOCUS:
    6.96 +		/* app lost focus */
    6.97 +		break;
    6.98 +
    6.99 +	case APP_CMD_WINDOW_RESIZED:
   6.100 +	case APP_CMD_CONFIG_CHANGED:
   6.101 +		{
   6.102 +			int nx = ANativeWindow_getWidth(app->window);
   6.103 +			int ny = ANativeWindow_getHeight(app->window);
   6.104 +			if(nx != win_width || ny != win_height) {
   6.105 +				game_reshape(nx, ny);
   6.106 +				win_width = nx;
   6.107 +				win_height = ny;
   6.108 +			}
   6.109 +		}
   6.110 +		break;
   6.111 +
   6.112 +	default:
   6.113 +		break;
   6.114 +	}
   6.115 +}
   6.116 +
   6.117 +static int handle_input(struct android_app *app, AInputEvent *ev)
   6.118 +{
   6.119 +	int evtype = AInputEvent_getType(ev);
   6.120 +
   6.121 +	switch(evtype) {
   6.122 +	case AINPUT_EVENT_TYPE_MOTION:
   6.123 +		return handle_touch_input(app, ev);
   6.124 +
   6.125 +	default:
   6.126 +		break;
   6.127 +	}
   6.128 +	return 0;
   6.129 +}
   6.130 +
   6.131 +#define MAX_TOUCH_IDS	32
   6.132 +
   6.133 +static int handle_touch_input(struct android_app *app, AInputEvent *ev)
   6.134 +{
   6.135 +	int x, y, idx, touch_id;
   6.136 +	unsigned int action;
   6.137 +	static int prev_pos[MAX_TOUCH_IDS][2];
   6.138 +
   6.139 +	action = AMotionEvent_getAction(ev);
   6.140 +
   6.141 +	idx = (action & AMOTION_EVENT_ACTION_POINTER_INDEX_MASK) >>
   6.142 +		AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT;
   6.143 +	touch_id = AMotionEvent_getPointerId(ev, idx);
   6.144 +
   6.145 +	x = AMotionEvent_getX(ev, idx);
   6.146 +	y = AMotionEvent_getY(ev, idx);
   6.147 +
   6.148 +	switch(action & AMOTION_EVENT_ACTION_MASK) {
   6.149 +	case AMOTION_EVENT_ACTION_DOWN:
   6.150 +	case AMOTION_EVENT_ACTION_POINTER_DOWN:
   6.151 +		game_mouse_button(touch_id, 0, 1, x, y);
   6.152 +		if(touch_id < MAX_TOUCH_IDS) {
   6.153 +			prev_pos[touch_id][0] = x;
   6.154 +			prev_pos[touch_id][1] = y;
   6.155 +		}
   6.156 +		break;
   6.157 +
   6.158 +	case AMOTION_EVENT_ACTION_UP:
   6.159 +	case AMOTION_EVENT_ACTION_POINTER_UP:
   6.160 +		game_mouse_button(touch_id, 0, 0, x, y);
   6.161 +		if(touch_id < MAX_TOUCH_IDS) {
   6.162 +			prev_pos[touch_id][0] = x;
   6.163 +			prev_pos[touch_id][1] = y;
   6.164 +		}
   6.165 +		break;
   6.166 +
   6.167 +	case AMOTION_EVENT_ACTION_MOVE:
   6.168 +		{
   6.169 +			int i, pcount = AMotionEvent_getPointerCount(ev);
   6.170 +			for(i=0; i<pcount; i++) {
   6.171 +				int id = AMotionEvent_getPointerId(ev, i);
   6.172 +				if(id < MAX_TOUCH_IDS && x != prev_pos[id][0] && y != prev_pos[id][1]) {
   6.173 +					game_mouse_motion(id, x, y);
   6.174 +					prev_pos[id][0] = x;
   6.175 +					prev_pos[id][1] = y;
   6.176 +				}
   6.177 +			}
   6.178 +		}
   6.179 +		break;
   6.180 +
   6.181 +	default:
   6.182 +		break;
   6.183 +	}
   6.184 +
   6.185 +	return 1;
   6.186 +}
   6.187 +
   6.188 +
   6.189 +static int init_gl(void)
   6.190 +{
   6.191 +	static const int eglattr[] = {
   6.192 +		EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
   6.193 +		EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
   6.194 +		EGL_RED_SIZE, 5,
   6.195 +		EGL_GREEN_SIZE, 5,
   6.196 +		EGL_BLUE_SIZE, 5,
   6.197 +		EGL_DEPTH_SIZE, 16,
   6.198 +		EGL_NONE
   6.199 +	};
   6.200 +	static const int ctxattr[] = { EGL_CONTEXT_CLIENT_VERSION, 1, EGL_NONE };
   6.201 +
   6.202 +	EGLConfig eglcfg;
   6.203 +	int count, vis;
   6.204 +
   6.205 +	dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
   6.206 +	if(!dpy || !eglInitialize(dpy, 0, 0)) {
   6.207 +		fprintf(stderr, "failed to initialize EGL\n");
   6.208 +		destroy_gl();
   6.209 +		return -1;
   6.210 +	}
   6.211 +
   6.212 +	if(!eglChooseConfig(dpy, eglattr, &eglcfg, 1, &count)) {
   6.213 +		fprintf(stderr, "no matching EGL config found\n");
   6.214 +		destroy_gl();
   6.215 +		return -1;
   6.216 +	}
   6.217 +
   6.218 +	/* configure the native window visual according to the chosen EGL config */
   6.219 +	eglGetConfigAttrib(dpy, &eglcfg, EGL_NATIVE_VISUAL_ID, &vis);
   6.220 +	ANativeWindow_setBuffersGeometry(app->window, 0, 0, vis);
   6.221 +
   6.222 +	if(!(surf = eglCreateWindowSurface(dpy, eglcfg, app->window, 0))) {
   6.223 +		fprintf(stderr, "failed to create window\n");
   6.224 +		destroy_gl();
   6.225 +		return -1;
   6.226 +	}
   6.227 +
   6.228 +	if(!(ctx = eglCreateContext(dpy, eglcfg, EGL_NO_CONTEXT, ctxattr))) {
   6.229 +		fprintf(stderr, "failed to create OpenGL ES context\n");
   6.230 +		destroy_gl();
   6.231 +		return -1;
   6.232 +	}
   6.233 +	eglMakeCurrent(dpy, surf, surf, ctx);
   6.234 +
   6.235 +	eglQuerySurface(dpy, surf, EGL_WIDTH, &win_width);
   6.236 +	eglQuerySurface(dpy, surf, EGL_HEIGHT, &win_height);
   6.237 +	game_reshape(win_width, win_height);
   6.238 +
   6.239 +	return 0;
   6.240 +}
   6.241 +
   6.242 +static void destroy_gl(void)
   6.243 +{
   6.244 +	if(!dpy) return;
   6.245 +
   6.246 +	eglMakeCurrent(dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
   6.247 +
   6.248 +	if(ctx) {
   6.249 +		eglDestroyContext(dpy, ctx);
   6.250 +		ctx = 0;
   6.251 +	}
   6.252 +	if(surf) {
   6.253 +		eglDestroySurface(dpy, surf);
   6.254 +		surf = 0;
   6.255 +	}
   6.256 +
   6.257 +	eglTerminate(dpy);
   6.258 +	dpy = 0;
   6.259 +}
   6.260 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/src/android/android_native_app_glue.c	Tue May 12 05:31:21 2015 +0300
     7.3 @@ -0,0 +1,440 @@
     7.4 +/*
     7.5 + * Copyright (C) 2010 The Android Open Source Project
     7.6 + *
     7.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     7.8 + * you may not use this file except in compliance with the License.
     7.9 + * You may obtain a copy of the License at
    7.10 + *
    7.11 + *      http://www.apache.org/licenses/LICENSE-2.0
    7.12 + *
    7.13 + * Unless required by applicable law or agreed to in writing, software
    7.14 + * distributed under the License is distributed on an "AS IS" BASIS,
    7.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    7.16 + * See the License for the specific language governing permissions and
    7.17 + * limitations under the License.
    7.18 + *
    7.19 + */
    7.20 +
    7.21 +#include <jni.h>
    7.22 +
    7.23 +#include <errno.h>
    7.24 +#include <string.h>
    7.25 +#include <unistd.h>
    7.26 +#include <sys/resource.h>
    7.27 +
    7.28 +#include "android_native_app_glue.h"
    7.29 +#include <android/log.h>
    7.30 +
    7.31 +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "threaded_app", __VA_ARGS__))
    7.32 +#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "threaded_app", __VA_ARGS__))
    7.33 +
    7.34 +/* For debug builds, always enable the debug traces in this library */
    7.35 +#ifndef NDEBUG
    7.36 +#  define LOGV(...)  ((void)__android_log_print(ANDROID_LOG_VERBOSE, "threaded_app", __VA_ARGS__))
    7.37 +#else
    7.38 +#  define LOGV(...)  ((void)0)
    7.39 +#endif
    7.40 +
    7.41 +static void free_saved_state(struct android_app* android_app) {
    7.42 +    pthread_mutex_lock(&android_app->mutex);
    7.43 +    if (android_app->savedState != NULL) {
    7.44 +        free(android_app->savedState);
    7.45 +        android_app->savedState = NULL;
    7.46 +        android_app->savedStateSize = 0;
    7.47 +    }
    7.48 +    pthread_mutex_unlock(&android_app->mutex);
    7.49 +}
    7.50 +
    7.51 +int8_t android_app_read_cmd(struct android_app* android_app) {
    7.52 +    int8_t cmd;
    7.53 +    if (read(android_app->msgread, &cmd, sizeof(cmd)) == sizeof(cmd)) {
    7.54 +        switch (cmd) {
    7.55 +            case APP_CMD_SAVE_STATE:
    7.56 +                free_saved_state(android_app);
    7.57 +                break;
    7.58 +        }
    7.59 +        return cmd;
    7.60 +    } else {
    7.61 +        LOGE("No data on command pipe!");
    7.62 +    }
    7.63 +    return -1;
    7.64 +}
    7.65 +
    7.66 +static void print_cur_config(struct android_app* android_app) {
    7.67 +    char lang[2], country[2];
    7.68 +    AConfiguration_getLanguage(android_app->config, lang);
    7.69 +    AConfiguration_getCountry(android_app->config, country);
    7.70 +
    7.71 +    LOGV("Config: mcc=%d mnc=%d lang=%c%c cnt=%c%c orien=%d touch=%d dens=%d "
    7.72 +            "keys=%d nav=%d keysHid=%d navHid=%d sdk=%d size=%d long=%d "
    7.73 +            "modetype=%d modenight=%d",
    7.74 +            AConfiguration_getMcc(android_app->config),
    7.75 +            AConfiguration_getMnc(android_app->config),
    7.76 +            lang[0], lang[1], country[0], country[1],
    7.77 +            AConfiguration_getOrientation(android_app->config),
    7.78 +            AConfiguration_getTouchscreen(android_app->config),
    7.79 +            AConfiguration_getDensity(android_app->config),
    7.80 +            AConfiguration_getKeyboard(android_app->config),
    7.81 +            AConfiguration_getNavigation(android_app->config),
    7.82 +            AConfiguration_getKeysHidden(android_app->config),
    7.83 +            AConfiguration_getNavHidden(android_app->config),
    7.84 +            AConfiguration_getSdkVersion(android_app->config),
    7.85 +            AConfiguration_getScreenSize(android_app->config),
    7.86 +            AConfiguration_getScreenLong(android_app->config),
    7.87 +            AConfiguration_getUiModeType(android_app->config),
    7.88 +            AConfiguration_getUiModeNight(android_app->config));
    7.89 +}
    7.90 +
    7.91 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd) {
    7.92 +    switch (cmd) {
    7.93 +        case APP_CMD_INPUT_CHANGED:
    7.94 +            LOGV("APP_CMD_INPUT_CHANGED\n");
    7.95 +            pthread_mutex_lock(&android_app->mutex);
    7.96 +            if (android_app->inputQueue != NULL) {
    7.97 +                AInputQueue_detachLooper(android_app->inputQueue);
    7.98 +            }
    7.99 +            android_app->inputQueue = android_app->pendingInputQueue;
   7.100 +            if (android_app->inputQueue != NULL) {
   7.101 +                LOGV("Attaching input queue to looper");
   7.102 +                AInputQueue_attachLooper(android_app->inputQueue,
   7.103 +                        android_app->looper, LOOPER_ID_INPUT, NULL,
   7.104 +                        &android_app->inputPollSource);
   7.105 +            }
   7.106 +            pthread_cond_broadcast(&android_app->cond);
   7.107 +            pthread_mutex_unlock(&android_app->mutex);
   7.108 +            break;
   7.109 +
   7.110 +        case APP_CMD_INIT_WINDOW:
   7.111 +            LOGV("APP_CMD_INIT_WINDOW\n");
   7.112 +            pthread_mutex_lock(&android_app->mutex);
   7.113 +            android_app->window = android_app->pendingWindow;
   7.114 +            pthread_cond_broadcast(&android_app->cond);
   7.115 +            pthread_mutex_unlock(&android_app->mutex);
   7.116 +            break;
   7.117 +
   7.118 +        case APP_CMD_TERM_WINDOW:
   7.119 +            LOGV("APP_CMD_TERM_WINDOW\n");
   7.120 +            pthread_cond_broadcast(&android_app->cond);
   7.121 +            break;
   7.122 +
   7.123 +        case APP_CMD_RESUME:
   7.124 +        case APP_CMD_START:
   7.125 +        case APP_CMD_PAUSE:
   7.126 +        case APP_CMD_STOP:
   7.127 +            LOGV("activityState=%d\n", cmd);
   7.128 +            pthread_mutex_lock(&android_app->mutex);
   7.129 +            android_app->activityState = cmd;
   7.130 +            pthread_cond_broadcast(&android_app->cond);
   7.131 +            pthread_mutex_unlock(&android_app->mutex);
   7.132 +            break;
   7.133 +
   7.134 +        case APP_CMD_CONFIG_CHANGED:
   7.135 +            LOGV("APP_CMD_CONFIG_CHANGED\n");
   7.136 +            AConfiguration_fromAssetManager(android_app->config,
   7.137 +                    android_app->activity->assetManager);
   7.138 +            print_cur_config(android_app);
   7.139 +            break;
   7.140 +
   7.141 +        case APP_CMD_DESTROY:
   7.142 +            LOGV("APP_CMD_DESTROY\n");
   7.143 +            android_app->destroyRequested = 1;
   7.144 +            break;
   7.145 +    }
   7.146 +}
   7.147 +
   7.148 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd) {
   7.149 +    switch (cmd) {
   7.150 +        case APP_CMD_TERM_WINDOW:
   7.151 +            LOGV("APP_CMD_TERM_WINDOW\n");
   7.152 +            pthread_mutex_lock(&android_app->mutex);
   7.153 +            android_app->window = NULL;
   7.154 +            pthread_cond_broadcast(&android_app->cond);
   7.155 +            pthread_mutex_unlock(&android_app->mutex);
   7.156 +            break;
   7.157 +
   7.158 +        case APP_CMD_SAVE_STATE:
   7.159 +            LOGV("APP_CMD_SAVE_STATE\n");
   7.160 +            pthread_mutex_lock(&android_app->mutex);
   7.161 +            android_app->stateSaved = 1;
   7.162 +            pthread_cond_broadcast(&android_app->cond);
   7.163 +            pthread_mutex_unlock(&android_app->mutex);
   7.164 +            break;
   7.165 +
   7.166 +        case APP_CMD_RESUME:
   7.167 +            free_saved_state(android_app);
   7.168 +            break;
   7.169 +    }
   7.170 +}
   7.171 +
   7.172 +void app_dummy() {
   7.173 +
   7.174 +}
   7.175 +
   7.176 +static void android_app_destroy(struct android_app* android_app) {
   7.177 +    LOGV("android_app_destroy!");
   7.178 +    free_saved_state(android_app);
   7.179 +    pthread_mutex_lock(&android_app->mutex);
   7.180 +    if (android_app->inputQueue != NULL) {
   7.181 +        AInputQueue_detachLooper(android_app->inputQueue);
   7.182 +    }
   7.183 +    AConfiguration_delete(android_app->config);
   7.184 +    android_app->destroyed = 1;
   7.185 +    pthread_cond_broadcast(&android_app->cond);
   7.186 +    pthread_mutex_unlock(&android_app->mutex);
   7.187 +    // Can't touch android_app object after this.
   7.188 +}
   7.189 +
   7.190 +static void process_input(struct android_app* app, struct android_poll_source* source) {
   7.191 +    AInputEvent* event = NULL;
   7.192 +    while (AInputQueue_getEvent(app->inputQueue, &event) >= 0) {
   7.193 +        LOGV("New input event: type=%d\n", AInputEvent_getType(event));
   7.194 +        if (AInputQueue_preDispatchEvent(app->inputQueue, event)) {
   7.195 +            continue;
   7.196 +        }
   7.197 +        int32_t handled = 0;
   7.198 +        if (app->onInputEvent != NULL) handled = app->onInputEvent(app, event);
   7.199 +        AInputQueue_finishEvent(app->inputQueue, event, handled);
   7.200 +    }
   7.201 +}
   7.202 +
   7.203 +static void process_cmd(struct android_app* app, struct android_poll_source* source) {
   7.204 +    int8_t cmd = android_app_read_cmd(app);
   7.205 +    android_app_pre_exec_cmd(app, cmd);
   7.206 +    if (app->onAppCmd != NULL) app->onAppCmd(app, cmd);
   7.207 +    android_app_post_exec_cmd(app, cmd);
   7.208 +}
   7.209 +
   7.210 +static void* android_app_entry(void* param) {
   7.211 +    struct android_app* android_app = (struct android_app*)param;
   7.212 +
   7.213 +    android_app->config = AConfiguration_new();
   7.214 +    AConfiguration_fromAssetManager(android_app->config, android_app->activity->assetManager);
   7.215 +
   7.216 +    print_cur_config(android_app);
   7.217 +
   7.218 +    android_app->cmdPollSource.id = LOOPER_ID_MAIN;
   7.219 +    android_app->cmdPollSource.app = android_app;
   7.220 +    android_app->cmdPollSource.process = process_cmd;
   7.221 +    android_app->inputPollSource.id = LOOPER_ID_INPUT;
   7.222 +    android_app->inputPollSource.app = android_app;
   7.223 +    android_app->inputPollSource.process = process_input;
   7.224 +
   7.225 +    ALooper* looper = ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS);
   7.226 +    ALooper_addFd(looper, android_app->msgread, LOOPER_ID_MAIN, ALOOPER_EVENT_INPUT, NULL,
   7.227 +            &android_app->cmdPollSource);
   7.228 +    android_app->looper = looper;
   7.229 +
   7.230 +    pthread_mutex_lock(&android_app->mutex);
   7.231 +    android_app->running = 1;
   7.232 +    pthread_cond_broadcast(&android_app->cond);
   7.233 +    pthread_mutex_unlock(&android_app->mutex);
   7.234 +
   7.235 +    android_main(android_app);
   7.236 +
   7.237 +    android_app_destroy(android_app);
   7.238 +    return NULL;
   7.239 +}
   7.240 +
   7.241 +// --------------------------------------------------------------------
   7.242 +// Native activity interaction (called from main thread)
   7.243 +// --------------------------------------------------------------------
   7.244 +
   7.245 +static struct android_app* android_app_create(ANativeActivity* activity,
   7.246 +        void* savedState, size_t savedStateSize) {
   7.247 +    struct android_app* android_app = (struct android_app*)malloc(sizeof(struct android_app));
   7.248 +    memset(android_app, 0, sizeof(struct android_app));
   7.249 +    android_app->activity = activity;
   7.250 +
   7.251 +    pthread_mutex_init(&android_app->mutex, NULL);
   7.252 +    pthread_cond_init(&android_app->cond, NULL);
   7.253 +
   7.254 +    if (savedState != NULL) {
   7.255 +        android_app->savedState = malloc(savedStateSize);
   7.256 +        android_app->savedStateSize = savedStateSize;
   7.257 +        memcpy(android_app->savedState, savedState, savedStateSize);
   7.258 +    }
   7.259 +
   7.260 +    int msgpipe[2];
   7.261 +    if (pipe(msgpipe)) {
   7.262 +        LOGE("could not create pipe: %s", strerror(errno));
   7.263 +        return NULL;
   7.264 +    }
   7.265 +    android_app->msgread = msgpipe[0];
   7.266 +    android_app->msgwrite = msgpipe[1];
   7.267 +
   7.268 +    pthread_attr_t attr; 
   7.269 +    pthread_attr_init(&attr);
   7.270 +    pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
   7.271 +    pthread_create(&android_app->thread, &attr, android_app_entry, android_app);
   7.272 +
   7.273 +    // Wait for thread to start.
   7.274 +    pthread_mutex_lock(&android_app->mutex);
   7.275 +    while (!android_app->running) {
   7.276 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   7.277 +    }
   7.278 +    pthread_mutex_unlock(&android_app->mutex);
   7.279 +
   7.280 +    return android_app;
   7.281 +}
   7.282 +
   7.283 +static void android_app_write_cmd(struct android_app* android_app, int8_t cmd) {
   7.284 +    if (write(android_app->msgwrite, &cmd, sizeof(cmd)) != sizeof(cmd)) {
   7.285 +        LOGE("Failure writing android_app cmd: %s\n", strerror(errno));
   7.286 +    }
   7.287 +}
   7.288 +
   7.289 +static void android_app_set_input(struct android_app* android_app, AInputQueue* inputQueue) {
   7.290 +    pthread_mutex_lock(&android_app->mutex);
   7.291 +    android_app->pendingInputQueue = inputQueue;
   7.292 +    android_app_write_cmd(android_app, APP_CMD_INPUT_CHANGED);
   7.293 +    while (android_app->inputQueue != android_app->pendingInputQueue) {
   7.294 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   7.295 +    }
   7.296 +    pthread_mutex_unlock(&android_app->mutex);
   7.297 +}
   7.298 +
   7.299 +static void android_app_set_window(struct android_app* android_app, ANativeWindow* window) {
   7.300 +    pthread_mutex_lock(&android_app->mutex);
   7.301 +    if (android_app->pendingWindow != NULL) {
   7.302 +        android_app_write_cmd(android_app, APP_CMD_TERM_WINDOW);
   7.303 +    }
   7.304 +    android_app->pendingWindow = window;
   7.305 +    if (window != NULL) {
   7.306 +        android_app_write_cmd(android_app, APP_CMD_INIT_WINDOW);
   7.307 +    }
   7.308 +    while (android_app->window != android_app->pendingWindow) {
   7.309 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   7.310 +    }
   7.311 +    pthread_mutex_unlock(&android_app->mutex);
   7.312 +}
   7.313 +
   7.314 +static void android_app_set_activity_state(struct android_app* android_app, int8_t cmd) {
   7.315 +    pthread_mutex_lock(&android_app->mutex);
   7.316 +    android_app_write_cmd(android_app, cmd);
   7.317 +    while (android_app->activityState != cmd) {
   7.318 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   7.319 +    }
   7.320 +    pthread_mutex_unlock(&android_app->mutex);
   7.321 +}
   7.322 +
   7.323 +static void android_app_free(struct android_app* android_app) {
   7.324 +    pthread_mutex_lock(&android_app->mutex);
   7.325 +    android_app_write_cmd(android_app, APP_CMD_DESTROY);
   7.326 +    while (!android_app->destroyed) {
   7.327 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   7.328 +    }
   7.329 +    pthread_mutex_unlock(&android_app->mutex);
   7.330 +
   7.331 +    close(android_app->msgread);
   7.332 +    close(android_app->msgwrite);
   7.333 +    pthread_cond_destroy(&android_app->cond);
   7.334 +    pthread_mutex_destroy(&android_app->mutex);
   7.335 +    free(android_app);
   7.336 +}
   7.337 +
   7.338 +static void onDestroy(ANativeActivity* activity) {
   7.339 +    LOGV("Destroy: %p\n", activity);
   7.340 +    android_app_free((struct android_app*)activity->instance);
   7.341 +}
   7.342 +
   7.343 +static void onStart(ANativeActivity* activity) {
   7.344 +    LOGV("Start: %p\n", activity);
   7.345 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_START);
   7.346 +}
   7.347 +
   7.348 +static void onResume(ANativeActivity* activity) {
   7.349 +    LOGV("Resume: %p\n", activity);
   7.350 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_RESUME);
   7.351 +}
   7.352 +
   7.353 +static void* onSaveInstanceState(ANativeActivity* activity, size_t* outLen) {
   7.354 +    struct android_app* android_app = (struct android_app*)activity->instance;
   7.355 +    void* savedState = NULL;
   7.356 +
   7.357 +    LOGV("SaveInstanceState: %p\n", activity);
   7.358 +    pthread_mutex_lock(&android_app->mutex);
   7.359 +    android_app->stateSaved = 0;
   7.360 +    android_app_write_cmd(android_app, APP_CMD_SAVE_STATE);
   7.361 +    while (!android_app->stateSaved) {
   7.362 +        pthread_cond_wait(&android_app->cond, &android_app->mutex);
   7.363 +    }
   7.364 +
   7.365 +    if (android_app->savedState != NULL) {
   7.366 +        savedState = android_app->savedState;
   7.367 +        *outLen = android_app->savedStateSize;
   7.368 +        android_app->savedState = NULL;
   7.369 +        android_app->savedStateSize = 0;
   7.370 +    }
   7.371 +
   7.372 +    pthread_mutex_unlock(&android_app->mutex);
   7.373 +
   7.374 +    return savedState;
   7.375 +}
   7.376 +
   7.377 +static void onPause(ANativeActivity* activity) {
   7.378 +    LOGV("Pause: %p\n", activity);
   7.379 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_PAUSE);
   7.380 +}
   7.381 +
   7.382 +static void onStop(ANativeActivity* activity) {
   7.383 +    LOGV("Stop: %p\n", activity);
   7.384 +    android_app_set_activity_state((struct android_app*)activity->instance, APP_CMD_STOP);
   7.385 +}
   7.386 +
   7.387 +static void onConfigurationChanged(ANativeActivity* activity) {
   7.388 +    struct android_app* android_app = (struct android_app*)activity->instance;
   7.389 +    LOGV("ConfigurationChanged: %p\n", activity);
   7.390 +    android_app_write_cmd(android_app, APP_CMD_CONFIG_CHANGED);
   7.391 +}
   7.392 +
   7.393 +static void onLowMemory(ANativeActivity* activity) {
   7.394 +    struct android_app* android_app = (struct android_app*)activity->instance;
   7.395 +    LOGV("LowMemory: %p\n", activity);
   7.396 +    android_app_write_cmd(android_app, APP_CMD_LOW_MEMORY);
   7.397 +}
   7.398 +
   7.399 +static void onWindowFocusChanged(ANativeActivity* activity, int focused) {
   7.400 +    LOGV("WindowFocusChanged: %p -- %d\n", activity, focused);
   7.401 +    android_app_write_cmd((struct android_app*)activity->instance,
   7.402 +            focused ? APP_CMD_GAINED_FOCUS : APP_CMD_LOST_FOCUS);
   7.403 +}
   7.404 +
   7.405 +static void onNativeWindowCreated(ANativeActivity* activity, ANativeWindow* window) {
   7.406 +    LOGV("NativeWindowCreated: %p -- %p\n", activity, window);
   7.407 +    android_app_set_window((struct android_app*)activity->instance, window);
   7.408 +}
   7.409 +
   7.410 +static void onNativeWindowDestroyed(ANativeActivity* activity, ANativeWindow* window) {
   7.411 +    LOGV("NativeWindowDestroyed: %p -- %p\n", activity, window);
   7.412 +    android_app_set_window((struct android_app*)activity->instance, NULL);
   7.413 +}
   7.414 +
   7.415 +static void onInputQueueCreated(ANativeActivity* activity, AInputQueue* queue) {
   7.416 +    LOGV("InputQueueCreated: %p -- %p\n", activity, queue);
   7.417 +    android_app_set_input((struct android_app*)activity->instance, queue);
   7.418 +}
   7.419 +
   7.420 +static void onInputQueueDestroyed(ANativeActivity* activity, AInputQueue* queue) {
   7.421 +    LOGV("InputQueueDestroyed: %p -- %p\n", activity, queue);
   7.422 +    android_app_set_input((struct android_app*)activity->instance, NULL);
   7.423 +}
   7.424 +
   7.425 +void ANativeActivity_onCreate(ANativeActivity* activity,
   7.426 +        void* savedState, size_t savedStateSize) {
   7.427 +    LOGV("Creating: %p\n", activity);
   7.428 +    activity->callbacks->onDestroy = onDestroy;
   7.429 +    activity->callbacks->onStart = onStart;
   7.430 +    activity->callbacks->onResume = onResume;
   7.431 +    activity->callbacks->onSaveInstanceState = onSaveInstanceState;
   7.432 +    activity->callbacks->onPause = onPause;
   7.433 +    activity->callbacks->onStop = onStop;
   7.434 +    activity->callbacks->onConfigurationChanged = onConfigurationChanged;
   7.435 +    activity->callbacks->onLowMemory = onLowMemory;
   7.436 +    activity->callbacks->onWindowFocusChanged = onWindowFocusChanged;
   7.437 +    activity->callbacks->onNativeWindowCreated = onNativeWindowCreated;
   7.438 +    activity->callbacks->onNativeWindowDestroyed = onNativeWindowDestroyed;
   7.439 +    activity->callbacks->onInputQueueCreated = onInputQueueCreated;
   7.440 +    activity->callbacks->onInputQueueDestroyed = onInputQueueDestroyed;
   7.441 +
   7.442 +    activity->instance = android_app_create(activity, savedState, savedStateSize);
   7.443 +}
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/android/android_native_app_glue.h	Tue May 12 05:31:21 2015 +0300
     8.3 @@ -0,0 +1,349 @@
     8.4 +/*
     8.5 + * Copyright (C) 2010 The Android Open Source Project
     8.6 + *
     8.7 + * Licensed under the Apache License, Version 2.0 (the "License");
     8.8 + * you may not use this file except in compliance with the License.
     8.9 + * You may obtain a copy of the License at
    8.10 + *
    8.11 + *      http://www.apache.org/licenses/LICENSE-2.0
    8.12 + *
    8.13 + * Unless required by applicable law or agreed to in writing, software
    8.14 + * distributed under the License is distributed on an "AS IS" BASIS,
    8.15 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    8.16 + * See the License for the specific language governing permissions and
    8.17 + * limitations under the License.
    8.18 + *
    8.19 + */
    8.20 +
    8.21 +#ifndef _ANDROID_NATIVE_APP_GLUE_H
    8.22 +#define _ANDROID_NATIVE_APP_GLUE_H
    8.23 +
    8.24 +#include <poll.h>
    8.25 +#include <pthread.h>
    8.26 +#include <sched.h>
    8.27 +
    8.28 +#include <android/configuration.h>
    8.29 +#include <android/looper.h>
    8.30 +#include <android/native_activity.h>
    8.31 +
    8.32 +#ifdef __cplusplus
    8.33 +extern "C" {
    8.34 +#endif
    8.35 +
    8.36 +/**
    8.37 + * The native activity interface provided by <android/native_activity.h>
    8.38 + * is based on a set of application-provided callbacks that will be called
    8.39 + * by the Activity's main thread when certain events occur.
    8.40 + *
    8.41 + * This means that each one of this callbacks _should_ _not_ block, or they
    8.42 + * risk having the system force-close the application. This programming
    8.43 + * model is direct, lightweight, but constraining.
    8.44 + *
    8.45 + * The 'android_native_app_glue' static library is used to provide a different
    8.46 + * execution model where the application can implement its own main event
    8.47 + * loop in a different thread instead. Here's how it works:
    8.48 + *
    8.49 + * 1/ The application must provide a function named "android_main()" that
    8.50 + *    will be called when the activity is created, in a new thread that is
    8.51 + *    distinct from the activity's main thread.
    8.52 + *
    8.53 + * 2/ android_main() receives a pointer to a valid "android_app" structure
    8.54 + *    that contains references to other important objects, e.g. the
    8.55 + *    ANativeActivity obejct instance the application is running in.
    8.56 + *
    8.57 + * 3/ the "android_app" object holds an ALooper instance that already
    8.58 + *    listens to two important things:
    8.59 + *
    8.60 + *      - activity lifecycle events (e.g. "pause", "resume"). See APP_CMD_XXX
    8.61 + *        declarations below.
    8.62 + *
    8.63 + *      - input events coming from the AInputQueue attached to the activity.
    8.64 + *
    8.65 + *    Each of these correspond to an ALooper identifier returned by
    8.66 + *    ALooper_pollOnce with values of LOOPER_ID_MAIN and LOOPER_ID_INPUT,
    8.67 + *    respectively.
    8.68 + *
    8.69 + *    Your application can use the same ALooper to listen to additional
    8.70 + *    file-descriptors.  They can either be callback based, or with return
    8.71 + *    identifiers starting with LOOPER_ID_USER.
    8.72 + *
    8.73 + * 4/ Whenever you receive a LOOPER_ID_MAIN or LOOPER_ID_INPUT event,
    8.74 + *    the returned data will point to an android_poll_source structure.  You
    8.75 + *    can call the process() function on it, and fill in android_app->onAppCmd
    8.76 + *    and android_app->onInputEvent to be called for your own processing
    8.77 + *    of the event.
    8.78 + *
    8.79 + *    Alternatively, you can call the low-level functions to read and process
    8.80 + *    the data directly...  look at the process_cmd() and process_input()
    8.81 + *    implementations in the glue to see how to do this.
    8.82 + *
    8.83 + * See the sample named "native-activity" that comes with the NDK with a
    8.84 + * full usage example.  Also look at the JavaDoc of NativeActivity.
    8.85 + */
    8.86 +
    8.87 +struct android_app;
    8.88 +
    8.89 +/**
    8.90 + * Data associated with an ALooper fd that will be returned as the "outData"
    8.91 + * when that source has data ready.
    8.92 + */
    8.93 +struct android_poll_source {
    8.94 +    // The identifier of this source.  May be LOOPER_ID_MAIN or
    8.95 +    // LOOPER_ID_INPUT.
    8.96 +    int32_t id;
    8.97 +
    8.98 +    // The android_app this ident is associated with.
    8.99 +    struct android_app* app;
   8.100 +
   8.101 +    // Function to call to perform the standard processing of data from
   8.102 +    // this source.
   8.103 +    void (*process)(struct android_app* app, struct android_poll_source* source);
   8.104 +};
   8.105 +
   8.106 +/**
   8.107 + * This is the interface for the standard glue code of a threaded
   8.108 + * application.  In this model, the application's code is running
   8.109 + * in its own thread separate from the main thread of the process.
   8.110 + * It is not required that this thread be associated with the Java
   8.111 + * VM, although it will need to be in order to make JNI calls any
   8.112 + * Java objects.
   8.113 + */
   8.114 +struct android_app {
   8.115 +    // The application can place a pointer to its own state object
   8.116 +    // here if it likes.
   8.117 +    void* userData;
   8.118 +
   8.119 +    // Fill this in with the function to process main app commands (APP_CMD_*)
   8.120 +    void (*onAppCmd)(struct android_app* app, int32_t cmd);
   8.121 +
   8.122 +    // Fill this in with the function to process input events.  At this point
   8.123 +    // the event has already been pre-dispatched, and it will be finished upon
   8.124 +    // return.  Return 1 if you have handled the event, 0 for any default
   8.125 +    // dispatching.
   8.126 +    int32_t (*onInputEvent)(struct android_app* app, AInputEvent* event);
   8.127 +
   8.128 +    // The ANativeActivity object instance that this app is running in.
   8.129 +    ANativeActivity* activity;
   8.130 +
   8.131 +    // The current configuration the app is running in.
   8.132 +    AConfiguration* config;
   8.133 +
   8.134 +    // This is the last instance's saved state, as provided at creation time.
   8.135 +    // It is NULL if there was no state.  You can use this as you need; the
   8.136 +    // memory will remain around until you call android_app_exec_cmd() for
   8.137 +    // APP_CMD_RESUME, at which point it will be freed and savedState set to NULL.
   8.138 +    // These variables should only be changed when processing a APP_CMD_SAVE_STATE,
   8.139 +    // at which point they will be initialized to NULL and you can malloc your
   8.140 +    // state and place the information here.  In that case the memory will be
   8.141 +    // freed for you later.
   8.142 +    void* savedState;
   8.143 +    size_t savedStateSize;
   8.144 +
   8.145 +    // The ALooper associated with the app's thread.
   8.146 +    ALooper* looper;
   8.147 +
   8.148 +    // When non-NULL, this is the input queue from which the app will
   8.149 +    // receive user input events.
   8.150 +    AInputQueue* inputQueue;
   8.151 +
   8.152 +    // When non-NULL, this is the window surface that the app can draw in.
   8.153 +    ANativeWindow* window;
   8.154 +
   8.155 +    // Current content rectangle of the window; this is the area where the
   8.156 +    // window's content should be placed to be seen by the user.
   8.157 +    ARect contentRect;
   8.158 +
   8.159 +    // Current state of the app's activity.  May be either APP_CMD_START,
   8.160 +    // APP_CMD_RESUME, APP_CMD_PAUSE, or APP_CMD_STOP; see below.
   8.161 +    int activityState;
   8.162 +
   8.163 +    // This is non-zero when the application's NativeActivity is being
   8.164 +    // destroyed and waiting for the app thread to complete.
   8.165 +    int destroyRequested;
   8.166 +
   8.167 +    // -------------------------------------------------
   8.168 +    // Below are "private" implementation of the glue code.
   8.169 +
   8.170 +    pthread_mutex_t mutex;
   8.171 +    pthread_cond_t cond;
   8.172 +
   8.173 +    int msgread;
   8.174 +    int msgwrite;
   8.175 +
   8.176 +    pthread_t thread;
   8.177 +
   8.178 +    struct android_poll_source cmdPollSource;
   8.179 +    struct android_poll_source inputPollSource;
   8.180 +
   8.181 +    int running;
   8.182 +    int stateSaved;
   8.183 +    int destroyed;
   8.184 +    int redrawNeeded;
   8.185 +    AInputQueue* pendingInputQueue;
   8.186 +    ANativeWindow* pendingWindow;
   8.187 +    ARect pendingContentRect;
   8.188 +};
   8.189 +
   8.190 +enum {
   8.191 +    /**
   8.192 +     * Looper data ID of commands coming from the app's main thread, which
   8.193 +     * is returned as an identifier from ALooper_pollOnce().  The data for this
   8.194 +     * identifier is a pointer to an android_poll_source structure.
   8.195 +     * These can be retrieved and processed with android_app_read_cmd()
   8.196 +     * and android_app_exec_cmd().
   8.197 +     */
   8.198 +    LOOPER_ID_MAIN = 1,
   8.199 +
   8.200 +    /**
   8.201 +     * Looper data ID of events coming from the AInputQueue of the
   8.202 +     * application's window, which is returned as an identifier from
   8.203 +     * ALooper_pollOnce().  The data for this identifier is a pointer to an
   8.204 +     * android_poll_source structure.  These can be read via the inputQueue
   8.205 +     * object of android_app.
   8.206 +     */
   8.207 +    LOOPER_ID_INPUT = 2,
   8.208 +
   8.209 +    /**
   8.210 +     * Start of user-defined ALooper identifiers.
   8.211 +     */
   8.212 +    LOOPER_ID_USER = 3,
   8.213 +};
   8.214 +
   8.215 +enum {
   8.216 +    /**
   8.217 +     * Command from main thread: the AInputQueue has changed.  Upon processing
   8.218 +     * this command, android_app->inputQueue will be updated to the new queue
   8.219 +     * (or NULL).
   8.220 +     */
   8.221 +    APP_CMD_INPUT_CHANGED,
   8.222 +
   8.223 +    /**
   8.224 +     * Command from main thread: a new ANativeWindow is ready for use.  Upon
   8.225 +     * receiving this command, android_app->window will contain the new window
   8.226 +     * surface.
   8.227 +     */
   8.228 +    APP_CMD_INIT_WINDOW,
   8.229 +
   8.230 +    /**
   8.231 +     * Command from main thread: the existing ANativeWindow needs to be
   8.232 +     * terminated.  Upon receiving this command, android_app->window still
   8.233 +     * contains the existing window; after calling android_app_exec_cmd
   8.234 +     * it will be set to NULL.
   8.235 +     */
   8.236 +    APP_CMD_TERM_WINDOW,
   8.237 +
   8.238 +    /**
   8.239 +     * Command from main thread: the current ANativeWindow has been resized.
   8.240 +     * Please redraw with its new size.
   8.241 +     */
   8.242 +    APP_CMD_WINDOW_RESIZED,
   8.243 +
   8.244 +    /**
   8.245 +     * Command from main thread: the system needs that the current ANativeWindow
   8.246 +     * be redrawn.  You should redraw the window before handing this to
   8.247 +     * android_app_exec_cmd() in order to avoid transient drawing glitches.
   8.248 +     */
   8.249 +    APP_CMD_WINDOW_REDRAW_NEEDED,
   8.250 +
   8.251 +    /**
   8.252 +     * Command from main thread: the content area of the window has changed,
   8.253 +     * such as from the soft input window being shown or hidden.  You can
   8.254 +     * find the new content rect in android_app::contentRect.
   8.255 +     */
   8.256 +    APP_CMD_CONTENT_RECT_CHANGED,
   8.257 +
   8.258 +    /**
   8.259 +     * Command from main thread: the app's activity window has gained
   8.260 +     * input focus.
   8.261 +     */
   8.262 +    APP_CMD_GAINED_FOCUS,
   8.263 +
   8.264 +    /**
   8.265 +     * Command from main thread: the app's activity window has lost
   8.266 +     * input focus.
   8.267 +     */
   8.268 +    APP_CMD_LOST_FOCUS,
   8.269 +
   8.270 +    /**
   8.271 +     * Command from main thread: the current device configuration has changed.
   8.272 +     */
   8.273 +    APP_CMD_CONFIG_CHANGED,
   8.274 +
   8.275 +    /**
   8.276 +     * Command from main thread: the system is running low on memory.
   8.277 +     * Try to reduce your memory use.
   8.278 +     */
   8.279 +    APP_CMD_LOW_MEMORY,
   8.280 +
   8.281 +    /**
   8.282 +     * Command from main thread: the app's activity has been started.
   8.283 +     */
   8.284 +    APP_CMD_START,
   8.285 +
   8.286 +    /**
   8.287 +     * Command from main thread: the app's activity has been resumed.
   8.288 +     */
   8.289 +    APP_CMD_RESUME,
   8.290 +
   8.291 +    /**
   8.292 +     * Command from main thread: the app should generate a new saved state
   8.293 +     * for itself, to restore from later if needed.  If you have saved state,
   8.294 +     * allocate it with malloc and place it in android_app.savedState with
   8.295 +     * the size in android_app.savedStateSize.  The will be freed for you
   8.296 +     * later.
   8.297 +     */
   8.298 +    APP_CMD_SAVE_STATE,
   8.299 +
   8.300 +    /**
   8.301 +     * Command from main thread: the app's activity has been paused.
   8.302 +     */
   8.303 +    APP_CMD_PAUSE,
   8.304 +
   8.305 +    /**
   8.306 +     * Command from main thread: the app's activity has been stopped.
   8.307 +     */
   8.308 +    APP_CMD_STOP,
   8.309 +
   8.310 +    /**
   8.311 +     * Command from main thread: the app's activity is being destroyed,
   8.312 +     * and waiting for the app thread to clean up and exit before proceeding.
   8.313 +     */
   8.314 +    APP_CMD_DESTROY,
   8.315 +};
   8.316 +
   8.317 +/**
   8.318 + * Call when ALooper_pollAll() returns LOOPER_ID_MAIN, reading the next
   8.319 + * app command message.
   8.320 + */
   8.321 +int8_t android_app_read_cmd(struct android_app* android_app);
   8.322 +
   8.323 +/**
   8.324 + * Call with the command returned by android_app_read_cmd() to do the
   8.325 + * initial pre-processing of the given command.  You can perform your own
   8.326 + * actions for the command after calling this function.
   8.327 + */
   8.328 +void android_app_pre_exec_cmd(struct android_app* android_app, int8_t cmd);
   8.329 +
   8.330 +/**
   8.331 + * Call with the command returned by android_app_read_cmd() to do the
   8.332 + * final post-processing of the given command.  You must have done your own
   8.333 + * actions for the command before calling this function.
   8.334 + */
   8.335 +void android_app_post_exec_cmd(struct android_app* android_app, int8_t cmd);
   8.336 +
   8.337 +/**
   8.338 + * Dummy function you can call to ensure glue code isn't stripped.
   8.339 + */
   8.340 +void app_dummy();
   8.341 +
   8.342 +/**
   8.343 + * This is the function that application code must implement, representing
   8.344 + * the main entry to the app.
   8.345 + */
   8.346 +extern void android_main(struct android_app* app);
   8.347 +
   8.348 +#ifdef __cplusplus
   8.349 +}
   8.350 +#endif
   8.351 +
   8.352 +#endif /* _ANDROID_NATIVE_APP_GLUE_H */
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/android/logger.c	Tue May 12 05:31:21 2015 +0300
     9.3 @@ -0,0 +1,60 @@
     9.4 +#include <stdio.h>
     9.5 +#include <assert.h>
     9.6 +#include <unistd.h>
     9.7 +#include <pthread.h>
     9.8 +#include <android/log.h>
     9.9 +#include "logger.h"
    9.10 +
    9.11 +static void *thread_func(void *arg);
    9.12 +
    9.13 +static int pfd[2];
    9.14 +static pthread_t thr;
    9.15 +static int initialized;
    9.16 +
    9.17 +int start_logger(void)
    9.18 +{
    9.19 +	if(initialized) {
    9.20 +		return 1;
    9.21 +	}
    9.22 +
    9.23 +	/* set stdout to line-buffered, and stderr to unbuffered */
    9.24 +	setvbuf(stdout, 0, _IOLBF, 0);
    9.25 +	setvbuf(stderr, 0, _IONBF, 0);
    9.26 +
    9.27 +	if(pipe(pfd) == -1) {
    9.28 +		perror("failed to create logging pipe");
    9.29 +		return -1;
    9.30 +	}
    9.31 +	assert(pfd[0] > 2 && pfd[1] > 2);
    9.32 +
    9.33 +	/* redirect stdout & stderr to the write-end of the pipe */
    9.34 +	dup2(pfd[1], 1);
    9.35 +	dup2(pfd[1], 2);
    9.36 +
    9.37 +	/* start the logging thread */
    9.38 +	if(pthread_create(&thr, 0, thread_func, 0) == -1) {
    9.39 +		perror("failed to spawn logging thread");
    9.40 +		return -1;
    9.41 +	}
    9.42 +	pthread_detach(thr);
    9.43 +	return 0;
    9.44 +}
    9.45 +
    9.46 +static void *thread_func(void *arg)
    9.47 +{
    9.48 +	ssize_t rdsz;
    9.49 +	char buf[257];
    9.50 +
    9.51 +	__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger starting up...");
    9.52 +
    9.53 +	while((rdsz = read(pfd[0], buf, sizeof buf - 1)) > 0) {
    9.54 +		if(buf[rdsz - 1] == '\n') {
    9.55 +			--rdsz;
    9.56 +		}
    9.57 +		buf[rdsz] = 0;
    9.58 +		__android_log_write(ANDROID_LOG_DEBUG, APP_NAME, buf);
    9.59 +	}
    9.60 +
    9.61 +	__android_log_print(ANDROID_LOG_DEBUG, APP_NAME, "logger shutting down...");
    9.62 +	return 0;
    9.63 +}
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/android/logger.h	Tue May 12 05:31:21 2015 +0300
    10.3 @@ -0,0 +1,6 @@
    10.4 +#ifndef LOGGER_H_
    10.5 +#define LOGGER_H_
    10.6 +
    10.7 +int start_logger(void);
    10.8 +
    10.9 +#endif	/* LOGGER_H_ */
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/game.c	Tue May 12 05:31:21 2015 +0300
    11.3 @@ -0,0 +1,107 @@
    11.4 +#include <stdio.h>
    11.5 +#include <stdlib.h>
    11.6 +#include <math.h>
    11.7 +#include "opengl.h"
    11.8 +#include "game.h"
    11.9 +
   11.10 +static int win_width, win_height;
   11.11 +
   11.12 +
   11.13 +int game_init(void)
   11.14 +{
   11.15 +	glEnable(GL_DEPTH_TEST);
   11.16 +	glEnable(GL_CULL_FACE);
   11.17 +	glEnable(GL_LIGHTING);
   11.18 +
   11.19 +	glClearColor(0.4, 0.4, 0.4, 1);
   11.20 +	return 0;
   11.21 +}
   11.22 +
   11.23 +void game_shutdown(void)
   11.24 +{
   11.25 +}
   11.26 +
   11.27 +void game_display(unsigned long msec)
   11.28 +{
   11.29 +	float tsec = (float)msec / 1000.0f;
   11.30 +
   11.31 +	glClearColor(sin(tsec * 10.0), cos(tsec * 10.0), -sin(tsec * 10.0), 1.0);
   11.32 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   11.33 +
   11.34 +	glMatrixMode(GL_MODELVIEW);
   11.35 +	glLoadIdentity();
   11.36 +}
   11.37 +
   11.38 +void game_reshape(int x, int y)
   11.39 +{
   11.40 +	win_width = x;
   11.41 +	win_height = y;
   11.42 +	glViewport(0, 0, x, y);
   11.43 +
   11.44 +	glMatrixMode(GL_PROJECTION);
   11.45 +	glLoadIdentity();
   11.46 +	glScalef((float)win_height / (float)win_width, 1.0, 1.0);
   11.47 +}
   11.48 +
   11.49 +void game_keyboard(int key, int pressed)
   11.50 +{
   11.51 +	if(!pressed) return;
   11.52 +
   11.53 +	switch(key) {
   11.54 +	case 27:
   11.55 +		exit(0);
   11.56 +
   11.57 +	default:
   11.58 +		break;
   11.59 +	}
   11.60 +}
   11.61 +
   11.62 +#define MAX_TOUCH_IDS	16
   11.63 +static struct {
   11.64 +	int bnstate[8];
   11.65 +	int prev_x, prev_y;
   11.66 +} mstate[MAX_TOUCH_IDS];
   11.67 +
   11.68 +void game_mouse_button(int id, int bn, int pressed, int x, int y)
   11.69 +{
   11.70 +	if(id >= MAX_TOUCH_IDS) return;
   11.71 +
   11.72 +	mstate[id].prev_x = x;
   11.73 +	mstate[id].prev_y = y;
   11.74 +	mstate[id].bnstate[bn] = pressed;
   11.75 +}
   11.76 +
   11.77 +void game_mouse_motion(int id, int x, int y)
   11.78 +{
   11.79 +	/*
   11.80 +	int dx, dy, cx, cy;
   11.81 +
   11.82 +	if(id >= MAX_TOUCH_IDS) return;
   11.83 +
   11.84 +	cx = win_width / 2;
   11.85 +	cy = win_height / 2;
   11.86 +
   11.87 +	dx = x - mstate[id].prev_x;
   11.88 +	dy = y - mstate[id].prev_y;
   11.89 +	mstate[id].prev_x = x;
   11.90 +	mstate[id].prev_y = y;
   11.91 +
   11.92 +	if(!dx && !dy) return;
   11.93 +
   11.94 +	if(mouselook || mstate[id].bnstate[0]) {
   11.95 +		player_turn(&player, dx * 0.5, dy * 0.5);
   11.96 +	}
   11.97 +	if(mstate[id].bnstate[2]) {
   11.98 +		dbg_cam_dist += 0.1 * dy;
   11.99 +		if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0;
  11.100 +	}
  11.101 +
  11.102 +	if(mouselook) {
  11.103 +		warping_mouse = 1;
  11.104 +		set_mouse_pos(cx, cy);
  11.105 +		mstate[id].prev_x = cx;
  11.106 +		mstate[id].prev_y = cy;
  11.107 +	}
  11.108 +	*/
  11.109 +}
  11.110 +
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/game.h	Tue May 12 05:31:21 2015 +0300
    12.3 @@ -0,0 +1,19 @@
    12.4 +#ifndef GAME_H_
    12.5 +#define GAME_H_
    12.6 +
    12.7 +int game_init(void);
    12.8 +void game_shutdown(void);
    12.9 +
   12.10 +void game_display(unsigned long msec);
   12.11 +void game_reshape(int x, int y);
   12.12 +
   12.13 +void game_keyboard(int key, int press);
   12.14 +void game_mouse_button(int id, int bn, int press, int x, int y);
   12.15 +void game_mouse_motion(int id, int x, int y);
   12.16 +
   12.17 +/* provided by the system frontend */
   12.18 +void set_mouse_pos(int x, int y);
   12.19 +void set_mouse_cursor(int enable);
   12.20 +
   12.21 +#endif /* GAME_H_ */
   12.22 +
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/opengl.h	Tue May 12 05:31:21 2015 +0300
    13.3 @@ -0,0 +1,6 @@
    13.4 +#ifndef OPENGL_H_
    13.5 +#define OPENGL_H_
    13.6 +
    13.7 +#include <GLES/gl.h>
    13.8 +
    13.9 +#endif	/* OPENGL_H_ */
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/timer.c	Tue May 12 05:31:21 2015 +0300
    14.3 @@ -0,0 +1,71 @@
    14.4 +#include "timer.h"
    14.5 +
    14.6 +#if defined(__APPLE__) && !defined(__unix__)
    14.7 +#define __unix__
    14.8 +#endif
    14.9 +
   14.10 +#ifdef __unix__
   14.11 +#include <time.h>
   14.12 +#include <unistd.h>
   14.13 +#include <sys/time.h>
   14.14 +
   14.15 +#ifdef CLOCK_MONOTONIC
   14.16 +unsigned long get_time_msec(void)
   14.17 +{
   14.18 +	struct timespec ts;
   14.19 +	static struct timespec ts0;
   14.20 +
   14.21 +	clock_gettime(CLOCK_MONOTONIC, &ts);
   14.22 +	if(ts0.tv_sec == 0 && ts0.tv_nsec == 0) {
   14.23 +		ts0 = ts;
   14.24 +		return 0;
   14.25 +	}
   14.26 +	return (ts.tv_sec - ts0.tv_sec) * 1000 + (ts.tv_nsec - ts0.tv_nsec) / 1000000;
   14.27 +}
   14.28 +#else	/* no fancy POSIX clocks, fallback to good'ol gettimeofday */
   14.29 +unsigned long get_time_msec(void)
   14.30 +{
   14.31 +	struct timeval tv;
   14.32 +	static struct timeval tv0;
   14.33 +
   14.34 +	gettimeofday(&tv, 0);
   14.35 +	if(tv0.tv_sec == 0 && tv0.tv_usec == 0) {
   14.36 +		tv0 = tv;
   14.37 +		return 0;
   14.38 +	}
   14.39 +	return (tv.tv_sec - tv0.tv_sec) * 1000 + (tv.tv_usec - tv0.tv_usec) / 1000;
   14.40 +}
   14.41 +#endif	/* !posix clock */
   14.42 +
   14.43 +void sleep_msec(unsigned long msec)
   14.44 +{
   14.45 +	usleep(msec * 1000);
   14.46 +}
   14.47 +#endif
   14.48 +
   14.49 +#ifdef WIN32
   14.50 +#include <windows.h>
   14.51 +#pragma comment(lib, "winmm.lib")
   14.52 +
   14.53 +unsigned long get_time_msec(void)
   14.54 +{
   14.55 +	return timeGetTime();
   14.56 +}
   14.57 +
   14.58 +void sleep_msec(unsigned long msec)
   14.59 +{
   14.60 +	Sleep(msec);
   14.61 +}
   14.62 +#endif
   14.63 +
   14.64 +double get_time_sec(void)
   14.65 +{
   14.66 +	return get_time_msec() / 1000.0f;
   14.67 +}
   14.68 +
   14.69 +void sleep_sec(double sec)
   14.70 +{
   14.71 +	if(sec > 0.0f) {
   14.72 +		sleep_msec(sec * 1000.0f);
   14.73 +	}
   14.74 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/timer.h	Tue May 12 05:31:21 2015 +0300
    15.3 @@ -0,0 +1,10 @@
    15.4 +#ifndef TIMER_H_
    15.5 +#define TIMER_H_
    15.6 +
    15.7 +unsigned long get_time_msec(void);
    15.8 +void sleep_msec(unsigned long msec);
    15.9 +
   15.10 +double get_time_sec(void);
   15.11 +void sleep_sec(double sec);
   15.12 +
   15.13 +#endif	/* TIMER_H_ */