diff --git a/build/android/boost-android-build.patch b/build/android/boost-android-build.patch
new file mode 100644
index 0000000000..8f55d1c303
--- /dev/null
+++ b/build/android/boost-android-build.patch
@@ -0,0 +1,43 @@
+--- temp/MysticTreeGames-Boost-for-Android-70838fc/build-android.sh 2011-10-16 14:34:17.000000000 +0100
++++ temp/MysticTreeGames-Boost-for-Android-70838fc/build-android.sh 2012-02-15 16:40:59.846370550 +0000
+@@ -104,19 +104,19 @@
+ ;;
+ windows|cygwin)
+ Platfrom=windows-x86
+ ;;
+ *) # let's play safe here
+ Platfrom=linux-x86
+ esac
+
+-CXXPATH=$AndroidNDKRoot/build/prebuilt/$Platfrom/arm-eabi-4.4.0/bin/arm-eabi-g++
+-CXXFLAGS=-I$AndroidNDKRoot/build/platforms/android-8/arch-arm/usr/include
+-TOOLSET=gcc-androidR4
++CXXPATH=$AndroidNDKRoot/bin/arm-linux-androideabi-g++
++CXXFLAGS=-I$AndroidNDKRoot/sysroot/usr/include
++TOOLSET=gcc-androidR5
+ if [ -n "$NDK_R5" ]; then
+ CXXPATH=$AndroidNDKRoot/toolchains/arm-linux-androideabi-4.4.3/prebuilt/$Platfrom/bin/arm-linux-androideabi-g++
+ CXXFLAGS="-I$AndroidNDKRoot/platforms/android-8/arch-arm/usr/include \
+ -I$AndroidNDKRoot/sources/cxx-stl/gnu-libstdc++/include \
+ -I$AndroidNDKRoot/sources/cxx-stl/gnu-libstdc++/libs/armeabi/include \
+ -I$AndroidNDKRoot/sources/wchar-support/include"
+ TOOLSET=gcc-androidR5
+ fi
+@@ -210,16 +210,17 @@
+ # ---------------
+
+ # Build boost for android
+ echo "Building boost for android"
+ cd $BOOST_DIR
+ env PATH=`dirname $CXXPATH`:$PATH \
+ AndroidNDKRoot=$AndroidNDKRoot NO_BZIP2=1 \
+ ./bjam toolset=$TOOLSET \
++ --with-filesystem --with-system \
+ cxxflags="$CXXFLAGS" \
+ link=static threading=multi --layout=versioned install 2>&1 | tee -a $PROGDIR/build.log
+ if [ $? != 0 ] ; then
+ dump "ERROR: Failed to build boost for android!"
+ exit 1
+ fi
+ cd $PROGDIR
+ dump "Done!"
diff --git a/build/android/js185-android-build.patch b/build/android/js185-android-build.patch
new file mode 100644
index 0000000000..60f88bf481
--- /dev/null
+++ b/build/android/js185-android-build.patch
@@ -0,0 +1,21 @@
+--- js/src/assembler/wtf/Platform.h 2012-02-13 22:50:06.343654548 +0000
++++ js/src/assembler/wtf/Platform.h 2012-02-13 22:50:44.631173638 +0000
+@@ -332,17 +332,17 @@
+ /* Note that for this platform PLATFORM(WIN_OS) is also defined. */
+ #if defined(_WIN32_WCE)
+ #define WTF_PLATFORM_WINCE 1
+ #endif
+
+ /* PLATFORM(LINUX) */
+ /* Operating system level dependencies for Linux-like systems that */
+ /* should be used regardless of operating environment */
+-#ifdef __linux__
++#if defined(__linux__) && !defined(ANDROID)
+ #define WTF_PLATFORM_LINUX 1
+ #endif
+
+ /* PLATFORM(FREEBSD) */
+ /* Operating system level dependencies for FreeBSD-like systems that */
+ /* should be used regardless of operating environment */
+ #ifdef __FreeBSD__
+ #define WTF_PLATFORM_FREEBSD 1
diff --git a/build/android/libxml2-android-build.patch b/build/android/libxml2-android-build.patch
new file mode 100644
index 0000000000..d303c8e315
--- /dev/null
+++ b/build/android/libxml2-android-build.patch
@@ -0,0 +1,24 @@
+--- libxml2-2.7.8/Makefile.in 2010-11-04 17:28:16.000000000 +0000
++++ libxml2-2.7.8/Makefile.in 2012-01-29 16:24:38.308456208 +0000
+@@ -36,19 +36,19 @@
+ PRE_UNINSTALL = :
+ POST_UNINSTALL = :
+ build_triplet = @build@
+ host_triplet = @host@
+ noinst_PROGRAMS = testSchemas$(EXEEXT) testRelax$(EXEEXT) \
+ testSAX$(EXEEXT) testHTML$(EXEEXT) testXPath$(EXEEXT) \
+ testURI$(EXEEXT) testThreads$(EXEEXT) testC14N$(EXEEXT) \
+ testAutomata$(EXEEXT) testRegexp$(EXEEXT) testReader$(EXEEXT) \
+- testapi$(EXEEXT) testModule$(EXEEXT) runtest$(EXEEXT) \
++ testapi$(EXEEXT) testModule$(EXEEXT) \
+ runsuite$(EXEEXT) testchar$(EXEEXT) testdict$(EXEEXT) \
+- runxmlconf$(EXEEXT) testrecurse$(EXEEXT)
++ runxmlconf$(EXEEXT)
+ bin_PROGRAMS = xmllint$(EXEEXT) xmlcatalog$(EXEEXT)
+ subdir = .
+ DIST_COMMON = README $(am__configure_deps) $(srcdir)/Makefile.am \
+ $(srcdir)/Makefile.in $(srcdir)/config.h.in \
+ $(srcdir)/libxml-2.0-uninstalled.pc.in \
+ $(srcdir)/libxml-2.0.pc.in $(srcdir)/libxml.spec.in \
+ $(srcdir)/xml2-config.in $(top_srcdir)/configure AUTHORS \
+ COPYING ChangeLog INSTALL NEWS TODO acconfig.h config.guess \
diff --git a/build/android/sdl-project/AndroidManifest.xml b/build/android/sdl-project/AndroidManifest.xml
new file mode 100644
index 0000000000..37f182ae96
--- /dev/null
+++ b/build/android/sdl-project/AndroidManifest.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/android/sdl-project/Makefile b/build/android/sdl-project/Makefile
new file mode 100644
index 0000000000..798cb218dd
--- /dev/null
+++ b/build/android/sdl-project/Makefile
@@ -0,0 +1,69 @@
+ANDROID=${HOME}/android
+NDK=${ANDROID}/android-ndk-r7-crystax-4
+SDK=${ANDROID}/android-sdk-linux
+TOOLCHAIN=${ANDROID}/toolchain-0ad
+SYSROOT=${TOOLCHAIN}/sysroot
+
+AAPT=${SDK}/platform-tools/aapt
+ADB=${SDK}/platform-tools/adb
+DX=${SDK}/platform-tools/dx
+ZIPALIGN=${SDK}/tools/zipalign
+NDKBUILD=${NDK}/ndk-build
+
+ANDROIDJAR=${SDK}/platforms/android-10/android.jar
+
+LIBPYRO=libpyrogenesis_dbg.so
+#LIBPYRO=libpyrogenesis.so
+
+PACKAGE=org/libsdl/app
+#PACKAGE=com/wildfiregames/zeroad
+
+all: bin/0ad.apk
+
+gen/${PACKAGE}/R.java:
+ mkdir -p bin/res
+ mkdir -p gen
+ ${AAPT} package -f -m -J gen/ -M AndroidManifest.xml -S bin/res -S res -I ${ANDROIDJAR}
+
+bin/classes/${PACKAGE}/SDLActivity.class: src/${PACKAGE}/SDLActivity.java gen/${PACKAGE}/R.java
+ mkdir -p bin/classes/${PACKAGE}/
+ javac \
+ -d bin/classes \
+ -classpath bin/classes:. \
+ -sourcepath src:gen \
+ -target 1.5 \
+ -bootclasspath ${ANDROIDJAR} \
+ -encoding UTF-8 \
+ -g \
+ -source 1.5 \
+ $^
+
+bin/classes.dex: bin/classes/${PACKAGE}/SDLActivity.class
+ ${DX} --dex --output $@ bin/classes
+
+libs/armeabi/libmain.so libs/armeabi/libSDL2.so: jni/src/pyrogenesis_wrapper.cpp
+ ${NDKBUILD}
+
+lib/armeabi/libmain.so lib/armeabi/libSDL2.so: libs/armeabi/libmain.so libs/armeabi/libSDL2.so
+ mkdir -p lib/armeabi
+ cp $^ lib/armeabi/
+
+bin/0ad.unaligned.apk: bin/classes.dex lib/armeabi/libmain.so lib/armeabi/libSDL2.so
+ ${AAPT} package -f -F $@ -M AndroidManifest.xml -S bin/res -S res -I ${ANDROIDJAR}
+ zip $@ -j bin/classes.dex
+ zip $@ -r lib
+ jarsigner -keystore ${HOME}/.android/debug.keystore -storepass android $@ androiddebugkey
+
+bin/0ad.apk: bin/0ad.unaligned.apk
+ ${ZIPALIGN} 4 $< $@
+
+push-apk: bin/0ad.apk
+ ${ADB} push $< /sdcard/
+
+push-so:
+ cp ../../../binaries/system/${LIBPYRO} libs/armeabi/
+ ${TOOLCHAIN}/bin/arm-linux-androideabi-strip libs/armeabi/${LIBPYRO}
+ ${ADB} push libs/armeabi/${LIBPYRO} /data/local/
+
+clean:
+ rm -rf bin gen lib libs obj
diff --git a/build/android/sdl-project/jni/Android.mk b/build/android/sdl-project/jni/Android.mk
new file mode 100644
index 0000000000..5053e7d643
--- /dev/null
+++ b/build/android/sdl-project/jni/Android.mk
@@ -0,0 +1 @@
+include $(call all-subdir-makefiles)
diff --git a/build/android/sdl-project/jni/src/Android.mk b/build/android/sdl-project/jni/src/Android.mk
new file mode 100644
index 0000000000..1eaf8aa11f
--- /dev/null
+++ b/build/android/sdl-project/jni/src/Android.mk
@@ -0,0 +1,19 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := main
+
+SDL_PATH := ../SDL
+
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/$(SDL_PATH)/include
+
+# Add your application source files here...
+LOCAL_SRC_FILES := $(SDL_PATH)/src/main/android/SDL_android_main.cpp \
+ pyrogenesis_wrapper.cpp
+
+LOCAL_SHARED_LIBRARIES := SDL2
+
+LOCAL_LDLIBS := -lGLESv2 -llog
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/build/android/sdl-project/jni/src/pyrogenesis_wrapper.cpp b/build/android/sdl-project/jni/src/pyrogenesis_wrapper.cpp
new file mode 100644
index 0000000000..e01ed37edd
--- /dev/null
+++ b/build/android/sdl-project/jni/src/pyrogenesis_wrapper.cpp
@@ -0,0 +1,30 @@
+#include
+
+#include
+
+#include "SDL.h" // sets up macro to wrap main()
+
+int main(int argc, char* argv[])
+{
+ __android_log_print(ANDROID_LOG_INFO, "pyrogenesis", "Started wrapper");
+
+ const char* pyropath = "/data/local/libpyrogenesis_dbg.so";
+ __android_log_print(ANDROID_LOG_INFO, "pyrogenesis", "Opening library %s", pyropath);
+ void* pyro = dlopen(pyropath, RTLD_NOW);
+ if (!pyro)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, "pyrogenesis", "Failed to open %s (dlerror %s)", pyropath, dlerror());
+ return -1;
+ }
+ __android_log_print(ANDROID_LOG_INFO, "pyrogenesis", "Library opened successfully");
+
+ void* pyromain = dlsym(pyro, "pyrogenesis_main");
+ if (!pyromain)
+ {
+ __android_log_print(ANDROID_LOG_ERROR, "pyrogenesis", "Failed to load entry symbol (dlerror %s)", dlerror());
+ return -1;
+ }
+
+ __android_log_print(ANDROID_LOG_INFO, "pyrogenesis", "Launching engine code");
+ return ((int(*)(int, char*[]))pyromain)(argc, argv);
+}
\ No newline at end of file
diff --git a/build/android/sdl-project/project.properties b/build/android/sdl-project/project.properties
new file mode 100644
index 0000000000..cc2a7c5cf3
--- /dev/null
+++ b/build/android/sdl-project/project.properties
@@ -0,0 +1 @@
+target=android-10
diff --git a/build/android/sdl-project/res/drawable-hdpi/icon.png b/build/android/sdl-project/res/drawable-hdpi/icon.png
new file mode 100644
index 0000000000..c815fe2615
--- /dev/null
+++ b/build/android/sdl-project/res/drawable-hdpi/icon.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:73a097cf4236c05d83e788029d7489fecbd79aab46f60c90b56bfddcfc01d9d4
+size 4147
diff --git a/build/android/sdl-project/res/drawable-ldpi/icon.png b/build/android/sdl-project/res/drawable-ldpi/icon.png
new file mode 100644
index 0000000000..0f81cb5363
--- /dev/null
+++ b/build/android/sdl-project/res/drawable-ldpi/icon.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:6d08f9080e829e786743b5441db18269cc8ad86297d528f57c47a4225cf2dfad
+size 1723
diff --git a/build/android/sdl-project/res/drawable-mdpi/icon.png b/build/android/sdl-project/res/drawable-mdpi/icon.png
new file mode 100644
index 0000000000..327aa57f33
--- /dev/null
+++ b/build/android/sdl-project/res/drawable-mdpi/icon.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:5f9136e6847229c124739b71fd1bd23e362b31a2454404d13d3e50747126e095
+size 2574
diff --git a/build/android/sdl-project/res/layout/main.xml b/build/android/sdl-project/res/layout/main.xml
new file mode 100644
index 0000000000..123c4b6eac
--- /dev/null
+++ b/build/android/sdl-project/res/layout/main.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
diff --git a/build/android/sdl-project/res/values/strings.xml b/build/android/sdl-project/res/values/strings.xml
new file mode 100644
index 0000000000..f73d46dfea
--- /dev/null
+++ b/build/android/sdl-project/res/values/strings.xml
@@ -0,0 +1,4 @@
+
+
+ 0 A.D.
+
diff --git a/build/android/sdl-project/src/org/libsdl/app/SDLActivity.java b/build/android/sdl-project/src/org/libsdl/app/SDLActivity.java
new file mode 100644
index 0000000000..4b54b2011a
--- /dev/null
+++ b/build/android/sdl-project/src/org/libsdl/app/SDLActivity.java
@@ -0,0 +1,579 @@
+package org.libsdl.app;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.opengles.GL10;
+import javax.microedition.khronos.egl.*;
+
+import android.app.*;
+import android.content.*;
+import android.view.*;
+import android.os.*;
+import android.util.Log;
+import android.graphics.*;
+import android.text.method.*;
+import android.text.*;
+import android.media.*;
+import android.hardware.*;
+import android.content.*;
+
+import java.lang.*;
+
+
+/**
+ SDL Activity
+*/
+public class SDLActivity extends Activity {
+
+ // Main components
+ private static SDLActivity mSingleton;
+ private static SDLSurface mSurface;
+
+ // This is what SDL runs in. It invokes SDL_main(), eventually
+ private static Thread mSDLThread;
+
+ // Audio
+ private static Thread mAudioThread;
+ private static AudioTrack mAudioTrack;
+
+ // EGL private objects
+ private static EGLContext mEGLContext;
+ private static EGLSurface mEGLSurface;
+ private static EGLDisplay mEGLDisplay;
+ private static EGLConfig mEGLConfig;
+ private static int mGLMajor, mGLMinor;
+
+ // Load the .so
+ static {
+ System.loadLibrary("SDL2");
+ //System.loadLibrary("SDL2_image");
+ //System.loadLibrary("SDL2_mixer");
+ //System.loadLibrary("SDL2_ttf");
+ System.loadLibrary("main");
+ }
+
+ // Setup
+ protected void onCreate(Bundle savedInstanceState) {
+ //Log.v("SDL", "onCreate()");
+ super.onCreate(savedInstanceState);
+
+ // So we can call stuff from static callbacks
+ mSingleton = this;
+
+ // Set up the surface
+ mSurface = new SDLSurface(getApplication());
+ setContentView(mSurface);
+ SurfaceHolder holder = mSurface.getHolder();
+ }
+
+ // Events
+ protected void onPause() {
+ Log.v("SDL", "onPause()");
+ super.onPause();
+ SDLActivity.nativePause();
+ }
+
+ protected void onResume() {
+ Log.v("SDL", "onResume()");
+ super.onResume();
+ SDLActivity.nativeResume();
+ }
+
+ protected void onDestroy() {
+ super.onDestroy();
+ Log.v("SDL", "onDestroy()");
+ // Send a quit message to the application
+ SDLActivity.nativeQuit();
+
+ // Now wait for the SDL thread to quit
+ if (mSDLThread != null) {
+ try {
+ mSDLThread.join();
+ } catch(Exception e) {
+ Log.v("SDL", "Problem stopping thread: " + e);
+ }
+ mSDLThread = null;
+
+ //Log.v("SDL", "Finished waiting for SDL thread");
+ }
+ }
+
+ // Messages from the SDLMain thread
+ static int COMMAND_CHANGE_TITLE = 1;
+
+ // Handler for the messages
+ Handler commandHandler = new Handler() {
+ public void handleMessage(Message msg) {
+ if (msg.arg1 == COMMAND_CHANGE_TITLE) {
+ setTitle((String)msg.obj);
+ }
+ }
+ };
+
+ // Send a message from the SDLMain thread
+ void sendCommand(int command, Object data) {
+ Message msg = commandHandler.obtainMessage();
+ msg.arg1 = command;
+ msg.obj = data;
+ commandHandler.sendMessage(msg);
+ }
+
+ // C functions we call
+ public static native void nativeInit();
+ public static native void nativeQuit();
+ public static native void nativePause();
+ public static native void nativeResume();
+ public static native void onNativeResize(int x, int y, int format);
+ public static native void onNativeKeyDown(int keycode);
+ public static native void onNativeKeyUp(int keycode);
+ public static native void onNativeTouch(int touchDevId, int pointerFingerId,
+ int action, float x,
+ float y, float p);
+ public static native void onNativeAccel(float x, float y, float z);
+ public static native void nativeRunAudioThread();
+
+
+ // Java functions called from C
+
+ public static boolean createGLContext(int majorVersion, int minorVersion) {
+ return initEGL(majorVersion, minorVersion);
+ }
+
+ public static void flipBuffers() {
+ flipEGL();
+ }
+
+ public static void setActivityTitle(String title) {
+ // Called from SDLMain() thread and can't directly affect the view
+ mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+ }
+
+ public static Context getContext() {
+ return mSingleton;
+ }
+
+ public static void startApp() {
+ // Start up the C app thread
+ if (mSDLThread == null) {
+ mSDLThread = new Thread(new SDLMain(), "SDLThread");
+ mSDLThread.start();
+ }
+ else {
+ SDLActivity.nativeResume();
+ }
+ }
+
+ // EGL functions
+ public static boolean initEGL(int majorVersion, int minorVersion) {
+ if (SDLActivity.mEGLDisplay == null) {
+ //Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
+
+ try {
+ EGL10 egl = (EGL10)EGLContext.getEGL();
+
+ EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+ int[] version = new int[2];
+ egl.eglInitialize(dpy, version);
+
+ int EGL_OPENGL_ES_BIT = 1;
+ int EGL_OPENGL_ES2_BIT = 4;
+ int renderableType = 0;
+ if (majorVersion == 2) {
+ renderableType = EGL_OPENGL_ES2_BIT;
+ } else if (majorVersion == 1) {
+ renderableType = EGL_OPENGL_ES_BIT;
+ }
+ int[] configSpec = {
+ //EGL10.EGL_DEPTH_SIZE, 16,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_SAMPLES, 4,
+ EGL10.EGL_RENDERABLE_TYPE, renderableType,
+ EGL10.EGL_NONE
+ };
+ EGLConfig[] configs = new EGLConfig[1];
+ int[] num_config = new int[1];
+ if (!egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config) || num_config[0] == 0) {
+ Log.e("SDL", "No EGL config available");
+ return false;
+ }
+ EGLConfig config = configs[0];
+
+ /*int EGL_CONTEXT_CLIENT_VERSION=0x3098;
+ int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL10.EGL_NONE };
+ EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
+
+ if (ctx == EGL10.EGL_NO_CONTEXT) {
+ Log.e("SDL", "Couldn't create context");
+ return false;
+ }
+ SDLActivity.mEGLContext = ctx;*/
+ SDLActivity.mEGLDisplay = dpy;
+ SDLActivity.mEGLConfig = config;
+ SDLActivity.mGLMajor = majorVersion;
+ SDLActivity.mGLMinor = minorVersion;
+
+ SDLActivity.createEGLSurface();
+ } catch(Exception e) {
+ Log.v("SDL", e + "");
+ for (StackTraceElement s : e.getStackTrace()) {
+ Log.v("SDL", s.toString());
+ }
+ }
+ }
+ else SDLActivity.createEGLSurface();
+
+ return true;
+ }
+
+ public static boolean createEGLContext() {
+ EGL10 egl = (EGL10)EGLContext.getEGL();
+ int EGL_CONTEXT_CLIENT_VERSION=0x3098;
+ int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, SDLActivity.mGLMajor, EGL10.EGL_NONE };
+ SDLActivity.mEGLContext = egl.eglCreateContext(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, EGL10.EGL_NO_CONTEXT, contextAttrs);
+ if (SDLActivity.mEGLContext == EGL10.EGL_NO_CONTEXT) {
+ Log.e("SDL", "Couldn't create context");
+ return false;
+ }
+ return true;
+ }
+
+ public static boolean createEGLSurface() {
+ if (SDLActivity.mEGLDisplay != null && SDLActivity.mEGLConfig != null) {
+ EGL10 egl = (EGL10)EGLContext.getEGL();
+ if (SDLActivity.mEGLContext == null) createEGLContext();
+
+ Log.v("SDL", "Creating new EGL Surface");
+ EGLSurface surface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity.mSurface, null);
+ if (surface == EGL10.EGL_NO_SURFACE) {
+ Log.e("SDL", "Couldn't create surface");
+ return false;
+ }
+
+ if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
+ Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
+ createEGLContext();
+ if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
+ Log.e("SDL", "Failed making EGL Context current");
+ return false;
+ }
+ }
+ SDLActivity.mEGLSurface = surface;
+ return true;
+ }
+ return false;
+ }
+
+ // EGL buffer flip
+ public static void flipEGL() {
+ try {
+ EGL10 egl = (EGL10)EGLContext.getEGL();
+
+ egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, null);
+
+ // drawing here
+
+ egl.eglWaitGL();
+
+ egl.eglSwapBuffers(SDLActivity.mEGLDisplay, SDLActivity.mEGLSurface);
+
+
+ } catch(Exception e) {
+ Log.v("SDL", "flipEGL(): " + e);
+ for (StackTraceElement s : e.getStackTrace()) {
+ Log.v("SDL", s.toString());
+ }
+ }
+ }
+
+ // Audio
+ private static Object buf;
+
+ public static Object audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
+ int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
+ int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
+ int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
+
+ Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ // Let the user pick a larger buffer if they really want -- but ye
+ // gods they probably shouldn't, the minimums are horrifyingly high
+ // latency already
+ desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
+
+ mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
+ channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
+
+ audioStartThread();
+
+ Log.v("SDL", "SDL audio: got " + ((mAudioTrack.getChannelCount() >= 2) ? "stereo" : "mono") + " " + ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit" : "8-bit") + " " + ((float)mAudioTrack.getSampleRate() / 1000f) + "kHz, " + desiredFrames + " frames buffer");
+
+ if (is16Bit) {
+ buf = new short[desiredFrames * (isStereo ? 2 : 1)];
+ } else {
+ buf = new byte[desiredFrames * (isStereo ? 2 : 1)];
+ }
+ return buf;
+ }
+
+ public static void audioStartThread() {
+ mAudioThread = new Thread(new Runnable() {
+ public void run() {
+ mAudioTrack.play();
+ nativeRunAudioThread();
+ }
+ });
+
+ // I'd take REALTIME if I could get it!
+ mAudioThread.setPriority(Thread.MAX_PRIORITY);
+ mAudioThread.start();
+ }
+
+ public static void audioWriteShortBuffer(short[] buffer) {
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w("SDL", "SDL audio: error return from write(short)");
+ return;
+ }
+ }
+ }
+
+ public static void audioWriteByteBuffer(byte[] buffer) {
+ for (int i = 0; i < buffer.length; ) {
+ int result = mAudioTrack.write(buffer, i, buffer.length - i);
+ if (result > 0) {
+ i += result;
+ } else if (result == 0) {
+ try {
+ Thread.sleep(1);
+ } catch(InterruptedException e) {
+ // Nom nom
+ }
+ } else {
+ Log.w("SDL", "SDL audio: error return from write(short)");
+ return;
+ }
+ }
+ }
+
+ public static void audioQuit() {
+ if (mAudioThread != null) {
+ try {
+ mAudioThread.join();
+ } catch(Exception e) {
+ Log.v("SDL", "Problem stopping audio thread: " + e);
+ }
+ mAudioThread = null;
+
+ //Log.v("SDL", "Finished waiting for audio thread");
+ }
+
+ if (mAudioTrack != null) {
+ mAudioTrack.stop();
+ mAudioTrack = null;
+ }
+ }
+}
+
+/**
+ Simple nativeInit() runnable
+*/
+class SDLMain implements Runnable {
+ public void run() {
+ // Runs SDL_main()
+ SDLActivity.nativeInit();
+
+ //Log.v("SDL", "SDL thread terminated");
+ }
+}
+
+
+/**
+ SDLSurface. This is what we draw on, so we need to know when it's created
+ in order to do anything useful.
+
+ Because of this, that's where we set up the SDL thread
+*/
+class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
+ View.OnKeyListener, View.OnTouchListener, SensorEventListener {
+
+ // Sensors
+ private static SensorManager mSensorManager;
+
+ // Startup
+ public SDLSurface(Context context) {
+ super(context);
+ getHolder().addCallback(this);
+
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestFocus();
+ setOnKeyListener(this);
+ setOnTouchListener(this);
+
+ mSensorManager = (SensorManager)context.getSystemService("sensor");
+ }
+
+ // Called when we have a valid drawing surface
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v("SDL", "surfaceCreated()");
+ holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ SDLActivity.createEGLSurface();
+ enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+ }
+
+ // Called when we lose the surface
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v("SDL", "surfaceDestroyed()");
+ SDLActivity.nativePause();
+ enableSensor(Sensor.TYPE_ACCELEROMETER, false);
+ }
+
+ // Called when the surface is resized
+ public void surfaceChanged(SurfaceHolder holder,
+ int format, int width, int height) {
+ Log.v("SDL", "surfaceChanged()");
+
+ int sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565 by default
+ switch (format) {
+ case PixelFormat.A_8:
+ Log.v("SDL", "pixel format A_8");
+ break;
+ case PixelFormat.LA_88:
+ Log.v("SDL", "pixel format LA_88");
+ break;
+ case PixelFormat.L_8:
+ Log.v("SDL", "pixel format L_8");
+ break;
+ case PixelFormat.RGBA_4444:
+ Log.v("SDL", "pixel format RGBA_4444");
+ sdlFormat = 0x85421002; // SDL_PIXELFORMAT_RGBA4444
+ break;
+ case PixelFormat.RGBA_5551:
+ Log.v("SDL", "pixel format RGBA_5551");
+ sdlFormat = 0x85441002; // SDL_PIXELFORMAT_RGBA5551
+ break;
+ case PixelFormat.RGBA_8888:
+ Log.v("SDL", "pixel format RGBA_8888");
+ sdlFormat = 0x86462004; // SDL_PIXELFORMAT_RGBA8888
+ break;
+ case PixelFormat.RGBX_8888:
+ Log.v("SDL", "pixel format RGBX_8888");
+ sdlFormat = 0x86262004; // SDL_PIXELFORMAT_RGBX8888
+ break;
+ case PixelFormat.RGB_332:
+ Log.v("SDL", "pixel format RGB_332");
+ sdlFormat = 0x84110801; // SDL_PIXELFORMAT_RGB332
+ break;
+ case PixelFormat.RGB_565:
+ Log.v("SDL", "pixel format RGB_565");
+ sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565
+ break;
+ case PixelFormat.RGB_888:
+ Log.v("SDL", "pixel format RGB_888");
+ // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
+ sdlFormat = 0x86161804; // SDL_PIXELFORMAT_RGB888
+ break;
+ default:
+ Log.v("SDL", "pixel format unknown " + format);
+ break;
+ }
+ SDLActivity.onNativeResize(width, height, sdlFormat);
+ Log.v("SDL", "Window size:" + width + "x"+height);
+
+ SDLActivity.startApp();
+ }
+
+ // unused
+ public void onDraw(Canvas canvas) {}
+
+
+
+
+ // Key events
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ //Log.v("SDL", "key down: " + keyCode);
+ SDLActivity.onNativeKeyDown(keyCode);
+ return true;
+ }
+ else if (event.getAction() == KeyEvent.ACTION_UP) {
+ //Log.v("SDL", "key up: " + keyCode);
+ SDLActivity.onNativeKeyUp(keyCode);
+ return true;
+ }
+
+ return false;
+ }
+
+ // Touch events
+ public boolean onTouch(View v, MotionEvent event) {
+ {
+ final int touchDevId = event.getDeviceId();
+ final int pointerCount = event.getPointerCount();
+ // touchId, pointerId, action, x, y, pressure
+ int actionPointerIndex = event.getActionIndex();
+ int pointerFingerId = event.getPointerId(actionPointerIndex);
+ int action = event.getActionMasked();
+
+ float x = event.getX(actionPointerIndex);
+ float y = event.getY(actionPointerIndex);
+ float p = event.getPressure(actionPointerIndex);
+
+ if (action == MotionEvent.ACTION_MOVE && pointerCount > 1) {
+ // TODO send motion to every pointer if its position has
+ // changed since prev event.
+ for (int i = 0; i < pointerCount; i++) {
+ pointerFingerId = event.getPointerId(i);
+ x = event.getX(i);
+ y = event.getY(i);
+ p = event.getPressure(i);
+ SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+ }
+ } else {
+ SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+ }
+ }
+ return true;
+ }
+
+ // Sensor events
+ public void enableSensor(int sensortype, boolean enabled) {
+ // TODO: This uses getDefaultSensor - what if we have >1 accels?
+ if (enabled) {
+ mSensorManager.registerListener(this,
+ mSensorManager.getDefaultSensor(sensortype),
+ SensorManager.SENSOR_DELAY_GAME, null);
+ } else {
+ mSensorManager.unregisterListener(this,
+ mSensorManager.getDefaultSensor(sensortype));
+ }
+ }
+
+ public void onAccuracyChanged(Sensor sensor, int accuracy) {
+ // TODO
+ }
+
+ public void onSensorChanged(SensorEvent event) {
+ if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
+ SDLActivity.onNativeAccel(event.values[0] / SensorManager.GRAVITY_EARTH,
+ event.values[1] / SensorManager.GRAVITY_EARTH,
+ event.values[2] / SensorManager.GRAVITY_EARTH);
+ }
+ }
+
+}
+
diff --git a/build/android/setup-libs.sh b/build/android/setup-libs.sh
new file mode 100755
index 0000000000..7200dfeccc
--- /dev/null
+++ b/build/android/setup-libs.sh
@@ -0,0 +1,170 @@
+#!/bin/bash
+
+set -e
+set -o nounset
+
+ANDROID=$HOME/android
+NDK=$ANDROID/android-ndk-r7-crystax-4
+SDK=$ANDROID/android-sdk-linux
+TOOLCHAIN=$ANDROID/toolchain-0ad
+
+build_toolchain=true
+
+build_boost=true
+build_curl=true
+build_libpng=true
+build_libjpeg=true
+build_libxml2=true
+build_enet=true
+build_js185=true
+
+JOBS=${JOBS:="-j4"}
+
+SYSROOT=$TOOLCHAIN/sysroot
+export PATH=$TOOLCHAIN/bin:$PATH
+CFLAGS="-mandroid -mthumb -mcpu=cortex-a9 -mfpu=neon -mfloat-abi=softfp"
+
+mkdir -p files
+pushd files
+
+if [ ! -e boost_1_45_0.tar.bz2 ]; then
+ wget http://downloads.sourceforge.net/project/boost/boost/1.45.0/boost_1_45_0.tar.bz2
+fi
+
+if [ ! -e curl-7.24.0.tar.bz2 ]; then
+ wget http://curl.haxx.se/download/curl-7.24.0.tar.bz2
+fi
+
+if [ ! -e MysticTreeGames-Boost-for-Android-70838fc.tar.gz ]; then
+ wget https://github.com/MysticTreeGames/Boost-for-Android/tarball/70838fcfba930646cac724a77f5c626e930431f6 -O MysticTreeGames-Boost-for-Android-70838fc.tar.gz
+fi
+
+if [ ! -e enet-1.3.3.tar.gz ]; then
+ wget http://enet.bespin.org/download/enet-1.3.3.tar.gz
+fi
+
+if [ ! -e js185-1.0.0.tar.gz ]; then
+ cp ../../../libraries/spidermonkey/js185-1.0.0.tar.gz .
+fi
+
+if [ ! -e libjpeg-turbo-1.1.1.tar.gz ]; then
+ wget http://downloads.sourceforge.net/project/libjpeg-turbo/1.1.1/libjpeg-turbo-1.1.1.tar.gz
+fi
+
+if [ ! -e libpng-1.5.8.tar.xz ]; then
+ wget http://prdownloads.sourceforge.net/libpng/libpng-1.5.8.tar.xz
+fi
+
+if [ ! -e libxml2-2.7.8.tar.gz ]; then
+ wget ftp://xmlsoft.org/libxml2/libxml2-2.7.8.tar.gz
+fi
+
+popd
+
+
+if [ "$build_toolchain" = "true" ]; then
+
+ rm -r $TOOLCHAIN || true
+ $NDK/build/tools/make-standalone-toolchain.sh --platform=android-9 --toolchain=arm-linux-androideabi-4.4.3 --install-dir=$TOOLCHAIN
+
+ mkdir -p $SYSROOT/usr/local
+
+ # Set up some symlinks to make the SpiderMonkey build system happy
+ ln -sfT ../platforms $NDK/build/platforms
+ for f in $TOOLCHAIN/bin/arm-linux-androideabi-*; do
+ ln -sf $f ${f/arm-linux-androideabi-/arm-eabi-}
+ done
+
+ # Set up some symlinks for the typical autoconf-based build systems
+ for f in $TOOLCHAIN/bin/arm-linux-androideabi-*; do
+ ln -sf $f ${f/arm-linux-androideabi-/arm-linux-eabi-}
+ done
+
+fi
+
+mkdir -p temp
+
+if [ "$build_boost" = "true" ]; then
+ rm -rf temp/MysticTreeGames-Boost-for-Android-70838fc
+ tar xvf files/MysticTreeGames-Boost-for-Android-70838fc.tar.gz -C temp/
+ cp files/boost_1_45_0.tar.bz2 temp/MysticTreeGames-Boost-for-Android-70838fc/
+ patch temp/MysticTreeGames-Boost-for-Android-70838fc/build-android.sh < boost-android-build.patch
+ pushd temp/MysticTreeGames-Boost-for-Android-70838fc
+ ./build-android.sh $TOOLCHAIN
+ cp -rv build/{include,lib} $SYSROOT/usr/local/
+ popd
+fi
+
+if [ "$build_curl" = "true" ]; then
+ rm -rf temp/curl-7.24.0
+ tar xvf files/curl-7.24.0.tar.bz2 -C temp/
+ pushd temp/curl-7.24.0
+ ./configure --host=arm-linux-androideabi --with-sysroot=$SYSROOT --prefix=$SYSROOT/usr/local CFLAGS="$CFLAGS" --disable-shared
+ make -j3
+ make install
+ popd
+fi
+
+if [ "$build_libpng" = "true" ]; then
+ rm -rf temp/libpng-1.5.7
+ tar xvf files/libpng-1.5.7.tar.xz -C temp/
+ pushd temp/libpng-1.5.7
+ ./configure --host=arm-linux-eabi --with-sysroot=$SYSROOT --prefix=$SYSROOT/usr/local CFLAGS="$CFLAGS"
+ make $JOBS
+ make install
+ popd
+fi
+
+if [ "$build_libjpeg" = "true" ]; then
+ rm -rf temp/libjpeg-turbo-1.1.1
+ tar xvf files/libjpeg-turbo-1.1.1.tar.gz -C temp/
+ pushd temp/libjpeg-turbo-1.1.1
+ ./configure --host=arm-linux-eabi --with-sysroot=$SYSROOT --prefix=$SYSROOT/usr/local CFLAGS="$CFLAGS"
+ make $JOBS
+ make install
+ popd
+fi
+
+if [ "$build_libxml2" = "true" ]; then
+ rm -rf temp/libxml2-2.7.8
+ tar xvf files/libxml2-2.7.8.tar.gz -C temp/
+ patch temp/libxml2-2.7.8/Makefile.in < libxml2-android-build.patch
+ pushd temp/libxml2-2.7.8
+ ./configure --host=arm-linux-eabi --with-sysroot=$SYSROOT --prefix=$SYSROOT/usr/local CFLAGS="$CFLAGS"
+ make $JOBS
+ make install
+ popd
+fi
+
+if [ "$build_enet" = "true" ]; then
+ rm -rf temp/enet-1.3.3
+ tar xvf files/enet-1.3.3.tar.gz -C temp/
+ pushd temp/enet-1.3.3
+ ./configure --host=arm-linux-eabi --with-sysroot=$SYSROOT --prefix=$SYSROOT/usr/local CFLAGS="$CFLAGS"
+ make $JOBS
+ make install
+ popd
+fi
+
+if [ "$build_js185" = "true" ]; then
+ rm -rf temp/js-1.8.5
+ tar xvf files/js185-1.0.0.tar.gz -C temp/
+ patch temp/js-1.8.5/js/src/assembler/wtf/Platform.h < js185-android-build.patch
+ pushd temp/js-1.8.5/js/src
+ CXXFLAGS="-I $TOOLCHAIN/arm-linux-androideabi/include/c++/4.4.3/arm-linux-androideabi" \
+ HOST_CXXFLAGS="-DFORCE_LITTLE_ENDIAN" \
+ ./configure \
+ --prefix=$SYSROOT/usr/local \
+ --target=arm-android-eabi \
+ --with-android-ndk=$NDK \
+ --with-android-sdk=$SDK \
+ --with-android-toolchain=$TOOLCHAIN \
+ --with-android-version=9 \
+ --disable-tests \
+ --disable-shared-js \
+ --with-arm-kuser \
+ CFLAGS="$CFLAGS"
+ make $JOBS JS_DISABLE_SHELL=1
+ make install JS_DISABLE_SHELL=1
+ popd
+fi
diff --git a/build/premake/extern_libs4.lua b/build/premake/extern_libs4.lua
index 83c1d83517..f599128983 100644
--- a/build/premake/extern_libs4.lua
+++ b/build/premake/extern_libs4.lua
@@ -217,9 +217,18 @@ extern_lib_defs = {
add_default_lib_paths("boost")
end
add_default_links({
- android_names = { "boost_signals-gcc-mt", "boost_filesystem-gcc-mt", "boost_system-gcc-mt" },
- unix_names = { "boost_signals-mt", "boost_filesystem-mt", "boost_system-mt" },
- bsd_names = { "boost_signals", "boost_filesystem", "boost_system" },
+ android_names = { "boost_filesystem-gcc-mt", "boost_system-gcc-mt" },
+ unix_names = { "boost_filesystem-mt", "boost_system-mt" },
+ bsd_names = { "boost_filesystem", "boost_system" },
+ })
+ end,
+ },
+ boost_signals = {
+ link_settings = function()
+ add_default_links({
+ android_names = { "boost_signals-gcc-mt" },
+ unix_names = { "boost_signals-mt" },
+ bsd_names = { "boost_signals" },
})
end,
},
@@ -451,8 +460,7 @@ extern_lib_defs = {
compile_settings = function()
if os.is("windows") then
includedirs { libraries_dir .. "sdl/include/SDL" }
- else
-
+ elseif not _OPTIONS["android"] then
-- Support SDL_CONFIG for overriding for the default PATH-based sdl-config
sdl_config_path = os.getenv("SDL_CONFIG")
if not sdl_config_path then
@@ -467,7 +475,7 @@ extern_lib_defs = {
link_settings = function()
if os.is("windows") then
add_default_lib_paths("sdl")
- else
+ elseif not _OPTIONS["android"] then
sdl_config_path = os.getenv("SDL_CONFIG")
if not sdl_config_path then
sdl_config_path = "sdl-config"
diff --git a/build/premake/premake4.lua b/build/premake/premake4.lua
index cb6c291e64..00b7f36524 100644
--- a/build/premake/premake4.lua
+++ b/build/premake/premake4.lua
@@ -908,6 +908,7 @@ function setup_atlas_projects()
atlas_extern_libs = {
"boost",
+ "boost_signals",
"comsuppw",
--"ffmpeg", -- disabled for now because it causes too many build difficulties
"libxml2",