project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java
changeset 6597 814683bbd230
parent 6487 bd3c736c1eac
child 6599 1d3746138113
equal deleted inserted replaced
6595:f567d52183ec 6597:814683bbd230
     7 import javax.microedition.khronos.egl.EGLSurface;
     7 import javax.microedition.khronos.egl.EGLSurface;
     8 
     8 
     9 import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
     9 import org.hedgewars.hedgeroid.EngineProtocol.EngineProtocolNetwork;
    10 import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
    10 import org.hedgewars.hedgeroid.EngineProtocol.GameConfig;
    11 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    11 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    12 import org.hedgewars.hedgeroid.UserInput.TouchInterface;
       
    13 
    12 
    14 import android.app.Activity;
    13 import android.app.Activity;
    15 import android.content.Context;
    14 import android.content.Context;
    16 import android.graphics.Canvas;
    15 import android.graphics.Canvas;
    17 import android.graphics.PixelFormat;
    16 import android.graphics.PixelFormat;
    25 import android.os.Bundle;
    24 import android.os.Bundle;
    26 import android.os.Handler;
    25 import android.os.Handler;
    27 import android.os.Message;
    26 import android.os.Message;
    28 import android.util.Log;
    27 import android.util.Log;
    29 import android.view.KeyEvent;
    28 import android.view.KeyEvent;
       
    29 import android.view.MotionEvent;
    30 import android.view.SurfaceHolder;
    30 import android.view.SurfaceHolder;
    31 import android.view.SurfaceView;
    31 import android.view.SurfaceView;
    32 import android.view.View;
    32 import android.view.View;
    33 
    33 
       
    34 
    34 /**
    35 /**
    35  * SDL Activity
    36     SDL Activity
    36  */
    37 */
    37 public class SDLActivity extends Activity {
    38 public class SDLActivity extends Activity {
    38 
    39 
    39 	// Main components
    40     // Main components
    40 	public static SDLActivity mSingleton;
    41     public static SDLActivity mSingleton;
    41 	public static SDLSurface mSurface;
    42     private static SDLSurface mSurface;
    42 
    43 
    43 	// Audio
    44     // This is what SDL runs in. It invokes SDL_main(), eventually
    44 	private static Thread mAudioThread;
    45     private static Thread mSDLThread;
    45 	private static AudioTrack mAudioTrack;
    46 
    46 
    47     // Audio
    47 	// Load the .so
    48     private static Thread mAudioThread;
    48 	static {
    49     private static AudioTrack mAudioTrack;
    49 		System.loadLibrary("SDL");
    50 
    50 		System.loadLibrary("SDL_image");
    51     // EGL private objects
    51 		System.loadLibrary("mikmod");
    52     private static EGLContext  mEGLContext;
    52 		System.loadLibrary("SDL_net");
    53     private static EGLSurface  mEGLSurface;
    53 		System.loadLibrary("SDL_mixer");
    54     private static EGLDisplay  mEGLDisplay;
    54 		System.loadLibrary("SDL_ttf");
    55     private static EGLConfig   mEGLConfig;
    55 		System.loadLibrary("lua5.1");
    56     private static int mGLMajor, mGLMinor;
    56 		System.loadLibrary("hwengine");
    57 
    57 		System.loadLibrary("main");
    58     // Load the .so
    58 	}
    59     static {
    59 
    60         System.loadLibrary("SDL");
    60 	// Setup
    61         //System.loadLibrary("SDL_image");
    61 	protected void onCreate(Bundle savedInstanceState) {
    62         //System.loadLibrary("SDL_mixer");
    62 		// Log.v("SDL", "onCreate()");
    63         //System.loadLibrary("SDL_ttf");
    63 		super.onCreate(savedInstanceState);
    64         System.loadLibrary("main");
    64 
    65     }
    65 		// So we can call stuff from static callbacks
    66 
    66 		mSingleton = this;
    67     // Setup
    67 
    68     protected void onCreate(Bundle savedInstanceState) {
    68 		// Set up the surface
    69         //Log.v("SDL", "onCreate()");
    69 		GameConfig config = getIntent().getParcelableExtra("config");
    70         super.onCreate(savedInstanceState);
    70 		mSurface = new SDLSurface(getApplication(), config);
    71         
    71 		setContentView(mSurface);
    72         // So we can call stuff from static callbacks
    72 		SurfaceHolder holder = mSurface.getHolder();
    73         mSingleton = this;
    73 		holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
    74 
    74 	}
    75         // Set up the surface
    75 
    76         GameConfig config = getIntent().getParcelableExtra("config");
    76 	// Events
    77         
    77 	protected void onPause() {
    78         mSurface = new SDLSurface(getApplication(), config);
    78 		// Log.v("SDL", "onPause()");
    79         setContentView(mSurface);
    79 		super.onPause();
    80         SurfaceHolder holder = mSurface.getHolder();
    80 
    81     }
    81 	}
    82 
    82 
    83     // Events
    83 	protected void onResume() {
    84     protected void onPause() {
    84 		// Log.v("SDL", "onResume()");
    85         Log.v("SDL", "onPause()");
    85 		super.onResume();
    86         super.onPause();
    86 	}
    87         SDLActivity.nativePause();
       
    88     }
       
    89 
       
    90     protected void onResume() {
       
    91         Log.v("SDL", "onResume()");
       
    92         super.onResume();
       
    93         SDLActivity.nativeResume();
       
    94     }
       
    95     
       
    96     public void onBackPressed(){
       
    97     	super.onBackPressed();
       
    98     	PascalExports.HWterminate(true);
       
    99     }
       
   100 
       
   101     protected void onDestroy() {
       
   102         super.onDestroy();
       
   103         Log.v("SDL", "onDestroy()");
       
   104         // Send a quit message to the application
       
   105         SDLActivity.nativeQuit();
       
   106 
       
   107         // Now wait for the SDL thread to quit
       
   108         if (mSDLThread != null) {
       
   109             try {
       
   110                 mSDLThread.join();
       
   111             } catch(Exception e) {
       
   112                 Log.v("SDL", "Problem stopping thread: " + e);
       
   113             }
       
   114             mSDLThread = null;
       
   115 
       
   116             //Log.v("SDL", "Finished waiting for SDL thread");
       
   117         }
       
   118     }
       
   119 
       
   120     // Messages from the SDLMain thread
       
   121     static int COMMAND_CHANGE_TITLE = 1;
       
   122 
       
   123     // Handler for the messages
       
   124     Handler commandHandler = new Handler() {
       
   125         public void handleMessage(Message msg) {
       
   126             if (msg.arg1 == COMMAND_CHANGE_TITLE) {
       
   127                 setTitle((String)msg.obj);
       
   128             }
       
   129         }
       
   130     };
       
   131 
       
   132     // Send a message from the SDLMain thread
       
   133     void sendCommand(int command, Object data) {
       
   134         Message msg = commandHandler.obtainMessage();
       
   135         msg.arg1 = command;
       
   136         msg.obj = data;
       
   137         commandHandler.sendMessage(msg);
       
   138     }
       
   139 
       
   140     // C functions we call
       
   141     public static native void nativeInit(String...args);
       
   142     public static native void nativeQuit();
       
   143     public static native void nativePause();
       
   144     public static native void nativeResume();
       
   145     public static native void onNativeResize(int x, int y, int format);
       
   146     public static native void onNativeKeyDown(int keycode);
       
   147     public static native void onNativeKeyUp(int keycode);
       
   148     public static native void onNativeTouch(int touchDevId, int pointerFingerId,
       
   149                                             int action, float x, 
       
   150                                             float y, float p);
       
   151     public static native void onNativeAccel(float x, float y, float z);
       
   152     public static native void nativeRunAudioThread();
       
   153 
       
   154 
       
   155     // Java functions called from C
       
   156 
       
   157     public static boolean createGLContext(int majorVersion, int minorVersion) {
       
   158         return initEGL(majorVersion, minorVersion);
       
   159     }
       
   160 
       
   161     public static void flipBuffers() {
       
   162         flipEGL();
       
   163     }
       
   164 
       
   165     public static void setActivityTitle(String title) {
       
   166         // Called from SDLMain() thread and can't directly affect the view
       
   167         mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
       
   168     }
       
   169 
       
   170     public static Context getContext() {
       
   171         return mSingleton;
       
   172     }
       
   173 
       
   174     public static void startApp(int width, int height, GameConfig config) {
       
   175         // Start up the C app thread
       
   176         if (mSDLThread == null) {
       
   177             mSDLThread = new Thread(new SDLMain(width, height, config), "SDLThread");
       
   178             mSDLThread.start();
       
   179         }
       
   180         else {
       
   181             SDLActivity.nativeResume();
       
   182         }
       
   183     }
       
   184 
       
   185     // EGL functions
       
   186     public static boolean initEGL(int majorVersion, int minorVersion) {
       
   187         if (SDLActivity.mEGLDisplay == null) {
       
   188             //Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
       
   189 
       
   190             try {
       
   191                 EGL10 egl = (EGL10)EGLContext.getEGL();
       
   192 
       
   193                 EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
       
   194 
       
   195                 int[] version = new int[2];
       
   196                 egl.eglInitialize(dpy, version);
       
   197 
       
   198                 int EGL_OPENGL_ES_BIT = 1;
       
   199                 int EGL_OPENGL_ES2_BIT = 4;
       
   200                 int renderableType = 0;
       
   201                 if (majorVersion == 2) {
       
   202                     renderableType = EGL_OPENGL_ES2_BIT;
       
   203                 } else if (majorVersion == 1) {
       
   204                     renderableType = EGL_OPENGL_ES_BIT;
       
   205                 }
       
   206                 int[] configSpec = {
       
   207                     //EGL10.EGL_DEPTH_SIZE,   16,
       
   208                     EGL10.EGL_RENDERABLE_TYPE, renderableType,
       
   209                     EGL10.EGL_NONE
       
   210                 };
       
   211                 EGLConfig[] configs = new EGLConfig[1];
       
   212                 int[] num_config = new int[1];
       
   213                 if (!egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config) || num_config[0] == 0) {
       
   214                     Log.e("SDL", "No EGL config available");
       
   215                     return false;
       
   216                 }
       
   217                 EGLConfig config = configs[0];
       
   218 
       
   219                 /*int EGL_CONTEXT_CLIENT_VERSION=0x3098;
       
   220                 int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL10.EGL_NONE };
       
   221                 EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
       
   222 
       
   223                 if (ctx == EGL10.EGL_NO_CONTEXT) {
       
   224                     Log.e("SDL", "Couldn't create context");
       
   225                     return false;
       
   226                 }
       
   227                 SDLActivity.mEGLContext = ctx;*/
       
   228                 SDLActivity.mEGLDisplay = dpy;
       
   229                 SDLActivity.mEGLConfig = config;
       
   230                 SDLActivity.mGLMajor = majorVersion;
       
   231                 SDLActivity.mGLMinor = minorVersion;
       
   232 
       
   233                 SDLActivity.createEGLSurface();
       
   234             } catch(Exception e) {
       
   235                 Log.v("SDL", e + "");
       
   236                 for (StackTraceElement s : e.getStackTrace()) {
       
   237                     Log.v("SDL", s.toString());
       
   238                 }
       
   239             }
       
   240         }
       
   241         else SDLActivity.createEGLSurface();
       
   242 
       
   243         return true;
       
   244     }
       
   245 
       
   246     public static boolean createEGLContext() {
       
   247         EGL10 egl = (EGL10)EGLContext.getEGL();
       
   248         int EGL_CONTEXT_CLIENT_VERSION=0x3098;
       
   249         int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, SDLActivity.mGLMajor, EGL10.EGL_NONE };
       
   250         SDLActivity.mEGLContext = egl.eglCreateContext(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, EGL10.EGL_NO_CONTEXT, contextAttrs);
       
   251         if (SDLActivity.mEGLContext == EGL10.EGL_NO_CONTEXT) {
       
   252             Log.e("SDL", "Couldn't create context");
       
   253             return false;
       
   254         }
       
   255         return true;
       
   256     }
       
   257 
       
   258     public static boolean createEGLSurface() {
       
   259         if (SDLActivity.mEGLDisplay != null && SDLActivity.mEGLConfig != null) {
       
   260             EGL10 egl = (EGL10)EGLContext.getEGL();
       
   261             if (SDLActivity.mEGLContext == null) createEGLContext();
       
   262 
       
   263             Log.v("SDL", "Creating new EGL Surface");
       
   264             EGLSurface surface = egl.eglCreateWindowSurface(SDLActivity.mEGLDisplay, SDLActivity.mEGLConfig, SDLActivity.mSurface, null);
       
   265             if (surface == EGL10.EGL_NO_SURFACE) {
       
   266                 Log.e("SDL", "Couldn't create surface");
       
   267                 return false;
       
   268             }
       
   269 
       
   270             if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
       
   271                 Log.e("SDL", "Old EGL Context doesnt work, trying with a new one");
       
   272                 createEGLContext();
       
   273                 if (!egl.eglMakeCurrent(SDLActivity.mEGLDisplay, surface, surface, SDLActivity.mEGLContext)) {
       
   274                     Log.e("SDL", "Failed making EGL Context current");
       
   275                     return false;
       
   276                 }
       
   277             }
       
   278             SDLActivity.mEGLSurface = surface;
       
   279             return true;
       
   280         }
       
   281         return false;
       
   282     }
       
   283 
       
   284     // EGL buffer flip
       
   285     public static void flipEGL() {
       
   286         try {
       
   287             EGL10 egl = (EGL10)EGLContext.getEGL();
       
   288 
       
   289             egl.eglWaitNative(EGL10.EGL_CORE_NATIVE_ENGINE, null);
       
   290 
       
   291             // drawing here
       
   292 
       
   293             egl.eglWaitGL();
       
   294 
       
   295             egl.eglSwapBuffers(SDLActivity.mEGLDisplay, SDLActivity.mEGLSurface);
       
   296 
       
   297 
       
   298         } catch(Exception e) {
       
   299             Log.v("SDL", "flipEGL(): " + e);
       
   300             for (StackTraceElement s : e.getStackTrace()) {
       
   301                 Log.v("SDL", s.toString());
       
   302             }
       
   303         }
       
   304     }
       
   305 
       
   306     // Audio
       
   307     private static Object buf;
       
   308     
       
   309     public static Object audioInit(int sampleRate, boolean is16Bit, boolean isStereo, int desiredFrames) {
       
   310         int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO : AudioFormat.CHANNEL_CONFIGURATION_MONO;
       
   311         int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT : AudioFormat.ENCODING_PCM_8BIT;
       
   312         int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
       
   313         
       
   314         Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono") + " " + (is16Bit ? "16-bit" : "8-bit") + " " + ((float)sampleRate / 1000f) + "kHz, " + desiredFrames + " frames buffer");
       
   315         
       
   316         // Let the user pick a larger buffer if they really want -- but ye
       
   317         // gods they probably shouldn't, the minimums are horrifyingly high
       
   318         // latency already
       
   319         desiredFrames = Math.max(desiredFrames, (AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat) + frameSize - 1) / frameSize);
       
   320         
       
   321         mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
       
   322                 channelConfig, audioFormat, desiredFrames * frameSize, AudioTrack.MODE_STREAM);
       
   323         
       
   324         audioStartThread();
       
   325         
       
   326         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");
       
   327         
       
   328         if (is16Bit) {
       
   329             buf = new short[desiredFrames * (isStereo ? 2 : 1)];
       
   330         } else {
       
   331             buf = new byte[desiredFrames * (isStereo ? 2 : 1)]; 
       
   332         }
       
   333         return buf;
       
   334     }
       
   335     
       
   336     public static void audioStartThread() {
       
   337         mAudioThread = new Thread(new Runnable() {
       
   338             public void run() {
       
   339                 mAudioTrack.play();
       
   340                 nativeRunAudioThread();
       
   341             }
       
   342         });
       
   343         
       
   344         // I'd take REALTIME if I could get it!
       
   345         mAudioThread.setPriority(Thread.MAX_PRIORITY);
       
   346         mAudioThread.start();
       
   347     }
       
   348     
       
   349     public static void audioWriteShortBuffer(short[] buffer) {
       
   350         for (int i = 0; i < buffer.length; ) {
       
   351             int result = mAudioTrack.write(buffer, i, buffer.length - i);
       
   352             if (result > 0) {
       
   353                 i += result;
       
   354             } else if (result == 0) {
       
   355                 try {
       
   356                     Thread.sleep(1);
       
   357                 } catch(InterruptedException e) {
       
   358                     // Nom nom
       
   359                 }
       
   360             } else {
       
   361                 Log.w("SDL", "SDL audio: error return from write(short)");
       
   362                 return;
       
   363             }
       
   364         }
       
   365     }
       
   366     
       
   367     public static void audioWriteByteBuffer(byte[] buffer) {
       
   368         for (int i = 0; i < buffer.length; ) {
       
   369             int result = mAudioTrack.write(buffer, i, buffer.length - i);
       
   370             if (result > 0) {
       
   371                 i += result;
       
   372             } else if (result == 0) {
       
   373                 try {
       
   374                     Thread.sleep(1);
       
   375                 } catch(InterruptedException e) {
       
   376                     // Nom nom
       
   377                 }
       
   378             } else {
       
   379                 Log.w("SDL", "SDL audio: error return from write(short)");
       
   380                 return;
       
   381             }
       
   382         }
       
   383     }
       
   384 
       
   385     public static void audioQuit() {
       
   386         if (mAudioThread != null) {
       
   387             try {
       
   388                 mAudioThread.join();
       
   389             } catch(Exception e) {
       
   390                 Log.v("SDL", "Problem stopping audio thread: " + e);
       
   391             }
       
   392             mAudioThread = null;
       
   393 
       
   394             //Log.v("SDL", "Finished waiting for audio thread");
       
   395         }
       
   396 
       
   397         if (mAudioTrack != null) {
       
   398             mAudioTrack.stop();
       
   399             mAudioTrack = null;
       
   400         }
       
   401     }
       
   402 }
       
   403 
       
   404 /**
       
   405     Simple nativeInit() runnable
       
   406 */
       
   407 class SDLMain implements Runnable {
    87 	
   408 	
    88 	public void onBackPressed(){
       
    89 		nativeQuit();
       
    90 		super.onBackPressed();
       
    91 	}
       
    92 
       
    93 	// Messages from the SDLMain thread
       
    94 	static int COMMAND_CHANGE_TITLE = 1;
       
    95 
       
    96 	// Handler for the messages
       
    97 	Handler commandHandler = new Handler() {
       
    98 		public void handleMessage(Message msg) {
       
    99 			if (msg.arg1 == COMMAND_CHANGE_TITLE) {
       
   100 				setTitle((String) msg.obj);
       
   101 			}
       
   102 		}
       
   103 	};
       
   104 
       
   105 	// Send a message from the SDLMain thread
       
   106 	void sendCommand(int command, Object data) {
       
   107 		Message msg = commandHandler.obtainMessage();
       
   108 		msg.arg1 = command;
       
   109 		msg.obj = data;
       
   110 		commandHandler.sendMessage(msg);
       
   111 	}
       
   112 
       
   113 	// C functions we call
       
   114 	public static native void nativeInit(String[] argv);
       
   115 
       
   116 	public static native void nativeQuit();
       
   117 
       
   118 	public static native void onNativeResize(int x, int y, int format);
       
   119 
       
   120 	public static native void onNativeKeyDown(int keycode);
       
   121 
       
   122 	public static native void onNativeKeyUp(int keycode);
       
   123 
       
   124 	public static native void onNativeTouch(int touchDevId, int pointerFingerId, int action, float x, float y,
       
   125 			float p);
       
   126 
       
   127 	public static native void onNativeAccel(float x, float y, float z);
       
   128 
       
   129 	public static native void nativeRunAudioThread();
       
   130 
       
   131 	// Java functions called from C
       
   132 
       
   133 	public static boolean createGLContext(int majorVersion, int minorVersion) {
       
   134 		return mSurface.initEGL(majorVersion, minorVersion);
       
   135 	}
       
   136 
       
   137 	public static void flipBuffers() {
       
   138 		mSurface.flipEGL();
       
   139 	}
       
   140 
       
   141 	public static void setActivityTitle(String title) {
       
   142 		// Called from SDLMain() thread and can't directly affect the view
       
   143 		mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
       
   144 	}
       
   145 
       
   146 	// Audio
       
   147 	private static Object buf;
       
   148 
       
   149 	public static Object audioInit(int sampleRate, boolean is16Bit,
       
   150 			boolean isStereo, int desiredFrames) {
       
   151 		int channelConfig = isStereo ? AudioFormat.CHANNEL_CONFIGURATION_STEREO
       
   152 				: AudioFormat.CHANNEL_CONFIGURATION_MONO;
       
   153 		int audioFormat = is16Bit ? AudioFormat.ENCODING_PCM_16BIT
       
   154 				: AudioFormat.ENCODING_PCM_8BIT;
       
   155 		int frameSize = (isStereo ? 2 : 1) * (is16Bit ? 2 : 1);
       
   156 
       
   157 		Log.v("SDL", "SDL audio: wanted " + (isStereo ? "stereo" : "mono")
       
   158 				+ " " + (is16Bit ? "16-bit" : "8-bit") + " "
       
   159 				+ ((float) sampleRate / 1000f) + "kHz, " + desiredFrames
       
   160 				+ " frames buffer");
       
   161 
       
   162 		// Let the user pick a larger buffer if they really want -- but ye
       
   163 		// gods they probably shouldn't, the minimums are horrifyingly high
       
   164 		// latency already
       
   165 		desiredFrames = Math.max(
       
   166 				desiredFrames,
       
   167 				(AudioTrack.getMinBufferSize(sampleRate, channelConfig,
       
   168 						audioFormat) + frameSize - 1)
       
   169 						/ frameSize);
       
   170 
       
   171 		mAudioTrack = new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate,
       
   172 				channelConfig, audioFormat, desiredFrames * frameSize,
       
   173 				AudioTrack.MODE_STREAM);
       
   174 
       
   175 		audioStartThread();
       
   176 
       
   177 		Log.v("SDL",
       
   178 				"SDL audio: got "
       
   179 						+ ((mAudioTrack.getChannelCount() >= 2) ? "stereo"
       
   180 								: "mono")
       
   181 						+ " "
       
   182 						+ ((mAudioTrack.getAudioFormat() == AudioFormat.ENCODING_PCM_16BIT) ? "16-bit"
       
   183 								: "8-bit") + " "
       
   184 						+ ((float) mAudioTrack.getSampleRate() / 1000f)
       
   185 						+ "kHz, " + desiredFrames + " frames buffer");
       
   186 
       
   187 		if (is16Bit) {
       
   188 			buf = new short[desiredFrames * (isStereo ? 2 : 1)];
       
   189 		} else {
       
   190 			buf = new byte[desiredFrames * (isStereo ? 2 : 1)];
       
   191 		}
       
   192 		return buf;
       
   193 	}
       
   194 
       
   195 	public static void audioStartThread() {
       
   196 		mAudioThread = new Thread(new Runnable() {
       
   197 			public void run() {
       
   198 				mAudioTrack.play();
       
   199 				nativeRunAudioThread();
       
   200 			}
       
   201 		});
       
   202 
       
   203 		// I'd take REALTIME if I could get it!
       
   204 		mAudioThread.setPriority(Thread.MAX_PRIORITY);
       
   205 		mAudioThread.start();
       
   206 	}
       
   207 
       
   208 	public static void audioWriteShortBuffer(short[] buffer) {
       
   209 		for (int i = 0; i < buffer.length;) {
       
   210 			int result = mAudioTrack.write(buffer, i, buffer.length - i);
       
   211 			if (result > 0) {
       
   212 				i += result;
       
   213 			} else if (result == 0) {
       
   214 				try {
       
   215 					Thread.sleep(1);
       
   216 				} catch (InterruptedException e) {
       
   217 					// Nom nom
       
   218 				}
       
   219 			} else {
       
   220 				Log.w("SDL", "SDL audio: error return from write(short)");
       
   221 				return;
       
   222 			}
       
   223 		}
       
   224 	}
       
   225 
       
   226 	public static void audioWriteByteBuffer(byte[] buffer) {
       
   227 		for (int i = 0; i < buffer.length;) {
       
   228 			int result = mAudioTrack.write(buffer, i, buffer.length - i);
       
   229 			if (result > 0) {
       
   230 				i += result;
       
   231 			} else if (result == 0) {
       
   232 				try {
       
   233 					Thread.sleep(1);
       
   234 				} catch (InterruptedException e) {
       
   235 					// Nom nom
       
   236 				}
       
   237 			} else {
       
   238 				Log.w("SDL", "SDL audio: error return from write(short)");
       
   239 				return;
       
   240 			}
       
   241 		}
       
   242 	}
       
   243 
       
   244 	public static void audioQuit() {
       
   245 		if (mAudioThread != null) {
       
   246 			try {
       
   247 				mAudioThread.join();
       
   248 			} catch (Exception e) {
       
   249 				Log.v("SDL", "Problem stopping audio thread: " + e);
       
   250 			}
       
   251 			mAudioThread = null;
       
   252 
       
   253 			// Log.v("SDL", "Finished waiting for audio thread");
       
   254 		}
       
   255 
       
   256 		if (mAudioTrack != null) {
       
   257 			mAudioTrack.stop();
       
   258 			mAudioTrack = null;
       
   259 		}
       
   260 	}
       
   261 }
       
   262 
       
   263 /**
       
   264  * Simple nativeInit() runnable
       
   265  */
       
   266 class SDLMain implements Runnable {
       
   267 	private int surfaceWidth, surfaceHeight;
   409 	private int surfaceWidth, surfaceHeight;
   268 	private GameConfig config;
   410 	private GameConfig config;
   269 
   411 
   270 	public SDLMain(int width, int height, GameConfig _config) {
   412 	public SDLMain(int width, int height, GameConfig _config) {
   271 		config = _config;
   413 		config = _config;
   291 			ipc.join();
   433 			ipc.join();
   292 		} catch (InterruptedException e) {
   434 		} catch (InterruptedException e) {
   293 			e.printStackTrace();
   435 			e.printStackTrace();
   294 		}
   436 		}
   295 		//Log.v("SDL", "SDL thread terminated");
   437 		//Log.v("SDL", "SDL thread terminated");
   296 		SDLActivity.mSingleton.finish();
   438         //Log.v("SDL", "SDL thread terminated");
   297 	}
   439     }
   298 }
   440 }
   299 
   441 
       
   442 
   300 /**
   443 /**
   301  * SDLSurface. This is what we draw on, so we need to know when it's created in
   444     SDLSurface. This is what we draw on, so we need to know when it's created
   302  * order to do anything useful.
   445     in order to do anything useful. 
   303  * 
   446 
   304  * Because of this, that's where we set up the SDL thread
   447     Because of this, that's where we set up the SDL thread
   305  */
   448 */
   306 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback,
   449 class SDLSurface extends SurfaceView implements SurfaceHolder.Callback, 
   307 		View.OnKeyListener, SensorEventListener {
   450     View.OnKeyListener, View.OnTouchListener, SensorEventListener  {
   308 
       
   309 	// This is what SDL runs in. It invokes SDL_main(), eventually
       
   310 	private Thread mSDLThread;
       
   311 
       
   312 	// EGL private objects
       
   313 	private EGLContext mEGLContext;
       
   314 	private EGLSurface mEGLSurface;
       
   315 	private EGLDisplay mEGLDisplay;
       
   316 
       
   317 	// Sensors
       
   318 	private static SensorManager mSensorManager;
       
   319 
   451 
   320 	private GameConfig config;
   452 	private GameConfig config;
   321 
   453 	
   322 	// Startup
   454     // Sensors
   323 	public SDLSurface(Context context, GameConfig _config) {
   455     private static SensorManager mSensorManager;
   324 		super(context);
   456 
   325 		getHolder().addCallback(this);
   457     // Startup    
   326 
   458     public SDLSurface(Context context, GameConfig _config) {
   327 		setFocusable(true);
   459         super(context);
   328 		setFocusableInTouchMode(true);
   460         getHolder().addCallback(this); 
   329 		requestFocus();
   461     
   330 		setOnKeyListener(this);
   462         setFocusable(true);
   331 		setOnTouchListener(TouchInterface.getTouchInterface());
   463         setFocusableInTouchMode(true);
   332 
   464         requestFocus();
   333 		mSensorManager = (SensorManager) context.getSystemService("sensor");
   465         setOnKeyListener(this); 
   334 
   466         setOnTouchListener(this);   
   335 		config = _config;
   467 
   336 	}
   468         mSensorManager = (SensorManager)context.getSystemService("sensor");
   337 
   469         config = _config;
   338 	// Called when we have a valid drawing surface
   470     }
   339 	public void surfaceCreated(SurfaceHolder holder) {
   471 
   340 		Log.v("SDL", "surfaceCreated()");
   472     // Called when we have a valid drawing surface
   341 
   473     public void surfaceCreated(SurfaceHolder holder) {
   342 		//enableSensor(Sensor.TYPE_ACCELEROMETER, true);
   474         Log.v("SDL", "surfaceCreated()");
   343 	}
   475         holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
   344 
   476         SDLActivity.createEGLSurface();
   345 	// Called when we lose the surface
   477         enableSensor(Sensor.TYPE_ACCELEROMETER, true);
   346 	public void surfaceDestroyed(SurfaceHolder holder) {
   478     }
   347 		Log.v("SDL", "surfaceDestroyed()");
   479 
   348 
   480     // Called when we lose the surface
   349 		// Send a quit message to the application
   481     public void surfaceDestroyed(SurfaceHolder holder) {
   350 		//SDLActivity.nativeQuit();
   482         Log.v("SDL", "surfaceDestroyed()");
   351                 PascalExports.HWterminate(true);
   483         SDLActivity.nativePause();
   352 
   484         enableSensor(Sensor.TYPE_ACCELEROMETER, false);
   353 		// Now wait for the SDL thread to quit
   485     }
   354 		if (mSDLThread != null) {
   486 
   355 			try {
   487     // Called when the surface is resized
   356 				mSDLThread.join();
   488     public void surfaceChanged(SurfaceHolder holder,
   357 			} catch (Exception e) {
   489                                int format, int width, int height) {
   358 				Log.v("SDL", "Problem stopping thread: " + e);
   490         Log.v("SDL", "surfaceChanged()");
   359 			}
   491 
   360 			mSDLThread = null;
   492         int sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565 by default
   361 
   493         switch (format) {
   362 			Log.v("SDL", "Finished waiting for SDL thread");
   494         case PixelFormat.A_8:
   363 		}
   495             Log.v("SDL", "pixel format A_8");
   364 
   496             break;
   365 		//enableSensor(Sensor.TYPE_ACCELEROMETER, false);
   497         case PixelFormat.LA_88:
   366 	}
   498             Log.v("SDL", "pixel format LA_88");
   367 
   499             break;
   368 	// Called when the surface is resized
   500         case PixelFormat.L_8:
   369 	public void surfaceChanged(SurfaceHolder holder, int format, int width,
   501             Log.v("SDL", "pixel format L_8");
   370 			int height) {
   502             break;
   371 		Log.d("SDL", "surfaceChanged()" + width + " + " + height);
   503         case PixelFormat.RGBA_4444:
   372 
   504             Log.v("SDL", "pixel format RGBA_4444");
   373 		int sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565 by default
   505             sdlFormat = 0x85421002; // SDL_PIXELFORMAT_RGBA4444
   374 		switch (format) {
   506             break;
   375 		case PixelFormat.A_8:
   507         case PixelFormat.RGBA_5551:
   376 			Log.v("SDL", "pixel format A_8");
   508             Log.v("SDL", "pixel format RGBA_5551");
   377 			break;
   509             sdlFormat = 0x85441002; // SDL_PIXELFORMAT_RGBA5551
   378 		case PixelFormat.LA_88:
   510             break;
   379 			Log.v("SDL", "pixel format LA_88");
   511         case PixelFormat.RGBA_8888:
   380 			break;
   512             Log.v("SDL", "pixel format RGBA_8888");
   381 		case PixelFormat.L_8:
   513             sdlFormat = 0x86462004; // SDL_PIXELFORMAT_RGBA8888
   382 			Log.v("SDL", "pixel format L_8");
   514             break;
   383 			break;
   515         case PixelFormat.RGBX_8888:
   384 		case PixelFormat.RGBA_4444:
   516             Log.v("SDL", "pixel format RGBX_8888");
   385 			Log.v("SDL", "pixel format RGBA_4444");
   517             sdlFormat = 0x86262004; // SDL_PIXELFORMAT_RGBX8888
   386 			sdlFormat = 0x85421002; // SDL_PIXELFORMAT_RGBA4444
   518             break;
   387 			break;
   519         case PixelFormat.RGB_332:
   388 		case PixelFormat.RGBA_5551:
   520             Log.v("SDL", "pixel format RGB_332");
   389 			Log.v("SDL", "pixel format RGBA_5551");
   521             sdlFormat = 0x84110801; // SDL_PIXELFORMAT_RGB332
   390 			sdlFormat = 0x85441002; // SDL_PIXELFORMAT_RGBA5551
   522             break;
   391 			break;
   523         case PixelFormat.RGB_565:
   392 		case PixelFormat.RGBA_8888:
   524             Log.v("SDL", "pixel format RGB_565");
   393 			Log.v("SDL", "pixel format RGBA_8888");
   525             sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565
   394 			sdlFormat = 0x86462004; // SDL_PIXELFORMAT_RGBA8888
   526             break;
   395 			break;
   527         case PixelFormat.RGB_888:
   396 		case PixelFormat.RGBX_8888:
   528             Log.v("SDL", "pixel format RGB_888");
   397 			Log.v("SDL", "pixel format RGBX_8888");
   529             // Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
   398 			sdlFormat = 0x86262004; // SDL_PIXELFORMAT_RGBX8888
   530             sdlFormat = 0x86161804; // SDL_PIXELFORMAT_RGB888
   399 			break;
   531             break;
   400 		case PixelFormat.RGB_332:
   532         default:
   401 			Log.v("SDL", "pixel format RGB_332");
   533             Log.v("SDL", "pixel format unknown " + format);
   402 			sdlFormat = 0x84110801; // SDL_PIXELFORMAT_RGB332
   534             break;
   403 			break;
   535         }
   404 		case PixelFormat.RGB_565:
   536         SDLActivity.onNativeResize(width, height, sdlFormat);
   405 			Log.v("SDL", "pixel format RGB_565");
   537         Log.v("SDL", "Window size:" + width + "x"+height);
   406 			sdlFormat = 0x85151002; // SDL_PIXELFORMAT_RGB565
   538 
   407 			break;
   539         SDLActivity.startApp(width, height, config);
   408 		case PixelFormat.RGB_888:
   540     }
   409 			Log.v("SDL", "pixel format RGB_888");
   541 
   410 			// Not sure this is right, maybe SDL_PIXELFORMAT_RGB24 instead?
   542     // unused
   411 			sdlFormat = 0x86161804; // SDL_PIXELFORMAT_RGB888
   543     public void onDraw(Canvas canvas) {}
   412 			break;
   544 
   413 		default:
   545 
   414 			Log.v("SDL", "pixel format unknown " + format);
   546 
   415 			break;
   547 
   416 		}
   548     // Key events
   417 		SDLActivity.onNativeResize(width, height, sdlFormat);
   549     public boolean onKey(View  v, int keyCode, KeyEvent event) {
   418 
   550     	if(keyCode == KeyEvent.KEYCODE_BACK) return false;
   419 		// Now start up the C app thread
   551         if (event.getAction() == KeyEvent.ACTION_DOWN) {
   420 		if (mSDLThread == null) {
   552             //Log.v("SDL", "key down: " + keyCode);
   421 			mSDLThread = new Thread(new SDLMain(width, height, config),
   553             SDLActivity.onNativeKeyDown(keyCode);
   422 					"SDLThread");
   554             return true;
   423 			mSDLThread.start();
   555         }
   424 		}
   556         else if (event.getAction() == KeyEvent.ACTION_UP) {
   425 	}
   557             //Log.v("SDL", "key up: " + keyCode);
   426 
   558             SDLActivity.onNativeKeyUp(keyCode);
   427 	// unused
   559             return true;
   428 	public void onDraw(Canvas canvas) {
   560         }
   429 	}
   561         
   430 
   562         return false;
   431 	// EGL functions
   563     }
   432 	public boolean initEGL(int majorVersion, int minorVersion) {
   564 
   433 		Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "."
   565     // Touch events
   434 				+ minorVersion);
   566     public boolean onTouch(View v, MotionEvent event) {
   435 
   567         {
   436 		try {
   568              final int touchDevId = event.getDeviceId();
   437 			EGL10 egl = (EGL10) EGLContext.getEGL();
   569              final int pointerCount = event.getPointerCount();
   438 
   570              // touchId, pointerId, action, x, y, pressure
   439 			EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
   571              int actionPointerIndex = event.getActionIndex();
   440 
   572              int pointerFingerId = event.getPointerId(actionPointerIndex);
   441 			int[] version = new int[2];
   573              int action = event.getActionMasked();
   442 			egl.eglInitialize(dpy, version);
   574 
   443 
   575              float x = event.getX(actionPointerIndex);
   444 			int EGL_OPENGL_ES_BIT = 1;
   576              float y = event.getY(actionPointerIndex);
   445 			int EGL_OPENGL_ES2_BIT = 4;
   577              float p = event.getPressure(actionPointerIndex);
   446 			int renderableType = 0;
   578 
   447 			if (majorVersion == 2) {
   579              if (action == MotionEvent.ACTION_MOVE && pointerCount > 1) {
   448 				renderableType = EGL_OPENGL_ES2_BIT;
   580                 // TODO send motion to every pointer if its position has
   449 			} else if (majorVersion == 1) {
   581                 // changed since prev event.
   450 				renderableType = EGL_OPENGL_ES_BIT;
   582                 for (int i = 0; i < pointerCount; i++) {
   451 			}
   583                     pointerFingerId = event.getPointerId(i);
   452 			int[] configSpec = {
   584                     x = event.getX(i);
   453 					// EGL10.EGL_DEPTH_SIZE, 16,
   585                     y = event.getY(i);
   454 					EGL10.EGL_RENDERABLE_TYPE, renderableType, EGL10.EGL_NONE };
   586                     p = event.getPressure(i);
   455 			EGLConfig[] configs = new EGLConfig[1];
   587                     SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
   456 			int[] num_config = new int[1];
   588                 }
   457 			if (!egl.eglChooseConfig(dpy, configSpec, configs, 1, num_config)
   589              } else {
   458 					|| num_config[0] == 0) {
   590                 SDLActivity.onNativeTouch(touchDevId, pointerFingerId, action, x, y, p);
   459 				Log.e("SDL", "No EGL config available");
   591              }
   460 				return false;
   592         }
   461 			}
   593       return true;
   462 			EGLConfig config = configs[0];
   594    } 
   463 
   595 
   464 			EGLContext ctx = egl.eglCreateContext(dpy, config,
   596     // Sensor events
   465 					EGL10.EGL_NO_CONTEXT, null);
   597     public void enableSensor(int sensortype, boolean enabled) {
   466 			if (ctx == EGL10.EGL_NO_CONTEXT) {
   598         // TODO: This uses getDefaultSensor - what if we have >1 accels?
   467 				Log.e("SDL", "Couldn't create context");
   599         if (enabled) {
   468 				return false;
   600             mSensorManager.registerListener(this, 
   469 			}
   601                             mSensorManager.getDefaultSensor(sensortype), 
   470 
   602                             SensorManager.SENSOR_DELAY_GAME, null);
   471 			EGLSurface surface = egl.eglCreateWindowSurface(dpy, config, this,
   603         } else {
   472 					null);
   604             mSensorManager.unregisterListener(this, 
   473 			if (surface == EGL10.EGL_NO_SURFACE) {
   605                             mSensorManager.getDefaultSensor(sensortype));
   474 				Log.e("SDL", "Couldn't create surface");
   606         }
   475 				return false;
   607     }
   476 			}
   608     
   477 
   609     public void onAccuracyChanged(Sensor sensor, int accuracy) {
   478 			if (!egl.eglMakeCurrent(dpy, surface, surface, ctx)) {
   610         // TODO
   479 				Log.e("SDL", "Couldn't make context current");
   611     }
   480 				return false;
   612 
   481 			}
   613     public void onSensorChanged(SensorEvent event) {
   482 
   614         if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
   483 			mEGLContext = ctx;
   615             SDLActivity.onNativeAccel(event.values[0] / SensorManager.GRAVITY_EARTH,
   484 			mEGLDisplay = dpy;
   616                                       event.values[1] / SensorManager.GRAVITY_EARTH,
   485 			mEGLSurface = surface;
   617                                       event.values[2] / SensorManager.GRAVITY_EARTH);
   486 
   618         }
   487 		} catch (Exception e) {
   619     }
   488 			Log.v("SDL", e + "");
       
   489 			for (StackTraceElement s : e.getStackTrace()) {
       
   490 				Log.v("SDL", s.toString());
       
   491 			}
       
   492 		}
       
   493 
       
   494 		return true;
       
   495 	}
       
   496 
       
   497 	// EGL buffer flip
       
   498 	public void flipEGL() {
       
   499 		try {
       
   500 			EGL10 egl = (EGL10) EGLContext.getEGL();
       
   501 
       
   502 			egl.eglWaitNative(EGL10.EGL_NATIVE_RENDERABLE, null);
       
   503 
       
   504 			// drawing here
       
   505 
       
   506 			egl.eglWaitGL();
       
   507 
       
   508 			egl.eglSwapBuffers(mEGLDisplay, mEGLSurface);
       
   509 
       
   510 		} catch (Exception e) {
       
   511 			Log.v("SDL", "flipEGL(): " + e);
       
   512 			for (StackTraceElement s : e.getStackTrace()) {
       
   513 				Log.v("SDL", s.toString());
       
   514 			}
       
   515 			
       
   516 		}
       
   517 	}
       
   518 
       
   519 	// Key events
       
   520 	public boolean onKey(View v, int keyCode, KeyEvent event) {
       
   521                 if(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) return false;
       
   522 		if (event.getAction() == KeyEvent.ACTION_DOWN) {
       
   523 			Log.v("SDL", "key down: " + keyCode);
       
   524 			if(keyCode == KeyEvent.KEYCODE_BACK){//TODO ask user to quit or not
       
   525 				PascalExports.HWterminate(true);
       
   526 				//SDLActivity.mSingleton.finish();
       
   527 			}else{
       
   528 				SDLActivity.onNativeKeyDown(keyCode);	
       
   529 			}
       
   530 			
       
   531 			return true;
       
   532 		} else if (event.getAction() == KeyEvent.ACTION_UP) {
       
   533 			Log.v("SDL", "key up: " + keyCode);
       
   534 			SDLActivity.onNativeKeyUp(keyCode);
       
   535 			return true;
       
   536 		}
       
   537 
       
   538 		return false;
       
   539 	}
       
   540 
       
   541 	// Sensor events
       
   542 	public void enableSensor(int sensortype, boolean enabled) {
       
   543 		// TODO: This uses getDefaultSensor - what if we have >1 accels?
       
   544 		if (enabled) {
       
   545 			mSensorManager.registerListener(this,
       
   546 					mSensorManager.getDefaultSensor(sensortype),
       
   547 					SensorManager.SENSOR_DELAY_GAME, null);
       
   548 		} else {
       
   549 			mSensorManager.unregisterListener(this,
       
   550 					mSensorManager.getDefaultSensor(sensortype));
       
   551 		}
       
   552 	}
       
   553 
       
   554 	public void onAccuracyChanged(Sensor sensor, int accuracy) {
       
   555 		// TODO
       
   556 	}
       
   557 
       
   558 	public void onSensorChanged(SensorEvent event) {
       
   559 		if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
       
   560 			SDLActivity.onNativeAccel(event.values[0], event.values[1],
       
   561 					event.values[2]);
       
   562 		}
       
   563 	}
       
   564 
   620 
   565 }
   621 }
       
   622