diff --git a/AndroidManifest.xml b/AndroidManifest.xml
index 68975318..457c5100 100644
--- a/AndroidManifest.xml
+++ b/AndroidManifest.xml
@@ -67,6 +67,12 @@
+
+
+
+
+
+
diff --git a/jni/Application.mk b/jni/Application.mk
index 299cb32e..2cac9797 100644
--- a/jni/Application.mk
+++ b/jni/Application.mk
@@ -3,7 +3,7 @@
# See CPLUSPLUS-SUPPORT.html in the NDK documentation for more information
#APP_STL := stlport_static
-XASH_SDL ?= 1
+XASH_SDL ?= 0
ifeq ($(XASH_SDL),1)
APP_PLATFORM := android-12
diff --git a/src/in/celest/xash3d/XashActivity.java b/src/in/celest/xash3d/XashActivity.java
new file mode 100644
index 00000000..9ac647ac
--- /dev/null
+++ b/src/in/celest/xash3d/XashActivity.java
@@ -0,0 +1,495 @@
+package in.celest.xash3d;
+
+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 XashActivity extends Activity {
+
+ // Main components
+ protected static XashActivity mSingleton;
+ private static EngineSurface mSurface;
+ private static String mArgv;
+
+ // Audio
+ private static Thread mAudioThread;
+ private static AudioTrack mAudioTrack;
+ // Load the .so
+ static {
+ System.loadLibrary("xash");
+ }
+
+ // Setup
+ protected void onCreate(Bundle savedInstanceState) {
+ //Log.v("SDL", "onCreate()");
+ super.onCreate(savedInstanceState);
+
+ // So we can call stuff from static callbacks
+ mSingleton = this;
+ Intent intent = getIntent();
+ // mArgv = intent.getStringExtra(in.celest.xash3d.LauncherActivity.ARGV);
+ // Set up the surface
+ mSurface = new EngineSurface(getApplication());
+ setContentView(mSurface);
+ SurfaceHolder holder = mSurface.getHolder();
+ holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ setenv( "XASH3D_BASEDIR", "/sdcard/xash", true );
+ }
+
+ // Events
+ protected void onPause() {
+ //Log.v("SDL", "onPause()");
+ super.onPause();
+ }
+
+ protected void onResume() {
+ //Log.v("SDL", "onResume()");
+ super.onResume();
+ }
+
+ // 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);
+ }
+ public static String[] getArguments()
+ {
+
+
+ return "-dev 5 -log -noch".split(" ");
+ }
+ // C functions we call
+ public static native int nativeInit(Object arguments);
+ public static native void nativeQuit();
+ public static native void onNativeResize(int x, int y);
+ 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();
+ public static native int setenv(String key, String value, boolean overwrite);
+
+
+ // Java functions called from C
+
+ public static boolean createGLContext() {
+ return mSurface.InitGL();
+ }
+
+ public static void swapBuffers() {
+ mSurface.SwapBuffers();
+ }
+
+ 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;
+ }
+
+ // 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 XashMain implements Runnable {
+ public void run() {
+ // Runs SDL_main()
+ XashActivity.createGLContext();
+
+ XashActivity.nativeInit(XashActivity.getArguments());
+
+ //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 EngineSurface extends SurfaceView implements SurfaceHolder.Callback,
+View.OnKeyListener, View.OnTouchListener {
+
+ // This is what SDL runs in. It invokes SDL_main(), eventually
+ private Thread mEngThread;
+
+ // EGL private objects
+ private EGLContext mEGLContext;
+ private EGLSurface mEGLSurface;
+ private EGLDisplay mEGLDisplay;
+
+ // Sensors
+
+ // Startup
+ public EngineSurface(Context context) {
+ super(context);
+ getHolder().addCallback(this);
+
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestFocus();
+ setOnKeyListener(this);
+ setOnTouchListener(this);
+ }
+
+ // Called when we have a valid drawing surface
+ public void surfaceCreated(SurfaceHolder holder) {
+ //Log.v("SDL", "surfaceCreated()");
+ }
+
+ // Called when we lose the surface
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ //Log.v("SDL", "surfaceDestroyed()");
+
+ // Send a quit message to the application
+ XashActivity.nativeQuit();
+
+ // Now wait for the SDL thread to quit
+ if (mEngThread != null) {
+ try {
+ mEngThread.join();
+ } catch(Exception e) {
+ Log.v("SDL", "Problem stopping thread: " + e);
+ }
+ mEngThread = null;
+
+ //Log.v("SDL", "Finished waiting for SDL thread");
+ }
+ }
+
+ // 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;
+ }*/
+
+
+ XashActivity.onNativeResize(width, height);
+ // Now start up the C app thread
+ if (mEngThread == null) {
+
+ mEngThread = new Thread(new XashMain(), "EngineThread");
+ mEngThread.start();
+ }
+ }
+
+ // unused
+ public void onDraw(Canvas canvas) {}
+
+
+ // EGL functions
+ public boolean InitGL() {
+
+ try {
+ EGL10 egl = (EGL10)EGLContext.getEGL();
+
+ EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+ int[] version = new int[2];
+ egl.eglInitialize(dpy, version);
+
+ int[] configSpec = {
+ EGL10.EGL_DEPTH_SIZE, 8,
+ EGL10.EGL_RED_SIZE, 8,
+ EGL10.EGL_GREEN_SIZE, 8,
+ EGL10.EGL_BLUE_SIZE, 8,
+ EGL10.EGL_RENDERABLE_TYPE, 1,
+ 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, 1,
+ 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;
+ }
+
+ EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this, null);
+ if (surface == EGL10.EGL_NO_SURFACE) {
+ Log.e("SDL", "Couldn't create surface");
+ return false;
+ }
+
+ if (!egl.eglMakeCurrent(dpy, surface, surface, ctx)) {
+ Log.e("SDL", "Couldn't make context current");
+ return false;
+ }
+
+ mEGLContext = ctx;
+ mEGLDisplay = dpy;
+ mEGLSurface = surface;
+
+ } catch(Exception e) {
+ Log.v("SDL", e + "");
+ for (StackTraceElement s : e.getStackTrace()) {
+ Log.v("SDL", s.toString());
+ }
+ }
+
+ return true;
+ }
+
+ // EGL buffer flip
+ public void SwapBuffers() {
+ try {
+ EGL10 egl = (EGL10)EGLContext.getEGL();
+
+ egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, null);
+
+ // drawing here
+
+ egl.eglWaitGL();
+
+ egl.eglSwapBuffers(mEGLDisplay, mEGLSurface);
+
+
+ } catch(Exception e) {
+ Log.v("SDL", "flipEGL(): " + e);
+ for (StackTraceElement s : e.getStackTrace()) {
+ Log.v("SDL", s.toString());
+ }
+ }
+ }
+
+ // Key events
+ public boolean onKey(View v, int keyCode, KeyEvent event) {
+
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ //Log.v("SDL", "key down: " + keyCode);
+ //XashActivity.controlInterp.onKeyDown(keyCode, event);
+ return true;
+ }
+ else if (event.getAction() == KeyEvent.ACTION_UP) {
+ //Log.v("SDL", "key up: " + keyCode);
+ // XashActivity.controlInterp.onKeyUp(keyCode, event);
+ 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);
+ XashActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+ }
+ } else {
+ XashActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
+ }
+ }*/
+ //XashActivity.controlInterp.onTouchEvent(event);
+ return true;
+ }
+
+}
+
diff --git a/test/AndroidManifest.xml b/test/AndroidManifest.xml
index 43af11e4..456202d2 100644
--- a/test/AndroidManifest.xml
+++ b/test/AndroidManifest.xml
@@ -73,10 +73,15 @@
-
+
+
+
+
+
+