--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java Thu Oct 20 22:54:34 2011 +0200
@@ -0,0 +1,565 @@
+package org.hedgewars.hedgeroid;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLContext;
+import javax.microedition.khronos.egl.EGLDisplay;
+import javax.microedition.khronos.egl.EGLSurface;
+
+import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
+import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
+import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
+import org.hedgewars.hedgeroid.TouchInterface.TouchInterface;
+
+import android.app.Activity;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.PixelFormat;
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
+import android.hardware.SensorManager;
+import android.media.AudioFormat;
+import android.media.AudioManager;
+import android.media.AudioTrack;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+import android.view.View;
+
+/**
+ * SDL Activity
+ */
+public class SDLActivity extends Activity {
+
+ // Main components
+ public static SDLActivity mSingleton;
+ public static SDLSurface mSurface;
+
+ // Audio
+ private static Thread mAudioThread;
+ private static AudioTrack mAudioTrack;
+
+ // Load the .so
+ static {
+ System.loadLibrary("SDL");
+ System.loadLibrary("SDL_image");
+ System.loadLibrary("mikmod");
+ System.loadLibrary("SDL_net");
+ System.loadLibrary("SDL_mixer");
+ System.loadLibrary("SDL_ttf");
+ System.loadLibrary("lua5.1");
+ System.loadLibrary("hwengine");
+ 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
+ GameConfig config = getIntent().getParcelableExtra("config");
+ mSurface = new SDLSurface(getApplication(), config);
+ setContentView(mSurface);
+ SurfaceHolder holder = mSurface.getHolder();
+ holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ }
+
+ // Events
+ protected void onPause() {
+ // Log.v("SDL", "onPause()");
+ super.onPause();
+
+ }
+
+ protected void onResume() {
+ // Log.v("SDL", "onResume()");
+ super.onResume();
+ }
+
+ public void onBackPressed(){
+ nativeQuit();
+ super.onBackPressed();
+ }
+
+ // 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(String[] argv);
+
+ public static native void nativeQuit();
+
+ 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 action, int pointer, 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 mSurface.initEGL(majorVersion, minorVersion);
+ }
+
+ public static void flipBuffers() {
+ mSurface.flipEGL();
+ }
+
+ public static void setActivityTitle(String title) {
+ // Called from SDLMain() thread and can't directly affect the view
+ mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
+ }
+
+ // 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 {
+ private int surfaceWidth, surfaceHeight;
+ private GameConfig config;
+
+ public SDLMain(int width, int height, GameConfig _config) {
+ config = _config;
+ surfaceWidth = width;
+ surfaceHeight = height;
+ }
+
+ public void run() {
+ //Set up the IPC socket server to communicate with the engine
+ EngineProtocolNetwork ipc = new EngineProtocolNetwork(config);
+
+ String path = Utils.getDownloadPath(SDLActivity.mSingleton);//This represents the data directory
+ path = path.substring(0, path.length()-1);//remove the trailing '/'
+
+
+ // Runs SDL_main() with added parameters
+ SDLActivity.nativeInit(new String[] { String.valueOf(ipc.port),
+ String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
+ "0", "null", "xeli", "1", "1", "1", path, "" });
+
+ try {
+ ipc.quitIPC();
+ ipc.join();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ //Log.v("SDL", "SDL thread terminated");
+ SDLActivity.mSingleton.finish();
+ }
+}
+
+/**
+ * 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, SensorEventListener {
+
+ // This is what SDL runs in. It invokes SDL_main(), eventually
+ private Thread mSDLThread;
+
+ // EGL private objects
+ private EGLContext mEGLContext;
+ private EGLSurface mEGLSurface;
+ private EGLDisplay mEGLDisplay;
+
+ // Sensors
+ private static SensorManager mSensorManager;
+
+ private GameConfig config;
+
+ // Startup
+ public SDLSurface(Context context, GameConfig _config) {
+ super(context);
+ getHolder().addCallback(this);
+
+ setFocusable(true);
+ setFocusableInTouchMode(true);
+ requestFocus();
+ setOnKeyListener(this);
+ setOnTouchListener(TouchInterface.getTouchInterface());
+
+ mSensorManager = (SensorManager) context.getSystemService("sensor");
+
+ config = _config;
+ }
+
+ // Called when we have a valid drawing surface
+ public void surfaceCreated(SurfaceHolder holder) {
+ Log.v("SDL", "surfaceCreated()");
+
+ //enableSensor(Sensor.TYPE_ACCELEROMETER, true);
+ }
+
+ // Called when we lose the surface
+ public void surfaceDestroyed(SurfaceHolder holder) {
+ Log.v("SDL", "surfaceDestroyed()");
+
+ // Send a quit message to the application
+ //SDLActivity.nativeQuit();
+ PascalExports.HWterminate(true);
+
+ // 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");
+ }
+
+ //enableSensor(Sensor.TYPE_ACCELEROMETER, false);
+ }
+
+ // Called when the surface is resized
+ public void surfaceChanged(SurfaceHolder holder, int format, int width,
+ int height) {
+ Log.d("SDL", "surfaceChanged()" + width + " + " + height);
+
+ 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);
+
+ // Now start up the C app thread
+ if (mSDLThread == null) {
+ mSDLThread = new Thread(new SDLMain(width, height, config),
+ "SDLThread");
+ mSDLThread.start();
+ }
+ }
+
+ // unused
+ public void onDraw(Canvas canvas) {
+ }
+
+ // EGL functions
+ public boolean initEGL(int majorVersion, int minorVersion) {
+ 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_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];
+
+ EGLContext ctx = egl.eglCreateContext(dpy, config,
+ EGL10.EGL_NO_CONTEXT, null);
+ 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 flipEGL() {
+ try {
+ EGL10 egl = (EGL10) EGLContext.getEGL();
+
+ egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, 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(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) return false;
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ Log.v("SDL", "key down: " + keyCode);
+ if(keyCode == KeyEvent.KEYCODE_BACK){//TODO ask user to quit or not
+ PascalExports.HWterminate(true);
+ //SDLActivity.mSingleton.finish();
+ }else{
+ 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;
+ }
+
+ // 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], event.values[1],
+ event.values[2]);
+ }
+ }
+
+}