project_files/Android-build/SDL-android-project/src/org/hedgewars/hedgeroid/SDLActivity.java
changeset 7582 714310efad8f
parent 7568 75ba91f14ed5
child 7584 7831c84cc644
equal deleted inserted replaced
7580:c92596feac0d 7582:714310efad8f
     1 package org.hedgewars.hedgeroid;
     1 package org.hedgewars.hedgeroid;
     2 
     2 /*
       
     3  * Copyright (c) 2004-2012 Andrey Korotaev <unC0Rr@gmail.com>
       
     4  */
       
     5 import java.io.IOException;
     3 import java.io.UnsupportedEncodingException;
     6 import java.io.UnsupportedEncodingException;
     4 import java.util.concurrent.atomic.AtomicBoolean;
     7 import java.net.ConnectException;
     5 
     8 
     6 import javax.microedition.khronos.egl.EGL10;
     9 import javax.microedition.khronos.egl.EGL10;
     7 import javax.microedition.khronos.egl.EGLConfig;
    10 import javax.microedition.khronos.egl.EGLConfig;
     8 import javax.microedition.khronos.egl.EGLContext;
    11 import javax.microedition.khronos.egl.EGLContext;
     9 import javax.microedition.khronos.egl.EGLDisplay;
    12 import javax.microedition.khronos.egl.EGLDisplay;
    10 import javax.microedition.khronos.egl.EGLSurface;
    13 import javax.microedition.khronos.egl.EGLSurface;
    11 
    14 
    12 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
    15 import org.hedgewars.hedgeroid.Datastructures.GameConfig;
    13 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    16 import org.hedgewars.hedgeroid.EngineProtocol.PascalExports;
    14 import org.hedgewars.hedgeroid.frontlib.Flib;
       
    15 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameSetupPtr;
       
    16 import org.hedgewars.hedgeroid.frontlib.Frontlib.GameconnPtr;
       
    17 import org.hedgewars.hedgeroid.frontlib.Frontlib.IntCallback;
       
    18 import org.hedgewars.hedgeroid.netplay.Netplay;
    17 import org.hedgewars.hedgeroid.netplay.Netplay;
    19 import org.hedgewars.hedgeroid.util.FileUtils;
    18 import org.hedgewars.hedgeroid.util.FileUtils;
    20 import org.hedgewars.hedgeroid.util.TickHandler;
       
    21 
       
    22 import com.sun.jna.Pointer;
       
    23 
    19 
    24 import android.app.Activity;
    20 import android.app.Activity;
    25 import android.content.Context;
    21 import android.content.Context;
    26 import android.graphics.Canvas;
    22 import android.graphics.Canvas;
    27 import android.graphics.PixelFormat;
    23 import android.graphics.PixelFormat;
    31 import android.hardware.SensorManager;
    27 import android.hardware.SensorManager;
    32 import android.media.AudioFormat;
    28 import android.media.AudioFormat;
    33 import android.media.AudioManager;
    29 import android.media.AudioManager;
    34 import android.media.AudioTrack;
    30 import android.media.AudioTrack;
    35 import android.os.Bundle;
    31 import android.os.Bundle;
    36 import android.os.Handler;
       
    37 import android.os.HandlerThread;
       
    38 import android.os.Message;
       
    39 import android.util.Base64;
    32 import android.util.Base64;
    40 import android.util.DisplayMetrics;
    33 import android.util.DisplayMetrics;
    41 import android.util.Log;
    34 import android.util.Log;
    42 import android.view.KeyEvent;
    35 import android.view.KeyEvent;
    43 import android.view.MotionEvent;
    36 import android.view.MotionEvent;
    59 	public static volatile boolean startNetgame;
    52 	public static volatile boolean startNetgame;
    60 	
    53 	
    61 	// Main components
    54 	// Main components
    62 	public static SDLActivity mSingleton;
    55 	public static SDLActivity mSingleton;
    63 	private static SDLSurface mSurface;
    56 	private static SDLSurface mSurface;
    64 
    57 	private static Thread mSDLThread;
    65 	// This is what SDL runs in. It invokes SDL_main(), eventually
       
    66 	private static Thread mSDLThread; // Guarded by SDLActivity.class
       
    67 
    58 
    68 	// Audio
    59 	// Audio
    69 	private static Thread mAudioThread;
    60 	private static Thread mAudioThread;
    70 	private static AudioTrack mAudioTrack;
    61 	private static AudioTrack mAudioTrack;
    71 
    62 
    77 	private static int mGLMajor, mGLMinor;
    68 	private static int mGLMajor, mGLMinor;
    78 
    69 
    79 	// Load the .so
    70 	// Load the .so
    80 	static {
    71 	static {
    81 		System.loadLibrary("SDL");
    72 		System.loadLibrary("SDL");
    82 		//System.loadLibrary("SDL_image");
       
    83 		//System.loadLibrary("SDL_mixer");
       
    84 		//System.loadLibrary("SDL_ttf");
       
    85 		System.loadLibrary("main");
    73 		System.loadLibrary("main");
    86 	}
    74 	}
    87 
    75 
    88 	// Setup
    76 	// Setup
    89 	protected void onCreate(Bundle savedInstanceState) {
    77 	protected void onCreate(Bundle savedInstanceState) {
    90 		//Log.v("SDL", "onCreate()");
       
    91 		super.onCreate(savedInstanceState);
    78 		super.onCreate(savedInstanceState);
    92 
    79 
    93 		// So we can call stuff from static callbacks
    80 		// So we can call stuff from static callbacks
    94 		mSingleton = this;
    81 		mSingleton = this;
    95 
    82 
    96 		// Set up the surface
    83 		// Set up the surface
    97 		mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
    84 		mSurface = new SDLSurface(getApplication(), startConfig, startNetgame);
       
    85 		startConfig = null;
    98 		setContentView(mSurface);
    86 		setContentView(mSurface);
    99 	}
    87 	}
   100 
    88 
   101 	// Events
    89 	// Events
   102 	protected void onPause() {
    90 	protected void onPause() {
   121 	protected void onDestroy() {
   109 	protected void onDestroy() {
   122 		super.onDestroy();
   110 		super.onDestroy();
   123 		Log.v("SDL", "onDestroy()");
   111 		Log.v("SDL", "onDestroy()");
   124 		// Send a quit message to the application
   112 		// Send a quit message to the application
   125 		SDLActivity.nativeQuit();
   113 		SDLActivity.nativeQuit();
   126 
       
   127 		// Now wait for the SDL thread to quit
   114 		// Now wait for the SDL thread to quit
   128 		synchronized(SDLActivity.class) {
   115 		if (mSDLThread != null) {
   129 			if (mSDLThread != null) {
   116 			try {
   130 				try {
   117 				mSDLThread.join();
   131 					mSDLThread.join();
   118 			} catch(Exception e) {
   132 				} catch(Exception e) {
   119 				Log.w("SDL", "Problem stopping thread: " + e);
   133 					Log.w("SDL", "Problem stopping thread: " + e);
   120 			}
   134 				}
   121 			mSDLThread = null;
   135 				mSDLThread = null;
   122 		}
   136 			}
   123 		mSingleton = null;
   137 		}
   124 	}
   138 	}
   125 	
   139 
       
   140 	// Messages from the SDLMain thread
       
   141 	static int COMMAND_CHANGE_TITLE = 1;
       
   142 
       
   143 	// Handler for the messages
       
   144 	Handler commandHandler = new Handler() {
       
   145 		public void handleMessage(Message msg) {
       
   146 			if (msg.arg1 == COMMAND_CHANGE_TITLE) {
       
   147 				setTitle((String)msg.obj);
       
   148 			}
       
   149 		}
       
   150 	};
       
   151 
       
   152 	// Send a message from the SDLMain thread
       
   153 	void sendCommand(int command, Object data) {
       
   154 		Message msg = commandHandler.obtainMessage();
       
   155 		msg.arg1 = command;
       
   156 		msg.obj = data;
       
   157 		commandHandler.sendMessage(msg);
       
   158 	}
       
   159 
       
   160 	public static void synchronizedNativeInit(String...args) {
   126 	public static void synchronizedNativeInit(String...args) {
   161 		synchronized(PascalExports.engineMutex) {
   127 		synchronized(PascalExports.engineMutex) {
   162 			nativeInit(args);
   128 			nativeInit(args);
   163 		}
   129 		}
   164 	}
   130 	}
   186 
   152 
   187 	public static void flipBuffers() {
   153 	public static void flipBuffers() {
   188 		flipEGL();
   154 		flipEGL();
   189 	}
   155 	}
   190 
   156 
   191 	public static void setActivityTitle(String title) {
   157 	public static void setActivityTitle(final String title) {
   192 		// Called from SDLMain() thread and can't directly affect the view
   158 		// Called from SDLMain() thread and can't directly affect the view
   193 		mSingleton.sendCommand(COMMAND_CHANGE_TITLE, title);
   159 		mSingleton.runOnUiThread(new Runnable() {
       
   160 			public void run() {
       
   161 				mSingleton.setTitle(title);
       
   162 			}
       
   163 		});
   194 	}
   164 	}
   195 
   165 
   196 	public static Context getContext() {
   166 	public static Context getContext() {
   197 		return mSingleton;
   167 		return mSingleton;
   198 	}
   168 	}
   199 
   169 
   200 	public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
   170 	public static void startApp(final int width, final int height, GameConfig config, boolean netgame) {
   201 		synchronized(SDLActivity.class) {
   171 		// Start up the C app thread
   202 			// Start up the C app thread TODO this is silly code
   172 		if (mSDLThread == null) {
   203 			if (mSDLThread == null) {
   173 			mSDLThread = new Thread(new SDLMain(width, height, config, netgame));
   204 				final AtomicBoolean gameconnStartDone = new AtomicBoolean(false);
   174 			mSDLThread.start();
   205 				GameConnection.Listener listener = new GameConnection.Listener() {
   175 		} else {
   206 					public void gameConnectionReady(int port) {
   176 			SDLActivity.nativeResume();
   207 						mSDLThread = new Thread(new SDLMain(width, height, port, "Medo"));
       
   208 						mSDLThread.start();
       
   209 						gameconnStartDone.set(true);
       
   210 					}
       
   211 					
       
   212 					public void gameConnectionDisconnected(int reason) {
       
   213 						Log.e("startApp", "disconnected: "+reason);
       
   214 						gameconnStartDone.set(true);
       
   215 					}
       
   216 				};
       
   217 				if(netgame) {
       
   218 					Netplay netplay = Netplay.getAppInstance(mSingleton.getApplicationContext());
       
   219 					GameConnection.forNetgame(config, netplay, listener);
       
   220 				} else {
       
   221 					GameConnection.forLocalGame(config, listener);
       
   222 				}
       
   223 			} else {
       
   224 				SDLActivity.nativeResume();
       
   225 			}
       
   226 		}
   177 		}
   227 	}
   178 	}
   228 
   179 
   229 	// EGL functions
   180 	// EGL functions
   230 	public static boolean initEGL(int majorVersion, int minorVersion) {
   181 	public static boolean initEGL(int majorVersion, int minorVersion) {
   231 		if (SDLActivity.mEGLDisplay == null) {
   182 		if (SDLActivity.mEGLDisplay == null) {
   232 			//Log.v("SDL", "Starting up OpenGL ES " + majorVersion + "." + minorVersion);
       
   233 
       
   234 			try {
   183 			try {
   235 				EGL10 egl = (EGL10)EGLContext.getEGL();
   184 				EGL10 egl = (EGL10)EGLContext.getEGL();
   236 
   185 
   237 				EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
   186 				EGLDisplay dpy = egl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
   238 
   187 
   246 					renderableType = EGL_OPENGL_ES2_BIT;
   195 					renderableType = EGL_OPENGL_ES2_BIT;
   247 				} else if (majorVersion == 1) {
   196 				} else if (majorVersion == 1) {
   248 					renderableType = EGL_OPENGL_ES_BIT;
   197 					renderableType = EGL_OPENGL_ES_BIT;
   249 				}
   198 				}
   250 				int[] configSpec = {
   199 				int[] configSpec = {
   251 						//EGL10.EGL_DEPTH_SIZE,   16,
       
   252 						EGL10.EGL_RENDERABLE_TYPE, renderableType,
   200 						EGL10.EGL_RENDERABLE_TYPE, renderableType,
   253 						EGL10.EGL_NONE
   201 						EGL10.EGL_NONE
   254 				};
   202 				};
   255 				EGLConfig[] configs = new EGLConfig[1];
   203 				EGLConfig[] configs = new EGLConfig[1];
   256 				int[] num_config = new int[1];
   204 				int[] num_config = new int[1];
   258 					Log.e("SDL", "No EGL config available");
   206 					Log.e("SDL", "No EGL config available");
   259 					return false;
   207 					return false;
   260 				}
   208 				}
   261 				EGLConfig config = configs[0];
   209 				EGLConfig config = configs[0];
   262 
   210 
   263 				/*int EGL_CONTEXT_CLIENT_VERSION=0x3098;
       
   264                 int contextAttrs[] = new int[] { EGL_CONTEXT_CLIENT_VERSION, majorVersion, EGL10.EGL_NONE };
       
   265                 EGLContext ctx = egl.eglCreateContext(dpy, config, EGL10.EGL_NO_CONTEXT, contextAttrs);
       
   266 
       
   267                 if (ctx == EGL10.EGL_NO_CONTEXT) {
       
   268                     Log.e("SDL", "Couldn't create context");
       
   269                     return false;
       
   270                 }
       
   271                 SDLActivity.mEGLContext = ctx;*/
       
   272 				SDLActivity.mEGLDisplay = dpy;
   211 				SDLActivity.mEGLDisplay = dpy;
   273 				SDLActivity.mEGLConfig = config;
   212 				SDLActivity.mEGLConfig = config;
   274 				SDLActivity.mGLMajor = majorVersion;
   213 				SDLActivity.mGLMajor = majorVersion;
   275 				SDLActivity.mGLMinor = minorVersion;
   214 				SDLActivity.mGLMinor = minorVersion;
   276 
   215 
   452 
   391 
   453 /**
   392 /**
   454     Simple nativeInit() runnable
   393     Simple nativeInit() runnable
   455  */
   394  */
   456 class SDLMain implements Runnable {
   395 class SDLMain implements Runnable {
   457 
   396 	public static final String TAG = "SDLMain";
       
   397 	
       
   398     public static final int RQ_LOWRES            = 0x00000001; // use half land array
       
   399     public static final int RQ_BLURRY_LAND       = 0x00000002; // downscaled terrain
       
   400     public static final int RQ_NO_BACKGROUND     = 0x00000004; // don't draw background
       
   401     public static final int RQ_SIMPLE_ROPE       = 0x00000008; // avoid drawing rope
       
   402     public static final int RQ_2D_WATER          = 0x00000010; // disabe 3D water effect
       
   403     public static final int RQ_SIMPLE_EXPLOSIONS = 0x00000020; // no fancy explosion effects
       
   404     public static final int RQ_NO_FLAKES         = 0x00000040; // no flakes
       
   405     public static final int RQ_NO_MENU_ANIM      = 0x00000080; // ammomenu appears with no animation
       
   406     public static final int RQ_NO_DROPLETS       = 0x00000100; // no droplets
       
   407     public static final int RQ_NO_CLAMPING       = 0x00000200; // don't clamp textures
       
   408     public static final int RQ_NO_TOOLTIPS       = 0x00000400; // tooltips are not drawn
       
   409     public static final int RQ_NO_VSYNC          = 0x00000800; // don't sync on vblank
       
   410 	
   458 	private final int surfaceWidth, surfaceHeight;
   411 	private final int surfaceWidth, surfaceHeight;
   459 	private final int port;
       
   460 	private final String playerName;
   412 	private final String playerName;
   461 	HandlerThread thread = new HandlerThread("IPC thread");
   413 	private final GameConfig config;
   462 	
   414 	private final boolean netgame;
   463 	public SDLMain(int width, int height, int port, String playerName) {
   415 	
       
   416 	public SDLMain(int width, int height, GameConfig config, boolean netgame) {
   464 		surfaceWidth = width;
   417 		surfaceWidth = width;
   465 		surfaceHeight = height;
   418 		surfaceHeight = height;
   466 		this.port = port;
   419 		if(netgame) {
   467 		this.playerName = playerName;
   420 			playerName = Netplay.getAppInstance(SDLActivity.getContext().getApplicationContext()).getPlayerName();
       
   421 		} else {
       
   422 			playerName = "Player";
       
   423 		}
       
   424 		this.config = config;
       
   425 		this.netgame = netgame;
   468 	}
   426 	}
   469 
   427 
   470 	public void run() {
   428 	public void run() {
   471 		//Set up the IPC socket server to communicate with the engine
   429 		//Set up the IPC socket server to communicate with the engine
   472 		String path = FileUtils.getDataPath(SDLActivity.mSingleton);//This represents the data directory
   430 		GameConnection gameConn;
   473 		path = path.substring(0, path.length()-1);//remove the trailing '/'
   431 		String path;
   474 
       
   475 		Log.d("SDLMain", "Starting engine");
       
   476 		// Runs SDL_main() with added parameters
       
   477 		try {
   432 		try {
   478 			SDLActivity.synchronizedNativeInit(new String[] { String.valueOf(port),
   433 			if(netgame) {
   479 					String.valueOf(surfaceWidth), String.valueOf(surfaceHeight),
   434 				Netplay netplay = Netplay.getAppInstance(SDLActivity.mSingleton.getApplicationContext());
   480 					Integer.toString(0x40+0x10+0x100+0x2), "en.txt", Base64.encodeToString(playerName.getBytes("UTF-8"), 0), "1", "1", "1", path, ""  });
   435 				gameConn = GameConnection.forNetgame(config, netplay);
   481 		} catch (UnsupportedEncodingException e) {
   436 			} else {
   482 			throw new AssertionError(e); // never happens
   437 				gameConn = GameConnection.forLocalGame(config);
   483 		}
   438 			}
   484 		Log.d("SDLMain", "Engine stopped");
   439 			
       
   440 			path = FileUtils.getDataPathFile(SDLActivity.mSingleton).getAbsolutePath();
       
   441 			Log.d(TAG, "Starting engine");
       
   442 			// Runs SDL_main() with added parameters
       
   443 			try {
       
   444 				String pPort = String.valueOf(gameConn.port);
       
   445 				String pWidth = String.valueOf(surfaceWidth);
       
   446 				String pHeight = String.valueOf(surfaceHeight);
       
   447 				String pQuality = Integer.toString(RQ_NO_FLAKES|RQ_NO_DROPLETS|RQ_SIMPLE_EXPLOSIONS);
       
   448 				String pPlayerName = Base64.encodeToString(playerName.getBytes("UTF-8"), 0);
       
   449 				SDLActivity.synchronizedNativeInit(new String[] { pPort, pWidth, pHeight, pQuality, "en.txt", pPlayerName, "1", "1", "1", path, ""  });
       
   450 			} catch (UnsupportedEncodingException e) {
       
   451 				throw new AssertionError(e); // never happens
       
   452 			}
       
   453 			Log.d(TAG, "Engine stopped");
       
   454 		} catch(ConnectException e) {
       
   455 			Log.e(TAG, "Error starting IPC connection");
       
   456 		} catch (IOException e) {
       
   457 			Log.e(TAG, "Missing SDCard");
       
   458 		}
       
   459 		SDLActivity.mSingleton.runOnUiThread(new Runnable() { public void run() {
       
   460 			if(SDLActivity.mSingleton != null) {
       
   461 				SDLActivity.mSingleton.finish();
       
   462 			}
       
   463 		}});
   485 	}
   464 	}
   486 }
   465 }
   487 
   466 
   488 
   467 
   489 /**
   468 /**
   595 
   574 
   596 	// Key events
   575 	// Key events
   597 	public boolean onKey(View  v, int keyCode, KeyEvent event) {
   576 	public boolean onKey(View  v, int keyCode, KeyEvent event) {
   598 		switch(keyCode){
   577 		switch(keyCode){
   599 		case KeyEvent.KEYCODE_BACK:
   578 		case KeyEvent.KEYCODE_BACK:
   600 		        PascalExports.HWterminate(true);
   579 			Log.d("SDL", "KEYCODE_BACK");
   601                         return true;
   580 			SDLActivity.nativeQuit();
       
   581             return true;
   602 		case KeyEvent.KEYCODE_VOLUME_DOWN:
   582 		case KeyEvent.KEYCODE_VOLUME_DOWN:
   603 		case KeyEvent.KEYCODE_VOLUME_UP:
   583 		case KeyEvent.KEYCODE_VOLUME_UP:
   604 		case KeyEvent.KEYCODE_VOLUME_MUTE:
   584 		case KeyEvent.KEYCODE_VOLUME_MUTE:
   605 			return false;
   585 			return false;
   606 		}
   586 		}