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",