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_ */