failures )
+ {
+ if( failures.size() == 0 )
+ {
+ if (!mAppInit)
+ {
+ InitProject64();
+ }
+
+ // Extraction succeeded, record new asset version and merge cheats
+ mTextView.setText( R.string.assetExtractor_finished );
+ NativeExports.UISettingsSaveDword(UISettingID.Asserts_Version.getValue(), ASSET_VERSION);
+
+ // Launch gallery activity
+ Intent intent = new Intent( this, GalleryActivity.class );
+ this.startActivity( intent );
+
+ // We never want to come back to this activity, so finish it
+ finish();
+ }
+ else
+ {
+ // Extraction failed, update the on-screen text and don't start next activity
+ String weblink = getResources().getString( R.string.assetExtractor_uriHelp );
+ String message = getString( R.string.assetExtractor_failed, weblink );
+ String textHtml = message.replace( "\n", "
" ) + "";
+ for( Failure failure : failures )
+ {
+ textHtml += failure.toString() + "
";
+ }
+ textHtml += "";
+ mTextView.setText( Html.fromHtml( textHtml ) );
+ }
+ }
+}
diff --git a/Android/src/emu/project64/compat/AppCompatPreferenceActivity.java b/Android/src/emu/project64/compat/AppCompatPreferenceActivity.java
new file mode 100644
index 000000000..21ee8c6e5
--- /dev/null
+++ b/Android/src/emu/project64/compat/AppCompatPreferenceActivity.java
@@ -0,0 +1,17 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.compat;
+
+import android.preference.PreferenceActivity;
+
+public class AppCompatPreferenceActivity extends PreferenceActivity
+{
+}
diff --git a/Android/src/emu/project64/dialog/ProgressDialog.java b/Android/src/emu/project64/dialog/ProgressDialog.java
new file mode 100644
index 000000000..f29a88eef
--- /dev/null
+++ b/Android/src/emu/project64/dialog/ProgressDialog.java
@@ -0,0 +1,245 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.dialog;
+
+import emu.project64.R;
+
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ProgressBar;
+import android.widget.TextView;
+
+public class ProgressDialog implements OnClickListener
+{
+ private static final float PROGRESS_PRECISION = 1000f;
+
+ private final Activity mActivity;
+ private final TextView mTextProgress;
+ private final TextView mTextSubprogress;
+ private final TextView mTextMessage;
+ private final ProgressBar mProgressSubtotal;
+ private final ProgressBar mProgressTotal;
+ private AlertDialog mDialog;
+ private AlertDialog mAbortDialog;
+
+ private long mMaxProgress = -1;
+ private long mMaxSubprogress = -1;
+ private long mProgress = 0;
+ private long mSubprogress = 0;
+
+ @SuppressLint( "InflateParams" )
+ public ProgressDialog( Activity activity, CharSequence title,
+ CharSequence subtitle, CharSequence message, boolean cancelable )
+ {
+ mActivity = activity;
+
+ final LayoutInflater inflater = (LayoutInflater) mActivity
+ .getSystemService( Context.LAYOUT_INFLATER_SERVICE );
+ View layout = inflater.inflate( R.layout.progress_dialog, null );
+
+ mTextProgress = (TextView) layout.findViewById( R.id.textProgress );
+ mTextSubprogress = (TextView) layout.findViewById( R.id.textSubprogress );
+ mTextMessage = (TextView) layout.findViewById( R.id.textMessage );
+ mProgressSubtotal = (ProgressBar) layout.findViewById( R.id.progressSubtotal );
+ mProgressTotal = (ProgressBar) layout.findViewById( R.id.progressTotal );
+
+ // Create main dialog
+ Builder builder = getBuilder( activity, title, subtitle, message, cancelable, layout );
+ mDialog = builder.create();
+
+ // Create canceling dialog
+ subtitle = mActivity.getString( R.string.toast_canceling );
+ message = mActivity.getString( R.string.toast_canceling );
+ layout = inflater.inflate( R.layout.progress_dialog, null );
+ builder = getBuilder( activity, title, subtitle, message, false, layout );
+ mAbortDialog = builder.create();
+ }
+
+ public ProgressDialog(ProgressDialog original, Activity activity, CharSequence title,
+ CharSequence subtitle, CharSequence message, boolean cancelable)
+ {
+ this(activity, title, subtitle, message, cancelable);
+
+ if(original != null)
+ {
+ setMaxProgress(original.mMaxProgress);
+ setMaxSubprogress(original.mMaxSubprogress);
+
+ mProgress = original.mProgress;
+ mSubprogress = original.mSubprogress;
+
+ incrementProgress(0);
+ incrementSubprogress(0);
+
+ mTextProgress.setText(original.mTextProgress.getText());
+ mTextSubprogress.setText(original.mTextSubprogress.getText());
+ mTextMessage.setText(original.mTextMessage.getText());
+ }
+ }
+
+ public void show()
+ {
+ mAbortDialog.show();
+ mDialog.show();
+ }
+
+ public void dismiss()
+ {
+ mAbortDialog.dismiss();
+ mDialog.dismiss();
+ }
+
+ @Override
+ public void onClick( DialogInterface dlg, int which )
+ {
+ if( which == DialogInterface.BUTTON_NEGATIVE)
+ {
+ }
+ }
+
+ private Builder getBuilder( Activity activity, CharSequence title, CharSequence subtitle,
+ CharSequence message, boolean cancelable, View layout )
+ {
+ TextView textSubtitle = (TextView) layout.findViewById( R.id.textSubtitle );
+ TextView textMessage = (TextView) layout.findViewById( R.id.textMessage );
+ textSubtitle.setText( subtitle );
+ textMessage.setText( message );
+
+ Builder builder = new Builder( activity ).setTitle( title ).setCancelable( false )
+ .setPositiveButton( null, null ).setView( layout );
+ if( cancelable )
+ builder.setNegativeButton( android.R.string.cancel, this );
+ else
+ builder.setNegativeButton( null, null );
+ return builder;
+ }
+
+ public void setText( final CharSequence text )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mTextProgress.setText( text );
+ }
+ } );
+ }
+
+ public void setSubtext( final CharSequence text )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mTextSubprogress.setText( text );
+ }
+ } );
+ }
+
+ public void setMessage( final CharSequence text )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mTextMessage.setText( text );
+ }
+ } );
+ }
+
+ public void setMessage( final int resid )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mTextMessage.setText( resid );
+ }
+ } );
+ }
+
+ public void setMaxProgress( final long size )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mMaxProgress = size;
+ mProgress = 0;
+ mProgressTotal.setProgress( 0 );
+ mProgressTotal.setVisibility( mMaxProgress > 0 ? View.VISIBLE : View.GONE );
+ }
+ } );
+ }
+
+ public void setMaxSubprogress( final long size )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ mMaxSubprogress = size;
+ mSubprogress = 0;
+ mProgressSubtotal.setProgress( 0 );
+ mProgressSubtotal.setVisibility( mMaxSubprogress > 0 ? View.VISIBLE : View.GONE );
+ }
+ } );
+ }
+
+ public void incrementProgress( final long inc )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if( mMaxProgress > 0 )
+ {
+ mProgress += inc;
+ int pctProgress = Math.round( ( PROGRESS_PRECISION * mProgress )
+ / mMaxProgress );
+ mProgressTotal.setProgress( pctProgress );
+ }
+ }
+ } );
+ }
+
+ public void incrementSubprogress( final long inc )
+ {
+ mActivity.runOnUiThread( new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ if( mMaxSubprogress > 0 )
+ {
+ mSubprogress += inc;
+ int pctSubprogress = Math.round( ( PROGRESS_PRECISION * mSubprogress )
+ / mMaxSubprogress );
+ mProgressSubtotal.setProgress( pctSubprogress );
+ }
+ }
+ } );
+ }
+}
diff --git a/Android/src/emu/project64/game/GameActivity.java b/Android/src/emu/project64/game/GameActivity.java
new file mode 100644
index 000000000..8df1c6673
--- /dev/null
+++ b/Android/src/emu/project64/game/GameActivity.java
@@ -0,0 +1,108 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.game;
+
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.SystemEvent;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+
+public class GameActivity extends Activity
+{
+ private GameLifecycleHandler mLifecycleHandler;
+ @SuppressWarnings("unused")
+ private GameMenuHandler mMenuHandler;
+
+ @Override
+ public void onWindowFocusChanged( boolean hasFocus )
+ {
+ super.onWindowFocusChanged( hasFocus );
+ mLifecycleHandler.onWindowFocusChanged( hasFocus );
+ }
+
+ @Override
+ public void onBackPressed()
+ {
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_PauseCPU_AppLostActive.getValue());
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setMessage("Confirm Exit\n\nDo you want to quit the game?")
+ .setPositiveButton("Quit Game", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ NativeExports.CloseSystem();
+ finish();
+ }
+ })
+ .setNegativeButton("Play On", new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResumeCPU_AppGainedActive.getValue());
+ }
+ })
+ .show();
+ }
+
+ @Override
+ protected void onCreate( Bundle savedInstanceState )
+ {
+ mLifecycleHandler = new GameLifecycleHandler( this );
+ mLifecycleHandler.onCreateBegin( savedInstanceState );
+ super.onCreate( savedInstanceState );
+ mLifecycleHandler.onCreateEnd( savedInstanceState );
+
+ mMenuHandler = new GameMenuHandler( this, mLifecycleHandler );
+ }
+
+ @Override
+ protected void onStart()
+ {
+ super.onStart();
+ mLifecycleHandler.onStart();
+ }
+
+ @Override
+ protected void onResume()
+ {
+ super.onResume();
+ mLifecycleHandler.onResume();
+ }
+
+ @Override
+ protected void onPause()
+ {
+ super.onPause();
+ mLifecycleHandler.onPause();
+ }
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ mLifecycleHandler.onStop();
+ }
+
+ @Override
+ protected void onDestroy()
+ {
+ super.onDestroy();
+ mLifecycleHandler.onDestroy();
+ }
+
+ @Override
+ protected void onActivityResult(int requestCode, int resultCode, Intent data)
+ {
+ if (requestCode == GameLifecycleHandler.RC_SETTINGS)
+ {
+ mLifecycleHandler.onSettingDone();
+ }
+ }
+}
diff --git a/Android/src/emu/project64/game/GameActivityXperiaPlay.java b/Android/src/emu/project64/game/GameActivityXperiaPlay.java
new file mode 100644
index 000000000..a050a3194
--- /dev/null
+++ b/Android/src/emu/project64/game/GameActivityXperiaPlay.java
@@ -0,0 +1,19 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.game;
+
+import android.annotation.TargetApi;
+import android.app.NativeActivity;
+
+@TargetApi( 9 )
+public class GameActivityXperiaPlay extends NativeActivity
+{
+}
diff --git a/Android/src/emu/project64/game/GameLifecycleHandler.java b/Android/src/emu/project64/game/GameLifecycleHandler.java
new file mode 100644
index 000000000..41084b13e
--- /dev/null
+++ b/Android/src/emu/project64/game/GameLifecycleHandler.java
@@ -0,0 +1,455 @@
+/****************************************************************************
+ * *
+ * Project 64 - A Nintendo 64 emulator. *
+ * http://www.pj64-emu.com/ *
+ * Copyright (C) 2012 Project64. All rights reserved. *
+ * *
+ * License: *
+ * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+ * *
+ ****************************************************************************/
+package emu.project64.game;
+
+import java.lang.ref.WeakReference;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+import com.bda.controller.Controller;
+
+import java.util.ArrayList;
+import java.util.Set;
+
+import emu.project64.AndroidDevice;
+import emu.project64.R;
+import emu.project64.hack.MogaHack;
+import emu.project64.input.AbstractController;
+import emu.project64.input.PeripheralController;
+import emu.project64.input.TouchController;
+import emu.project64.input.map.InputMap;
+import emu.project64.input.map.VisibleTouchMap;
+import emu.project64.input.provider.AbstractProvider;
+import emu.project64.input.provider.AxisProvider;
+import emu.project64.input.provider.KeyProvider;
+import emu.project64.input.provider.KeyProvider.ImeFormula;
+import emu.project64.input.provider.MogaProvider;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.NativeXperiaTouchpad;
+import emu.project64.jni.SettingsID;
+import emu.project64.jni.SystemEvent;
+import emu.project64.jni.UISettingID;
+import emu.project64.persistent.ConfigFile;
+import emu.project64.persistent.ConfigFile.ConfigSection;
+import emu.project64.profile.Profile;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.Color;
+import android.graphics.drawable.ColorDrawable;
+import android.os.Bundle;
+import android.os.Vibrator;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.SurfaceHolder;
+import android.view.View;
+import android.view.Window;
+import android.view.WindowManager.LayoutParams;
+
+public class GameLifecycleHandler implements View.OnKeyListener, SurfaceHolder.Callback, GameSurface.SurfaceInfo
+{
+ private final static boolean LOG_GAMELIFECYCLEHANDLER = false;
+ public final static int RC_SETTINGS = 10005;
+
+ // Activity and views
+ private Activity mActivity;
+ private GameSurface mSurface;
+ private GameOverlay mOverlay;
+
+ // Input resources
+ private final ArrayList mControllers;
+ private VisibleTouchMap mTouchscreenMap;
+ private KeyProvider mKeyProvider;
+ private Controller mMogaController;
+
+ // Internal flags
+ private final boolean mIsXperiaPlay;
+ private boolean mStarted = false;
+ private boolean mStopped = false;
+
+ // Lifecycle state tracking
+ private boolean mIsFocused = false; // true if the window is focused
+ private boolean mIsResumed = false; // true if the activity is resumed
+ private boolean mIsSurface = false; // true if the surface is available
+
+ private float mtouchscreenScale = ((float)NativeExports.UISettingsLoadDword(UISettingID.TouchScreen_ButtonScale.getValue())) / 100.0f;
+ private String mlayout = NativeExports.UISettingsLoadString(UISettingID.TouchScreen_Layout.getValue());
+
+ public GameLifecycleHandler(Activity activity)
+ {
+ mActivity = activity;
+ mControllers = new ArrayList();
+ mIsXperiaPlay = !(activity instanceof GameActivity);
+ mMogaController = Controller.getInstance( mActivity );
+ }
+
+ @TargetApi(11)
+ public void onCreateBegin(Bundle savedInstanceState)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onCreateBegin");
+ }
+ // Initialize MOGA controller API
+ // TODO: Remove hack after MOGA SDK is fixed
+ // mMogaController.init();
+ MogaHack.init( mMogaController, mActivity );
+
+
+ // For Honeycomb, let the action bar overlay the rendered view (rather
+ // than squeezing it)
+ // For earlier APIs, remove the title bar to yield more space
+ Window window = mActivity.getWindow();
+ window.requestFeature(AndroidDevice.IS_ACTION_BAR_AVAILABLE ? Window.FEATURE_ACTION_BAR_OVERLAY : Window.FEATURE_NO_TITLE);
+
+ // Enable full-screen mode
+ window.setFlags(LayoutParams.FLAG_FULLSCREEN, LayoutParams.FLAG_FULLSCREEN);
+
+ // Keep screen from going to sleep
+ window.setFlags(LayoutParams.FLAG_KEEP_SCREEN_ON, LayoutParams.FLAG_KEEP_SCREEN_ON);
+
+ // Set the screen orientation
+ mActivity.setRequestedOrientation(NativeExports.UISettingsLoadDword(UISettingID.Screen_Orientation.getValue()));
+ }
+
+ @TargetApi(11)
+ public void onCreateEnd(Bundle savedInstanceState)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onCreateEnd");
+ }
+
+ // Take control of the GameSurface if necessary
+ if (mIsXperiaPlay)
+ {
+ mActivity.getWindow().takeSurface(null);
+ }
+
+ // Lay out content and get the views
+ mActivity.setContentView(R.layout.game_activity);
+ mSurface = (GameSurface) mActivity.findViewById( R.id.gameSurface );
+ mOverlay = (GameOverlay) mActivity.findViewById(R.id.gameOverlay);
+
+ // Listen to game surface events (created, changed, destroyed)
+ mSurface.getHolder().addCallback( this );
+ mSurface.createGLContext((ActivityManager)mActivity.getSystemService(Context.ACTIVITY_SERVICE));
+
+ // Configure the action bar introduced in higher Android versions
+ if (AndroidDevice.IS_ACTION_BAR_AVAILABLE)
+ {
+ mActivity.getActionBar().hide();
+ ColorDrawable color = new ColorDrawable(Color.parseColor("#303030"));
+ color.setAlpha(50 /*mGlobalPrefs.displayActionBarTransparency*/);
+ mActivity.getActionBar().setBackgroundDrawable(color);
+ }
+
+ CreateTouchScreenControls();
+
+ // Initialize user interface devices
+ View inputSource = mIsXperiaPlay ? new NativeXperiaTouchpad(mActivity) : mOverlay;
+ initControllers(inputSource);
+
+ // Override the peripheral controllers' key provider, to add some extra functionality
+ inputSource.setOnKeyListener( this );
+ }
+
+ public void onStart()
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onStart");
+ }
+ }
+
+ public void onResume()
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onResume");
+ }
+ mIsResumed = true;
+ tryRunning();
+
+ mMogaController.onResume();
+ }
+
+ @Override
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "surfaceCreated");
+ }
+ }
+
+ @Override
+ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "surfaceChanged");
+ }
+ mIsSurface = true;
+ tryRunning();
+ }
+
+ public void onWindowFocusChanged(boolean hasFocus)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onWindowFocusChanged: " + hasFocus);
+ }
+ // Only try to run; don't try to pause. User may just be touching the
+ // in-game menu.
+ mIsFocused = hasFocus;
+ if (hasFocus)
+ {
+ tryRunning();
+ }
+ }
+
+ public void AutoSave()
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "OnAutoSave");
+ }
+ if (NativeExports.SettingsLoadBool(SettingsID.GameRunning_CPU_Running.getValue()) == true)
+ {
+ Boolean pause = false;
+ int PauseType = 0;
+ if (NativeExports.SettingsLoadBool(SettingsID.GameRunning_CPU_Paused.getValue()) == true)
+ {
+ pause = true;
+ PauseType = NativeExports.SettingsLoadDword(SettingsID.GameRunning_CPU_PausedType.getValue());
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResumeCPU_FromMenu.getValue());
+ }
+ int CurrentSaveState = NativeExports.SettingsLoadDword(SettingsID.Game_CurrentSaveState.getValue());
+ int OriginalSaveTime = NativeExports.SettingsLoadDword(SettingsID.Game_LastSaveTime.getValue());
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 0);
+ NativeExports.ExternalEvent(SystemEvent.SysEvent_SaveMachineState.getValue());
+ for (int i = 0; i < 100; i++)
+ {
+ int LastSaveTime = NativeExports.SettingsLoadDword(SettingsID.Game_LastSaveTime.getValue());
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "LastSaveTime = " + LastSaveTime + " OriginalSaveTime = " + OriginalSaveTime);
+ }
+ if (LastSaveTime != OriginalSaveTime)
+ {
+ break;
+ }
+ try
+ {
+ Thread.sleep(100);
+ }
+ catch(InterruptedException ex)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), CurrentSaveState);
+ if (pause)
+ {
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_PauseCPU_FromMenu.getValue());
+ NativeExports.SettingsSaveDword(SettingsID.GameRunning_CPU_PausedType.getValue(), PauseType);
+ }
+ }
+ else if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "CPU not running, not doing anything");
+ }
+
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "OnAutoSave Done");
+ }
+ }
+
+ public void onPause()
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onPause");
+ }
+ mIsResumed = false;
+ if (NativeExports.SettingsLoadBool(SettingsID.GameRunning_CPU_Running.getValue()) == true)
+ {
+ AutoSave();
+ }
+ mMogaController.onPause();
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onPause - done");
+ }
+ }
+
+ @Override
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "surfaceDestroyed");
+ }
+ mIsSurface = false;
+ }
+
+ public void onStop()
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onStop");
+ }
+ }
+
+ public void onDestroy()
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onDestroy");
+ }
+ mMogaController.exit();
+ }
+
+ public void onSettingDone ()
+ {
+ float touchscreenScale = ((float)NativeExports.UISettingsLoadDword(UISettingID.TouchScreen_ButtonScale.getValue())) / 100.0f;
+ boolean recreateTouchScreenControls = false;
+ if (touchscreenScale != mtouchscreenScale)
+ {
+ mtouchscreenScale = touchscreenScale;
+ recreateTouchScreenControls = true;
+ }
+
+ String layout = NativeExports.UISettingsLoadString(UISettingID.TouchScreen_Layout.getValue());
+ if (layout != mlayout)
+ {
+ mlayout = layout;
+ recreateTouchScreenControls = true;
+ }
+
+ if (recreateTouchScreenControls)
+ {
+ CreateTouchScreenControls();
+ }
+ }
+
+ private void CreateTouchScreenControls()
+ {
+ boolean isTouchscreenAnimated = false; //mGlobalPrefs.isTouchscreenAnimated
+ boolean isTouchscreenHidden = false; //!isTouchscreenEnabled || globalPrefs.touchscreenTransparency == 0;
+ String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
+ String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
+ ConfigFile touchscreenConfigFile = new ConfigFile( touchscreenProfiles_cfg );
+ ConfigSection section = touchscreenConfigFile.get(mlayout);
+ if (section == null)
+ {
+ mlayout = "Analog";
+ section = touchscreenConfigFile.get(mlayout);
+ }
+ Profile touchscreenProfile = new Profile( true, section);
+ int touchscreenTransparency = 100;
+ String touchscreenSkinsDir = AndroidDevice.PACKAGE_DIRECTORY + "/skins/touchscreen";
+ String touchscreenSkin = touchscreenSkinsDir + "/Outline";
+
+ // The touch map and overlay are needed to display frame rate and/or controls
+ mTouchscreenMap = new VisibleTouchMap( mActivity.getResources() );
+ mTouchscreenMap.load(touchscreenSkin, touchscreenProfile, isTouchscreenAnimated, mtouchscreenScale, touchscreenTransparency );
+ mOverlay.initialize( mTouchscreenMap, !isTouchscreenHidden, isTouchscreenAnimated );
+ }
+
+ @Override
+ public boolean onKey( View view, int keyCode, KeyEvent event )
+ {
+ // If PeripheralControllers exist and handle the event,
+ // they return true. Else they return false, signaling
+ // Android to handle the event (menu button, vol keys).
+ if( mKeyProvider != null )
+ {
+ return mKeyProvider.onKey( view, keyCode, event );
+ }
+ return false;
+ }
+
+ @SuppressLint("InlinedApi")
+ private void initControllers(View inputSource)
+ {
+ // By default, send Player 1 rumbles through phone vibrator
+ Vibrator vibrator = (Vibrator) mActivity.getSystemService( Context.VIBRATOR_SERVICE );
+ int touchscreenAutoHold = 0;
+ boolean isTouchscreenFeedbackEnabled = false;
+ Set autoHoldableButtons = null;
+
+ // Create the touchscreen controller
+ TouchController touchscreenController = new TouchController( mTouchscreenMap,
+ inputSource, mOverlay, vibrator, touchscreenAutoHold,
+ isTouchscreenFeedbackEnabled, autoHoldableButtons );
+ mControllers.add( touchscreenController );
+
+ // Create the input providers shared among all peripheral controllers
+ String profile_name = NativeExports.UISettingsLoadString(UISettingID.Controller_CurrentProfile.getValue());
+ ConfigFile ControllerConfigFile = new ConfigFile(NativeExports.UISettingsLoadString(UISettingID.Controller_ConfigFile.getValue()));
+ ConfigSection section = ControllerConfigFile.get( profile_name );
+ if (section != null)
+ {
+ Profile ControllerProfile = new Profile( false, section );
+ InputMap map = new InputMap( ControllerProfile.get( "map" ) );
+
+ mKeyProvider = new KeyProvider( inputSource, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
+ MogaProvider mogaProvider = new MogaProvider( mMogaController );
+ AbstractProvider axisProvider = AndroidDevice.IS_HONEYCOMB_MR1 ? new AxisProvider( inputSource ) : null;
+ int Deadzone = NativeExports.UISettingsLoadDword(UISettingID.Controller_Deadzone.getValue());
+ int Sensitivity = NativeExports.UISettingsLoadDword(UISettingID.Controller_Sensitivity.getValue());
+ mControllers.add( new PeripheralController( 1, map, Deadzone, Sensitivity, mKeyProvider, axisProvider, mogaProvider ) );
+ }
+ }
+
+ private void tryRunning()
+ {
+ if (mIsFocused && mIsResumed && mIsSurface && mStopped)
+ {
+ mStopped = false;
+ NativeExports.StartEmulation();
+ }
+ if (mIsFocused && mIsResumed && mIsSurface && !mStarted)
+ {
+ mStarted = true;
+ final GameLifecycleHandler handler = this;
+
+ NativeExports.StartGame(mActivity, new GameSurface.GLThread(new WeakReference(mSurface), handler));
+ }
+ }
+
+ @Override
+ public void onSurfaceCreated(GL10 gl, EGLConfig config)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onSurfaceCreated");
+ }
+ NativeExports.onSurfaceCreated();
+ }
+
+ @Override
+ public void onSurfaceChanged(GL10 gl, int width, int height)
+ {
+ if (LOG_GAMELIFECYCLEHANDLER)
+ {
+ Log.i("GameLifecycleHandler", "onSurfaceChanged");
+ }
+ NativeExports.onSurfaceChanged(width, height);
+ }
+}
diff --git a/Android/src/emu/project64/game/GameMenuHandler.java b/Android/src/emu/project64/game/GameMenuHandler.java
new file mode 100644
index 000000000..2acd0d3d8
--- /dev/null
+++ b/Android/src/emu/project64/game/GameMenuHandler.java
@@ -0,0 +1,209 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.game;
+
+import java.io.File;
+import java.sql.Date;
+import java.text.SimpleDateFormat;
+
+import emu.project64.R;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.SettingsID;
+import emu.project64.jni.SystemEvent;
+import emu.project64.settings.SettingsActivity;
+import android.annotation.SuppressLint;
+import android.app.Activity;
+import android.content.Intent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.ImageButton;
+import android.widget.PopupMenu;
+
+public class GameMenuHandler implements PopupMenu.OnMenuItemClickListener, PopupMenu.OnDismissListener
+{
+ private Activity mActivity = null;
+ private GameLifecycleHandler mLifecycleHandler = null;
+ private Boolean mOpeningSubmenu = false;
+
+ public GameMenuHandler( Activity activity, GameLifecycleHandler LifecycleHandler )
+ {
+ mActivity = activity;
+ mLifecycleHandler = LifecycleHandler;
+
+ final ImageButton MenuButton = (ImageButton)activity.findViewById( R.id.gameMenu );
+ final Activity activityContext = activity;
+ final GameMenuHandler menuHandler = this;
+ MenuButton.setOnClickListener(new View.OnClickListener()
+ {
+ @Override
+ public void onClick(View view)
+ {
+ Boolean GamePaused = NativeExports.SettingsLoadBool(SettingsID.GameRunning_CPU_Paused.getValue());
+ Boolean RecordExecutionTimes = NativeExports.SettingsLoadBool(SettingsID.Debugger_RecordExecutionTimes.getValue());
+ Boolean ShowDebugMenu = NativeExports.SettingsLoadBool(SettingsID.Debugger_Enabled.getValue());
+
+ if (!RecordExecutionTimes)
+ {
+ ShowDebugMenu = false;
+ }
+
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_PauseCPU_AppLostActive.getValue());
+
+ PopupMenu popupMenu = new PopupMenu(activityContext, MenuButton);
+ popupMenu.setOnDismissListener(menuHandler);
+ popupMenu.setOnMenuItemClickListener(menuHandler);
+ popupMenu.inflate(R.menu.game_activity);
+
+ int CurrentSaveState = NativeExports.SettingsLoadDword(SettingsID.Game_CurrentSaveState.getValue());
+ Menu menu = popupMenu.getMenu();
+
+ menu.findItem(R.id.menuItem_pause).setVisible(GamePaused ? false : true);
+ menu.findItem(R.id.menuItem_resume).setVisible(GamePaused ? true : false);
+ menu.findItem(R.id.menuItem_ResetFunctionTimes).setVisible(RecordExecutionTimes);
+ menu.findItem(R.id.menuItem_DumpFunctionTimes).setVisible(RecordExecutionTimes);
+ menu.findItem(R.id.menuItem_DebuggingMenu).setVisible(ShowDebugMenu);
+
+ String SaveDirectory = NativeExports.SettingsLoadString(SettingsID.Directory_InstantSave.getValue());
+ if ( NativeExports.SettingsLoadBool(SettingsID.Setting_UniqueSaveDir.getValue()))
+ {
+ SaveDirectory += "/" + NativeExports.SettingsLoadString(SettingsID.Game_UniqueSaveDir.getValue());
+ }
+
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSaveAuto, 0);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave1, 1);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave2, 2);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave3, 3);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave4, 4);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave5, 5);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave6, 6);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave7, 7);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave8, 8);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave9, 9);
+ FixSaveStateMenu(SaveDirectory, CurrentSaveState, menu, R.id.menuItem_CurrentSave10, 10);
+ popupMenu.show();
+ }
+ });
+ }
+
+ public boolean onMenuItemClick(MenuItem item)
+ {
+ switch (item.getItemId())
+ {
+ case R.id.menuItem_CurrentSaveState:
+ case R.id.menuItem_DebuggingMenu:
+ mOpeningSubmenu = true;
+ break;
+ case R.id.menuItem_SaveState:
+ NativeExports.ExternalEvent(SystemEvent.SysEvent_SaveMachineState.getValue());
+ break;
+ case R.id.menuItem_LoadState:
+ NativeExports.ExternalEvent(SystemEvent.SysEvent_LoadMachineState.getValue());
+ break;
+ case R.id.menuItem_CurrentSaveAuto:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 0);
+ break;
+ case R.id.menuItem_CurrentSave1:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 1);
+ break;
+ case R.id.menuItem_CurrentSave2:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 2);
+ break;
+ case R.id.menuItem_CurrentSave3:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 3);
+ break;
+ case R.id.menuItem_CurrentSave4:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 4);
+ break;
+ case R.id.menuItem_CurrentSave5:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 5);
+ break;
+ case R.id.menuItem_CurrentSave6:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 6);
+ break;
+ case R.id.menuItem_CurrentSave7:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 7);
+ break;
+ case R.id.menuItem_CurrentSave8:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 8);
+ break;
+ case R.id.menuItem_CurrentSave9:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 9);
+ break;
+ case R.id.menuItem_CurrentSave10:
+ NativeExports.SettingsSaveDword(SettingsID.Game_CurrentSaveState.getValue(), 10);
+ break;
+ case R.id.menuItem_pause:
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_PauseCPU_FromMenu.getValue());
+ break;
+ case R.id.menuItem_resume:
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResumeCPU_FromMenu.getValue());
+ break;
+ case R.id.menuItem_HardReset:
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResetCPU_Hard.getValue());
+ break;
+ case R.id.menuItem_ResetFunctionTimes:
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResetFunctionTimes.getValue());
+ break;
+ case R.id.menuItem_DumpFunctionTimes:
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_DumpFunctionTimes.getValue());
+ break;
+ case R.id.menuItem_EndEmulation:
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResumeCPU_FromMenu.getValue());
+ mLifecycleHandler.AutoSave();
+ NativeExports.CloseSystem();
+ break;
+ case R.id.menuItem_settings:
+ Intent SettingsIntent = new Intent(mActivity, SettingsActivity.class);
+ mActivity.startActivityForResult( SettingsIntent, GameLifecycleHandler.RC_SETTINGS );
+ return true;
+ }
+ return false;
+ }
+
+ public void onDismiss (PopupMenu menu)
+ {
+ if (!mOpeningSubmenu)
+ {
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResumeCPU_AppGainedActive.getValue());
+ }
+ mOpeningSubmenu = false;
+ }
+
+ @SuppressLint("SimpleDateFormat")
+ private void FixSaveStateMenu(String SaveDirectory, int CurrentSaveState,Menu menu, int MenuId, int SaveSlot )
+ {
+ MenuItem item = menu.findItem(MenuId);
+ if (CurrentSaveState == SaveSlot)
+ {
+ item.setChecked(true);
+ }
+ String SaveFileName = SaveDirectory + "/" + NativeExports.SettingsLoadString(SettingsID.Game_GoodName.getValue()) + ".pj";
+ String Timestamp = "";
+ if (SaveSlot != 0)
+ {
+ SaveFileName += SaveSlot;
+ }
+ File SaveFile = new File(SaveFileName+".zip");
+ long LastModified = SaveFile.lastModified();
+ if (LastModified == 0)
+ {
+ SaveFile = new File(SaveFileName);
+ LastModified = SaveFile.lastModified();
+ }
+ if (LastModified != 0)
+ {
+ Timestamp = new SimpleDateFormat(" [yyyy/MM/dd HH:mm]").format(new Date(LastModified));
+ }
+ String SlotName = SaveSlot == 0 ? "Auto" : "Slot " + SaveSlot;
+ item.setTitle(SlotName + Timestamp);
+ }
+}
diff --git a/Android/src/emu/project64/game/GameOverlay.java b/Android/src/emu/project64/game/GameOverlay.java
new file mode 100644
index 000000000..5423ad404
--- /dev/null
+++ b/Android/src/emu/project64/game/GameOverlay.java
@@ -0,0 +1,179 @@
+/****************************************************************************
+ * *
+ * Project 64 - A Nintendo 64 emulator. *
+ * http://www.pj64-emu.com/ *
+ * Copyright (C) 2012 Project64. All rights reserved. *
+ * *
+ * License: *
+ * GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+ * *
+ ****************************************************************************/
+package emu.project64.game;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+import emu.project64.input.TouchController;
+import emu.project64.input.map.VisibleTouchMap;
+import emu.project64.util.DeviceUtil;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.Typeface;
+import android.util.AttributeSet;
+import android.view.View;
+
+public class GameOverlay extends View implements TouchController.OnStateChangedListener
+{
+ private VisibleTouchMap mTouchMap;
+ private boolean mDrawingEnabled = true;
+ private int mHatRefreshPeriod = 0;
+ private int mHatRefreshCount = 0;
+ private Paint mPaint = new Paint();
+ private Rect mRectangle = new Rect();
+ private String mDisplayMessage = "";
+ private String mDisplayMessage2 = "";
+ private int mDisplayMessageDuration = 0;
+ private Timer mTimer = null;
+
+ public GameOverlay(Context context, AttributeSet attribs)
+ {
+ super(context, attribs);
+ requestFocus();
+ }
+
+ public void initialize( VisibleTouchMap touchMap, boolean drawingEnabled, boolean joystickAnimated )
+ {
+ mTouchMap = touchMap;
+ mDrawingEnabled = drawingEnabled;
+ mHatRefreshPeriod = joystickAnimated ? 3 : 0;
+ }
+
+ public void SetDisplayMessage(String Message, int Duratation)
+ {
+ if (Duratation >= mDisplayMessageDuration)
+ {
+ mDisplayMessage = Message;
+ mDisplayMessageDuration = Duratation;
+ if (mTimer != null)
+ {
+ mTimer.cancel();
+ mTimer.purge();
+ }
+ if (Duratation == 0)
+ {
+ Duratation = 10;
+ }
+ TimerTask task = new TimerTask()
+ {
+ @Override
+ public void run()
+ {
+ mDisplayMessage = "";
+ mDisplayMessageDuration = 0;
+ Timer CurrentTimer = mTimer;
+ mTimer = null;
+ CurrentTimer.cancel();
+ CurrentTimer.purge();
+ }
+
+ };
+ mTimer = new Timer();
+ mTimer.schedule(task, Duratation * 1000);
+ }
+ postInvalidate();
+ }
+
+ public void SetDisplayMessage2(String Message)
+ {
+ mDisplayMessage2 = Message;
+ postInvalidate();
+ }
+
+ @Override
+ public void onAnalogChanged(float axisFractionX, float axisFractionY)
+ {
+ if (mHatRefreshPeriod > 0 && mDrawingEnabled)
+ {
+ // Increment the count since last refresh
+ mHatRefreshCount++;
+
+ // If stick re-centered, always refresh
+ if (axisFractionX == 0 && axisFractionY == 0)
+ {
+ mHatRefreshCount = 0;
+ }
+
+ // Update the analog stick assets and redraw if required
+ if (mHatRefreshCount % mHatRefreshPeriod == 0 && mTouchMap != null
+ && mTouchMap.updateAnalog(axisFractionX, axisFractionY))
+ {
+ postInvalidate();
+ }
+ }
+ }
+
+ @Override
+ public void onAutoHold(boolean autoHold, int index)
+ {
+ // Update the AutoHold mask, and redraw if required
+ if (mTouchMap != null && mTouchMap.updateAutoHold(autoHold, index))
+ {
+ postInvalidate();
+ }
+ }
+
+ @Override
+ protected void onSizeChanged(int w, int h, int oldw, int oldh)
+ {
+ // Recompute skin layout geometry
+ if (mTouchMap != null)
+ {
+ mTouchMap.resize(w, h, DeviceUtil.getDisplayMetrics(this));
+ }
+ super.onSizeChanged(w, h, oldw, oldh);
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas)
+ {
+ if (canvas == null)
+ {
+ return;
+ }
+
+ if (mTouchMap != null && mDrawingEnabled)
+ {
+ // Redraw the static buttons
+ mTouchMap.drawButtons(canvas);
+
+ // Redraw the dynamic analog stick
+ mTouchMap.drawAnalog(canvas);
+
+ // Redraw the autoHold mask
+ mTouchMap.drawAutoHold(canvas);
+ }
+
+ String txt = mDisplayMessage;
+ if (txt.length() > 0 && mDisplayMessage2.length() > 0)
+ {
+ txt += " - ";
+ }
+ txt += mDisplayMessage2;
+ if (txt.length() > 0)
+ {
+ mPaint.setStyle(Paint.Style.FILL);
+ mPaint.setColor(Color.parseColor("#DDDDDD"));
+ mPaint.setAntiAlias(true);
+ mPaint.setTextSize(25);
+ mPaint.setTextAlign(Paint.Align.CENTER);
+ Typeface typeface = Typeface.create(Typeface.SANS_SERIF,
+ Typeface.BOLD_ITALIC);
+ mPaint.setTypeface(typeface);
+ mPaint.getTextBounds(txt, 0, txt.length(), mRectangle);
+ canvas.drawText(txt, Math.abs(canvas.getWidth() / 2), Math.abs((int) (canvas.getHeight() * 0.95)) - Math.abs(mRectangle.height()), mPaint);
+ }
+ }
+}
diff --git a/Android/src/emu/project64/game/GameSurface.java b/Android/src/emu/project64/game/GameSurface.java
new file mode 100644
index 000000000..91f1f1df2
--- /dev/null
+++ b/Android/src/emu/project64/game/GameSurface.java
@@ -0,0 +1,1739 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.game;
+
+import java.io.Writer;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGL11;
+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 javax.microedition.khronos.opengles.GL;
+import javax.microedition.khronos.opengles.GL10;
+
+import android.app.ActivityManager;
+import android.content.Context;
+import android.content.pm.ConfigurationInfo;
+import android.os.Build;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+public class GameSurface extends SurfaceView implements SurfaceHolder.Callback
+{
+ public class EGL14
+ {
+ public static final int EGL_OPENGL_ES2_BIT = 0x0004;
+ }
+
+ public class EGLExt
+ {
+ public static final int EGL_OPENGL_ES3_BIT_KHR = 0x0040;
+ }
+
+ private final static boolean LOG_THREADS = false;
+ private final static boolean LOG_SURFACE = false;
+ private final static boolean LOG_EGL = false;
+
+ /**
+ * Check glError() after every GL call and throw an exception if glError indicates
+ * that an error has occurred. This can be used to help track down which OpenGL ES call
+ * is causing an error.
+ *
+ * @see #getDebugFlags
+ * @see #setDebugFlags
+ */
+ public final static int DEBUG_CHECK_GL_ERROR = 1;
+
+ /**
+ * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
+ *
+ * @see #getDebugFlags
+ * @see #setDebugFlags
+ */
+ public final static int DEBUG_LOG_GL_CALLS = 2;
+
+ // LogCat strings for debugging, defined here to simplify maintenance/lookup
+ private static final String TAG = "GameSurface";
+
+ public interface SurfaceInfo
+ {
+ /**
+ * Called when the surface is created or recreated.
+ *
+ * Called when the rendering thread
+ * starts and whenever the EGL context is lost. The EGL context will typically
+ * be lost when the Android device awakes after going to sleep.
+ *
+ * Since this method is called at the beginning of rendering, as well as
+ * every time the EGL context is lost, this method is a convenient place to put
+ * code to create resources that need to be created when the rendering
+ * starts, and that need to be recreated when the EGL context is lost.
+ * Textures are an example of a resource that you might want to create
+ * here.
+ *
+ * Note that when the EGL context is lost, all OpenGL resources associated
+ * with that context will be automatically deleted. You do not need to call
+ * the corresponding "glDelete" methods such as glDeleteTextures to
+ * manually delete these lost resources.
+ *
+ * @param mGl the GL interface. Use instanceof
to
+ * test if the interface supports GL11 or higher interfaces.
+ * @param config the EGLConfig of the created surface. Can be used
+ * to create matching pbuffers.
+ */
+ void onSurfaceCreated(GL10 mGl, EGLConfig config);
+
+ /**
+ * Called when the surface changed size.
+ *
+ * Called after the surface is created and whenever
+ * the OpenGL ES surface size changes.
+ *
+ * Typically you will set your viewport here. If your camera
+ * is fixed then you could also set your projection matrix here:
+ *
+ * void onSurfaceChanged(GL10 mGl, int width, int height) {
+ * mGl.glViewport(0, 0, width, height);
+ * // for a fixed camera, set the projection too
+ * float ratio = (float) width / height;
+ * mGl.glMatrixMode(GL10.GL_PROJECTION);
+ * mGl.glLoadIdentity();
+ * mGl.glFrustumf(-ratio, ratio, -1, 1, 1, 10);
+ * }
+ *
+ * @param mGl the GL interface. Use instanceof
to
+ * test if the interface supports GL11 or higher interfaces.
+ * @param width
+ * @param height
+ */
+ void onSurfaceChanged(GL10 mGl, int width, int height);
+ }
+
+ /**
+ * Constructor that is called when inflating a view from XML. This is called when a view is
+ * being constructed from an XML file, supplying attributes that were specified in the XML file.
+ * This version uses a default style of 0, so the only attribute values applied are those in the
+ * Context's Theme and the given AttributeSet. The method onFinishInflate() will be called after
+ * all children have been added.
+ *
+ * @param context The Context the view is running in, through which it can access the current
+ * theme, resources, etc.
+ * @param attrs The attributes of the XML tag that is inflating the view.
+ */
+ public GameSurface( Context context, AttributeSet attribs )
+ {
+ super( context, attribs );
+ init();
+ }
+
+ @Override
+ protected void finalize() throws Throwable
+ {
+ super.finalize();
+ }
+
+ private void init()
+ {
+ // Install a SurfaceHolder.Callback so we get notified when the
+ // underlying surface is created and destroyed
+ SurfaceHolder holder = getHolder();
+ holder.addCallback(this);
+ // setFormat is done by SurfaceView in SDK 2.3 and newer. Uncomment
+ // this statement if back-porting to 2.2 or older:
+ // holder.setFormat(PixelFormat.RGB_565);
+ //
+ // setType is not needed for SDK 2.0 or newer. Uncomment this
+ // statement if back-porting this code to older SDKs.
+ // holder.setType(SurfaceHolder.SURFACE_TYPE_GPU);
+ if (mEGLConfigChooser == null)
+ {
+ mEGLConfigChooser = new SimpleEGLConfigChooser(true);
+ }
+ if (mEGLContextFactory == null)
+ {
+ mEGLContextFactory = new DefaultContextFactory();
+ }
+ if (mEGLWindowSurfaceFactory == null)
+ {
+ mEGLWindowSurfaceFactory = new DefaultWindowSurfaceFactory();
+ }
+ mEglHelper = new EglHelper(new WeakReference(this));
+ }
+
+ public boolean createGLContext( ActivityManager activityManager )
+ {
+ ConfigurationInfo configurationInfo = activityManager.getDeviceConfigurationInfo();
+
+ final boolean supportsEs2 = configurationInfo.reqGlEsVersion >= 0x20000 || isProbablyEmulator();
+ if (supportsEs2)
+ {
+ if (isProbablyEmulator())
+ {
+ // Avoids crashes on startup with some emulator images.
+ this.setEGLConfigChooser(8, 8, 8, 8, 16, 0);
+ }
+
+ this.setEGLContextClientVersion(2);
+ }
+ else
+ {
+ // Should never be seen in production, since the manifest filters
+ // unsupported devices.
+ Log.e(TAG, "This device does not support OpenGL ES 2.0.");
+ return false;
+ }
+ return true;
+ }
+
+ private boolean isProbablyEmulator()
+ {
+ return Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH_MR1
+ && (Build.FINGERPRINT.startsWith("generic")
+ || Build.FINGERPRINT.startsWith("unknown")
+ || Build.MODEL.contains("google_sdk")
+ || Build.MODEL.contains("Emulator")
+ || Build.MODEL.contains("Android SDK built for x86"));
+ }
+
+ public boolean ableToDraw()
+ {
+ return mHaveEglContext && mHaveEglSurface && readyToDraw();
+ }
+
+ boolean readyToDraw()
+ {
+ return (!mPaused) && mHasSurface && (!mSurfaceIsBad)
+ && (mWidth > 0) && (mHeight > 0);
+ }
+
+ /**
+ * Install a custom EGLWindowSurfaceFactory.
+ * If this method is
+ * called, it must be called before {@link #setRenderer(Renderer)}
+ * is called.
+ *
+ * If this method is not called, then by default
+ * a window surface will be created with a null attribute list.
+ */
+ public void setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory factory)
+ {
+ mEGLWindowSurfaceFactory = factory;
+ }
+
+ /**
+ * Install a custom EGLConfigChooser.
+ *
If this method is
+ * called, it must be called before {@link #setRenderer(Renderer)}
+ * is called.
+ *
+ * If no setEGLConfigChooser method is called, then by default the
+ * view will choose an EGLConfig that is compatible with the current
+ * android.view.Surface, with a depth buffer depth of
+ * at least 16 bits.
+ * @param configChooser
+ */
+ public void setEGLConfigChooser(EGLConfigChooser configChooser)
+ {
+ mEGLConfigChooser = configChooser;
+ }
+
+ /**
+ * Install a config chooser which will choose a config
+ * with at least the specified depthSize and stencilSize,
+ * and exactly the specified redSize, greenSize, blueSize and alphaSize.
+ *
If this method is
+ * called, it must be called before {@link #setRenderer(Renderer)}
+ * is called.
+ *
+ * If no setEGLConfigChooser method is called, then by default the
+ * view will choose an RGB_888 surface with a depth buffer depth of
+ * at least 16 bits.
+ *
+ */
+ public void setEGLConfigChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)
+ {
+ setEGLConfigChooser(new ComponentSizeChooser(redSize, greenSize, blueSize, alphaSize, depthSize, stencilSize));
+ }
+
+ /**
+ * Inform the default EGLContextFactory and default EGLConfigChooser
+ * which EGLContext client version to pick.
+ *
Use this method to create an OpenGL ES 2.0-compatible context.
+ * Example:
+ *
+ * public MyView(Context context) {
+ * super(context);
+ * setEGLContextClientVersion(2); // Pick an OpenGL ES 2.0 context.
+ * setRenderer(new MyRenderer());
+ * }
+ *
+ * Note: Activities which require OpenGL ES 2.0 should indicate this by
+ * setting @lt;uses-feature android:glEsVersion="0x00020000" /> in the activity's
+ * AndroidManifest.xml file.
+ *
If this method is called, it must be called before {@link #setRenderer(Renderer)}
+ * is called.
+ *
This method only affects the behavior of the default EGLContexFactory and the
+ * default EGLConfigChooser. If
+ * {@link #setEGLContextFactory(EGLContextFactory)} has been called, then the supplied
+ * EGLContextFactory is responsible for creating an OpenGL ES 2.0-compatible context.
+ * If
+ * {@link #setEGLConfigChooser(EGLConfigChooser)} has been called, then the supplied
+ * EGLConfigChooser is responsible for choosing an OpenGL ES 2.0-compatible config.
+ * @param version The EGLContext client version to choose. Use 2 for OpenGL ES 2.0
+ */
+ public void setEGLContextClientVersion(int version)
+ {
+ mEGLContextClientVersion = version;
+ }
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of GLSurfaceView.
+ */
+ public void surfaceCreated(SurfaceHolder holder)
+ {
+ synchronized(sGLThreadManager)
+ {
+ if (LOG_THREADS)
+ {
+ Log.i("GLThread", "surfaceCreated tid=" + getId());
+ }
+ mHasSurface = true;
+ mFinishedCreatingEglSurface = false;
+ sGLThreadManager.notifyAll();
+ while (mWaitingForSurface && !mFinishedCreatingEglSurface && !mExited)
+ {
+ try
+ {
+ sGLThreadManager.wait();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of GLSurfaceView.
+ */
+ public void surfaceDestroyed(SurfaceHolder holder)
+ {
+ synchronized(sGLThreadManager)
+ {
+ if (LOG_THREADS)
+ {
+ Log.i("GLThread", "surfaceDestroyed tid=" + getId());
+ }
+ mHasSurface = false;
+ sGLThreadManager.notifyAll();
+ while((!mWaitingForSurface) && (!mExited))
+ {
+ try
+ {
+ sGLThreadManager.wait();
+ }
+ catch (InterruptedException e)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * This method is part of the SurfaceHolder.Callback interface, and is
+ * not normally called or subclassed by clients of GLSurfaceView.
+ */
+ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h)
+ {
+ synchronized (sGLThreadManager)
+ {
+ mWidth = w;
+ mHeight = h;
+ mSizeChanged = true;
+ mRequestRender = true;
+ mRenderComplete = false;
+ sGLThreadManager.notifyAll();
+
+ // Wait for thread to react to resize and render a frame
+ while (! mExited && !mPaused && !mRenderComplete && ableToDraw())
+ {
+ if (LOG_SURFACE) {
+ Log.i("Main thread", "onWindowResize waiting for render complete from tid=" + getId());
+ }
+ try
+ {
+ sGLThreadManager.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ }
+
+ /**
+ * An interface used to wrap a GL interface.
+ *
Typically
+ * used for implementing debugging and tracing on top of the default
+ * GL interface. You would typically use this by creating your own class
+ * that implemented all the GL methods by delegating to another GL instance.
+ * Then you could add your own behavior before or after calling the
+ * delegate. All the GLWrapper would do was instantiate and return the
+ * wrapper GL instance:
+ *
+ * class MyGLWrapper implements GLWrapper {
+ * GL wrap(GL gl) {
+ * return new MyGLImplementation(gl);
+ * }
+ * static class MyGLImplementation implements GL,GL10,GL11,... {
+ * ...
+ * }
+ * }
+ *
+ * @see #setGLWrapper(GLWrapper)
+ */
+ public interface GLWrapper
+ {
+ /**
+ * Wraps a gl interface in another gl interface.
+ * @param gl a GL interface that is to be wrapped.
+ * @return either the input argument or another GL object that wraps the input argument.
+ */
+ GL wrap(GL gl);
+ }
+
+ /**
+ * An EGL helper class.
+ */
+ static class EglHelper
+ {
+ public EglHelper(WeakReference glSurfaceViewWeakRef)
+ {
+ mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
+ }
+
+ /**
+ * Initialize EGL for a given configuration spec.
+ * @param configSpec
+ */
+ public void start()
+ {
+ if (LOG_EGL)
+ {
+ Log.w("EglHelper", "start() tid=" + Thread.currentThread().getId());
+ }
+ /*
+ * Get an EGL instance
+ */
+ mEgl = (EGL10) EGLContext.getEGL();
+
+ /*
+ * Get to the default display.
+ */
+ mEglDisplay = mEgl.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
+
+ if (mEglDisplay == EGL10.EGL_NO_DISPLAY)
+ {
+ throw new RuntimeException("eglGetDisplay failed");
+ }
+
+ /*
+ * We can now initialize EGL for that display
+ */
+ int[] version = new int[2];
+ if(!mEgl.eglInitialize(mEglDisplay, version))
+ {
+ throw new RuntimeException("eglInitialize failed");
+ }
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view == null)
+ {
+ mEglConfig = null;
+ mEglContext = null;
+ }
+ else
+ {
+ mEglConfig = view.mEGLConfigChooser.chooseConfig(mEgl, mEglDisplay);
+
+ /*
+ * Create an EGL context. We want to do this as rarely as we can, because an
+ * EGL context is a somewhat heavy object.
+ */
+ mEglContext = view.mEGLContextFactory.createContext(mEgl, mEglDisplay, mEglConfig);
+ }
+ if (mEglContext == null || mEglContext == EGL10.EGL_NO_CONTEXT)
+ {
+ mEglContext = null;
+ throwEglException("createContext");
+ }
+ if (LOG_EGL)
+ {
+ Log.w("EglHelper", "createContext " + mEglContext + " tid=" + Thread.currentThread().getId());
+ }
+
+ mEglSurface = null;
+ }
+
+ /**
+ * Create an egl surface for the current SurfaceHolder surface. If a surface
+ * already exists, destroy it before creating the new surface.
+ *
+ * @return true if the surface was created successfully.
+ */
+ public boolean createSurface()
+ {
+ if (LOG_EGL)
+ {
+ Log.w("EglHelper", "createSurface() tid=" + Thread.currentThread().getId());
+ }
+ /*
+ * Check preconditions.
+ */
+ if (mEgl == null)
+ {
+ throw new RuntimeException("egl not initialized");
+ }
+ if (mEglDisplay == null)
+ {
+ throw new RuntimeException("eglDisplay not initialized");
+ }
+ if (mEglConfig == null)
+ {
+ throw new RuntimeException("mEglConfig not initialized");
+ }
+
+ /*
+ * The window size has changed, so we need to create a new
+ * surface.
+ */
+ destroySurfaceImp();
+
+ /*
+ * Create an EGL surface we can render into.
+ */
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view != null)
+ {
+ mEglSurface = view.mEGLWindowSurfaceFactory.createWindowSurface(mEgl, mEglDisplay, mEglConfig, view.getHolder());
+ }
+ else
+ {
+ mEglSurface = null;
+ }
+
+ if (mEglSurface == null || mEglSurface == EGL10.EGL_NO_SURFACE)
+ {
+ int error = mEgl.eglGetError();
+ if (error == EGL10.EGL_BAD_NATIVE_WINDOW)
+ {
+ Log.e("EglHelper", "createWindowSurface returned EGL_BAD_NATIVE_WINDOW.");
+ }
+ return false;
+ }
+
+ /*
+ * Before we can issue GL commands, we need to make sure
+ * the context is current and bound to a surface.
+ */
+ if (!mEgl.eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface, mEglContext))
+ {
+ /*
+ * Could not make the context current, probably because the underlying
+ * SurfaceView surface has been destroyed.
+ */
+ logEglErrorAsWarning("EGLHelper", "eglMakeCurrent", mEgl.eglGetError());
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Create a GL object for the current EGL context.
+ * @return
+ */
+ GL createGL()
+ {
+ GL gl = mEglContext.getGL();
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view != null)
+ {
+ if (view.mGLWrapper != null)
+ {
+ gl = view.mGLWrapper.wrap(gl);
+ }
+ }
+ return gl;
+ }
+
+ /**
+ * Display the current render surface.
+ * @return the EGL error code from eglSwapBuffers.
+ */
+ public int swap()
+ {
+ if (! mEgl.eglSwapBuffers(mEglDisplay, mEglSurface))
+ {
+ return mEgl.eglGetError();
+ }
+ return EGL10.EGL_SUCCESS;
+ }
+
+ public void destroySurface()
+ {
+ if (LOG_EGL)
+ {
+ Log.w("EglHelper", "destroySurface() tid=" + Thread.currentThread().getId());
+ }
+ destroySurfaceImp();
+ }
+
+ private void destroySurfaceImp()
+ {
+ if (mEglSurface != null && mEglSurface != EGL10.EGL_NO_SURFACE)
+ {
+ mEgl.eglMakeCurrent(mEglDisplay, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_SURFACE, EGL10.EGL_NO_CONTEXT);
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view != null)
+ {
+ view.mEGLWindowSurfaceFactory.destroySurface(mEgl, mEglDisplay, mEglSurface);
+ }
+ mEglSurface = null;
+ }
+ }
+
+ public void finish()
+ {
+ if (LOG_EGL)
+ {
+ Log.w("EglHelper", "finish() tid=" + Thread.currentThread().getId());
+ }
+ if (mEglContext != null)
+ {
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view != null)
+ {
+ view.mEGLContextFactory.destroyContext(mEgl, mEglDisplay, mEglContext);
+ }
+ mEglContext = null;
+ }
+ if (mEglDisplay != null)
+ {
+ mEgl.eglTerminate(mEglDisplay);
+ mEglDisplay = null;
+ }
+ }
+
+ private void throwEglException(String function)
+ {
+ throwEglException(function, mEgl.eglGetError());
+ }
+
+ public static void throwEglException(String function, int error)
+ {
+ String message = formatEglError(function, error);
+ if (LOG_THREADS)
+ {
+ Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " + message);
+ }
+ throw new RuntimeException(message);
+ }
+
+ public static void logEglErrorAsWarning(String tag, String function, int error)
+ {
+ Log.w(tag, formatEglError(function, error));
+ }
+
+ public static String formatEglError(String function, int error)
+ {
+ return function + " failed: " + error;
+ }
+
+ private WeakReference mGLSurfaceViewWeakRef;
+ EGL10 mEgl;
+ EGLDisplay mEglDisplay;
+ EGLSurface mEglSurface;
+ EGLConfig mEglConfig;
+ EGLContext mEglContext;
+ }
+
+ /**
+ * An interface for customizing the eglCreateContext and eglDestroyContext calls.
+ *
+ * This interface must be implemented by clients wishing to call
+ * {@link GLSurfaceView#setEGLContextFactory(EGLContextFactory)}
+ */
+ public interface EGLContextFactory
+ {
+ EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig eglConfig);
+ void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context);
+ }
+
+ private class DefaultContextFactory implements EGLContextFactory
+ {
+ private int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
+
+ public EGLContext createContext(EGL10 egl, EGLDisplay display, EGLConfig config)
+ {
+ int[] attrib_list = {EGL_CONTEXT_CLIENT_VERSION, mEGLContextClientVersion, EGL10.EGL_NONE };
+
+ return egl.eglCreateContext(display, config, EGL10.EGL_NO_CONTEXT, mEGLContextClientVersion != 0 ? attrib_list : null);
+ }
+
+ public void destroyContext(EGL10 egl, EGLDisplay display, EGLContext context)
+ {
+ if (!egl.eglDestroyContext(display, context))
+ {
+ Log.e("DefaultContextFactory", "display:" + display + " context: " + context);
+ if (LOG_THREADS)
+ {
+ Log.i("DefaultContextFactory", "tid=" + Thread.currentThread().getId());
+ }
+ String message = "eglDestroyContex failed: " + egl.eglGetError();
+ if (LOG_THREADS)
+ {
+ Log.e("EglHelper", "throwEglException tid=" + Thread.currentThread().getId() + " " + message);
+ }
+ throw new RuntimeException(message);
+ }
+ }
+ }
+
+ /**
+ * An interface for customizing the eglCreateWindowSurface and eglDestroySurface calls.
+ *
+ * This interface must be implemented by clients wishing to call
+ * {@link GLSurfaceView#setEGLWindowSurfaceFactory(EGLWindowSurfaceFactory)}
+ */
+ public interface EGLWindowSurfaceFactory
+ {
+ /**
+ * @return null if the surface cannot be constructed.
+ */
+ EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow);
+ void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface);
+ }
+
+ private static class DefaultWindowSurfaceFactory implements EGLWindowSurfaceFactory
+ {
+
+ public EGLSurface createWindowSurface(EGL10 egl, EGLDisplay display, EGLConfig config, Object nativeWindow)
+ {
+ EGLSurface result = null;
+ try
+ {
+ result = egl.eglCreateWindowSurface(display, config, nativeWindow, null);
+ }
+ catch (IllegalArgumentException e)
+ {
+ // This exception indicates that the surface flinger surface
+ // is not valid. This can happen if the surface flinger surface has
+ // been torn down, but the application has not yet been
+ // notified via SurfaceHolder.Callback.surfaceDestroyed.
+ // In theory the application should be notified first,
+ // but in practice sometimes it is not. See b/4588890
+ Log.e(TAG, "eglCreateWindowSurface", e);
+ }
+ return result;
+ }
+
+ public void destroySurface(EGL10 egl, EGLDisplay display, EGLSurface surface)
+ {
+ egl.eglDestroySurface(display, surface);
+ }
+ }
+
+ /**
+ * An interface for choosing an EGLConfig configuration from a list of
+ * potential configurations.
+ *
+ * This interface must be implemented by clients wishing to call
+ * {@link GLSurfaceView#setEGLConfigChooser(EGLConfigChooser)}
+ */
+ public interface EGLConfigChooser
+ {
+ /**
+ * Choose a configuration from the list. Implementors typically
+ * implement this method by calling
+ * {@link EGL10#eglChooseConfig} and iterating through the results. Please consult the
+ * EGL specification available from The Khronos Group to learn how to call eglChooseConfig.
+ * @param egl the EGL10 for the current display.
+ * @param display the current display.
+ * @return the chosen configuration.
+ */
+ EGLConfig chooseConfig(EGL10 egl, EGLDisplay display);
+ }
+
+ private abstract class BaseConfigChooser implements EGLConfigChooser
+ {
+ public BaseConfigChooser(int[] configSpec)
+ {
+ mConfigSpec = filterConfigSpec(configSpec);
+ }
+
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display)
+ {
+ int[] num_config = new int[1];
+ if (!egl.eglChooseConfig(display, mConfigSpec, null, 0, num_config))
+ {
+ throw new IllegalArgumentException("eglChooseConfig failed");
+ }
+
+ int numConfigs = num_config[0];
+
+ if (numConfigs <= 0)
+ {
+ throw new IllegalArgumentException( "No configs match configSpec");
+ }
+
+ EGLConfig[] configs = new EGLConfig[numConfigs];
+ if (!egl.eglChooseConfig(display, mConfigSpec, configs, numConfigs, num_config))
+ {
+ throw new IllegalArgumentException("eglChooseConfig#2 failed");
+ }
+ EGLConfig config = chooseConfig(egl, display, configs);
+ if (config == null)
+ {
+ throw new IllegalArgumentException("No config chosen");
+ }
+ return config;
+ }
+
+ abstract EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs);
+
+ protected int[] mConfigSpec;
+
+ private int[] filterConfigSpec(int[] configSpec)
+ {
+ if (mEGLContextClientVersion != 2 && mEGLContextClientVersion != 3)
+ {
+ return configSpec;
+ }
+ /* We know none of the subclasses define EGL_RENDERABLE_TYPE.
+ * And we know the configSpec is well formed.
+ */
+ int len = configSpec.length;
+ int[] newConfigSpec = new int[len + 2];
+ System.arraycopy(configSpec, 0, newConfigSpec, 0, len-1);
+ newConfigSpec[len-1] = EGL10.EGL_RENDERABLE_TYPE;
+ if (mEGLContextClientVersion == 2)
+ {
+ newConfigSpec[len] = EGL14.EGL_OPENGL_ES2_BIT; /* EGL_OPENGL_ES2_BIT */
+ }
+ else
+ {
+ newConfigSpec[len] = EGLExt.EGL_OPENGL_ES3_BIT_KHR; /* EGL_OPENGL_ES3_BIT_KHR */
+ }
+ newConfigSpec[len+1] = EGL10.EGL_NONE;
+ return newConfigSpec;
+ }
+ }
+
+ /**
+ * Choose a configuration with exactly the specified r,g,b,a sizes,
+ * and at least the specified depth and stencil sizes.
+ */
+ private class ComponentSizeChooser extends BaseConfigChooser
+ {
+ public ComponentSizeChooser(int redSize, int greenSize, int blueSize, int alphaSize, int depthSize, int stencilSize)
+ {
+ super(new int[]
+ {
+ EGL10.EGL_RED_SIZE, redSize,
+ EGL10.EGL_GREEN_SIZE, greenSize,
+ EGL10.EGL_BLUE_SIZE, blueSize,
+ EGL10.EGL_ALPHA_SIZE, alphaSize,
+ EGL10.EGL_DEPTH_SIZE, depthSize,
+ EGL10.EGL_STENCIL_SIZE, stencilSize,
+ EGL10.EGL_NONE
+ });
+ mValue = new int[1];
+ mRedSize = redSize;
+ mGreenSize = greenSize;
+ mBlueSize = blueSize;
+ mAlphaSize = alphaSize;
+ mDepthSize = depthSize;
+ mStencilSize = stencilSize;
+ }
+
+ @Override
+ public EGLConfig chooseConfig(EGL10 egl, EGLDisplay display, EGLConfig[] configs)
+ {
+ for (EGLConfig config : configs)
+ {
+ int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
+ int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
+ if ((d >= mDepthSize) && (s >= mStencilSize))
+ {
+ int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
+ int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
+ int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
+ int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
+ if ((r == mRedSize) && (g == mGreenSize) && (b == mBlueSize) && (a == mAlphaSize))
+ {
+ return config;
+ }
+ }
+ }
+ return null;
+ }
+
+ private int findConfigAttrib(EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue)
+ {
+ if (egl.eglGetConfigAttrib(display, config, attribute, mValue))
+ {
+ return mValue[0];
+ }
+ return defaultValue;
+ }
+
+ private int[] mValue;
+ // Subclasses can adjust these values:
+ protected int mRedSize;
+ protected int mGreenSize;
+ protected int mBlueSize;
+ protected int mAlphaSize;
+ protected int mDepthSize;
+ protected int mStencilSize;
+ }
+
+ /**
+ * This class will choose a RGB_888 surface with
+ * or without a depth buffer.
+ *
+ */
+ private class SimpleEGLConfigChooser extends ComponentSizeChooser
+ {
+ public SimpleEGLConfigChooser(boolean withDepthBuffer)
+ {
+ super(8, 8, 8, 0, withDepthBuffer ? 16 : 0, 0);
+ }
+ }
+
+ static class LogWriter extends Writer
+ {
+ @Override
+ public void close()
+ {
+ flushBuilder();
+ }
+
+ @Override
+ public void flush()
+ {
+ flushBuilder();
+ }
+
+ @Override
+ public void write(char[] buf, int offset, int count)
+ {
+ for(int i = 0; i < count; i++)
+ {
+ char c = buf[offset + i];
+ if ( c == '\n')
+ {
+ flushBuilder();
+ }
+ else
+ {
+ mBuilder.append(c);
+ }
+ }
+ }
+
+ private void flushBuilder()
+ {
+ if (mBuilder.length() > 0)
+ {
+ Log.v("GLSurfaceView", mBuilder.toString());
+ mBuilder.delete(0, mBuilder.length());
+ }
+ }
+
+ private StringBuilder mBuilder = new StringBuilder();
+ }
+
+ static class GLThreadManager
+ {
+ private static String TAG = "GLThreadManager";
+
+ public synchronized void threadExiting(GLThread thread)
+ {
+ if (LOG_THREADS)
+ {
+ Log.i("GLThread", "exiting tid=" + Thread.currentThread().getId());
+ }
+ if (mEglOwner == thread)
+ {
+ mEglOwner = null;
+ }
+ notifyAll();
+ }
+
+ /*
+ * Tries once to acquire the right to use an EGL
+ * context. Does not block. Requires that we are already
+ * in the sGLThreadManager monitor when this is called.
+ *
+ * @return true if the right to use an EGL context was acquired.
+ */
+ public boolean tryAcquireEglContextLocked(GLThread thread)
+ {
+ if (mEglOwner == thread || mEglOwner == null)
+ {
+ mEglOwner = thread;
+ notifyAll();
+ return true;
+ }
+ checkGLESVersion();
+ if (mMultipleGLESContextsAllowed)
+ {
+ return true;
+ }
+ // Notify the owning thread that it should release the context.
+ // TODO: implement a fairness policy. Currently
+ // if the owning thread is drawing continuously it will just
+ // reacquire the EGL context.
+ if (mEglOwner != null)
+ {
+ mEglOwner.requestReleaseEglContextLocked();
+ }
+ return false;
+ }
+
+ /*
+ * Releases the EGL context. Requires that we are already in the
+ * sGLThreadManager monitor when this is called.
+ */
+ public void releaseEglContextLocked(GLThread thread)
+ {
+ if (mEglOwner == thread) {
+ mEglOwner = null;
+ }
+ notifyAll();
+ }
+
+ public synchronized boolean shouldReleaseEGLContextWhenPausing()
+ {
+ // Release the EGL context when pausing even if
+ // the hardware supports multiple EGL contexts.
+ // Otherwise the device could run out of EGL contexts.
+ return mLimitedGLESContexts;
+ }
+
+ public synchronized boolean shouldTerminateEGLWhenPausing()
+ {
+ checkGLESVersion();
+ return !mMultipleGLESContextsAllowed;
+ }
+
+ public synchronized void checkGLDriver(GL10 gl)
+ {
+ if (! mGLESDriverCheckComplete)
+ {
+ checkGLESVersion();
+ String renderer = gl.glGetString(GL10.GL_RENDERER);
+ if (mGLESVersion < kGLES_20)
+ {
+ mMultipleGLESContextsAllowed = ! renderer.startsWith(kMSM7K_RENDERER_PREFIX);
+ notifyAll();
+ }
+ mLimitedGLESContexts = !mMultipleGLESContextsAllowed;
+ if (LOG_SURFACE)
+ {
+ Log.w(TAG, "checkGLDriver renderer = \"" + renderer + "\" multipleContextsAllowed = " + mMultipleGLESContextsAllowed + " mLimitedGLESContexts = " + mLimitedGLESContexts);
+ }
+ mGLESDriverCheckComplete = true;
+ }
+ }
+
+ private void checkGLESVersion()
+ {
+ if (! mGLESVersionCheckComplete)
+ {
+ try
+ {
+ Class> SP = Class.forName("android.os.SystemProperties");
+ mGLESVersion = (Integer)SP.getMethod("getInt", String.class, int.class).invoke(null, "ro.opengles.version", ConfigurationInfo.GL_ES_VERSION_UNDEFINED);
+ if (mGLESVersion >= kGLES_20)
+ {
+ mMultipleGLESContextsAllowed = true;
+ }
+ }
+ catch (Exception e)
+ {
+ }
+ if (LOG_SURFACE)
+ {
+ Log.w(TAG, "checkGLESVersion mGLESVersion =" + " " + mGLESVersion + " mMultipleGLESContextsAllowed = " + mMultipleGLESContextsAllowed);
+ }
+ mGLESVersionCheckComplete = true;
+ }
+ }
+
+ /**
+ * This check was required for some pre-Android-3.0 hardware. Android 3.0 provides
+ * support for hardware-accelerated views, therefore multiple EGL contexts are
+ * supported on all Android 3.0+ EGL drivers.
+ */
+ private boolean mGLESVersionCheckComplete;
+ private int mGLESVersion;
+ private boolean mGLESDriverCheckComplete;
+ private boolean mMultipleGLESContextsAllowed;
+ private boolean mLimitedGLESContexts;
+ private static final int kGLES_20 = 0x20000;
+ private static final String kMSM7K_RENDERER_PREFIX = "Q3Dimension MSM7500 ";
+ private GLThread mEglOwner;
+ }
+
+ /**
+ * A generic GL Thread. Takes care of initializing EGL and GL. Delegates
+ * to a Renderer instance to do the actual drawing. Can be configured to
+ * render continuously or on request.
+ *
+ * All potentially blocking synchronization is done through the
+ * sGLThreadManager object. This avoids multiple-lock ordering issues.
+ *
+ */
+ public static class GLThread
+ {
+ private final static boolean LOG_THREADS = false;
+ private final static boolean LOG_SURFACE = false;
+ private final static boolean LOG_PAUSE_RESUME = false;
+ private final static boolean LOG_RENDERER = false;
+
+ /**
+ * Check glError() after every GL call and throw an exception if glError indicates
+ * that an error has occurred. This can be used to help track down which OpenGL ES call
+ * is causing an error.
+ *
+ * @see #getDebugFlags
+ * @see #setDebugFlags
+ */
+ public final static int DEBUG_CHECK_GL_ERROR = 1;
+
+ /**
+ * Log GL calls to the system log at "verbose" level with tag "GLSurfaceView".
+ *
+ * @see #getDebugFlags
+ * @see #setDebugFlags
+ */
+ public final static int DEBUG_LOG_GL_CALLS = 2;
+
+ public GLThread(WeakReference glSurfaceViewWeakRef, GameSurface.SurfaceInfo surfaceInfo)
+ {
+ super();
+ glSurfaceViewWeakRef.get().mRequestRender = true;
+ mGLSurfaceViewWeakRef = glSurfaceViewWeakRef;
+ mSurfaceInfo = surfaceInfo;
+ }
+
+ public void ThreadStarting()
+ {
+ Log.i("GLThread", "ThreadStarting: start tid=" + Thread.currentThread().getId());
+ if (LOG_THREADS)
+ {
+ Log.i("GLThread", "starting tid=" + Thread.currentThread().getId());
+ }
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ view.mHaveEglContext = false;
+ view.mHaveEglSurface = false;
+ ReadyToDraw();
+ if (LOG_THREADS)
+ {
+ Log.i("GLThread", "starting tid=" + Thread.currentThread().getId());
+ }
+ Log.i("GLThread", "ThreadStarting: done tid=" + Thread.currentThread().getId());
+ }
+
+ public void ThreadExiting()
+ {
+ Log.i("GLThread", "ThreadExiting: start tid=" + Thread.currentThread().getId());
+ /*
+ * clean-up everything...
+ */
+ GameSurface.sGLThreadManager.threadExiting(this);
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ view.mExited = true;
+ synchronized (GameSurface.sGLThreadManager)
+ {
+ stopEglSurfaceLocked();
+ stopEglContextLocked();
+ }
+ Log.i("GLThread", "ThreadExiting: done tid=" + Thread.currentThread().getId());
+ }
+
+ /*
+ * This private method should only be called inside a
+ * synchronized(sGLThreadManager) block.
+ */
+ private void stopEglSurfaceLocked()
+ {
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view.mHaveEglSurface)
+ {
+ view.mHaveEglSurface = false;
+ view.mEglHelper.destroySurface();
+ }
+ }
+
+ /*
+ * This private method should only be called inside a
+ * synchronized(sGLThreadManager) block.
+ */
+ private void stopEglContextLocked()
+ {
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ if (view.mHaveEglContext)
+ {
+ view.mEglHelper.finish();
+ view.mHaveEglContext = false;
+ GameSurface.sGLThreadManager.releaseEglContextLocked(this);
+ }
+ }
+
+ public void ReadyToDraw()
+ {
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ try
+ {
+ synchronized (GameSurface.sGLThreadManager)
+ {
+ while (true)
+ {
+ if (mShouldExit)
+ {
+ return;
+ }
+
+ if (! mEventQueue.isEmpty())
+ {
+ mEvent = mEventQueue.remove(0);
+ break;
+ }
+
+ // Update the pause state.
+ boolean pausing = false;
+ if (view.mPaused != mRequestPaused)
+ {
+ pausing = mRequestPaused;
+ view.mPaused = mRequestPaused;
+ GameSurface.sGLThreadManager.notifyAll();
+ if (LOG_PAUSE_RESUME)
+ {
+ Log.i("GLThread", "mPaused is now " + view.mPaused + " tid=" + Thread.currentThread().getId());
+ }
+ }
+
+ // Do we need to give up the EGL context?
+ if (mShouldReleaseEglContext)
+ {
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "releasing EGL context because asked to tid=" + Thread.currentThread().getId());
+ }
+ stopEglSurfaceLocked();
+ stopEglContextLocked();
+ mShouldReleaseEglContext = false;
+ mAskedToReleaseEglContext = true;
+ }
+
+ // Have we lost the EGL context?
+ if (mLostEglContext)
+ {
+ stopEglSurfaceLocked();
+ stopEglContextLocked();
+ mLostEglContext = false;
+ }
+
+ // When pausing, release the EGL surface:
+ if (pausing && view.mHaveEglSurface)
+ {
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "releasing EGL surface because paused tid=" + Thread.currentThread().getId());
+ }
+ stopEglSurfaceLocked();
+ }
+
+ // When pausing, optionally release the EGL Context:
+ if (pausing && view.mHaveEglContext)
+ {
+ boolean preserveEglContextOnPause = view == null ? false : view.mPreserveEGLContextOnPause;
+ if (!preserveEglContextOnPause || GameSurface.sGLThreadManager.shouldReleaseEGLContextWhenPausing())
+ {
+ stopEglContextLocked();
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "releasing EGL context because paused tid=" + Thread.currentThread().getId());
+ }
+ }
+ }
+
+ // When pausing, optionally terminate EGL:
+ if (pausing)
+ {
+ if (GameSurface.sGLThreadManager.shouldTerminateEGLWhenPausing())
+ {
+ view.mEglHelper.finish();
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "terminating EGL because paused tid=" + Thread.currentThread().getId());
+ }
+ }
+ }
+
+ // Have we lost the SurfaceView surface?
+ if ((!view.mHasSurface) && (!view.mWaitingForSurface))
+ {
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "noticed surfaceView surface lost tid=" + Thread.currentThread().getId());
+ }
+ if (view.mHaveEglSurface)
+ {
+ stopEglSurfaceLocked();
+ }
+ view.mWaitingForSurface = true;
+ view.mSurfaceIsBad = false;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+
+ // Have we acquired the surface view surface?
+ if (view.mHasSurface && view.mWaitingForSurface)
+ {
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "noticed surfaceView surface acquired tid=" + Thread.currentThread().getId());
+ }
+ view.mWaitingForSurface = false;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+
+ if (mDoRenderNotification)
+ {
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "sending render notification tid=" + Thread.currentThread().getId());
+ }
+ mWantRenderNotification = false;
+ mDoRenderNotification = false;
+ view.mRenderComplete = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+
+ // Ready to draw?
+ if (view.readyToDraw())
+ {
+ // If we don't have an EGL context, try to acquire one.
+ if (!view.mHaveEglContext)
+ {
+ if (mAskedToReleaseEglContext)
+ {
+ mAskedToReleaseEglContext = false;
+ }
+ else if (GameSurface.sGLThreadManager.tryAcquireEglContextLocked(this))
+ {
+ try
+ {
+ view.mEglHelper.start();
+ }
+ catch (RuntimeException t)
+ {
+ GameSurface.sGLThreadManager.releaseEglContextLocked(this);
+ throw t;
+ }
+ view.mHaveEglContext = true;
+ mCreateEglContext = true;
+
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+ }
+
+ if (view.mHaveEglContext && !view.mHaveEglSurface)
+ {
+ view.mHaveEglSurface = true;
+ mCreateEglSurface = true;
+ mCreateGlInterface = true;
+ mSizeChanged = true;
+ }
+
+ if (view.mHaveEglSurface)
+ {
+ if (view.mSizeChanged)
+ {
+ mSizeChanged = true;
+ mW = view.mWidth;
+ mH = view.mHeight;
+ mWantRenderNotification = true;
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "noticing that we want render notification tid=" + Thread.currentThread().getId());
+ }
+
+ // Destroy and recreate the EGL surface.
+ mCreateEglSurface = true;
+
+ view.mSizeChanged = false;
+ }
+ view.mRequestRender = false;
+ GameSurface.sGLThreadManager.notifyAll();
+ break;
+ }
+ }
+
+ // By design, this is the only place in a GLThread thread where we wait().
+ if (LOG_THREADS)
+ {
+ Log.i("GLThread", "waiting tid=" + Thread.currentThread().getId()
+ + " mHaveEglContext: " + view.mHaveEglContext
+ + " mHaveEglSurface: " + view.mHaveEglSurface
+ + " mFinishedCreatingEglSurface: " + view.mFinishedCreatingEglSurface
+ + " mPaused: " + view.mPaused
+ + " mHasSurface: " + view.mHasSurface
+ + " mSurfaceIsBad: " + view.mSurfaceIsBad
+ + " mWaitingForSurface: " + view.mWaitingForSurface
+ + " mWidth: " + view.mWidth
+ + " mHeight: " + view.mHeight
+ + " mRequestRender: " + view.mRequestRender);
+ }
+
+ try
+ {
+ GameSurface.sGLThreadManager.wait();
+ }
+ catch (InterruptedException e)
+ {
+ // fall thru and exit normally
+ }
+ }
+ } // end of synchronized(sGLThreadManager)
+
+ if (mEvent != null)
+ {
+ mEvent.run();
+ mEvent = null;
+ ReadyToDraw();
+ return;
+ }
+
+ if (mCreateEglSurface)
+ {
+ if (LOG_SURFACE)
+ {
+ Log.w("GLThread", "egl createSurface");
+ }
+ if (view.mEglHelper.createSurface())
+ {
+ synchronized(GameSurface.sGLThreadManager)
+ {
+ view.mFinishedCreatingEglSurface = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+ }
+ else
+ {
+ synchronized(GameSurface.sGLThreadManager)
+ {
+ view.mFinishedCreatingEglSurface = true;
+ view.mSurfaceIsBad = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+ ReadyToDraw();
+ return;
+ }
+ mCreateEglSurface = false;
+ }
+
+ if (mCreateGlInterface)
+ {
+ mGl = (GL10) view.mEglHelper.createGL();
+
+ GameSurface.sGLThreadManager.checkGLDriver(mGl);
+ mCreateGlInterface = false;
+ }
+
+ if (mCreateEglContext)
+ {
+ if (LOG_RENDERER)
+ {
+ Log.w("GLThread", "onSurfaceCreated");
+ }
+ if (view != null)
+ {
+ try
+ {
+ //Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceCreated");
+ mSurfaceInfo.onSurfaceCreated(mGl, view.mEglHelper.mEglConfig);
+ }
+ finally
+ {
+ //Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+ mCreateEglContext = false;
+ }
+
+ if (mSizeChanged)
+ {
+ if (LOG_RENDERER)
+ {
+ Log.w("GLThread", "onSurfaceChanged(" + mW + ", " + mH + ")");
+ }
+ if (view != null)
+ {
+ try
+ {
+ //Trace.traceBegin(Trace.TRACE_TAG_VIEW, "onSurfaceChanged");
+ mSurfaceInfo.onSurfaceChanged(mGl, mW, mH);
+ }
+ finally
+ {
+ //Trace.traceEnd(Trace.TRACE_TAG_VIEW);
+ }
+ }
+ mSizeChanged = false;
+ }
+ }
+ finally
+ {
+ /*
+ * clean-up everything...
+ */
+ }
+ }
+
+ public void SwapBuffers()
+ {
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ int swapError = view.mEglHelper.swap();
+ switch (swapError)
+ {
+ case EGL10.EGL_SUCCESS:
+ break;
+ case EGL11.EGL_CONTEXT_LOST:
+ if (LOG_SURFACE)
+ {
+ Log.i("GLThread", "egl context lost tid=" + Thread.currentThread().getId());
+ }
+ mLostEglContext = true;
+ break;
+ default:
+ // Other errors typically mean that the current surface is bad,
+ // probably because the SurfaceView surface has been destroyed,
+ // but we haven't been notified yet.
+ // Log the error to help developers understand why rendering stopped.
+ EglHelper.logEglErrorAsWarning("GLThread", "eglSwapBuffers", swapError);
+
+ synchronized(GameSurface.sGLThreadManager)
+ {
+ view.mSurfaceIsBad = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+ break;
+ }
+
+ if (mWantRenderNotification)
+ {
+ mDoRenderNotification = true;
+ }
+ ReadyToDraw();
+ }
+
+ public void requestRender()
+ {
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ synchronized(GameSurface.sGLThreadManager)
+ {
+ view.mRequestRender = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+ }
+
+ public void onPause()
+ {
+ Log.i("GLThread", "onPause start");
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ synchronized (GameSurface.sGLThreadManager)
+ {
+ if (LOG_PAUSE_RESUME)
+ {
+ Log.i("GLThread", "onPause tid=" + Thread.currentThread().getId());
+ }
+ mRequestPaused = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ while ((! view.mExited) && (! view.mPaused))
+ {
+ if (LOG_PAUSE_RESUME)
+ {
+ Log.i("Main thread", "onPause waiting for mPaused.");
+ }
+ try
+ {
+ GameSurface.sGLThreadManager.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ Log.i("GLThread", "onPause done");
+ }
+
+ public void onResume()
+ {
+ Log.i("GLThread", "onResume start");
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ synchronized (GameSurface.sGLThreadManager)
+ {
+ if (LOG_PAUSE_RESUME)
+ {
+ Log.i("GLThread", "onResume tid=" + Thread.currentThread().getId());
+ }
+ mRequestPaused = false;
+ view.mRequestRender = true;
+ view.mRenderComplete = false;
+ GameSurface.sGLThreadManager.notifyAll();
+ while ((!view.mExited) && view.mPaused && (!view.mRenderComplete))
+ {
+ if (LOG_PAUSE_RESUME)
+ {
+ Log.i("Main thread", "onResume waiting for !mPaused.");
+ }
+ try
+ {
+ GameSurface.sGLThreadManager.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ Log.i("GLThread", "onResume Done");
+ }
+
+ public void requestExitAndWait()
+ {
+ Log.i("GLThread", "requestExitAndWait start");
+ // don't call this from GLThread thread or it is a guaranteed
+ // deadlock!
+ GameSurface view = mGLSurfaceViewWeakRef.get();
+ synchronized(GameSurface.sGLThreadManager)
+ {
+ mShouldExit = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ while (!view.mExited)
+ {
+ try
+ {
+ GameSurface.sGLThreadManager.wait();
+ }
+ catch (InterruptedException ex)
+ {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+ Log.i("GLThread", "requestExitAndWait exit");
+ }
+
+ public void requestReleaseEglContextLocked()
+ {
+ mShouldReleaseEglContext = true;
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+
+ /**
+ * Queue an "mEvent" to be run on the GL rendering thread.
+ * @param r the runnable to be run on the GL rendering thread.
+ */
+ public void queueEvent(Runnable r)
+ {
+ Log.i("GLThread", "queueEvent start");
+ if (r == null)
+ {
+ throw new IllegalArgumentException("r must not be null");
+ }
+ synchronized(GameSurface.sGLThreadManager)
+ {
+ mEventQueue.add(r);
+ GameSurface.sGLThreadManager.notifyAll();
+ }
+ Log.i("GLThread", "queueEvent Done");
+ }
+
+ // Once the thread is started, all accesses to the following member
+ // variables are protected by the sGLThreadManager monitor
+ private boolean mShouldExit;
+ private boolean mRequestPaused;
+ private boolean mShouldReleaseEglContext;
+ private GameSurface.SurfaceInfo mSurfaceInfo;
+ private ArrayList mEventQueue = new ArrayList();
+
+ // End of member variables protected by the sGLThreadManager monitor.
+
+ /**
+ * Set once at thread construction time, nulled out when the parent view is garbage
+ * called. This weak reference allows the GLSurfaceView to be garbage collected while
+ * the GLThread is still alive.
+ */
+ private WeakReference mGLSurfaceViewWeakRef;
+
+ GL10 mGl = null;
+ boolean mCreateEglContext = false;
+ boolean mCreateEglSurface = false;
+ boolean mCreateGlInterface = false;
+ boolean mLostEglContext = false;
+ boolean mSizeChanged = false;
+ boolean mWantRenderNotification = false;
+ boolean mDoRenderNotification = false;
+ boolean mAskedToReleaseEglContext = false;
+ int mW = 0;
+ int mH = 0;
+ Runnable mEvent = null;
+ }
+
+ static final GLThreadManager sGLThreadManager = new GLThreadManager();
+
+ EGLConfigChooser mEGLConfigChooser;
+ EGLContextFactory mEGLContextFactory;
+ EGLWindowSurfaceFactory mEGLWindowSurfaceFactory;
+ GLWrapper mGLWrapper;
+ int mDebugFlags;
+ int mEGLContextClientVersion;
+ boolean mPreserveEGLContextOnPause;
+ int mWidth;
+ int mHeight;
+ boolean mSizeChanged = true;
+ boolean mRequestRender;
+ boolean mRenderComplete;
+ boolean mExited;
+ boolean mPaused;
+ boolean mHasSurface;
+ boolean mSurfaceIsBad;
+ boolean mHaveEglSurface;
+ boolean mWaitingForSurface;
+ boolean mFinishedCreatingEglSurface;
+ boolean mHaveEglContext;
+ EglHelper mEglHelper;
+}
\ No newline at end of file
diff --git a/Android/src/emu/project64/hack/MogaHack.java b/Android/src/emu/project64/hack/MogaHack.java
new file mode 100644
index 000000000..ded933dd6
--- /dev/null
+++ b/Android/src/emu/project64/hack/MogaHack.java
@@ -0,0 +1,110 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2016 Project64. All rights reserved. *
+* Copyright (C) 2013 Paul Lamb
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.hack;
+
+import java.util.List;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.util.Log;
+
+import com.bda.controller.Controller;
+import com.bda.controller.IControllerService;
+
+import emu.project64.AndroidDevice;
+
+/**
+ * Temporary hack for crash in MOGA library on Lollipop. This hack can be removed once MOGA fixes
+ * their library. The actual issue is caused by the use of implicit service intents, which are
+ * illegal in Lollipop, as seen in the logcat message below.
+ *
+ *
+ * {@code Service Intent must be explicit: Intent { act=com.bda.controller.IControllerService } }
+ *
+ *
+ * @see MOGA developer site
+ * @see
+ * Discussion on explicit intents
+ */
+public class MogaHack
+{
+ public static void init( Controller controller, Context context )
+ {
+ if( AndroidDevice.IS_LOLLIPOP )
+ {
+ boolean mIsBound = false;
+ java.lang.reflect.Field fIsBound = null;
+ android.content.ServiceConnection mServiceConnection = null;
+ java.lang.reflect.Field fServiceConnection = null;
+ try
+ {
+ Class> cMogaController = controller.getClass();
+ fIsBound = cMogaController.getDeclaredField( "mIsBound" );
+ fIsBound.setAccessible( true );
+ mIsBound = fIsBound.getBoolean( controller );
+ fServiceConnection = cMogaController.getDeclaredField( "mServiceConnection" );
+ fServiceConnection.setAccessible( true );
+ mServiceConnection = ( android.content.ServiceConnection ) fServiceConnection.get( controller );
+ }
+ catch( NoSuchFieldException e )
+ {
+ Log.e( "MogaHack", "MOGA Lollipop Hack NoSuchFieldException (get)", e );
+ }
+ catch( IllegalAccessException e )
+ {
+ Log.e( "MogaHack", "MOGA Lollipop Hack IllegalAccessException (get)", e );
+ }
+ catch( IllegalArgumentException e )
+ {
+ Log.e( "MogaHack", "MOGA Lollipop Hack IllegalArgumentException (get)", e );
+ }
+ if( ( !mIsBound ) && ( mServiceConnection != null ) )
+ {
+ // Convert implicit intent to explicit intent, see http://stackoverflow.com/a/26318757
+ Intent intent = new Intent( IControllerService.class.getName() );
+ List resolveInfos = context.getPackageManager().queryIntentServices( intent, 0 );
+ if( resolveInfos == null || resolveInfos.size() != 1 )
+ {
+ Log.e( "MogaHack", "Somebody is trying to intercept our intent. Disabling MOGA controller for security." );
+ return;
+ }
+ ServiceInfo serviceInfo = resolveInfos.get( 0 ).serviceInfo;
+ String packageName = serviceInfo.packageName;
+ String className = serviceInfo.name;
+ intent.setComponent( new ComponentName( packageName, className ) );
+
+ // Start the service explicitly
+ context.startService( intent );
+ context.bindService( intent, mServiceConnection, 1 );
+ try
+ {
+ fIsBound.setBoolean( controller, true );
+ }
+ catch( IllegalAccessException e )
+ {
+ Log.e( "MogaHack", "MOGA Lollipop Hack IllegalAccessException (set)", e );
+ }
+ catch( IllegalArgumentException e )
+ {
+ Log.e( "MogaHack", "MOGA Lollipop Hack IllegalArgumentException (set)", e );
+ }
+ }
+ }
+ else
+ {
+ controller.init();
+ }
+ }
+}
diff --git a/Android/src/emu/project64/inAppPurchase/IabBroadcastReceiver.java b/Android/src/emu/project64/inAppPurchase/IabBroadcastReceiver.java
new file mode 100644
index 000000000..5cae146fb
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/IabBroadcastReceiver.java
@@ -0,0 +1,60 @@
+/* Copyright (c) 2014 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+/**
+ * Receiver for the "com.android.vending.billing.PURCHASES_UPDATED" Action
+ * from the Play Store.
+ *
+ * It is possible that an in-app item may be acquired without the
+ * application calling getBuyIntent(), for example if the item can be
+ * redeemed from inside the Play Store using a promotional code. If this
+ * application isn't running at the time, then when it is started a call
+ * to getPurchases() will be sufficient notification. However, if the
+ * application is already running in the background when the item is acquired,
+ * a message to this BroadcastReceiver will indicate that the an item
+ * has been acquired.
+ */
+public class IabBroadcastReceiver extends BroadcastReceiver {
+ /**
+ * Listener interface for received broadcast messages.
+ */
+ public interface IabBroadcastListener {
+ void receivedBroadcast();
+ }
+
+ /**
+ * The Intent action that this Receiver should filter for.
+ */
+ public static final String ACTION = "com.android.vending.billing.PURCHASES_UPDATED";
+
+ private final IabBroadcastListener mListener;
+
+ public IabBroadcastReceiver(IabBroadcastListener listener) {
+ mListener = listener;
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (mListener != null) {
+ mListener.receivedBroadcast();
+ }
+ }
+}
diff --git a/Android/src/emu/project64/inAppPurchase/IabException.java b/Android/src/emu/project64/inAppPurchase/IabException.java
new file mode 100644
index 000000000..a7cc54e5f
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/IabException.java
@@ -0,0 +1,43 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+/**
+ * Exception thrown when something went wrong with in-app billing.
+ * An IabException has an associated IabResult (an error).
+ * To get the IAB result that caused this exception to be thrown,
+ * call {@link #getResult()}.
+ */
+public class IabException extends Exception {
+ IabResult mResult;
+
+ public IabException(IabResult r) {
+ this(r, null);
+ }
+ public IabException(int response, String message) {
+ this(new IabResult(response, message));
+ }
+ public IabException(IabResult r, Exception cause) {
+ super(r.getMessage(), cause);
+ mResult = r;
+ }
+ public IabException(int response, String message, Exception cause) {
+ this(new IabResult(response, message), cause);
+ }
+
+ /** Returns the IAB result (error) that this exception signals. */
+ public IabResult getResult() { return mResult; }
+}
\ No newline at end of file
diff --git a/Android/src/emu/project64/inAppPurchase/IabHelper.java b/Android/src/emu/project64/inAppPurchase/IabHelper.java
new file mode 100644
index 000000000..c8dea07b9
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/IabHelper.java
@@ -0,0 +1,1116 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentSender.SendIntentException;
+import android.content.ServiceConnection;
+import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.vending.billing.IInAppBillingService;
+
+import org.json.JSONException;
+
+import java.util.ArrayList;
+import java.util.List;
+
+
+/**
+ * Provides convenience methods for in-app billing. You can create one instance of this
+ * class for your application and use it to process in-app billing operations.
+ * It provides synchronous (blocking) and asynchronous (non-blocking) methods for
+ * many common in-app billing operations, as well as automatic signature
+ * verification.
+ *
+ * After instantiating, you must perform setup in order to start using the object.
+ * To perform setup, call the {@link #startSetup} method and provide a listener;
+ * that listener will be notified when setup is complete, after which (and not before)
+ * you may call other methods.
+ *
+ * After setup is complete, you will typically want to request an inventory of owned
+ * items and subscriptions. See {@link #queryInventory}, {@link #queryInventoryAsync}
+ * and related methods.
+ *
+ * When you are done with this object, don't forget to call {@link #dispose}
+ * to ensure proper cleanup. This object holds a binding to the in-app billing
+ * service, which will leak unless you dispose of it correctly. If you created
+ * the object on an Activity's onCreate method, then the recommended
+ * place to dispose of it is the Activity's onDestroy method. It is invalid to
+ * dispose the object while an asynchronous operation is in progress. You can
+ * call {@link #disposeWhenFinished()} to ensure that any in-progress operation
+ * completes before the object is disposed.
+ *
+ * A note about threading: When using this object from a background thread, you may
+ * call the blocking versions of methods; when using from a UI thread, call
+ * only the asynchronous versions and handle the results via callbacks.
+ * Also, notice that you can only call one asynchronous operation at a time;
+ * attempting to start a second asynchronous operation while the first one
+ * has not yet completed will result in an exception being thrown.
+ *
+ */
+public class IabHelper {
+ // Is debug logging enabled?
+ boolean mDebugLog = false;
+ String mDebugTag = "IabHelper";
+
+ // Is setup done?
+ boolean mSetupDone = false;
+
+ // Has this object been disposed of? (If so, we should ignore callbacks, etc)
+ boolean mDisposed = false;
+
+ // Do we need to dispose this object after an in-progress asynchronous operation?
+ boolean mDisposeAfterAsync = false;
+
+ // Are subscriptions supported?
+ boolean mSubscriptionsSupported = false;
+
+ // Is subscription update supported?
+ boolean mSubscriptionUpdateSupported = false;
+
+ // Is an asynchronous operation in progress?
+ // (only one at a time can be in progress)
+ boolean mAsyncInProgress = false;
+
+ // Ensure atomic access to mAsyncInProgress and mDisposeAfterAsync.
+ private final Object mAsyncInProgressLock = new Object();
+
+ // (for logging/debugging)
+ // if mAsyncInProgress == true, what asynchronous operation is in progress?
+ String mAsyncOperation = "";
+
+ // Context we were passed during initialization
+ Context mContext;
+
+ // Connection to the service
+ IInAppBillingService mService;
+ ServiceConnection mServiceConn;
+
+ // The request code used to launch purchase flow
+ int mRequestCode;
+
+ // The item type of the current purchase flow
+ String mPurchasingItemType;
+
+ // Public key for verifying signature, in base64 encoding
+ String mSignatureBase64 = null;
+
+ // Billing response codes
+ public static final int BILLING_RESPONSE_RESULT_OK = 0;
+ public static final int BILLING_RESPONSE_RESULT_USER_CANCELED = 1;
+ public static final int BILLING_RESPONSE_RESULT_SERVICE_UNAVAILABLE = 2;
+ public static final int BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE = 3;
+ public static final int BILLING_RESPONSE_RESULT_ITEM_UNAVAILABLE = 4;
+ public static final int BILLING_RESPONSE_RESULT_DEVELOPER_ERROR = 5;
+ public static final int BILLING_RESPONSE_RESULT_ERROR = 6;
+ public static final int BILLING_RESPONSE_RESULT_ITEM_ALREADY_OWNED = 7;
+ public static final int BILLING_RESPONSE_RESULT_ITEM_NOT_OWNED = 8;
+
+ // IAB Helper error codes
+ public static final int IABHELPER_ERROR_BASE = -1000;
+ public static final int IABHELPER_REMOTE_EXCEPTION = -1001;
+ public static final int IABHELPER_BAD_RESPONSE = -1002;
+ public static final int IABHELPER_VERIFICATION_FAILED = -1003;
+ public static final int IABHELPER_SEND_INTENT_FAILED = -1004;
+ public static final int IABHELPER_USER_CANCELLED = -1005;
+ public static final int IABHELPER_UNKNOWN_PURCHASE_RESPONSE = -1006;
+ public static final int IABHELPER_MISSING_TOKEN = -1007;
+ public static final int IABHELPER_UNKNOWN_ERROR = -1008;
+ public static final int IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE = -1009;
+ public static final int IABHELPER_INVALID_CONSUMPTION = -1010;
+ public static final int IABHELPER_SUBSCRIPTION_UPDATE_NOT_AVAILABLE = -1011;
+
+ // Keys for the responses from InAppBillingService
+ public static final String RESPONSE_CODE = "RESPONSE_CODE";
+ public static final String RESPONSE_GET_SKU_DETAILS_LIST = "DETAILS_LIST";
+ public static final String RESPONSE_BUY_INTENT = "BUY_INTENT";
+ public static final String RESPONSE_INAPP_PURCHASE_DATA = "INAPP_PURCHASE_DATA";
+ public static final String RESPONSE_INAPP_SIGNATURE = "INAPP_DATA_SIGNATURE";
+ public static final String RESPONSE_INAPP_ITEM_LIST = "INAPP_PURCHASE_ITEM_LIST";
+ public static final String RESPONSE_INAPP_PURCHASE_DATA_LIST = "INAPP_PURCHASE_DATA_LIST";
+ public static final String RESPONSE_INAPP_SIGNATURE_LIST = "INAPP_DATA_SIGNATURE_LIST";
+ public static final String INAPP_CONTINUATION_TOKEN = "INAPP_CONTINUATION_TOKEN";
+
+ // Item types
+ public static final String ITEM_TYPE_INAPP = "inapp";
+ public static final String ITEM_TYPE_SUBS = "subs";
+
+ // some fields on the getSkuDetails response bundle
+ public static final String GET_SKU_DETAILS_ITEM_LIST = "ITEM_ID_LIST";
+ public static final String GET_SKU_DETAILS_ITEM_TYPE_LIST = "ITEM_TYPE_LIST";
+
+ /**
+ * Creates an instance. After creation, it will not yet be ready to use. You must perform
+ * setup by calling {@link #startSetup} and wait for setup to complete. This constructor does not
+ * block and is safe to call from a UI thread.
+ *
+ * @param ctx Your application or Activity context. Needed to bind to the in-app billing service.
+ * @param base64PublicKey Your application's public key, encoded in base64.
+ * This is used for verification of purchase signatures. You can find your app's base64-encoded
+ * public key in your application's page on Google Play Developer Console. Note that this
+ * is NOT your "developer public key".
+ */
+ public IabHelper(Context ctx, String base64PublicKey) {
+ mContext = ctx.getApplicationContext();
+ mSignatureBase64 = base64PublicKey;
+ logDebug("IAB helper created.");
+ }
+
+ /**
+ * Enables or disable debug logging through LogCat.
+ */
+ public void enableDebugLogging(boolean enable, String tag) {
+ checkNotDisposed();
+ mDebugLog = enable;
+ mDebugTag = tag;
+ }
+
+ public void enableDebugLogging(boolean enable) {
+ checkNotDisposed();
+ mDebugLog = enable;
+ }
+
+ /**
+ * Callback for setup process. This listener's {@link #onIabSetupFinished} method is called
+ * when the setup process is complete.
+ */
+ public interface OnIabSetupFinishedListener {
+ /**
+ * Called to notify that setup is complete.
+ *
+ * @param result The result of the setup process.
+ */
+ void onIabSetupFinished(IabResult result);
+ }
+
+ /**
+ * Starts the setup process. This will start up the setup process asynchronously.
+ * You will be notified through the listener when the setup process is complete.
+ * This method is safe to call from a UI thread.
+ *
+ * @param listener The listener to notify when the setup process is complete.
+ */
+ public void startSetup(final OnIabSetupFinishedListener listener) {
+ // If already set up, can't do it again.
+ checkNotDisposed();
+ if (mSetupDone) throw new IllegalStateException("IAB helper is already set up.");
+
+ // Connection to IAB service
+ logDebug("Starting in-app billing setup.");
+ mServiceConn = new ServiceConnection() {
+ @Override
+ public void onServiceDisconnected(ComponentName name) {
+ logDebug("Billing service disconnected.");
+ mService = null;
+ }
+
+ @Override
+ public void onServiceConnected(ComponentName name, IBinder service) {
+ if (mDisposed) return;
+ logDebug("Billing service connected.");
+ mService = IInAppBillingService.Stub.asInterface(service);
+ String packageName = mContext.getPackageName();
+ try {
+ logDebug("Checking for in-app billing 3 support.");
+
+ // check for in-app billing v3 support
+ int response = mService.isBillingSupported(3, packageName, ITEM_TYPE_INAPP);
+ if (response != BILLING_RESPONSE_RESULT_OK) {
+ if (listener != null) listener.onIabSetupFinished(new IabResult(response,
+ "Error checking for billing v3 support."));
+
+ // if in-app purchases aren't supported, neither are subscriptions
+ mSubscriptionsSupported = false;
+ mSubscriptionUpdateSupported = false;
+ return;
+ } else {
+ logDebug("In-app billing version 3 supported for " + packageName);
+ }
+
+ // Check for v5 subscriptions support. This is needed for
+ // getBuyIntentToReplaceSku which allows for subscription update
+ response = mService.isBillingSupported(5, packageName, ITEM_TYPE_SUBS);
+ if (response == BILLING_RESPONSE_RESULT_OK) {
+ logDebug("Subscription re-signup AVAILABLE.");
+ mSubscriptionUpdateSupported = true;
+ } else {
+ logDebug("Subscription re-signup not available.");
+ mSubscriptionUpdateSupported = false;
+ }
+
+ if (mSubscriptionUpdateSupported) {
+ mSubscriptionsSupported = true;
+ } else {
+ // check for v3 subscriptions support
+ response = mService.isBillingSupported(3, packageName, ITEM_TYPE_SUBS);
+ if (response == BILLING_RESPONSE_RESULT_OK) {
+ logDebug("Subscriptions AVAILABLE.");
+ mSubscriptionsSupported = true;
+ } else {
+ logDebug("Subscriptions NOT AVAILABLE. Response: " + response);
+ mSubscriptionsSupported = false;
+ mSubscriptionUpdateSupported = false;
+ }
+ }
+
+ mSetupDone = true;
+ }
+ catch (RemoteException e) {
+ if (listener != null) {
+ listener.onIabSetupFinished(new IabResult(IABHELPER_REMOTE_EXCEPTION,
+ "RemoteException while setting up in-app billing."));
+ }
+ e.printStackTrace();
+ return;
+ }
+
+ if (listener != null) {
+ listener.onIabSetupFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Setup successful."));
+ }
+ }
+ };
+
+ Intent serviceIntent = new Intent("com.android.vending.billing.InAppBillingService.BIND");
+ serviceIntent.setPackage("com.android.vending");
+ List intentServices = mContext.getPackageManager().queryIntentServices(serviceIntent, 0);
+ if (intentServices != null && !intentServices.isEmpty()) {
+ // service available to handle that Intent
+ mContext.bindService(serviceIntent, mServiceConn, Context.BIND_AUTO_CREATE);
+ }
+ else {
+ // no service available to handle that Intent
+ if (listener != null) {
+ listener.onIabSetupFinished(
+ new IabResult(BILLING_RESPONSE_RESULT_BILLING_UNAVAILABLE,
+ "Billing service unavailable on device."));
+ }
+ }
+ }
+
+ /**
+ * Dispose of object, releasing resources. It's very important to call this
+ * method when you are done with this object. It will release any resources
+ * used by it such as service connections. Naturally, once the object is
+ * disposed of, it can't be used again.
+ */
+ public void dispose() throws IabAsyncInProgressException {
+ synchronized (mAsyncInProgressLock) {
+ if (mAsyncInProgress) {
+ throw new IabAsyncInProgressException("Can't dispose because an async operation " +
+ "(" + mAsyncOperation + ") is in progress.");
+ }
+ }
+ logDebug("Disposing.");
+ mSetupDone = false;
+ if (mServiceConn != null) {
+ logDebug("Unbinding from service.");
+ if (mContext != null) mContext.unbindService(mServiceConn);
+ }
+ mDisposed = true;
+ mContext = null;
+ mServiceConn = null;
+ mService = null;
+ mPurchaseListener = null;
+ }
+
+ /**
+ * Disposes of object, releasing resources. If there is an in-progress async operation, this
+ * method will queue the dispose to occur after the operation has finished.
+ */
+ public void disposeWhenFinished() {
+ synchronized (mAsyncInProgressLock) {
+ if (mAsyncInProgress) {
+ logDebug("Will dispose after async operation finishes.");
+ mDisposeAfterAsync = true;
+ } else {
+ try {
+ dispose();
+ } catch (IabAsyncInProgressException e) {
+ // Should never be thrown, because we call dispose() only after checking that
+ // there's not already an async operation in progress.
+ }
+ }
+ }
+ }
+
+ private void checkNotDisposed() {
+ if (mDisposed) throw new IllegalStateException("IabHelper was disposed of, so it cannot be used.");
+ }
+
+ /** Returns whether subscriptions are supported. */
+ public boolean subscriptionsSupported() {
+ checkNotDisposed();
+ return mSubscriptionsSupported;
+ }
+
+
+ /**
+ * Callback that notifies when a purchase is finished.
+ */
+ public interface OnIabPurchaseFinishedListener {
+ /**
+ * Called to notify that an in-app purchase finished. If the purchase was successful,
+ * then the sku parameter specifies which item was purchased. If the purchase failed,
+ * the sku and extraData parameters may or may not be null, depending on how far the purchase
+ * process went.
+ *
+ * @param result The result of the purchase.
+ * @param info The purchase information (null if purchase failed)
+ */
+ void onIabPurchaseFinished(IabResult result, Purchase info);
+ }
+
+ // The listener registered on launchPurchaseFlow, which we have to call back when
+ // the purchase finishes
+ OnIabPurchaseFinishedListener mPurchaseListener;
+
+ public void launchPurchaseFlow(Activity act, String sku, int requestCode, OnIabPurchaseFinishedListener listener)
+ throws IabAsyncInProgressException {
+ launchPurchaseFlow(act, sku, requestCode, listener, "");
+ }
+
+ public void launchPurchaseFlow(Activity act, String sku, int requestCode,
+ OnIabPurchaseFinishedListener listener, String extraData)
+ throws IabAsyncInProgressException {
+ launchPurchaseFlow(act, sku, ITEM_TYPE_INAPP, null, requestCode, listener, extraData);
+ }
+
+ public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode,
+ OnIabPurchaseFinishedListener listener) throws IabAsyncInProgressException {
+ launchSubscriptionPurchaseFlow(act, sku, requestCode, listener, "");
+ }
+
+ public void launchSubscriptionPurchaseFlow(Activity act, String sku, int requestCode,
+ OnIabPurchaseFinishedListener listener, String extraData)
+ throws IabAsyncInProgressException {
+ launchPurchaseFlow(act, sku, ITEM_TYPE_SUBS, null, requestCode, listener, extraData);
+ }
+
+ /**
+ * Initiate the UI flow for an in-app purchase. Call this method to initiate an in-app purchase,
+ * which will involve bringing up the Google Play screen. The calling activity will be paused
+ * while the user interacts with Google Play, and the result will be delivered via the
+ * activity's {@link android.app.Activity#onActivityResult} method, at which point you must call
+ * this object's {@link #handleActivityResult} method to continue the purchase flow. This method
+ * MUST be called from the UI thread of the Activity.
+ *
+ * @param act The calling activity.
+ * @param sku The sku of the item to purchase.
+ * @param itemType indicates if it's a product or a subscription (ITEM_TYPE_INAPP or
+ * ITEM_TYPE_SUBS)
+ * @param oldSkus A list of SKUs which the new SKU is replacing or null if there are none
+ * @param requestCode A request code (to differentiate from other responses -- as in
+ * {@link android.app.Activity#startActivityForResult}).
+ * @param listener The listener to notify when the purchase process finishes
+ * @param extraData Extra data (developer payload), which will be returned with the purchase
+ * data when the purchase completes. This extra data will be permanently bound to that
+ * purchase and will always be returned when the purchase is queried.
+ */
+ public void launchPurchaseFlow(Activity act, String sku, String itemType, List oldSkus,
+ int requestCode, OnIabPurchaseFinishedListener listener, String extraData)
+ throws IabAsyncInProgressException {
+ checkNotDisposed();
+ checkSetupDone("launchPurchaseFlow");
+ flagStartAsync("launchPurchaseFlow");
+ IabResult result;
+
+ if (itemType.equals(ITEM_TYPE_SUBS) && !mSubscriptionsSupported) {
+ IabResult r = new IabResult(IABHELPER_SUBSCRIPTIONS_NOT_AVAILABLE,
+ "Subscriptions are not available.");
+ flagEndAsync();
+ if (listener != null) listener.onIabPurchaseFinished(r, null);
+ return;
+ }
+
+ try {
+ logDebug("Constructing buy intent for " + sku + ", item type: " + itemType);
+ Bundle buyIntentBundle;
+ if (oldSkus == null || oldSkus.isEmpty()) {
+ // Purchasing a new item or subscription re-signup
+ buyIntentBundle = mService.getBuyIntent(3, mContext.getPackageName(), sku, itemType,
+ extraData);
+ } else {
+ // Subscription upgrade/downgrade
+ if (!mSubscriptionUpdateSupported) {
+ IabResult r = new IabResult(IABHELPER_SUBSCRIPTION_UPDATE_NOT_AVAILABLE,
+ "Subscription updates are not available.");
+ flagEndAsync();
+ if (listener != null) listener.onIabPurchaseFinished(r, null);
+ return;
+ }
+ buyIntentBundle = mService.getBuyIntentToReplaceSkus(5, mContext.getPackageName(),
+ oldSkus, sku, itemType, extraData);
+ }
+ int response = getResponseCodeFromBundle(buyIntentBundle);
+ if (response != BILLING_RESPONSE_RESULT_OK) {
+ logError("Unable to buy item, Error response: " + getResponseDesc(response));
+ flagEndAsync();
+ result = new IabResult(response, "Unable to buy item");
+ if (listener != null) listener.onIabPurchaseFinished(result, null);
+ return;
+ }
+
+ PendingIntent pendingIntent = buyIntentBundle.getParcelable(RESPONSE_BUY_INTENT);
+ logDebug("Launching buy intent for " + sku + ". Request code: " + requestCode);
+ mRequestCode = requestCode;
+ mPurchaseListener = listener;
+ mPurchasingItemType = itemType;
+ act.startIntentSenderForResult(pendingIntent.getIntentSender(),
+ requestCode, new Intent(),
+ Integer.valueOf(0), Integer.valueOf(0),
+ Integer.valueOf(0));
+ }
+ catch (SendIntentException e) {
+ logError("SendIntentException while launching purchase flow for sku " + sku);
+ e.printStackTrace();
+ flagEndAsync();
+
+ result = new IabResult(IABHELPER_SEND_INTENT_FAILED, "Failed to send intent.");
+ if (listener != null) listener.onIabPurchaseFinished(result, null);
+ }
+ catch (RemoteException e) {
+ logError("RemoteException while launching purchase flow for sku " + sku);
+ e.printStackTrace();
+ flagEndAsync();
+
+ result = new IabResult(IABHELPER_REMOTE_EXCEPTION, "Remote exception while starting purchase flow");
+ if (listener != null) listener.onIabPurchaseFinished(result, null);
+ }
+ }
+
+ /**
+ * Handles an activity result that's part of the purchase flow in in-app billing. If you
+ * are calling {@link #launchPurchaseFlow}, then you must call this method from your
+ * Activity's {@link android.app.Activity@onActivityResult} method. This method
+ * MUST be called from the UI thread of the Activity.
+ *
+ * @param requestCode The requestCode as you received it.
+ * @param resultCode The resultCode as you received it.
+ * @param data The data (Intent) as you received it.
+ * @return Returns true if the result was related to a purchase flow and was handled;
+ * false if the result was not related to a purchase, in which case you should
+ * handle it normally.
+ */
+ public boolean handleActivityResult(int requestCode, int resultCode, Intent data) {
+ IabResult result;
+ if (requestCode != mRequestCode) return false;
+
+ checkNotDisposed();
+ checkSetupDone("handleActivityResult");
+
+ // end of async purchase operation that started on launchPurchaseFlow
+ flagEndAsync();
+
+ if (data == null) {
+ logError("Null data in IAB activity result.");
+ result = new IabResult(IABHELPER_BAD_RESPONSE, "Null data in IAB result");
+ if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
+ return true;
+ }
+
+ int responseCode = getResponseCodeFromIntent(data);
+ String purchaseData = data.getStringExtra(RESPONSE_INAPP_PURCHASE_DATA);
+ String dataSignature = data.getStringExtra(RESPONSE_INAPP_SIGNATURE);
+
+ if (resultCode == Activity.RESULT_OK && responseCode == BILLING_RESPONSE_RESULT_OK) {
+ logDebug("Successful resultcode from purchase activity.");
+ logDebug("Purchase data: " + purchaseData);
+ logDebug("Data signature: " + dataSignature);
+ logDebug("Extras: " + data.getExtras());
+ logDebug("Expected item type: " + mPurchasingItemType);
+
+ if (purchaseData == null || dataSignature == null) {
+ logError("BUG: either purchaseData or dataSignature is null.");
+ logDebug("Extras: " + data.getExtras().toString());
+ result = new IabResult(IABHELPER_UNKNOWN_ERROR, "IAB returned null purchaseData or dataSignature");
+ if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
+ return true;
+ }
+
+ Purchase purchase = null;
+ try {
+ purchase = new Purchase(mPurchasingItemType, purchaseData, dataSignature);
+ String sku = purchase.getSku();
+
+ // Verify signature
+ if (!Security.verifyPurchase(mSignatureBase64, purchaseData, dataSignature)) {
+ logError("Purchase signature verification FAILED for sku " + sku);
+ result = new IabResult(IABHELPER_VERIFICATION_FAILED, "Signature verification failed for sku " + sku);
+ if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, purchase);
+ return true;
+ }
+ logDebug("Purchase signature successfully verified.");
+ }
+ catch (JSONException e) {
+ logError("Failed to parse purchase data.");
+ e.printStackTrace();
+ result = new IabResult(IABHELPER_BAD_RESPONSE, "Failed to parse purchase data.");
+ if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
+ return true;
+ }
+
+ if (mPurchaseListener != null) {
+ mPurchaseListener.onIabPurchaseFinished(new IabResult(BILLING_RESPONSE_RESULT_OK, "Success"), purchase);
+ }
+ }
+ else if (resultCode == Activity.RESULT_OK) {
+ // result code was OK, but in-app billing response was not OK.
+ logDebug("Result code was OK but in-app billing response was not OK: " + getResponseDesc(responseCode));
+ if (mPurchaseListener != null) {
+ result = new IabResult(responseCode, "Problem purchashing item.");
+ mPurchaseListener.onIabPurchaseFinished(result, null);
+ }
+ }
+ else if (resultCode == Activity.RESULT_CANCELED) {
+ logDebug("Purchase canceled - Response: " + getResponseDesc(responseCode));
+ result = new IabResult(IABHELPER_USER_CANCELLED, "User canceled.");
+ if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
+ }
+ else {
+ logError("Purchase failed. Result code: " + Integer.toString(resultCode)
+ + ". Response: " + getResponseDesc(responseCode));
+ result = new IabResult(IABHELPER_UNKNOWN_PURCHASE_RESPONSE, "Unknown purchase response.");
+ if (mPurchaseListener != null) mPurchaseListener.onIabPurchaseFinished(result, null);
+ }
+ return true;
+ }
+
+ public Inventory queryInventory() throws IabException {
+ return queryInventory(false, null, null);
+ }
+
+ /**
+ * Queries the inventory. This will query all owned items from the server, as well as
+ * information on additional skus, if specified. This method may block or take long to execute.
+ * Do not call from a UI thread. For that, use the non-blocking version {@link #queryInventoryAsync}.
+ *
+ * @param querySkuDetails if true, SKU details (price, description, etc) will be queried as well
+ * as purchase information.
+ * @param moreItemSkus additional PRODUCT skus to query information on, regardless of ownership.
+ * Ignored if null or if querySkuDetails is false.
+ * @param moreSubsSkus additional SUBSCRIPTIONS skus to query information on, regardless of ownership.
+ * Ignored if null or if querySkuDetails is false.
+ * @throws IabException if a problem occurs while refreshing the inventory.
+ */
+ public Inventory queryInventory(boolean querySkuDetails, List moreItemSkus,
+ List moreSubsSkus) throws IabException {
+ checkNotDisposed();
+ checkSetupDone("queryInventory");
+ try {
+ Inventory inv = new Inventory();
+ int r = queryPurchases(inv, ITEM_TYPE_INAPP);
+ if (r != BILLING_RESPONSE_RESULT_OK) {
+ throw new IabException(r, "Error refreshing inventory (querying owned items).");
+ }
+
+ if (querySkuDetails) {
+ r = querySkuDetails(ITEM_TYPE_INAPP, inv, moreItemSkus);
+ if (r != BILLING_RESPONSE_RESULT_OK) {
+ throw new IabException(r, "Error refreshing inventory (querying prices of items).");
+ }
+ }
+
+ // if subscriptions are supported, then also query for subscriptions
+ if (mSubscriptionsSupported) {
+ r = queryPurchases(inv, ITEM_TYPE_SUBS);
+ if (r != BILLING_RESPONSE_RESULT_OK) {
+ throw new IabException(r, "Error refreshing inventory (querying owned subscriptions).");
+ }
+
+ if (querySkuDetails) {
+ r = querySkuDetails(ITEM_TYPE_SUBS, inv, moreSubsSkus);
+ if (r != BILLING_RESPONSE_RESULT_OK) {
+ throw new IabException(r, "Error refreshing inventory (querying prices of subscriptions).");
+ }
+ }
+ }
+
+ return inv;
+ }
+ catch (RemoteException e) {
+ throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while refreshing inventory.", e);
+ }
+ catch (JSONException e) {
+ throw new IabException(IABHELPER_BAD_RESPONSE, "Error parsing JSON response while refreshing inventory.", e);
+ }
+ }
+
+ /**
+ * Listener that notifies when an inventory query operation completes.
+ */
+ public interface QueryInventoryFinishedListener {
+ /**
+ * Called to notify that an inventory query operation completed.
+ *
+ * @param result The result of the operation.
+ * @param inv The inventory.
+ */
+ void onQueryInventoryFinished(IabResult result, Inventory inv);
+ }
+
+
+ /**
+ * Asynchronous wrapper for inventory query. This will perform an inventory
+ * query as described in {@link #queryInventory}, but will do so asynchronously
+ * and call back the specified listener upon completion. This method is safe to
+ * call from a UI thread.
+ *
+ * @param querySkuDetails as in {@link #queryInventory}
+ * @param moreItemSkus as in {@link #queryInventory}
+ * @param moreSubsSkus as in {@link #queryInventory}
+ * @param listener The listener to notify when the refresh operation completes.
+ */
+ public void queryInventoryAsync(final boolean querySkuDetails, final List moreItemSkus,
+ final List moreSubsSkus, final QueryInventoryFinishedListener listener)
+ throws IabAsyncInProgressException {
+ final Handler handler = new Handler();
+ checkNotDisposed();
+ checkSetupDone("queryInventory");
+ flagStartAsync("refresh inventory");
+ (new Thread(new Runnable() {
+ public void run() {
+ IabResult result = new IabResult(BILLING_RESPONSE_RESULT_OK, "Inventory refresh successful.");
+ Inventory inv = null;
+ try {
+ inv = queryInventory(querySkuDetails, moreItemSkus, moreSubsSkus);
+ }
+ catch (IabException ex) {
+ result = ex.getResult();
+ }
+
+ flagEndAsync();
+
+ final IabResult result_f = result;
+ final Inventory inv_f = inv;
+ if (!mDisposed && listener != null) {
+ handler.post(new Runnable() {
+ public void run() {
+ listener.onQueryInventoryFinished(result_f, inv_f);
+ }
+ });
+ }
+ }
+ })).start();
+ }
+
+ public void queryInventoryAsync(QueryInventoryFinishedListener listener)
+ throws IabAsyncInProgressException{
+ queryInventoryAsync(false, null, null, listener);
+ }
+
+ /**
+ * Consumes a given in-app product. Consuming can only be done on an item
+ * that's owned, and as a result of consumption, the user will no longer own it.
+ * This method may block or take long to return. Do not call from the UI thread.
+ * For that, see {@link #consumeAsync}.
+ *
+ * @param itemInfo The PurchaseInfo that represents the item to consume.
+ * @throws IabException if there is a problem during consumption.
+ */
+ void consume(Purchase itemInfo) throws IabException {
+ checkNotDisposed();
+ checkSetupDone("consume");
+
+ if (!itemInfo.mItemType.equals(ITEM_TYPE_INAPP)) {
+ throw new IabException(IABHELPER_INVALID_CONSUMPTION,
+ "Items of type '" + itemInfo.mItemType + "' can't be consumed.");
+ }
+
+ try {
+ String token = itemInfo.getToken();
+ String sku = itemInfo.getSku();
+ if (token == null || token.equals("")) {
+ logError("Can't consume "+ sku + ". No token.");
+ throw new IabException(IABHELPER_MISSING_TOKEN, "PurchaseInfo is missing token for sku: "
+ + sku + " " + itemInfo);
+ }
+
+ logDebug("Consuming sku: " + sku + ", token: " + token);
+ int response = mService.consumePurchase(3, mContext.getPackageName(), token);
+ if (response == BILLING_RESPONSE_RESULT_OK) {
+ logDebug("Successfully consumed sku: " + sku);
+ }
+ else {
+ logDebug("Error consuming consuming sku " + sku + ". " + getResponseDesc(response));
+ throw new IabException(response, "Error consuming sku " + sku);
+ }
+ }
+ catch (RemoteException e) {
+ throw new IabException(IABHELPER_REMOTE_EXCEPTION, "Remote exception while consuming. PurchaseInfo: " + itemInfo, e);
+ }
+ }
+
+ /**
+ * Callback that notifies when a consumption operation finishes.
+ */
+ public interface OnConsumeFinishedListener {
+ /**
+ * Called to notify that a consumption has finished.
+ *
+ * @param purchase The purchase that was (or was to be) consumed.
+ * @param result The result of the consumption operation.
+ */
+ void onConsumeFinished(Purchase purchase, IabResult result);
+ }
+
+ /**
+ * Callback that notifies when a multi-item consumption operation finishes.
+ */
+ public interface OnConsumeMultiFinishedListener {
+ /**
+ * Called to notify that a consumption of multiple items has finished.
+ *
+ * @param purchases The purchases that were (or were to be) consumed.
+ * @param results The results of each consumption operation, corresponding to each
+ * sku.
+ */
+ void onConsumeMultiFinished(List purchases, List results);
+ }
+
+ /**
+ * Asynchronous wrapper to item consumption. Works like {@link #consume}, but
+ * performs the consumption in the background and notifies completion through
+ * the provided listener. This method is safe to call from a UI thread.
+ *
+ * @param purchase The purchase to be consumed.
+ * @param listener The listener to notify when the consumption operation finishes.
+ */
+ public void consumeAsync(Purchase purchase, OnConsumeFinishedListener listener)
+ throws IabAsyncInProgressException {
+ checkNotDisposed();
+ checkSetupDone("consume");
+ List purchases = new ArrayList();
+ purchases.add(purchase);
+ consumeAsyncInternal(purchases, listener, null);
+ }
+
+ /**
+ * Same as {@link #consumeAsync}, but for multiple items at once.
+ * @param purchases The list of PurchaseInfo objects representing the purchases to consume.
+ * @param listener The listener to notify when the consumption operation finishes.
+ */
+ public void consumeAsync(List purchases, OnConsumeMultiFinishedListener listener)
+ throws IabAsyncInProgressException {
+ checkNotDisposed();
+ checkSetupDone("consume");
+ consumeAsyncInternal(purchases, null, listener);
+ }
+
+ /**
+ * Returns a human-readable description for the given response code.
+ *
+ * @param code The response code
+ * @return A human-readable string explaining the result code.
+ * It also includes the result code numerically.
+ */
+ public static String getResponseDesc(int code) {
+ String[] iab_msgs = ("0:OK/1:User Canceled/2:Unknown/" +
+ "3:Billing Unavailable/4:Item unavailable/" +
+ "5:Developer Error/6:Error/7:Item Already Owned/" +
+ "8:Item not owned").split("/");
+ String[] iabhelper_msgs = ("0:OK/-1001:Remote exception during initialization/" +
+ "-1002:Bad response received/" +
+ "-1003:Purchase signature verification failed/" +
+ "-1004:Send intent failed/" +
+ "-1005:User cancelled/" +
+ "-1006:Unknown purchase response/" +
+ "-1007:Missing token/" +
+ "-1008:Unknown error/" +
+ "-1009:Subscriptions not available/" +
+ "-1010:Invalid consumption attempt").split("/");
+
+ if (code <= IABHELPER_ERROR_BASE) {
+ int index = IABHELPER_ERROR_BASE - code;
+ if (index >= 0 && index < iabhelper_msgs.length) return iabhelper_msgs[index];
+ else return String.valueOf(code) + ":Unknown IAB Helper Error";
+ }
+ else if (code < 0 || code >= iab_msgs.length)
+ return String.valueOf(code) + ":Unknown";
+ else
+ return iab_msgs[code];
+ }
+
+
+ // Checks that setup was done; if not, throws an exception.
+ void checkSetupDone(String operation) {
+ if (!mSetupDone) {
+ logError("Illegal state for operation (" + operation + "): IAB helper is not set up.");
+ throw new IllegalStateException("IAB helper is not set up. Can't perform operation: " + operation);
+ }
+ }
+
+ // Workaround to bug where sometimes response codes come as Long instead of Integer
+ int getResponseCodeFromBundle(Bundle b) {
+ Object o = b.get(RESPONSE_CODE);
+ if (o == null) {
+ logDebug("Bundle with null response code, assuming OK (known issue)");
+ return BILLING_RESPONSE_RESULT_OK;
+ }
+ else if (o instanceof Integer) return ((Integer)o).intValue();
+ else if (o instanceof Long) return (int)((Long)o).longValue();
+ else {
+ logError("Unexpected type for bundle response code.");
+ logError(o.getClass().getName());
+ throw new RuntimeException("Unexpected type for bundle response code: " + o.getClass().getName());
+ }
+ }
+
+ // Workaround to bug where sometimes response codes come as Long instead of Integer
+ int getResponseCodeFromIntent(Intent i) {
+ Object o = i.getExtras().get(RESPONSE_CODE);
+ if (o == null) {
+ logError("Intent with no response code, assuming OK (known issue)");
+ return BILLING_RESPONSE_RESULT_OK;
+ }
+ else if (o instanceof Integer) return ((Integer)o).intValue();
+ else if (o instanceof Long) return (int)((Long)o).longValue();
+ else {
+ logError("Unexpected type for intent response code.");
+ logError(o.getClass().getName());
+ throw new RuntimeException("Unexpected type for intent response code: " + o.getClass().getName());
+ }
+ }
+
+ void flagStartAsync(String operation) throws IabAsyncInProgressException {
+ synchronized (mAsyncInProgressLock) {
+ if (mAsyncInProgress) {
+ throw new IabAsyncInProgressException("Can't start async operation (" +
+ operation + ") because another async operation (" + mAsyncOperation +
+ ") is in progress.");
+ }
+ mAsyncOperation = operation;
+ mAsyncInProgress = true;
+ logDebug("Starting async operation: " + operation);
+ }
+ }
+
+ void flagEndAsync() {
+ synchronized (mAsyncInProgressLock) {
+ logDebug("Ending async operation: " + mAsyncOperation);
+ mAsyncOperation = "";
+ mAsyncInProgress = false;
+ if (mDisposeAfterAsync) {
+ try {
+ dispose();
+ } catch (IabAsyncInProgressException e) {
+ // Should not be thrown, because we reset mAsyncInProgress immediately before
+ // calling dispose().
+ }
+ }
+ }
+ }
+
+ /**
+ * Exception thrown when the requested operation cannot be started because an async operation
+ * is still in progress.
+ */
+ public static class IabAsyncInProgressException extends Exception {
+ public IabAsyncInProgressException(String message) {
+ super(message);
+ }
+ }
+
+ int queryPurchases(Inventory inv, String itemType) throws JSONException, RemoteException {
+ // Query purchases
+ logDebug("Querying owned items, item type: " + itemType);
+ logDebug("Package name: " + mContext.getPackageName());
+ boolean verificationFailed = false;
+ String continueToken = null;
+
+ do {
+ logDebug("Calling getPurchases with continuation token: " + continueToken);
+ Bundle ownedItems = mService.getPurchases(3, mContext.getPackageName(),
+ itemType, continueToken);
+
+ int response = getResponseCodeFromBundle(ownedItems);
+ logDebug("Owned items response: " + String.valueOf(response));
+ if (response != BILLING_RESPONSE_RESULT_OK) {
+ logDebug("getPurchases() failed: " + getResponseDesc(response));
+ return response;
+ }
+ if (!ownedItems.containsKey(RESPONSE_INAPP_ITEM_LIST)
+ || !ownedItems.containsKey(RESPONSE_INAPP_PURCHASE_DATA_LIST)
+ || !ownedItems.containsKey(RESPONSE_INAPP_SIGNATURE_LIST)) {
+ logError("Bundle returned from getPurchases() doesn't contain required fields.");
+ return IABHELPER_BAD_RESPONSE;
+ }
+
+ ArrayList ownedSkus = ownedItems.getStringArrayList(
+ RESPONSE_INAPP_ITEM_LIST);
+ ArrayList purchaseDataList = ownedItems.getStringArrayList(
+ RESPONSE_INAPP_PURCHASE_DATA_LIST);
+ ArrayList signatureList = ownedItems.getStringArrayList(
+ RESPONSE_INAPP_SIGNATURE_LIST);
+
+ for (int i = 0; i < purchaseDataList.size(); ++i) {
+ String purchaseData = purchaseDataList.get(i);
+ String signature = signatureList.get(i);
+ String sku = ownedSkus.get(i);
+ if (Security.verifyPurchase(mSignatureBase64, purchaseData, signature)) {
+ logDebug("Sku is owned: " + sku);
+ Purchase purchase = new Purchase(itemType, purchaseData, signature);
+
+ if (TextUtils.isEmpty(purchase.getToken())) {
+ logWarn("BUG: empty/null token!");
+ logDebug("Purchase data: " + purchaseData);
+ }
+
+ // Record ownership and token
+ inv.addPurchase(purchase);
+ }
+ else {
+ logWarn("Purchase signature verification **FAILED**. Not adding item.");
+ logDebug(" Purchase data: " + purchaseData);
+ logDebug(" Signature: " + signature);
+ verificationFailed = true;
+ }
+ }
+
+ continueToken = ownedItems.getString(INAPP_CONTINUATION_TOKEN);
+ logDebug("Continuation token: " + continueToken);
+ } while (!TextUtils.isEmpty(continueToken));
+
+ return verificationFailed ? IABHELPER_VERIFICATION_FAILED : BILLING_RESPONSE_RESULT_OK;
+ }
+
+ int querySkuDetails(String itemType, Inventory inv, List moreSkus)
+ throws RemoteException, JSONException {
+ logDebug("Querying SKU details.");
+ ArrayList skuList = new ArrayList();
+ skuList.addAll(inv.getAllOwnedSkus(itemType));
+ if (moreSkus != null) {
+ for (String sku : moreSkus) {
+ if (!skuList.contains(sku)) {
+ skuList.add(sku);
+ }
+ }
+ }
+
+ if (skuList.size() == 0) {
+ logDebug("queryPrices: nothing to do because there are no SKUs.");
+ return BILLING_RESPONSE_RESULT_OK;
+ }
+
+ // Split the sku list in blocks of no more than 20 elements.
+ ArrayList> packs = new ArrayList>();
+ ArrayList tempList;
+ int n = skuList.size() / 20;
+ int mod = skuList.size() % 20;
+ for (int i = 0; i < n; i++) {
+ tempList = new ArrayList();
+ for (String s : skuList.subList(i * 20, i * 20 + 20)) {
+ tempList.add(s);
+ }
+ packs.add(tempList);
+ }
+ if (mod != 0) {
+ tempList = new ArrayList();
+ for (String s : skuList.subList(n * 20, n * 20 + mod)) {
+ tempList.add(s);
+ }
+ packs.add(tempList);
+ }
+
+ for (ArrayList skuPartList : packs) {
+ Bundle querySkus = new Bundle();
+ querySkus.putStringArrayList(GET_SKU_DETAILS_ITEM_LIST, skuPartList);
+ Bundle skuDetails = mService.getSkuDetails(3, mContext.getPackageName(),
+ itemType, querySkus);
+
+ if (!skuDetails.containsKey(RESPONSE_GET_SKU_DETAILS_LIST)) {
+ int response = getResponseCodeFromBundle(skuDetails);
+ if (response != BILLING_RESPONSE_RESULT_OK) {
+ logDebug("getSkuDetails() failed: " + getResponseDesc(response));
+ return response;
+ } else {
+ logError("getSkuDetails() returned a bundle with neither an error nor a detail list.");
+ return IABHELPER_BAD_RESPONSE;
+ }
+ }
+
+ ArrayList responseList = skuDetails.getStringArrayList(
+ RESPONSE_GET_SKU_DETAILS_LIST);
+
+ for (String thisResponse : responseList) {
+ SkuDetails d = new SkuDetails(itemType, thisResponse);
+ logDebug("Got sku details: " + d);
+ inv.addSkuDetails(d);
+ }
+ }
+
+ return BILLING_RESPONSE_RESULT_OK;
+ }
+
+ void consumeAsyncInternal(final List purchases,
+ final OnConsumeFinishedListener singleListener,
+ final OnConsumeMultiFinishedListener multiListener)
+ throws IabAsyncInProgressException {
+ final Handler handler = new Handler();
+ flagStartAsync("consume");
+ (new Thread(new Runnable() {
+ public void run() {
+ final List results = new ArrayList();
+ for (Purchase purchase : purchases) {
+ try {
+ consume(purchase);
+ results.add(new IabResult(BILLING_RESPONSE_RESULT_OK, "Successful consume of sku " + purchase.getSku()));
+ }
+ catch (IabException ex) {
+ results.add(ex.getResult());
+ }
+ }
+
+ flagEndAsync();
+ if (!mDisposed && singleListener != null) {
+ handler.post(new Runnable() {
+ public void run() {
+ singleListener.onConsumeFinished(purchases.get(0), results.get(0));
+ }
+ });
+ }
+ if (!mDisposed && multiListener != null) {
+ handler.post(new Runnable() {
+ public void run() {
+ multiListener.onConsumeMultiFinished(purchases, results);
+ }
+ });
+ }
+ }
+ })).start();
+ }
+
+ void logDebug(String msg) {
+ if (mDebugLog) Log.d(mDebugTag, msg);
+ }
+
+ void logError(String msg) {
+ Log.e(mDebugTag, "In-app billing error: " + msg);
+ }
+
+ void logWarn(String msg) {
+ Log.w(mDebugTag, "In-app billing warning: " + msg);
+ }
+}
diff --git a/Android/src/emu/project64/inAppPurchase/IabResult.java b/Android/src/emu/project64/inAppPurchase/IabResult.java
new file mode 100644
index 000000000..c59df03f9
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/IabResult.java
@@ -0,0 +1,45 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+/**
+ * Represents the result of an in-app billing operation.
+ * A result is composed of a response code (an integer) and possibly a
+ * message (String). You can get those by calling
+ * {@link #getResponse} and {@link #getMessage()}, respectively. You
+ * can also inquire whether a result is a success or a failure by
+ * calling {@link #isSuccess()} and {@link #isFailure()}.
+ */
+public class IabResult {
+ int mResponse;
+ String mMessage;
+
+ public IabResult(int response, String message) {
+ mResponse = response;
+ if (message == null || message.trim().length() == 0) {
+ mMessage = IabHelper.getResponseDesc(response);
+ }
+ else {
+ mMessage = message + " (response: " + IabHelper.getResponseDesc(response) + ")";
+ }
+ }
+ public int getResponse() { return mResponse; }
+ public String getMessage() { return mMessage; }
+ public boolean isSuccess() { return mResponse == IabHelper.BILLING_RESPONSE_RESULT_OK; }
+ public boolean isFailure() { return !isSuccess(); }
+ public String toString() { return "IabResult: " + getMessage(); }
+}
+
diff --git a/Android/src/emu/project64/inAppPurchase/Inventory.java b/Android/src/emu/project64/inAppPurchase/Inventory.java
new file mode 100644
index 000000000..ccd1c5d8e
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/Inventory.java
@@ -0,0 +1,91 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Represents a block of information about in-app items.
+ * An Inventory is returned by such methods as {@link IabHelper#queryInventory}.
+ */
+public class Inventory {
+ Map mSkuMap = new HashMap();
+ Map mPurchaseMap = new HashMap();
+
+ Inventory() { }
+
+ /** Returns the listing details for an in-app product. */
+ public SkuDetails getSkuDetails(String sku) {
+ return mSkuMap.get(sku);
+ }
+
+ /** Returns purchase information for a given product, or null if there is no purchase. */
+ public Purchase getPurchase(String sku) {
+ return mPurchaseMap.get(sku);
+ }
+
+ /** Returns whether or not there exists a purchase of the given product. */
+ public boolean hasPurchase(String sku) {
+ return mPurchaseMap.containsKey(sku);
+ }
+
+ /** Return whether or not details about the given product are available. */
+ public boolean hasDetails(String sku) {
+ return mSkuMap.containsKey(sku);
+ }
+
+ /**
+ * Erase a purchase (locally) from the inventory, given its product ID. This just
+ * modifies the Inventory object locally and has no effect on the server! This is
+ * useful when you have an existing Inventory object which you know to be up to date,
+ * and you have just consumed an item successfully, which means that erasing its
+ * purchase data from the Inventory you already have is quicker than querying for
+ * a new Inventory.
+ */
+ public void erasePurchase(String sku) {
+ if (mPurchaseMap.containsKey(sku)) mPurchaseMap.remove(sku);
+ }
+
+ /** Returns a list of all owned product IDs. */
+ List getAllOwnedSkus() {
+ return new ArrayList(mPurchaseMap.keySet());
+ }
+
+ /** Returns a list of all owned product IDs of a given type */
+ List getAllOwnedSkus(String itemType) {
+ List result = new ArrayList();
+ for (Purchase p : mPurchaseMap.values()) {
+ if (p.getItemType().equals(itemType)) result.add(p.getSku());
+ }
+ return result;
+ }
+
+ /** Returns a list of all purchases. */
+ List getAllPurchases() {
+ return new ArrayList(mPurchaseMap.values());
+ }
+
+ void addSkuDetails(SkuDetails d) {
+ mSkuMap.put(d.getSku(), d);
+ }
+
+ void addPurchase(Purchase p) {
+ mPurchaseMap.put(p.getSku(), p);
+ }
+}
diff --git a/Android/src/emu/project64/inAppPurchase/Purchase.java b/Android/src/emu/project64/inAppPurchase/Purchase.java
new file mode 100644
index 000000000..62a087779
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/Purchase.java
@@ -0,0 +1,66 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Represents an in-app billing purchase.
+ */
+public class Purchase {
+ String mItemType; // ITEM_TYPE_INAPP or ITEM_TYPE_SUBS
+ String mOrderId;
+ String mPackageName;
+ String mSku;
+ long mPurchaseTime;
+ int mPurchaseState;
+ String mDeveloperPayload;
+ String mToken;
+ String mOriginalJson;
+ String mSignature;
+ boolean mIsAutoRenewing;
+
+ public Purchase(String itemType, String jsonPurchaseInfo, String signature) throws JSONException {
+ mItemType = itemType;
+ mOriginalJson = jsonPurchaseInfo;
+ JSONObject o = new JSONObject(mOriginalJson);
+ mOrderId = o.optString("orderId");
+ mPackageName = o.optString("packageName");
+ mSku = o.optString("productId");
+ mPurchaseTime = o.optLong("purchaseTime");
+ mPurchaseState = o.optInt("purchaseState");
+ mDeveloperPayload = o.optString("developerPayload");
+ mToken = o.optString("token", o.optString("purchaseToken"));
+ mIsAutoRenewing = o.optBoolean("autoRenewing");
+ mSignature = signature;
+ }
+
+ public String getItemType() { return mItemType; }
+ public String getOrderId() { return mOrderId; }
+ public String getPackageName() { return mPackageName; }
+ public String getSku() { return mSku; }
+ public long getPurchaseTime() { return mPurchaseTime; }
+ public int getPurchaseState() { return mPurchaseState; }
+ public String getDeveloperPayload() { return mDeveloperPayload; }
+ public String getToken() { return mToken; }
+ public String getOriginalJson() { return mOriginalJson; }
+ public String getSignature() { return mSignature; }
+ public boolean isAutoRenewing() { return mIsAutoRenewing; }
+
+ @Override
+ public String toString() { return "PurchaseInfo(type:" + mItemType + "):" + mOriginalJson; }
+}
diff --git a/Android/src/emu/project64/inAppPurchase/Security.java b/Android/src/emu/project64/inAppPurchase/Security.java
new file mode 100644
index 000000000..5e7c4b476
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/Security.java
@@ -0,0 +1,121 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+import android.text.TextUtils;
+import android.util.Base64;
+import android.util.Log;
+
+import java.security.InvalidKeyException;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.PublicKey;
+import java.security.Signature;
+import java.security.SignatureException;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+
+/**
+ * Security-related methods. For a secure implementation, all of this code
+ * should be implemented on a server that communicates with the
+ * application on the device. For the sake of simplicity and clarity of this
+ * example, this code is included here and is executed on the device. If you
+ * must verify the purchases on the phone, you should obfuscate this code to
+ * make it harder for an attacker to replace the code with stubs that treat all
+ * purchases as verified.
+ */
+public class Security {
+ private static final String TAG = "IABUtil/Security";
+
+ private static final String KEY_FACTORY_ALGORITHM = "RSA";
+ private static final String SIGNATURE_ALGORITHM = "SHA1withRSA";
+
+ /**
+ * Verifies that the data was signed with the given signature, and returns
+ * the verified purchase. The data is in JSON format and signed
+ * with a private key. The data also contains the {@link PurchaseState}
+ * and product ID of the purchase.
+ * @param base64PublicKey the base64-encoded public key to use for verifying.
+ * @param signedData the signed JSON string (signed, not encrypted)
+ * @param signature the signature for the data, signed with the private key
+ */
+ public static boolean verifyPurchase(String base64PublicKey, String signedData, String signature) {
+ if (TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) ||
+ TextUtils.isEmpty(signature)) {
+ Log.e(TAG, "Purchase verification failed: missing data.");
+ return false;
+ }
+
+ PublicKey key = Security.generatePublicKey(base64PublicKey);
+ return Security.verify(key, signedData, signature);
+ }
+
+ /**
+ * Generates a PublicKey instance from a string containing the
+ * Base64-encoded public key.
+ *
+ * @param encodedPublicKey Base64-encoded public key
+ * @throws IllegalArgumentException if encodedPublicKey is invalid
+ */
+ public static PublicKey generatePublicKey(String encodedPublicKey) {
+ try {
+ byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT);
+ KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM);
+ return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey));
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException(e);
+ } catch (InvalidKeySpecException e) {
+ Log.e(TAG, "Invalid key specification.");
+ throw new IllegalArgumentException(e);
+ }
+ }
+
+ /**
+ * Verifies that the signature from the server matches the computed
+ * signature on the data. Returns true if the data is correctly signed.
+ *
+ * @param publicKey public key associated with the developer account
+ * @param signedData signed data from server
+ * @param signature server signature
+ * @return true if the data and signature match
+ */
+ public static boolean verify(PublicKey publicKey, String signedData, String signature) {
+ byte[] signatureBytes;
+ try {
+ signatureBytes = Base64.decode(signature, Base64.DEFAULT);
+ } catch (IllegalArgumentException e) {
+ Log.e(TAG, "Base64 decoding failed.");
+ return false;
+ }
+ try {
+ Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
+ sig.initVerify(publicKey);
+ sig.update(signedData.getBytes());
+ if (!sig.verify(signatureBytes)) {
+ Log.e(TAG, "Signature verification failed.");
+ return false;
+ }
+ return true;
+ } catch (NoSuchAlgorithmException e) {
+ Log.e(TAG, "NoSuchAlgorithmException.");
+ } catch (InvalidKeyException e) {
+ Log.e(TAG, "Invalid key specification.");
+ } catch (SignatureException e) {
+ Log.e(TAG, "Signature exception.");
+ }
+ return false;
+ }
+}
diff --git a/Android/src/emu/project64/inAppPurchase/SkuDetails.java b/Android/src/emu/project64/inAppPurchase/SkuDetails.java
new file mode 100644
index 000000000..f9da64201
--- /dev/null
+++ b/Android/src/emu/project64/inAppPurchase/SkuDetails.java
@@ -0,0 +1,64 @@
+/* Copyright (c) 2012 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package emu.project64.inAppPurchase;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Represents an in-app product's listing details.
+ */
+public class SkuDetails {
+ private final String mItemType;
+ private final String mSku;
+ private final String mType;
+ private final String mPrice;
+ private final long mPriceAmountMicros;
+ private final String mPriceCurrencyCode;
+ private final String mTitle;
+ private final String mDescription;
+ private final String mJson;
+
+ public SkuDetails(String jsonSkuDetails) throws JSONException {
+ this(IabHelper.ITEM_TYPE_INAPP, jsonSkuDetails);
+ }
+
+ public SkuDetails(String itemType, String jsonSkuDetails) throws JSONException {
+ mItemType = itemType;
+ mJson = jsonSkuDetails;
+ JSONObject o = new JSONObject(mJson);
+ mSku = o.optString("productId");
+ mType = o.optString("type");
+ mPrice = o.optString("price");
+ mPriceAmountMicros = o.optLong("price_amount_micros");
+ mPriceCurrencyCode = o.optString("price_currency_code");
+ mTitle = o.optString("title");
+ mDescription = o.optString("description");
+ }
+
+ public String getSku() { return mSku; }
+ public String getType() { return mType; }
+ public String getPrice() { return mPrice; }
+ public long getPriceAmountMicros() { return mPriceAmountMicros; }
+ public String getPriceCurrencyCode() { return mPriceCurrencyCode; }
+ public String getTitle() { return mTitle; }
+ public String getDescription() { return mDescription; }
+
+ @Override
+ public String toString() {
+ return "SkuDetails:" + mJson;
+ }
+}
diff --git a/Android/src/emu/project64/input/AbstractController.java b/Android/src/emu/project64/input/AbstractController.java
new file mode 100644
index 000000000..988762c42
--- /dev/null
+++ b/Android/src/emu/project64/input/AbstractController.java
@@ -0,0 +1,182 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input;
+
+import java.util.ArrayList;
+
+import android.util.Log;
+import emu.project64.jni.NativeInput;
+
+/**
+ * The abstract base class for implementing all N64 controllers.
+ *
+ * Subclasses should implement the following pattern:
+ *
+ * - Register a listener to the upstream input (e.g. touch, keyboard, mouse, joystick, etc.).
+ * - Translate the input data into N64 controller button/axis states, and set the values of the
+ * protected fields mState.buttons and mState.axisFraction* accordingly.
+ * - Call the protected method notifyChanged().
+ *
+ * This abstract class will call the emulator's native libraries to update game state whenever
+ * notifyChanged() is called. Subclasses should not call any native methods themselves. (If they do,
+ * then this abstract class should be expanded to cover those needs.)
+ *
+ * Note that this class is stateful, in that it remembers controller button/axis state between calls
+ * from the subclass. For best performance, subclasses should only call notifyChanged() when the
+ * input state has actually changed, and should bundle the protected field modifications before
+ * calling notifyChanged(). For example,
+ *
+ *
+ * {@code
+ * buttons[0] = true; notifyChanged(); buttons[1] = false; notifyChanged(); // Inefficient
+ * buttons[0] = true; buttons[1] = false; notifyChanged(); // Better
+ * }
+ *
+ *
+ * @see PeripheralController
+ * @see TouchController
+ */
+public abstract class AbstractController
+{
+ protected final static boolean LOG_CONTROLLER = false;
+
+ /**
+ * A small class that encapsulates controller state.
+ */
+ protected static class State
+ {
+ /** The pressed state of each controller button. */
+ public boolean[] buttons = new boolean[NUM_N64_BUTTONS];
+
+ /** The fractional value of the analog-x axis, between -1 and 1, inclusive. */
+ public float axisFractionX = 0;
+
+ /** The fractional value of the analog-y axis, between -1 and 1, inclusive. */
+ public float axisFractionY = 0;
+ }
+
+ // Constants must match EButton listing in plugin.h! (input-sdl plug-in)
+
+ /** N64 button: dpad-right. */
+ public static final int DPD_R = 0;
+
+ /** N64 button: dpad-left. */
+ public static final int DPD_L = 1;
+
+ /** N64 button: dpad-down. */
+ public static final int DPD_D = 2;
+
+ /** N64 button: dpad-up. */
+ public static final int DPD_U = 3;
+
+ /** N64 button: start. */
+ public static final int START = 4;
+
+ /** N64 button: trigger-z. */
+ public static final int BTN_Z = 5;
+
+ /** N64 button: b. */
+ public static final int BTN_B = 6;
+
+ /** N64 button: a. */
+ public static final int BTN_A = 7;
+
+ /** N64 button: cpad-right. */
+ public static final int CPD_R = 8;
+
+ /** N64 button: cpad-left. */
+ public static final int CPD_L = 9;
+
+ /** N64 button: cpad-down. */
+ public static final int CPD_D = 10;
+
+ /** N64 button: cpad-up. */
+ public static final int CPD_U = 11;
+
+ /** N64 button: shoulder-r. */
+ public static final int BTN_R = 12;
+
+ /** N64 button: shoulder-l. */
+ public static final int BTN_L = 13;
+
+ /** N64 button: reserved-1. */
+ public static final int BTN_RESERVED1 = 14;
+
+ /** N64 button: reserved-2. */
+ public static final int BTN_RESERVED2 = 15;
+
+ /** Total number of N64 buttons. */
+ public static final int NUM_N64_BUTTONS = 16;
+
+ /** The state of all four player controllers. */
+ private static final ArrayList sStates = new ArrayList();
+
+ /** The state of this controller. */
+ protected State mState;
+
+ /** The player number, between 1 and 4, inclusive. */
+ protected int mPlayerNumber = 1;
+
+ /** The factor by which the axis fractions are scaled before going to the core. */
+ private static final float AXIS_SCALE = 80;
+
+ static
+ {
+ sStates.add( new State() );
+ sStates.add( new State() );
+ sStates.add( new State() );
+ sStates.add( new State() );
+ }
+
+ /**
+ * Instantiates a new abstract controller.
+ */
+ protected AbstractController()
+ {
+ mState = sStates.get( 0 );
+ }
+
+ /**
+ * Notifies the core that the N64 controller state has changed.
+ */
+ protected void notifyChanged()
+ {
+
+ int axisX = Math.round( AXIS_SCALE * mState.axisFractionX );
+ int axisY = Math.round( AXIS_SCALE * mState.axisFractionY );
+ if (LOG_CONTROLLER)
+ {
+ Log.i("Controller", "notifyChanged: axisX=" + axisX + " axisY=" + axisY);
+ }
+ NativeInput.setState( mPlayerNumber - 1, mState.buttons, axisX, axisY );
+ }
+
+ /**
+ * Gets the player number.
+ *
+ * @return The player number, between 1 and 4, inclusive.
+ */
+ public int getPlayerNumber()
+ {
+ return mPlayerNumber;
+ }
+
+ /**
+ * Sets the player number.
+ *
+ * @param player The new player number, between 1 and 4, inclusive.
+ */
+ public void setPlayerNumber( int player )
+ {
+ mPlayerNumber = player;
+ mState = sStates.get( mPlayerNumber - 1 );
+ }
+}
diff --git a/Android/src/emu/project64/input/PeripheralController.java b/Android/src/emu/project64/input/PeripheralController.java
new file mode 100644
index 000000000..558ea1e5e
--- /dev/null
+++ b/Android/src/emu/project64/input/PeripheralController.java
@@ -0,0 +1,173 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2016 Project64. All rights reserved. *
+* Copyright (C) 2013 Paul Lamb, littleguy77 *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input;
+
+import java.util.ArrayList;
+
+import emu.project64.input.map.InputMap;
+import emu.project64.input.provider.AbstractProvider;
+import emu.project64.util.Utility;
+import android.annotation.TargetApi;
+import android.util.FloatMath;
+import android.util.Log;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+
+/**
+ * A class for generating N64 controller commands from peripheral hardware (gamepads, joysticks,
+ * keyboards, mice, etc.).
+ */
+public class PeripheralController extends AbstractController implements
+ AbstractProvider.OnInputListener
+{
+ /** The map from input codes to commands. */
+ private final InputMap mInputMap;
+
+ /** The analog deadzone, between 0 and 1, inclusive. */
+ private final float mDeadzoneFraction;
+
+ /** The analog sensitivity, the amount by which to scale stick values, nominally 1. */
+ private final float mSensitivityFraction;
+
+ /** The user input providers. */
+ private final ArrayList mProviders;
+
+ /** The positive analog-x strength, between 0 and 1, inclusive. */
+ private float mStrengthXpos;
+
+ /** The negative analog-x strength, between 0 and 1, inclusive. */
+ private float mStrengthXneg;
+
+ /** The positive analog-y strength, between 0 and 1, inclusive. */
+ private float mStrengthYpos;
+
+ /** The negative analogy-y strength, between 0 and 1, inclusive. */
+ private float mStrengthYneg;
+
+ /**
+ * Instantiates a new peripheral controller.
+ *
+ * @param player The player number, between 1 and 4, inclusive.
+ * @param inputMap The map from input codes to commands.
+ * @param inputDeadzone The analog deadzone in percent.
+ * @param inputSensitivity The analog sensitivity in percent.
+ * @param providers The user input providers. Null elements are safe.
+ */
+ public PeripheralController( int player, InputMap inputMap, int inputDeadzone, int inputSensitivity, AbstractProvider... providers )
+ {
+ setPlayerNumber( player );
+
+ // Assign the maps
+ mInputMap = inputMap;
+ mDeadzoneFraction = ( (float) inputDeadzone ) / 100f;
+ mSensitivityFraction = ( (float) inputSensitivity ) / 100f;
+
+ // Assign the non-null input providers
+ mProviders = new ArrayList();
+ for( AbstractProvider provider : providers )
+ {
+ if( provider != null )
+ {
+ mProviders.add( provider );
+ provider.registerListener( this );
+ }
+ }
+ }
+
+ @TargetApi( 16 )
+ @Override
+ public void onInput( int inputCode, float strength, int hardwareId )
+ {
+ // Apply user changes to the controller state
+ apply( inputCode, strength );
+
+ // Notify the core that controller state has changed
+ notifyChanged();
+ }
+
+ @Override
+ public void onInput( int[] inputCodes, float[] strengths, int hardwareId )
+ {
+ // Apply user changes to the controller state
+ for( int i = 0; i < inputCodes.length; i++ )
+ apply( inputCodes[i], strengths[i] );
+
+ // Notify the core that controller state has changed
+ notifyChanged();
+ }
+
+ /**
+ * Apply user input to the N64 controller state.
+ *
+ * @param inputCode The universal input code that was dispatched.
+ * @param strength The input strength, between 0 and 1, inclusive.
+ *
+ * @return True, if controller state changed.
+ */
+ private boolean apply( int inputCode, float strength )
+ {
+ boolean keyDown = strength > AbstractProvider.STRENGTH_THRESHOLD;
+ int n64Index = mInputMap.get( inputCode );
+
+ if( n64Index >= 0 && n64Index < NUM_N64_BUTTONS )
+ {
+ mState.buttons[n64Index] = keyDown;
+ return true;
+ }
+ else if( n64Index < InputMap.NUM_N64_CONTROLS )
+ {
+ switch( n64Index )
+ {
+ case InputMap.AXIS_R:
+ mStrengthXpos = strength;
+ break;
+ case InputMap.AXIS_L:
+ mStrengthXneg = strength;
+ break;
+ case InputMap.AXIS_D:
+ mStrengthYneg = strength;
+ break;
+ case InputMap.AXIS_U:
+ mStrengthYpos = strength;
+ break;
+ default:
+ return false;
+ }
+
+ // Calculate the net position of the analog stick
+ float rawX = mSensitivityFraction * ( mStrengthXpos - mStrengthXneg );
+ float rawY = mSensitivityFraction * ( mStrengthYpos - mStrengthYneg );
+ float magnitude = (float) Math.sqrt( ( rawX * rawX ) + ( rawY * rawY ) );
+
+ // Update controller state
+ if( magnitude > mDeadzoneFraction )
+ {
+ // Normalize the vector
+ float normalizedX = rawX / magnitude;
+ float normalizedY = rawY / magnitude;
+
+ // Rescale strength to account for deadzone
+ magnitude = ( magnitude - mDeadzoneFraction ) / ( 1f - mDeadzoneFraction );
+ magnitude = Utility.clamp( magnitude, 0f, 1f );
+ mState.axisFractionX = normalizedX * magnitude;
+ mState.axisFractionY = normalizedY * magnitude;
+ }
+ else
+ {
+ // In the deadzone
+ mState.axisFractionX = 0;
+ mState.axisFractionY = 0;
+ }
+ }
+ return false;
+ }
+}
diff --git a/Android/src/emu/project64/input/TouchController.java b/Android/src/emu/project64/input/TouchController.java
new file mode 100644
index 000000000..466aeb810
--- /dev/null
+++ b/Android/src/emu/project64/input/TouchController.java
@@ -0,0 +1,532 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input;
+
+import java.util.Set;
+
+import emu.project64.AndroidDevice;
+import emu.project64.input.map.TouchMap;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.graphics.Point;
+import android.os.Vibrator;
+import android.util.SparseIntArray;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnTouchListener;
+
+/**
+ * A class for generating N64 controller commands from a touchscreen.
+ */
+public class TouchController extends AbstractController implements OnTouchListener
+{
+ public interface OnStateChangedListener
+ {
+ /**
+ * Called after the analog stick values have changed.
+ *
+ * @param axisFractionX The x-axis fraction, between -1 and 1, inclusive.
+ * @param axisFractionY The y-axis fraction, between -1 and 1, inclusive.
+ */
+ public void onAnalogChanged( float axisFractionX, float axisFractionY );
+
+ /**
+ * Called after auto-hold button state changed.
+ *
+ * @param pressed The auto-hold state.
+ * @param index The index of the auto-hold mask.
+ */
+ public void onAutoHold( boolean pressed, int index );
+ }
+
+ public static final int AUTOHOLD_METHOD_DISABLED = 0;
+ public static final int AUTOHOLD_METHOD_LONGPRESS = 1;
+ public static final int AUTOHOLD_METHOD_SLIDEOUT = 2;
+
+ /** The number of milliseconds to wait before auto-holding (long-press method). */
+ private static final int AUTOHOLD_LONGPRESS_TIME = 1000;
+
+ /** The pattern vibration when auto-hold is engaged. */
+ private static final long[] AUTOHOLD_VIBRATE_PATTERN = { 0, 50, 50, 50 };
+
+ /** The number of milliseconds of vibration when pressing a key. */
+ private static final int FEEDBACK_VIBRATE_TIME = 50;
+
+ /** The maximum number of pointers to query. */
+ private static final int MAX_POINTER_IDS = 256;
+
+ /** The state change listener. */
+ private final OnStateChangedListener mListener;
+
+ /** The map from screen coordinates to N64 controls. */
+ private final TouchMap mTouchMap;
+
+ /** The map from pointer ids to N64 controls. */
+ private final SparseIntArray mPointerMap = new SparseIntArray();
+
+ /** The method used for auto-holding buttons. */
+ private final int mAutoHoldMethod;
+
+ /** The set of auto-holdable buttons. */
+ private final Set mAutoHoldables;
+
+ /** Whether touchscreen feedback is enabled. */
+ private final boolean mTouchscreenFeedback;
+
+ /** The touch state of each pointer. True indicates down, false indicates up. */
+ private final boolean[] mTouchState = new boolean[MAX_POINTER_IDS];
+
+ /** The x-coordinate of each pointer, between 0 and (screenwidth-1), inclusive. */
+ private final int[] mPointerX = new int[MAX_POINTER_IDS];
+
+ /** The y-coordinate of each pointer, between 0 and (screenheight-1), inclusive. */
+ private final int[] mPointerY = new int[MAX_POINTER_IDS];
+
+ /** The pressed start time of each pointer. */
+ private final long[] mStartTime = new long[MAX_POINTER_IDS];
+
+ /** The time between press and release of each pointer. */
+ private final long[] mElapsedTime = new long[MAX_POINTER_IDS];
+
+ /**
+ * The identifier of the pointer associated with the analog stick. -1 indicates the stick has
+ * been released.
+ */
+ private int mAnalogPid = -1;
+
+ /** The touch event source to listen to, or 0 to listen to all sources. */
+ private int mSourceFilter = 0;
+
+ private Vibrator mVibrator = null;
+
+ /**
+ * Instantiates a new touch controller.
+ *
+ * @param touchMap The map from touch coordinates to N64 controls.
+ * @param view The view receiving touch event data.
+ * @param listener The listener for controller state changes.
+ * @param vibrator The haptic feedback device. MUST BE NULL if vibrate permission not granted.
+ * @param autoHoldMethod The method for auto-holding buttons.
+ * @param touchscreenFeedback True if haptic feedback should be used.
+ * @param autoHoldableButtons The N64 commands that correspond to auto-holdable buttons.
+ */
+ public TouchController( TouchMap touchMap, View view, OnStateChangedListener listener,
+ Vibrator vibrator, int autoHoldMethod, boolean touchscreenFeedback,
+ Set autoHoldableButtons )
+ {
+ mListener = listener;
+ mTouchMap = touchMap;
+ mVibrator = vibrator;
+ mAutoHoldMethod = autoHoldMethod;
+ mTouchscreenFeedback = touchscreenFeedback;
+ mAutoHoldables = autoHoldableButtons;
+ view.setOnTouchListener( this );
+ }
+
+ /**
+ * Sets the touch event source filter.
+ *
+ * @param source The source to listen to, or 0 to listen to all sources.
+ */
+ public void setSourceFilter( int source )
+ {
+ mSourceFilter = source;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View.OnTouchListener#onTouch(android.view.View, android.view.MotionEvent)
+ */
+ @SuppressLint( "ClickableViewAccessibility" )
+ @Override
+ @TargetApi( 9 )
+ public boolean onTouch( View view, MotionEvent event )
+ {
+ // Filter by source, if applicable
+ int source = AndroidDevice.IS_GINGERBREAD ? event.getSource() : 0;
+ if( mSourceFilter != 0 && mSourceFilter != source )
+ return false;
+
+ int action = event.getAction();
+ int actionCode = action & MotionEvent.ACTION_MASK;
+
+ int pid = -1;
+ switch( actionCode )
+ {
+ case MotionEvent.ACTION_POINTER_DOWN:
+ // A non-primary touch has been made
+ pid = event.getPointerId( action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT );
+ mStartTime[pid] = System.currentTimeMillis();
+ mTouchState[pid] = true;
+ break;
+ case MotionEvent.ACTION_POINTER_UP:
+ // A non-primary touch has been released
+ pid = event.getPointerId( action >> MotionEvent.ACTION_POINTER_INDEX_SHIFT );
+ mElapsedTime[pid] = System.currentTimeMillis() - mStartTime[pid];
+ mTouchState[pid] = false;
+ break;
+ case MotionEvent.ACTION_DOWN:
+ // A touch gesture has started (e.g. analog stick movement)
+ for( int i = 0; i < event.getPointerCount(); i++ )
+ {
+ pid = event.getPointerId( i );
+ mStartTime[pid] = System.currentTimeMillis();
+ mTouchState[pid] = true;
+ }
+ break;
+ case MotionEvent.ACTION_UP:
+ case MotionEvent.ACTION_CANCEL:
+ // A touch gesture has ended or canceled (e.g. analog stick movement)
+ for( int i = 0; i < event.getPointerCount(); i++ )
+ {
+ pid = event.getPointerId( i );
+ mElapsedTime[pid] = System.currentTimeMillis() - mStartTime[pid];
+ mTouchState[pid] = false;
+ }
+ break;
+ default:
+ break;
+ }
+
+ // Update the coordinates of down pointers and record max PID for speed
+ int maxPid = -1;
+ for( int i = 0; i < event.getPointerCount(); i++ )
+ {
+ pid = event.getPointerId( i );
+ if( pid > maxPid )
+ maxPid = pid;
+ if( mTouchState[pid] )
+ {
+ mPointerX[pid] = (int) event.getX( i );
+ mPointerY[pid] = (int) event.getY( i );
+ }
+ }
+
+ // Process each touch
+ processTouches( mTouchState, mPointerX, mPointerY, mElapsedTime, maxPid );
+
+ return true;
+ }
+
+ /**
+ * Sets the N64 controller state based on where the screen is (multi-) touched. Values outside
+ * the ranges listed below are safe.
+ *
+ * @param touchstate The touch state of each pointer. True indicates down, false indicates up.
+ * @param pointerX The x-coordinate of each pointer, between 0 and (screenwidth-1), inclusive.
+ * @param pointerY The y-coordinate of each pointer, between 0 and (screenheight-1), inclusive.
+ * @param maxPid Maximum ID of the pointers that have changed (speed optimization).
+ */
+ private void processTouches( boolean[] touchstate, int[] pointerX, int[] pointerY,
+ long[] elapsedTime, int maxPid )
+ {
+ boolean analogMoved = false;
+
+ // Process each pointer in sequence
+ for( int pid = 0; pid <= maxPid; pid++ )
+ {
+ // Release analog if its pointer is not touching the screen
+ if( pid == mAnalogPid && !touchstate[pid] )
+ {
+ analogMoved = true;
+ mAnalogPid = -1;
+ mState.axisFractionX = 0;
+ mState.axisFractionY = 0;
+ }
+
+ // Process button inputs
+ if( pid != mAnalogPid )
+ processButtonTouch( touchstate[pid], pointerX[pid], pointerY[pid],
+ elapsedTime[pid], pid );
+
+ // Process analog inputs
+ if( touchstate[pid] && processAnalogTouch( pid, pointerX[pid], pointerY[pid] ) )
+ analogMoved = true;
+ }
+
+ // Call the super method to send the input to the core
+ notifyChanged();
+
+ // Update the skin if the virtual analog stick moved
+ if( analogMoved && mListener != null )
+ mListener.onAnalogChanged( mState.axisFractionX, mState.axisFractionY );
+ }
+
+ /**
+ * Process a touch as if intended for a button. Values outside the ranges listed below are safe.
+ *
+ * @param touched Whether the button is pressed or not.
+ * @param xLocation The x-coordinate of the touch, between 0 and (screenwidth-1), inclusive.
+ * @param yLocation The y-coordinate of the touch, between 0 and (screenheight-1), inclusive.
+ * @param pid The identifier of the touch pointer.
+ */
+ private void processButtonTouch( boolean touched, int xLocation, int yLocation,
+ long timeElapsed, int pid )
+ {
+ // Determine the index of the button that was pressed
+ int index = touched
+ ? mTouchMap.getButtonPress( xLocation, yLocation )
+ : mPointerMap.get( pid, TouchMap.UNMAPPED );
+
+ // Update the pointer map
+ if( !touched )
+ {
+ // Finger lifted off screen, forget what this pointer was touching
+ mPointerMap.delete( pid );
+ }
+ else
+ {
+ // Determine where the finger came from if is was slid
+ int prevIndex = mPointerMap.get( pid, TouchMap.UNMAPPED );
+
+ // Finger touched somewhere on screen, remember what this pointer is touching
+ mPointerMap.put( pid, index );
+
+ if( prevIndex != index )
+ {
+ // Finger slid from somewhere else, act accordingly
+ // There are three possibilities:
+ // - old button --> new button
+ // - nothing --> new button
+ // - old button --> nothing
+
+ // Reset this pointer's start time
+ mStartTime[pid] = System.currentTimeMillis();
+
+ if( prevIndex != TouchMap.UNMAPPED )
+ {
+ // Slid off a valid button
+ if( !isAutoHoldable( prevIndex ) || mAutoHoldMethod == AUTOHOLD_METHOD_DISABLED )
+ {
+ // Slid off a non-auto-hold button
+ setTouchState( prevIndex, false );
+ }
+ else
+ {
+ // Slid off an auto-hold button
+ switch( mAutoHoldMethod )
+ {
+ case AUTOHOLD_METHOD_LONGPRESS:
+ // Using long-press method, release auto-hold button
+ if( mListener != null )
+ mListener.onAutoHold( false, prevIndex );
+ setTouchState( prevIndex, false );
+ break;
+
+ case AUTOHOLD_METHOD_SLIDEOUT:
+ // Using slide-off method, engage auto-hold button
+ if( mVibrator != null )
+ {
+ mVibrator.cancel();
+ mVibrator.vibrate( AUTOHOLD_VIBRATE_PATTERN, -1 );
+ }
+ if( mListener != null )
+ mListener.onAutoHold( true, prevIndex );
+ setTouchState( prevIndex, true );
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ if( index != TouchMap.UNMAPPED )
+ {
+ // Finger is on a valid button
+
+ // Provide simple vibration feedback for any valid button when first touched
+ if( touched && mTouchscreenFeedback && mVibrator != null )
+ {
+ boolean firstTouched;
+ if( index < NUM_N64_BUTTONS )
+ {
+ // Single button pressed
+ firstTouched = !mState.buttons[index];
+ }
+ else
+ {
+ // Two d-pad buttons pressed simultaneously
+ switch( index )
+ {
+ case TouchMap.DPD_RU:
+ firstTouched = !( mState.buttons[DPD_R] && mState.buttons[DPD_U] );
+ break;
+ case TouchMap.DPD_RD:
+ firstTouched = !( mState.buttons[DPD_R] && mState.buttons[DPD_D] );
+ break;
+ case TouchMap.DPD_LD:
+ firstTouched = !( mState.buttons[DPD_L] && mState.buttons[DPD_D] );
+ break;
+ case TouchMap.DPD_LU:
+ firstTouched = !( mState.buttons[DPD_L] && mState.buttons[DPD_U] );
+ break;
+ default:
+ firstTouched = false;
+ break;
+ }
+ }
+
+ if( firstTouched )
+ {
+ mVibrator.cancel();
+ mVibrator.vibrate( FEEDBACK_VIBRATE_TIME );
+ }
+ }
+
+ // Set the controller state accordingly
+ if( touched || !isAutoHoldable( index ) || mAutoHoldMethod == AUTOHOLD_METHOD_DISABLED )
+ {
+ // Finger just touched a button (any kind) OR
+ // Finger just lifted off non-auto-holdable button
+ setTouchState( index, touched );
+ // Do not provide auto-hold feedback yet
+ }
+ else
+ {
+ // Finger just lifted off an auto-holdable button
+ switch( mAutoHoldMethod )
+ {
+ case AUTOHOLD_METHOD_SLIDEOUT:
+ // Release auto-hold button if using slide-off method
+ if( mListener != null )
+ mListener.onAutoHold( false, index );
+ setTouchState( index, false );
+ break;
+
+ case AUTOHOLD_METHOD_LONGPRESS:
+ if( timeElapsed < AUTOHOLD_LONGPRESS_TIME )
+ {
+ // Release auto-hold if short-pressed
+ if( mListener != null )
+ mListener.onAutoHold( false, index );
+ setTouchState( index, false );
+ }
+ else
+ {
+ // Engage auto-hold if long-pressed
+ if( mVibrator != null )
+ {
+ mVibrator.cancel();
+ mVibrator.vibrate( AUTOHOLD_VIBRATE_PATTERN, -1 );
+ }
+ if( mListener != null )
+ mListener.onAutoHold( true, index );
+ setTouchState( index, true );
+ }
+ break;
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks if the button mapped to an N64 command is auto-holdable.
+ *
+ * @param commandIndex The index to the N64 command.
+ *
+ * @return True if the button mapped to the command is auto-holdable.
+ */
+ private boolean isAutoHoldable( int commandIndex )
+ {
+ return mAutoHoldables != null && mAutoHoldables.contains( commandIndex );
+ }
+
+ /**
+ * Sets the state of a button, and handles the D-Pad diagonals.
+ *
+ * @param index Which button is affected.
+ * @param touched Whether the button is pressed or not.
+ */
+ private void setTouchState( int index, boolean touched )
+ {
+ // Set the button state
+ if( index < AbstractController.NUM_N64_BUTTONS )
+ {
+ // A single button was pressed
+ mState.buttons[index] = touched;
+ }
+ else
+ {
+ // Two d-pad buttons pressed simultaneously
+ switch( index )
+ {
+ case TouchMap.DPD_RU:
+ mState.buttons[DPD_R] = touched;
+ mState.buttons[DPD_U] = touched;
+ break;
+ case TouchMap.DPD_RD:
+ mState.buttons[DPD_R] = touched;
+ mState.buttons[DPD_D] = touched;
+ break;
+ case TouchMap.DPD_LD:
+ mState.buttons[DPD_L] = touched;
+ mState.buttons[DPD_D] = touched;
+ break;
+ case TouchMap.DPD_LU:
+ mState.buttons[DPD_L] = touched;
+ mState.buttons[DPD_U] = touched;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ /**
+ * Process a touch as if intended for the analog stick. Values outside the ranges listed below
+ * are safe.
+ *
+ * @param pointerId The pointer identifier.
+ * @param xLocation The x-coordinate of the touch, between 0 and (screenwidth-1), inclusive.
+ * @param yLocation The y-coordinate of the touch, between 0 and (screenheight-1), inclusive.
+ *
+ * @return True, if the analog state changed.
+ */
+ private boolean processAnalogTouch( int pointerId, int xLocation, int yLocation )
+ {
+ // Get the cartesian displacement of the analog stick
+ Point point = mTouchMap.getAnalogDisplacement( xLocation, yLocation );
+
+ // Compute the pythagorean displacement of the stick
+ int dX = point.x;
+ int dY = point.y;
+ float displacement = (float) Math.sqrt( ( dX * dX ) + ( dY * dY ) );
+
+ // "Capture" the analog control
+ if( mTouchMap.isInCaptureRange( displacement ) )
+ mAnalogPid = pointerId;
+
+ if( pointerId == mAnalogPid )
+ {
+ // User is controlling the analog stick
+
+ // Limit range of motion to an octagon (like the real N64 controller)
+ point = mTouchMap.getConstrainedDisplacement( dX, dY );
+ dX = point.x;
+ dY = point.y;
+ displacement = (float) Math.sqrt( ( dX * dX ) + ( dY * dY ) );
+
+ // Fraction of full-throttle, between 0 and 1, inclusive
+ float p = mTouchMap.getAnalogStrength( displacement );
+
+ // Store the axis values in the super fields (screen y is inverted)
+ mState.axisFractionX = p * dX / displacement;
+ mState.axisFractionY = -p * dY / displacement;
+
+ // Analog state changed
+ return true;
+ }
+
+ // Analog state did not change
+ return false;
+ }
+}
diff --git a/Android/src/emu/project64/input/map/AxisMap.java b/Android/src/emu/project64/input/map/AxisMap.java
new file mode 100644
index 000000000..5a071796a
--- /dev/null
+++ b/Android/src/emu/project64/input/map/AxisMap.java
@@ -0,0 +1,203 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.map;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+import android.annotation.TargetApi;
+import android.text.TextUtils;
+import android.util.SparseArray;
+import android.view.InputDevice;
+import android.view.InputDevice.MotionRange;
+import android.view.MotionEvent;
+
+@TargetApi( 9 )
+public class AxisMap extends SerializableMap
+{
+ public static final int AXIS_CLASS_UNKNOWN = 0;
+ public static final int AXIS_CLASS_IGNORED = 1;
+ public static final int AXIS_CLASS_STICK = 2;
+ public static final int AXIS_CLASS_TRIGGER = 3;
+ public static final int AXIS_CLASS_N64_USB_STICK = 102;
+
+ private static final int SIGNATURE_HASH_XBOX360 = 449832952;
+ private static final int SIGNATURE_HASH_XBOX360_WIRELESS = -412618953;
+ private static final int SIGNATURE_HASH_PS3 = -528816963;
+ private static final int SIGNATURE_HASH_LOGITECH_WINGMAN_RUMBLEPAD = 1247256123;
+ private static final int SIGNATURE_HASH_MOGA_PRO = -1933523749;
+ private static final int SIGNATURE_HASH_OUYA = 699487739;
+ private static final int SIGNATURE_HASH_AMAZON_FIRE = 2050752785;
+
+ private static final SparseArray sAllMaps = new SparseArray();
+ private final String mSignature;
+ private final String mSignatureName;
+
+ public static AxisMap getMap( InputDevice device )
+ {
+ if( device == null )
+ return null;
+
+ int id = device.hashCode();
+ AxisMap map = sAllMaps.get( id );
+ if( map == null )
+ {
+ // Add an entry to the map if not found
+ map = new AxisMap( device );
+ sAllMaps.put( id, map );
+ }
+ return map;
+ }
+
+ @TargetApi( 12 )
+ public AxisMap( InputDevice device )
+ {
+ // Auto-classify the axes
+ List motionRanges = device.getMotionRanges();
+ List axisCodes = new ArrayList();
+ for( MotionRange motionRange : motionRanges )
+ {
+ if( motionRange.getSource() == InputDevice.SOURCE_JOYSTICK )
+ {
+ int axisCode = motionRange.getAxis();
+ int axisClass = detectClass( motionRange );
+ setClass( axisCode, axisClass );
+ axisCodes.add( axisCode );
+ }
+ }
+
+ // Construct the signature based on the available axes
+ Collections.sort( axisCodes );
+ mSignature = TextUtils.join( ",", axisCodes );
+ String signatureName = "Default";
+ String deviceName = device.getName();
+
+ // Use the signature to override faulty auto-classifications
+ switch( mSignature.hashCode() )
+ {
+ case SIGNATURE_HASH_XBOX360:
+ // Resting value is -1 on the analog triggers; fix that
+ if( deviceName.contains( "Sony Computer Entertainment Wireless Controller" ) )
+ {
+ // Note that the PS4 controller uses the same axes but uses different ones for
+ // the triggers, so we have to differentiate them.
+ setClass( MotionEvent.AXIS_RX, AXIS_CLASS_TRIGGER );
+ setClass( MotionEvent.AXIS_RY, AXIS_CLASS_TRIGGER );
+ signatureName = "PS4 compatible";
+ }
+ else
+ {
+ setClass( MotionEvent.AXIS_Z, AXIS_CLASS_TRIGGER );
+ setClass( MotionEvent.AXIS_RZ, AXIS_CLASS_TRIGGER );
+ signatureName = "Xbox 360 compatible";
+ }
+ break;
+
+ case SIGNATURE_HASH_XBOX360_WIRELESS:
+ // Resting value is -1 on the analog triggers; fix that
+ setClass( MotionEvent.AXIS_Z, AXIS_CLASS_TRIGGER );
+ setClass( MotionEvent.AXIS_RZ, AXIS_CLASS_TRIGGER );
+ signatureName = "Xbox 360 wireless";
+ break;
+
+ case SIGNATURE_HASH_PS3:
+ // Ignore pressure sensitive buttons (buggy on Android)
+ setClass( MotionEvent.AXIS_GENERIC_1, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_2, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_3, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_4, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_5, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_6, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_7, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_8, AXIS_CLASS_IGNORED );
+ signatureName = "PS3 compatible";
+ break;
+
+ case SIGNATURE_HASH_LOGITECH_WINGMAN_RUMBLEPAD:
+ // Bug in controller firmware cross-wires throttle and right stick up/down
+ setClass( MotionEvent.AXIS_THROTTLE, AXIS_CLASS_STICK );
+ signatureName = "Logitech Wingman Rumblepad";
+ break;
+
+ case SIGNATURE_HASH_MOGA_PRO:
+ // Ignore two spurious axes for MOGA Pro in HID (B) mode (as of MOGA Pivot v1.15)
+ // http://www.paulscode.com/forum/index.php?topic=581.msg10094#msg10094
+ setClass( MotionEvent.AXIS_GENERIC_1, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_2, AXIS_CLASS_IGNORED );
+ signatureName = "Moga Pro (HID mode)";
+ break;
+
+ case SIGNATURE_HASH_OUYA:
+ // Ignore phantom triggers
+ setClass( MotionEvent.AXIS_GENERIC_1, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_2, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_3, AXIS_CLASS_IGNORED );
+ setClass( MotionEvent.AXIS_GENERIC_4, AXIS_CLASS_IGNORED );
+ signatureName = "OUYA controller";
+ break;
+
+ case SIGNATURE_HASH_AMAZON_FIRE:
+ // Ignore floating generic axis
+ setClass( MotionEvent.AXIS_GENERIC_1, AXIS_CLASS_IGNORED );
+ signatureName = "Amazon Fire Game Controller";
+ break;
+ }
+
+ // Check if the controller is an N64/USB adapter, to compensate for range of motion
+ if( deviceName.contains( "raphnet.net GC/N64_USB" ) ||
+ deviceName.contains( "raphnet.net GC/N64 to USB, v2" ) ||
+ deviceName.contains( "HuiJia USB GamePad" ) ) // double space is not a typo
+ {
+ setClass( MotionEvent.AXIS_X, AXIS_CLASS_N64_USB_STICK );
+ setClass( MotionEvent.AXIS_Y, AXIS_CLASS_N64_USB_STICK );
+ signatureName = "N64 USB adapter";
+ }
+
+ mSignatureName = signatureName;
+ }
+
+ public void setClass( int axisCode, int axisClass )
+ {
+ if( axisClass == AXIS_CLASS_UNKNOWN )
+ mMap.delete( axisCode );
+ else
+ mMap.put( axisCode, axisClass );
+ }
+
+ public int getClass( int axisCode )
+ {
+ return mMap.get( axisCode );
+ }
+
+ public String getSignature()
+ {
+ return mSignature;
+ }
+
+ public String getSignatureName()
+ {
+ return mSignatureName;
+ }
+
+ @TargetApi( 12 )
+ private static int detectClass( MotionRange motionRange )
+ {
+ if( motionRange != null )
+ {
+ if( motionRange.getMin() == -1 )
+ return AXIS_CLASS_STICK;
+ else if( motionRange.getMin() == 0 )
+ return AXIS_CLASS_TRIGGER;
+ }
+ return AXIS_CLASS_UNKNOWN;
+ }
+}
diff --git a/Android/src/emu/project64/input/map/InputMap.java b/Android/src/emu/project64/input/map/InputMap.java
new file mode 100644
index 000000000..816c13648
--- /dev/null
+++ b/Android/src/emu/project64/input/map/InputMap.java
@@ -0,0 +1,135 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.map;
+
+import emu.project64.input.AbstractController;
+import emu.project64.input.provider.AbstractProvider;
+
+/**
+ * A class for mapping arbitrary user inputs to N64 buttons/axes.
+ *
+ * @see AbstractProvider
+ * @see PeripheralController
+ * @see ControllerProfileActivity
+ */
+public class InputMap extends SerializableMap
+{
+ /** Map flag: Input code is not mapped. */
+ public static final int UNMAPPED = -1;
+
+ /** Map offset: N64 non-button controls. */
+ public static final int OFFSET_EXTRAS = AbstractController.NUM_N64_BUTTONS;
+
+ /** N64 control: analog-right. */
+ public static final int AXIS_R = OFFSET_EXTRAS;
+
+ /** N64 control: analog-left. */
+ public static final int AXIS_L = OFFSET_EXTRAS + 1;
+
+ /** N64 control: analog-down. */
+ public static final int AXIS_D = OFFSET_EXTRAS + 2;
+
+ /** N64 control: analog-up. */
+ public static final int AXIS_U = OFFSET_EXTRAS + 3;
+
+ /** Total number of N64 controls. */
+ public static final int NUM_N64_CONTROLS = OFFSET_EXTRAS + 4;
+ /** Total number of mappable controls/functions. */
+ public static final int NUM_MAPPABLES = NUM_N64_CONTROLS;
+
+ public InputMap( String serializedMap )
+ {
+ super( serializedMap );
+ }
+
+ /**
+ * Gets the command mapped to a given input code.
+ *
+ * @param inputCode The standardized input code.
+ *
+ * @return The command the code is mapped to, or UNMAPPED.
+ *
+ * @see AbstractProvider
+ * @see InputMap#UNMAPPED
+ */
+ public int get( int inputCode )
+ {
+ return mMap.get( inputCode, UNMAPPED );
+ }
+
+ /**
+ * Maps an input code to a command.
+ *
+ * @param inputCode The standardized input code to be mapped.
+ * @param command The index to the N64/Mupen command.
+ */
+ public void map( int inputCode, int command )
+ {
+ // Map the input if a valid index was given
+ if( command >= 0 && command < NUM_MAPPABLES && inputCode != 0 )
+ {
+ if( inputCode < 0 )
+ {
+ // If an analog input is mapped, it should be the only thing mapped to this command
+ unmapCommand( command );
+ }
+ else
+ {
+ // If a digital input is mapped, no analog inputs can be mapped to this command
+ for( int i = mMap.size() - 1; i >= 0; i-- )
+ {
+ if( mMap.valueAt( i ) == command && mMap.keyAt( i ) < 0 )
+ mMap.removeAt( i );
+ }
+ }
+ mMap.put( inputCode, command );
+ }
+ }
+
+ /**
+ * Unmaps a command.
+ *
+ * @param command The index to the command.
+ */
+ public void unmapCommand( int command )
+ {
+ // Remove any matching key-value pairs (count down to accommodate removal)
+ for( int i = mMap.size() - 1; i >= 0; i-- )
+ {
+ if( mMap.valueAt( i ) == command )
+ mMap.removeAt( i );
+ }
+ }
+
+ /**
+ * Checks if a command is mapped to at least one input code.
+ *
+ * @param command The index to the command.
+ *
+ * @return True, if the mapping exists.
+ */
+ public boolean isMapped( int command )
+ {
+ return mMap.indexOfValue( command ) >= 0;
+ }
+ public String getMappedCodeInfo( int command )
+ {
+ String result = "";
+ for( int i = 0; i < mMap.size(); i++ )
+ {
+ if( mMap.valueAt( i ) == command )
+ {
+ result += AbstractProvider.getInputName( mMap.keyAt( i ) ) + "\n";
+ }
+ }
+ return result.trim();
+ }
+}
diff --git a/Android/src/emu/project64/input/map/SerializableMap.java b/Android/src/emu/project64/input/map/SerializableMap.java
new file mode 100644
index 000000000..3ee42d111
--- /dev/null
+++ b/Android/src/emu/project64/input/map/SerializableMap.java
@@ -0,0 +1,96 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.map;
+
+import android.util.SparseIntArray;
+
+public class SerializableMap
+{
+ /** Storage for the map. */
+ protected final SparseIntArray mMap = new SparseIntArray();
+
+ /**
+ * Instantiates a new map.
+ */
+ public SerializableMap()
+ {
+ }
+
+ /**
+ * Instantiates a new map from a serialization.
+ *
+ * @param serializedMap The serialization of the map.
+ */
+ public SerializableMap( String serializedMap )
+ {
+ this();
+ deserialize( serializedMap );
+ }
+
+ /**
+ * Removes all entries from the map.
+ */
+ public void unmapAll()
+ {
+ mMap.clear();
+ }
+
+ /**
+ * Serializes the map data to a string.
+ *
+ * @return The string representation of the map data.
+ */
+ public String serialize()
+ {
+ // Serialize the map data to a multi-delimited string
+ String result = "";
+ for( int i = 0; i < mMap.size(); i++ )
+ {
+ // Putting the value first makes the string a bit more human readable IMO
+ result += mMap.valueAt( i ) + ":" + mMap.keyAt( i ) + ",";
+ }
+ return result;
+ }
+
+ /**
+ * Deserializes the map data from a string.
+ *
+ * @param s The string representation of the map data.
+ */
+ public void deserialize( String s )
+ {
+ // Reset the map
+ unmapAll();
+
+ // Parse the new map data from the multi-delimited string
+ if( s != null )
+ {
+ // Read the input mappings
+ String[] pairs = s.split( "," );
+ for( String pair : pairs )
+ {
+ String[] elements = pair.split( ":" );
+ if( elements.length == 2 )
+ {
+ try
+ {
+ int value = Integer.parseInt( elements[0] );
+ int key = Integer.parseInt( elements[1] );
+ mMap.put( key, value );
+ }
+ catch( NumberFormatException ignored )
+ {
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Android/src/emu/project64/input/map/TouchMap.java b/Android/src/emu/project64/input/map/TouchMap.java
new file mode 100644
index 000000000..17df147b9
--- /dev/null
+++ b/Android/src/emu/project64/input/map/TouchMap.java
@@ -0,0 +1,589 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.map;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import emu.project64.input.AbstractController;
+import emu.project64.input.TouchController;
+import emu.project64.persistent.ConfigFile;
+import emu.project64.persistent.ConfigFile.ConfigSection;
+import emu.project64.profile.Profile;
+import emu.project64.util.Image;
+import emu.project64.util.Utility;
+import android.annotation.SuppressLint;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.util.Log;
+import android.util.SparseArray;
+
+/**
+ * A class for mapping digitizer coordinates to N64 buttons/axes.
+ *
+ * @see VisibleTouchMap
+ * @see TouchController
+ */
+@SuppressLint("FloatMath")
+public class TouchMap
+{
+ /** Map flag: Touch location is not mapped. */
+ public static final int UNMAPPED = -1;
+
+ /** Map offset: N64 pseudo-buttons. */
+ public static final int OFFSET_EXTRAS = AbstractController.NUM_N64_BUTTONS;
+
+ /** N64 pseudo-button: dpad-right-up. */
+ public static final int DPD_RU = OFFSET_EXTRAS;
+
+ /** N64 pseudo-button: dpad-right-down. */
+ public static final int DPD_RD = OFFSET_EXTRAS + 1;
+
+ /** N64 pseudo-button: dpad-left-down. */
+ public static final int DPD_LD = OFFSET_EXTRAS + 2;
+
+ /** N64 pseudo-button: dpad-left-up. */
+ public static final int DPD_LU = OFFSET_EXTRAS + 3;
+
+ /** Total number of N64 (pseudo-)buttons. */
+ public static final int NUM_N64_PSEUDOBUTTONS = OFFSET_EXTRAS + 4;
+
+ /** Folder containing the images. */
+ protected String skinFolder;
+
+ /** Scaling factor to apply to images. */
+ protected float scale = 1.0f;
+
+ /** Button images. */
+ protected ArrayList buttonImages;
+
+ /** Button masks. */
+ private final ArrayList buttonMasks;
+
+ /** X-coordinates of the buttons, in percent. */
+ private final ArrayList buttonX;
+
+ /** Y-coordinates of the buttons, in percent. */
+ private final ArrayList buttonY;
+
+ /** names of the buttons. */
+ private final ArrayList buttonNames;
+
+ /** Analog background image (fixed). */
+ protected Image analogBackImage;
+
+ /** Analog foreground image (movable). */
+ protected Image analogForeImage;
+
+ /** X-coordinate of the analog background, in percent. */
+ private int analogBackX;
+
+ /** Y-coordinate of the analog background, in percent. */
+ private int analogBackY;
+
+ /** Deadzone of the analog stick, in pixels. */
+ private int analogDeadzone;
+
+ /** Maximum displacement of the analog stick, in pixels. */
+ protected int analogMaximum;
+
+ /** Extra region beyond maximum in which the analog stick can be captured, in pixels. */
+ private int analogPadding;
+
+ /** The resources of the associated activity. */
+ protected final Resources mResources;
+
+ /** Map from N64 (pseudo-)button to mask color. */
+ private final int[] mN64ToColor;
+
+ /** The map from strings in the skin.ini file to N64 button indices. */
+ public static final HashMap MASK_KEYS = new HashMap();
+
+ /** The map from N64 button indices to asset name prefixes in the skin folder. */
+ public static final SparseArray ASSET_NAMES = new SparseArray();
+
+ /** The error in RGB (256x256x256) space that we tolerate when matching mask colors. */
+ private static final int MATCH_TOLERANCE = 10;
+
+ static
+ {
+ // Define the map from skin.ini keys to N64 button indices
+ // @formatter:off
+ MASK_KEYS.put( "Dr", AbstractController.DPD_R );
+ MASK_KEYS.put( "Dl", AbstractController.DPD_L );
+ MASK_KEYS.put( "Dd", AbstractController.DPD_D );
+ MASK_KEYS.put( "Du", AbstractController.DPD_U );
+ MASK_KEYS.put( "S", AbstractController.START );
+ MASK_KEYS.put( "Z", AbstractController.BTN_Z );
+ MASK_KEYS.put( "B", AbstractController.BTN_B );
+ MASK_KEYS.put( "A", AbstractController.BTN_A );
+ MASK_KEYS.put( "Cr", AbstractController.CPD_R );
+ MASK_KEYS.put( "Cl", AbstractController.CPD_L );
+ MASK_KEYS.put( "Cd", AbstractController.CPD_D );
+ MASK_KEYS.put( "Cu", AbstractController.CPD_U );
+ MASK_KEYS.put( "R", AbstractController.BTN_R );
+ MASK_KEYS.put( "L", AbstractController.BTN_L );
+ MASK_KEYS.put( "Dru", DPD_RU );
+ MASK_KEYS.put( "Drd", DPD_RD );
+ MASK_KEYS.put( "Dld", DPD_LD );
+ MASK_KEYS.put( "Dlu", DPD_LU );
+ // @formatter:on
+
+ // Define the map from N64 button indices to profile key prefixes
+ ASSET_NAMES.put( AbstractController.DPD_R, "dpad" );
+ ASSET_NAMES.put( AbstractController.DPD_L, "dpad" );
+ ASSET_NAMES.put( AbstractController.DPD_D, "dpad" );
+ ASSET_NAMES.put( AbstractController.DPD_U, "dpad" );
+ ASSET_NAMES.put( AbstractController.START, "buttonS" );
+ ASSET_NAMES.put( AbstractController.BTN_Z, "buttonZ" );
+ ASSET_NAMES.put( AbstractController.BTN_B, "groupAB" );
+ ASSET_NAMES.put( AbstractController.BTN_A, "groupAB" );
+ ASSET_NAMES.put( AbstractController.CPD_R, "groupC" );
+ ASSET_NAMES.put( AbstractController.CPD_L, "groupC" );
+ ASSET_NAMES.put( AbstractController.CPD_D, "groupC" );
+ ASSET_NAMES.put( AbstractController.CPD_U, "groupC" );
+ ASSET_NAMES.put( AbstractController.BTN_R, "buttonR" );
+ ASSET_NAMES.put( AbstractController.BTN_L, "buttonL" );
+ ASSET_NAMES.put( DPD_LU, "dpad" );
+ ASSET_NAMES.put( DPD_LD, "dpad" );
+ ASSET_NAMES.put( DPD_RD, "dpad" );
+ ASSET_NAMES.put( DPD_RU, "dpad" );
+ }
+
+ /**
+ * Instantiates a new touch map.
+ *
+ * @param resources The resources of the activity associated with this touch map.
+ */
+ public TouchMap( Resources resources )
+ {
+ mResources = resources;
+ mN64ToColor = new int[NUM_N64_PSEUDOBUTTONS];
+ buttonImages = new ArrayList();
+ buttonMasks = new ArrayList();
+ buttonX = new ArrayList();
+ buttonY = new ArrayList();
+ buttonNames = new ArrayList();
+ }
+
+ /**
+ * Clears the map data.
+ */
+ public void clear()
+ {
+ buttonImages.clear();
+ buttonMasks.clear();
+ buttonX.clear();
+ buttonY.clear();
+ buttonNames.clear();
+ analogBackImage = null;
+ analogForeImage = null;
+ analogBackX = analogBackY = 0;
+ analogPadding = 32;
+ analogDeadzone = 2;
+ analogMaximum = 360;
+ for( int i = 0; i < mN64ToColor.length; i++ )
+ mN64ToColor[i] = -1;
+ }
+
+ /**
+ * Recomputes the map data for a given digitizer size.
+ *
+ * @param w The width of the digitizer, in pixels.
+ * @param h The height of the digitizer, in pixels.
+ */
+ public void resize( int w, int h )
+ {
+ // Recompute button locations
+ for( int i = 0; i < buttonImages.size(); i++ )
+ {
+ buttonImages.get( i ).setScale( scale );
+ buttonImages.get( i ).fitPercent( buttonX.get( i ), buttonY.get( i ), w, h );
+ buttonMasks.get( i ).setScale( scale );
+ buttonMasks.get( i ).fitPercent( buttonX.get( i ), buttonY.get( i ), w, h );
+ }
+
+ // Recompute analog background location
+ if( analogBackImage != null )
+ {
+ analogBackImage.setScale( scale );
+ analogBackImage.fitPercent( analogBackX, analogBackY, w, h );
+ }
+ }
+
+ /**
+ * Gets the N64 button mapped to a given touch location.
+ *
+ * @param xLocation The x-coordinate of the touch, in pixels.
+ * @param yLocation The y-coordinate of the touch, in pixels.
+ *
+ * @return The N64 button the location is mapped to, or UNMAPPED.
+ *
+ * @see TouchMap#UNMAPPED
+ */
+ public int getButtonPress( int xLocation, int yLocation )
+ {
+ // Search through every button mask to see if the corresponding button was touched
+ for( Image mask : buttonMasks )
+ {
+ if( mask != null )
+ {
+ int left = mask.x;
+ int right = left + (int) ( mask.width * mask.scale );
+ int bottom = mask.y;
+ int top = bottom + (int) ( mask.height * mask.scale );
+
+ // See if the touch falls in the vicinity of the button (conservative test)
+ if( xLocation >= left && xLocation < right && yLocation >= bottom
+ && yLocation < top )
+ {
+ // Get the mask color at this location
+ int c = mask.image.getPixel( (int) ( ( xLocation - mask.x ) / scale ), (int) ( ( yLocation - mask.y ) / scale ) );
+
+ // Ignore the alpha component if any
+ int rgb = c & 0x00ffffff;
+
+ // Ignore black and get the N64 button associated with this color
+ if( rgb > 0 )
+ return getButtonFromColor( rgb );
+ }
+ }
+ }
+ return UNMAPPED;
+ }
+
+ /**
+ * Gets the frame for the N64 button with a given asset name
+ *
+ * @param assetName The asset name for the button
+ *
+ * @return The frame for the N64 button with the given asset name
+ *
+ */
+ public Rect getButtonFrame( String assetName )
+ {
+ for( int i = 0; i < buttonNames.size(); i++ )
+ {
+ if ( buttonNames.get( i ).equals( assetName ) )
+ return new Rect( buttonMasks.get( i ).drawRect );
+ }
+ return new Rect(0, 0, 0, 0);
+ }
+
+ /**
+ * Gets the N64 button mapped to a given mask color.
+ *
+ * @param color The mask color.
+ *
+ * @return The N64 button the color is mapped to, or UNMAPPED.
+ */
+ private int getButtonFromColor( int color )
+ {
+ // Find the N64 button whose mask matches the given color. Because we scale the mask images,
+ // the mask boundaries can get softened. Therefore we tolerate a bit of error in the match.
+ int closestMatch = UNMAPPED;
+ int matchDif = MATCH_TOLERANCE * MATCH_TOLERANCE;
+
+ // Get the RGB values of the given color
+ int r = ( color & 0xFF0000 ) >> 16;
+ int g = ( color & 0x00FF00 ) >> 8;
+ int b = ( color & 0x0000FF );
+
+ // Find the mask color with the smallest squared error
+ for( int i = 0; i < mN64ToColor.length; i++ )
+ {
+ int color2 = mN64ToColor[i];
+
+ // Compute squared error in RGB space
+ int difR = r - ( ( color2 & 0xFF0000 ) >> 16 );
+ int difG = g - ( ( color2 & 0x00FF00 ) >> 8 );
+ int difB = b - ( ( color2 & 0x0000FF ) );
+ int dif = difR * difR + difG * difG + difB * difB;
+
+ if( dif < matchDif )
+ {
+ closestMatch = i;
+ matchDif = dif;
+ }
+ }
+ return closestMatch;
+ }
+
+ /**
+ * Gets the N64 analog stick displacement.
+ *
+ * @param xLocation The x-coordinate of the touch, in pixels.
+ * @param yLocation The y-coordinate of the touch, in pixels.
+ *
+ * @return The analog displacement, in pixels.
+ */
+ public Point getAnalogDisplacement( int xLocation, int yLocation )
+ {
+ if( analogBackImage == null )
+ return new Point( 0, 0 );
+
+ // Distance from center along x-axis
+ int dX = xLocation - ( analogBackImage.x + (int) ( analogBackImage.hWidth * scale ) );
+
+ // Distance from center along y-axis
+ int dY = yLocation - ( analogBackImage.y + (int) ( analogBackImage.hHeight * scale ) );
+
+ return new Point( dX, dY );
+ }
+
+ /**
+ * Gets the N64 analog stick's frame.
+ *
+ * @return The analog stick's frame.
+ */
+ public Rect getAnalogFrame()
+ {
+ if( analogBackImage != null )
+ return new Rect( analogBackImage.drawRect );
+ return new Rect(0, 0, 0, 0);
+ }
+
+ /**
+ * Gets the N64 analog stick displacement, constrained to an octagon.
+ *
+ * @param dX The x-displacement of the stick, in pixels.
+ * @param dY The y-displacement of the stick, in pixels.
+ *
+ * @return The constrained analog displacement, in pixels.
+ */
+ public Point getConstrainedDisplacement( int dX, int dY )
+ {
+ final float dC = (int) ( analogMaximum * scale );
+ final float dA = dC * (float)Math.sqrt( 0.5f );
+ final float signX = (dX < 0) ? -1 : 1;
+ final float signY = (dY < 0) ? -1 : 1;
+
+ Point crossPt = new Point();
+ crossPt.x = dX;
+ crossPt.y = dY;
+
+ if( ( signX * dX ) > ( signY * dY ) )
+ segsCross( 0, 0, dX, dY, signX * dC, 0, signX * dA, signY * dA, crossPt );
+ else
+ segsCross( 0, 0, dX, dY, 0, signY * dC, signX * dA, signY * dA, crossPt );
+
+ return crossPt;
+ }
+
+ /**
+ * Gets the analog strength, accounting for deadzone and motion limits.
+ *
+ * @param displacement The Pythagorean displacement of the analog stick, in pixels.
+ *
+ * @return The analog strength, between 0 and 1, inclusive.
+ */
+ public float getAnalogStrength( float displacement )
+ {
+ displacement /= scale;
+ float p = ( displacement - analogDeadzone ) / ( analogMaximum - analogDeadzone );
+ return Utility.clamp( p, 0.0f, 1.0f );
+ }
+
+ /**
+ * Checks if a touch is within capture range of the analog stick.
+ *
+ * @param displacement The displacement of the touch with respect to analog center, in pixels.
+ *
+ * @return True, if the touch is in capture range of the stick.
+ */
+ public boolean isInCaptureRange( float displacement )
+ {
+ displacement /= scale;
+ return ( displacement >= analogDeadzone ) && ( displacement < analogMaximum + analogPadding );
+ }
+
+ /**
+ * Loads all touch map data from the filesystem.
+ *
+ * @param skinDir The directory containing the skin.ini and image files.
+ * @param profile The name of the layout profile.
+ * @param animated True to load the analog assets in two parts for animation.
+ */
+ public void load( String skinDir, Profile profile, boolean animated )
+ {
+ // Clear any old assets and map data
+ clear();
+
+ // Load the configuration files
+ skinFolder = skinDir;
+ ConfigFile skin_ini = new ConfigFile( skinFolder + "/skin.ini" );
+
+ // Look up the mask colors
+ loadMaskColors( skin_ini );
+
+ // Loop through all the configuration sections
+ loadAllAssets( profile, animated );
+ }
+
+ /**
+ * Loads the mask colors from a configuration file.
+ *
+ * @param skin_ini The configuration file containing mask info.
+ */
+ private void loadMaskColors( ConfigFile skin_ini )
+ {
+ ConfigSection section = skin_ini.get( "MASK_COLOR" );
+ if( section != null )
+ {
+ // Loop through the key-value pairs
+ for( String key : section.keySet() )
+ {
+ // Assign the map colors to the appropriate N64 button
+ String val = section.get( key );
+ Integer index = MASK_KEYS.get( key );
+ if( index != null )
+ {
+ try
+ {
+ mN64ToColor[index] = Integer.parseInt( val, 16 );
+ }
+ catch( NumberFormatException ex )
+ {
+ mN64ToColor[index] = -1;
+ Log.w( "TouchMap", "Invalid mask color '" + val + "' in " + skinFolder + "/skin.ini" );
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Loads all assets and properties specified in a profile.
+ *
+ * @param profile The touchscreen/touchpad profile.
+ * @param animated True to load the analog assets in two parts for animation.
+ */
+ protected void loadAllAssets( Profile profile, boolean animated )
+ {
+ if( profile != null )
+ {
+ loadAnalog( profile, animated );
+ loadButton( profile, "dpad" );
+ loadButton( profile, "groupAB" );
+ loadButton( profile, "groupC" );
+ loadButton( profile, "buttonL" );
+ loadButton( profile, "buttonR" );
+ loadButton( profile, "buttonZ" );
+ loadButton( profile, "buttonS" );
+ }
+ }
+
+ /**
+ * Loads analog assets and properties from the filesystem.
+ *
+ * @param profile The touchscreen/touchpad profile containing the analog properties.
+ * @param animated True to load the assets in two parts for animation.
+ */
+ protected void loadAnalog( Profile profile, boolean animated )
+ {
+ int x = profile.getInt( "analog-x", -1 );
+ int y = profile.getInt( "analog-y", -1 );
+
+ if( x >= 0 && y >= 0 )
+ {
+ // Position (percentages of the digitizer dimensions)
+ analogBackX = x;
+ analogBackY = y;
+
+ // The images (used by touchscreens) are in PNG image format.
+ if( animated )
+ {
+ analogBackImage = new Image( mResources, skinFolder + "/analog-back.png" );
+ analogForeImage = new Image( mResources, skinFolder + "/analog-fore.png" );
+ }
+ else
+ {
+ analogBackImage = new Image( mResources, skinFolder + "/analog.png" );
+ }
+
+ // Sensitivity (percentages of the radius, i.e. half the image width)
+ analogDeadzone = (int) ( analogBackImage.hWidth * ( profile.getFloat( "analog-min", 1 ) / 100.0f ) );
+ analogMaximum = (int) ( analogBackImage.hWidth * ( profile.getFloat( "analog-max", 55 ) / 100.0f ) );
+ analogPadding = (int) ( analogBackImage.hWidth * ( profile.getFloat( "analog-buff", 55 ) / 100.0f ) );
+ }
+ }
+
+ /**
+ * Loads button assets and properties from the filesystem.
+ *
+ * @param profile The touchscreen/touchpad profile containing the button properties.
+ * @param name The name of the button/group to load.
+ */
+ protected void loadButton( Profile profile, String name )
+ {
+ int x = profile.getInt( name + "-x", -1 );
+ int y = profile.getInt( name + "-y", -1 );
+
+ if( x >= 0 && y >= 0 )
+ {
+ // Position (percentages of the digitizer dimensions)
+ buttonX.add( x );
+ buttonY.add( y );
+ buttonNames.add( name );
+
+ // Load the displayed and mask images
+ buttonImages.add( new Image( mResources, skinFolder + "/" + name + ".png" ) );
+ buttonMasks.add( new Image( mResources, skinFolder + "/" + name + "-mask.png" ) );
+ }
+ }
+
+ /**
+ * Determines if the two specified line segments intersect with each other, and calculates where
+ * the intersection occurs if they do.
+ *
+ * @param seg1pt1_x X-coordinate for the first end of the first line segment.
+ * @param seg1pt1_y Y-coordinate for the first end of the first line segment.
+ * @param seg1pt2_x X-coordinate for the second end of the first line segment.
+ * @param seg1pt2_y Y-coordinate for the second end of the first line segment.
+ * @param seg2pt1_x X-coordinate for the first end of the second line segment.
+ * @param seg2pt1_y Y-coordinate for the first end of the second line segment.
+ * @param seg2pt2_x X-coordinate for the second end of the second line segment.
+ * @param seg2pt2_y Y-coordinate for the second end of the second line segment.
+ * @param crossPt Changed to the point of intersection if there is one, otherwise unchanged.
+ *
+ * @return True if the two line segments intersect.
+ */
+ private static boolean segsCross( float seg1pt1_x, float seg1pt1_y, float seg1pt2_x,
+ float seg1pt2_y, float seg2pt1_x, float seg2pt1_y, float seg2pt2_x, float seg2pt2_y,
+ Point crossPt )
+ {
+ float vec1_x = seg1pt2_x - seg1pt1_x;
+ float vec1_y = seg1pt2_y - seg1pt1_y;
+
+ float vec2_x = seg2pt2_x - seg2pt1_x;
+ float vec2_y = seg2pt2_y - seg2pt1_y;
+
+ float div = ( -vec2_x * vec1_y + vec1_x * vec2_y );
+
+ // Segments don't cross
+ if( div == 0 )
+ return false;
+
+ float s = ( -vec1_y * ( seg1pt1_x - seg2pt1_x ) + vec1_x * ( seg1pt1_y - seg2pt1_y ) ) / div;
+ float t = ( vec2_x * ( seg1pt1_y - seg2pt1_y ) - vec2_y * ( seg1pt1_x - seg2pt1_x ) ) / div;
+
+ if( s >= 0 && s < 1 && t >= 0 && t <= 1 )
+ {
+ // Segments cross, point of intersection stored in 'crossPt'
+ crossPt.x = (int) ( seg1pt1_x + ( t * vec1_x ) );
+ crossPt.y = (int) ( seg1pt1_y + ( t * vec1_y ) );
+ return true;
+ }
+
+ // Segments don't cross
+ return false;
+ }
+}
diff --git a/Android/src/emu/project64/input/map/VisibleTouchMap.java b/Android/src/emu/project64/input/map/VisibleTouchMap.java
new file mode 100644
index 000000000..d3c19c036
--- /dev/null
+++ b/Android/src/emu/project64/input/map/VisibleTouchMap.java
@@ -0,0 +1,357 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.map;
+
+import java.util.concurrent.CopyOnWriteArrayList;
+
+import emu.project64.game.GameOverlay;
+import emu.project64.persistent.ConfigFile;
+import emu.project64.profile.Profile;
+import emu.project64.util.Image;
+import emu.project64.util.SafeMethods;
+import emu.project64.util.Utility;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.util.DisplayMetrics;
+import android.util.Log;
+
+/**
+ * A kind of touch map that can be drawn on a canvas.
+ *
+ * @see TouchMap
+ * @see GameOverlay
+ */
+public class VisibleTouchMap extends TouchMap
+{
+ /** The factor to scale images by. */
+ private float mScalingFactor = 1.0f;
+
+ /** Touchscreen opacity. */
+ private int mTouchscreenTransparency;
+
+ /** Reference screen width in pixels (if provided in skin.ini). */
+ private int mReferenceWidth = 0;
+
+ /** Reference screen height in pixels (if provided in skin.ini). */
+ private int mReferenceHeight = 0;
+
+ /** The last width passed to {@link #resize(int, int, DisplayMetrics)}. */
+ private static int cacheWidth = 0;
+
+ /** The last height passed to {@link #resize(int, int, DisplayMetrics)}. */
+ private static int cacheHeight = 0;
+
+ /** The last height passed to {@link #resize(int, int, DisplayMetrics)}. */
+ private DisplayMetrics cacheMetrics;
+
+ /** Auto-hold overlay images. */
+ public final Image[] autoHoldImages;
+
+ /** X-coordinates of the AutoHold mask, in percent. */
+ private final int[] autoHoldX;
+
+ /** Y-coordinates of the AutoHold mask, in percent. */
+ private final int[] autoHoldY;
+
+ /**
+ * Instantiates a new visible touch map.
+ *
+ * @param resources The resources of the activity associated with this touch map.
+ */
+ public VisibleTouchMap( Resources resources )
+ {
+ super( resources );
+ autoHoldImages = new Image[NUM_N64_PSEUDOBUTTONS];
+ autoHoldX = new int[NUM_N64_PSEUDOBUTTONS];
+ autoHoldY = new int[NUM_N64_PSEUDOBUTTONS];
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see emu.project64.input.map.TouchMap#clear()
+ */
+ @Override
+ public void clear()
+ {
+ super.clear();
+ for( int i = 0; i < autoHoldImages.length; i++ )
+ autoHoldImages[i] = null;
+ for( int i = 0; i < autoHoldX.length; i++ )
+ autoHoldX[i] = 0;
+ for( int i = 0; i < autoHoldY.length; i++ )
+ autoHoldY[i] = 0;
+ }
+
+ /**
+ * Recomputes the map data for a given digitizer size, and
+ * recalculates the scaling factor.
+ *
+ * @param w The width of the digitizer, in pixels.
+ * @param h The height of the digitizer, in pixels.
+ * @param metrics Metrics about the display (for use in scaling).
+ */
+ public void resize( int w, int h, DisplayMetrics metrics )
+ {
+ // Cache the width and height in case we need to reload assets
+ cacheWidth = w;
+ cacheHeight = h;
+ cacheMetrics = metrics;
+ scale = 1.0f;
+
+ if( metrics != null )
+ {
+ // Scale buttons to match the skin designer's proportions
+ float scaleW = 1f;
+ float scaleH = 1f;
+ if( mReferenceWidth > 0 )
+ scaleW = Math.max( metrics.widthPixels, metrics.heightPixels ) / (float) mReferenceWidth;
+ if( mReferenceHeight > 0 )
+ scaleH = Math.min( metrics.widthPixels, metrics.heightPixels ) / (float) mReferenceHeight;
+ scale = Math.min( scaleW, scaleH );
+ }
+ // Apply the global scaling factor (derived from user prefs)
+ scale *= mScalingFactor;
+
+ resize( w, h );
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see emu.project64.input.map.TouchMap#resize(int, int)
+ */
+ @Override
+ public void resize( int w, int h )
+ {
+ super.resize( w, h );
+
+ // Compute analog foreground location (centered)
+ if( analogBackImage != null && analogForeImage != null )
+ {
+ int cX = analogBackImage.x + (int) ( analogBackImage.hWidth * scale );
+ int cY = analogBackImage.y + (int) ( analogBackImage.hHeight * scale );
+ analogForeImage.setScale( scale );
+ analogForeImage.fitCenter( cX, cY, analogBackImage.x, analogBackImage.y,
+ (int) ( analogBackImage.width * scale ), (int) ( analogBackImage.height * scale ) );
+ }
+
+ // Compute auto-hold overlay locations
+ for( int i = 0; i < autoHoldImages.length; i++ )
+ {
+ if( autoHoldImages[i] != null )
+ {
+ autoHoldImages[i].setScale( scale );
+ autoHoldImages[i].fitPercent( autoHoldX[i], autoHoldY[i], w, h );
+ }
+ }
+ }
+
+ /**
+ * Draws the buttons.
+ *
+ * @param canvas The canvas on which to draw.
+ */
+ public void drawButtons( Canvas canvas )
+ {
+ // Draw the buttons onto the canvas
+ for( Image button : buttonImages )
+ {
+ button.draw( canvas );
+ }
+ }
+
+ /**
+ * Draws the AutoHold mask.
+ *
+ * @param canvas The canvas on which to draw.
+ */
+ public void drawAutoHold( Canvas canvas )
+ {
+ // Draw the AutoHold mask onto the canvas
+ for( Image autoHoldImage : autoHoldImages )
+ {
+ if( autoHoldImage != null )
+ {
+ autoHoldImage.draw( canvas );
+ }
+ }
+ }
+
+ /**
+ * Draws the analog stick.
+ *
+ * @param canvas The canvas on which to draw.
+ */
+ public void drawAnalog( Canvas canvas )
+ {
+ // Draw the background image
+ if( analogBackImage != null )
+ {
+ analogBackImage.draw( canvas );
+ }
+
+ // Draw the movable foreground (the stick)
+ if( analogForeImage != null )
+ {
+ analogForeImage.draw( canvas );
+ }
+ }
+
+ /**
+ * Updates the analog stick assets to reflect a new position.
+ *
+ * @param axisFractionX The x-axis fraction, between -1 and 1, inclusive.
+ * @param axisFractionY The y-axis fraction, between -1 and 1, inclusive.
+ *
+ * @return True if the analog assets changed.
+ */
+ public boolean updateAnalog( float axisFractionX, float axisFractionY )
+ {
+ if( analogForeImage != null && analogBackImage != null )
+ {
+ // Get the location of stick center
+ int hX = (int) ( ( analogBackImage.hWidth + ( axisFractionX * analogMaximum ) ) * scale );
+ int hY = (int) ( ( analogBackImage.hHeight - ( axisFractionY * analogMaximum ) ) * scale );
+
+ // Use other values if invalid
+ if( hX < 0 )
+ hX = (int) ( analogBackImage.hWidth * scale );
+ if( hY < 0 )
+ hY = (int) ( analogBackImage.hHeight * scale );
+
+ // Update the position of the stick
+ int cX = analogBackImage.x + hX;
+ int cY = analogBackImage.y + hY;
+ analogForeImage.fitCenter( cX, cY, analogBackImage.x, analogBackImage.y,
+ (int) ( analogBackImage.width * scale ), (int) ( analogBackImage.height * scale ) );
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Updates the auto-hold assets to reflect a new value.
+ *
+ * @param pressed The new autohold state value.
+ * @param index The index of the auto-hold mask.
+ *
+ * @return True if the autohold assets changed.
+ */
+ public boolean updateAutoHold( boolean pressed, int index )
+ {
+ if( autoHoldImages[index] != null )
+ {
+ if( pressed )
+ autoHoldImages[index].setAlpha( mTouchscreenTransparency );
+ else
+ autoHoldImages[index].setAlpha( 0 );
+ return true;
+ }
+ return false;
+ }
+
+ /**
+ * Loads all touch map data from the filesystem.
+ *
+ * @param skinDir The directory containing the skin.ini and image files.
+ * @param profile The name of the touchscreen profile.
+ * @param animated True to load the analog assets in two parts for animation.
+ * @param scale The factor to scale images by.
+ * @param alpha The opacity of the visible elements.
+ */
+ public void load( String skinDir, Profile profile, boolean animated, float scale, int alpha )
+ {
+ mScalingFactor = scale;
+ mTouchscreenTransparency = alpha;
+
+ super.load( skinDir, profile, animated );
+ ConfigFile skin_ini = new ConfigFile( skinFolder + "/skin.ini" );
+ mReferenceWidth = SafeMethods.toInt( skin_ini.get( "INFO", "referenceScreenWidth" ), 0 );
+ mReferenceHeight = SafeMethods.toInt( skin_ini.get( "INFO", "referenceScreenHeight" ), 0 );
+
+ // Scale the assets to the last screensize used
+ resize( cacheWidth, cacheHeight, cacheMetrics );
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see
+ * emu.project64.input.map.TouchMap#loadAllAssets(emu.project64
+ * .profile.Profile, boolean)
+ */
+ @Override
+ protected void loadAllAssets( Profile profile, boolean animated )
+ {
+ super.loadAllAssets( profile, animated );
+
+ // Set the transparency of the images
+ for( Image buttonImage : buttonImages )
+ {
+ buttonImage.setAlpha( mTouchscreenTransparency );
+ }
+ if( analogBackImage != null )
+ {
+ analogBackImage.setAlpha( mTouchscreenTransparency );
+ }
+ if( analogForeImage != null )
+ {
+ analogForeImage.setAlpha( mTouchscreenTransparency );
+ }
+
+ // Load the autohold images
+ if( profile != null )
+ {
+ loadAutoHoldImages( profile, "groupAB-holdA" );
+ loadAutoHoldImages( profile, "groupAB-holdB" );
+ loadAutoHoldImages( profile, "groupC-holdCu" );
+ loadAutoHoldImages( profile, "groupC-holdCd" );
+ loadAutoHoldImages( profile, "groupC-holdCl" );
+ loadAutoHoldImages( profile, "groupC-holdCr" );
+ loadAutoHoldImages( profile, "buttonL-holdL" );
+ loadAutoHoldImages( profile, "buttonR-holdR" );
+ loadAutoHoldImages( profile, "buttonZ-holdZ" );
+ loadAutoHoldImages( profile, "buttonS-holdS" );
+ }
+ }
+
+ /**
+ * Loads auto-hold assets and properties from the filesystem.
+ *
+ * @param profile The touchscreen profile containing the auto-hold properties.
+ * @param name The name of the image to load.
+ */
+ private void loadAutoHoldImages( Profile profile, String name )
+ {
+ if ( !name.contains("-hold") )
+ return;
+
+ String[] fields = name.split( "-hold" );
+ String group = fields[0];
+ String hold = fields[1];
+
+ int x = profile.getInt( group + "-x", -1 );
+ int y = profile.getInt( group + "-y", -1 );
+ Integer index = MASK_KEYS.get( hold );
+
+ if( x >= 0 && y >= 0 && index != null )
+ {
+ // Position (percentages of the digitizer dimensions)
+ autoHoldX[index] = x;
+ autoHoldY[index] = y;
+
+ // The drawable image is in PNG image format.
+ autoHoldImages[index] = new Image( mResources, skinFolder + "/" + name + ".png" );
+ autoHoldImages[index].setAlpha( 0 );
+ }
+ }
+}
diff --git a/Android/src/emu/project64/input/provider/AbstractProvider.java b/Android/src/emu/project64/input/provider/AbstractProvider.java
new file mode 100644
index 000000000..f8ac15f72
--- /dev/null
+++ b/Android/src/emu/project64/input/provider/AbstractProvider.java
@@ -0,0 +1,391 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2016 Project64. All rights reserved. *
+* Copyright (C) 2013 Paul Lamb
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.provider;
+
+import java.util.ArrayList;
+
+import emu.project64.AndroidDevice;
+import tv.ouya.console.api.OuyaController;
+import android.annotation.TargetApi;
+import android.view.InputDevice;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+
+/**
+ * The base class for transforming arbitrary input data into a common format.
+ *
+ * @see KeyProvider
+ * @see AxisProvider
+ * @see SensorProvider
+ * @see InputMap
+ */
+public abstract class AbstractProvider
+{
+ /** The offset used to construct the hardware ID for a MOGA controller. */
+ private static final int HARDWARE_ID_MOGA_OFFSET = 1000;
+
+ /** The maximum possible hardware ID for a MOGA controller, inclusive. */
+ private static final int HARDWARE_ID_MOGA_MAX = 1010;
+
+ /**
+ * The interface for listening to a provider.
+ */
+ public interface OnInputListener
+ {
+ /**
+ * Called when a single input has been dispatched.
+ *
+ * @param inputCode The universal input code that was dispatched.
+ * @param strength The input strength, between 0 and 1, inclusive.
+ * @param hardwareId The identifier of the source device.
+ */
+ public void onInput( int inputCode, float strength, int hardwareId );
+
+ /**
+ * Called when multiple inputs have been dispatched simultaneously.
+ *
+ * @param inputCodes The universal input codes that were dispatched.
+ * @param strengths The input strengths, between 0 and 1, inclusive.
+ * @param hardwareId The identifier of the source device.
+ */
+ public void onInput( int[] inputCodes, float[] strengths, int hardwareId );
+ }
+
+ /** The strength threshold above which an input is said to be "on". */
+ public static final float STRENGTH_THRESHOLD = 0.5f;
+
+ /** Listener management. */
+ private final ArrayList mPublisher;
+
+ /**
+ * Instantiates a new abstract provider.
+ */
+ protected AbstractProvider()
+ {
+ mPublisher = new ArrayList();
+ }
+
+ /**
+ * Registers a listener to start receiving input notifications.
+ *
+ * @param listener The listener to register. Null values are safe.
+ */
+ public void registerListener( AbstractProvider.OnInputListener listener )
+ {
+ if( ( listener != null ) && !mPublisher.contains( listener ) )
+ {
+ mPublisher.add( listener );
+ }
+ }
+
+ /**
+ * Unregisters a listener to stop receiving input notifications.
+ *
+ * @param listener The listener to unregister. Null values are safe.
+ */
+ public void unregisterListener( AbstractProvider.OnInputListener listener )
+ {
+ if( listener != null )
+ {
+ mPublisher.remove( listener );
+ }
+ }
+
+ /**
+ * Unregisters all listeners.
+ */
+ public void unregisterAllListeners()
+ {
+ mPublisher.clear();
+ }
+
+ /**
+ * Obtains unique hardware id from an input event.
+ *
+ * @param event The event generated by the hardware.
+ *
+ * @return The unique identifier of the hardware.
+ */
+ public static int getHardwareId( KeyEvent event )
+ {
+ // This might be replaced by something else in the future... so we abstract it
+ return event.getDeviceId();
+ }
+
+ /**
+ * Obtains unique hardware id from an input event.
+ *
+ * @param event The event generated by the hardware.
+ *
+ * @return The unique identifier of the hardware.
+ */
+ public static int getHardwareId( MotionEvent event )
+ {
+ // This might be replaced by something else in the future... so we abstract it
+ return event.getDeviceId();
+ }
+
+ /**
+ * Obtains unique hardware id from an input event.
+ *
+ * @param event The event generated by the hardware.
+ *
+ * @return The unique identifier of the hardware.
+ */
+ public static int getHardwareId( com.bda.controller.KeyEvent event )
+ {
+ // This might be replaced by something else in the future... so we abstract it
+ return event.getControllerId() + HARDWARE_ID_MOGA_OFFSET;
+ }
+
+ /**
+ * Obtains unique hardware id from an input event.
+ *
+ * @param event The event generated by the hardware.
+ *
+ * @return The unique identifier of the hardware.
+ */
+ public static int getHardwareId( com.bda.controller.MotionEvent event )
+ {
+ // This might be replaced by something else in the future... so we abstract it
+ return event.getControllerId() + HARDWARE_ID_MOGA_OFFSET;
+ }
+
+ /**
+ * Determines whether the hardware is available. This is a conservative test in that it will
+ * return true if the availability cannot be conclusively determined.
+ *
+ * @param id The unique hardware identifier.
+ *
+ * @return True if the associated hardware is available or indeterminate.
+ */
+ @TargetApi( 9 )
+ public static boolean isHardwareAvailable( int id )
+ {
+ // This might be replaced by something else in the future... so we abstract it
+ if( id > HARDWARE_ID_MOGA_OFFSET && id <= HARDWARE_ID_MOGA_MAX )
+ {
+ return true;
+ }
+ else if( AndroidDevice.IS_GINGERBREAD )
+ {
+ InputDevice device = InputDevice.getDevice( id );
+ return device != null;
+ }
+ else
+ {
+ return true;
+ }
+ }
+
+ /**
+ * Gets the human-readable name of the hardware.
+ *
+ * @param id The unique hardware identifier.
+ *
+ * @return The name of the hardware, or null if hardware not found.
+ */
+ @TargetApi( 9 )
+ public static String getHardwareName( int id )
+ {
+ if( id > HARDWARE_ID_MOGA_OFFSET && id <= HARDWARE_ID_MOGA_MAX )
+ {
+ return "moga-" + ( id - HARDWARE_ID_MOGA_OFFSET );
+ }
+ else if( AndroidDevice.IS_GINGERBREAD )
+ {
+ InputDevice device = InputDevice.getDevice( id );
+ return device == null ? null : device.getName();
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ /**
+ * Gets the human-readable name of the input.
+ *
+ * @param inputCode The universal input code.
+ *
+ * @return The name of the input.
+ */
+ @SuppressWarnings( "deprecation" )
+ @TargetApi( 12 )
+ public static String getInputName( int inputCode )
+ {
+ if( inputCode > 0 )
+ {
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ String name = null;
+ if( inputCode != -1 && AndroidDevice.IS_OUYA_HARDWARE )
+ {
+ if( inputCode == OuyaController.BUTTON_A )
+ name = "OUYA BUTTON_A";
+ else if( inputCode == OuyaController.BUTTON_DPAD_DOWN )
+ name = "OUYA BUTTON_DPAD_DOWN";
+ else if( inputCode == OuyaController.BUTTON_DPAD_LEFT )
+ name = "OUYA BUTTON_DPAD_LEFT";
+ else if( inputCode == OuyaController.BUTTON_DPAD_RIGHT )
+ name = "OUYA BUTTON_DPAD_RIGHT";
+ else if( inputCode == OuyaController.BUTTON_DPAD_UP )
+ name = "OUYA BUTTON_DPAD_UP";
+ else if( inputCode == OuyaController.BUTTON_L1 )
+ name = "OUYA BUTTON_L1";
+ else if( inputCode == OuyaController.BUTTON_L2 )
+ name = "OUYA BUTTON_L2";
+ else if( inputCode == OuyaController.BUTTON_L3 )
+ name = "OUYA BUTTON_L3";
+ else if( inputCode == OuyaController.BUTTON_MENU )
+ name = "OUYA BUTTON_MENU";
+ else if( inputCode == OuyaController.BUTTON_O )
+ name = "OUYA BUTTON_O";
+ else if( inputCode == OuyaController.BUTTON_R1 )
+ name = "OUYA BUTTON_R1";
+ else if( inputCode == OuyaController.BUTTON_R2 )
+ name = "OUYA BUTTON_R2";
+ else if( inputCode == OuyaController.BUTTON_R3 )
+ name = "OUYA BUTTON_R3";
+ else if( inputCode == OuyaController.BUTTON_U )
+ name = "OUYA BUTTON_U";
+ else if( inputCode == OuyaController.BUTTON_Y )
+ name = "OUYA BUTTON_Y";
+ }
+ if( name == null )
+ return KeyEvent.keyCodeToString( inputCode );
+ else
+ return name + " (" + KeyEvent.keyCodeToString( inputCode ) + ")";
+ }
+ else
+ return "KEYCODE_" + inputCode;
+ }
+ else if( inputCode < 0 )
+ {
+ int axis = inputToAxisCode( inputCode );
+ String direction = inputToAxisDirection( inputCode ) ? " (+)" : " (-)";
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ String name = null;
+ if( axis != -1 && AndroidDevice.IS_OUYA_HARDWARE )
+ {
+ if( axis == OuyaController.AXIS_L2 )
+ name = "OUYA AXIS_L2";
+ else if( axis == OuyaController.AXIS_LS_X )
+ name = "OUYA AXIS_LS_X";
+ else if( axis == OuyaController.AXIS_LS_Y )
+ name = "OUYA AXIS_LS_Y";
+ else if( axis == OuyaController.AXIS_R2 )
+ name = "OUYA AXIS_R2";
+ else if( axis == OuyaController.AXIS_RS_X )
+ name = "OUYA AXIS_RS_X";
+ else if( axis == OuyaController.AXIS_RS_Y )
+ name = "OUYA AXIS_RS_Y";
+ }
+ if( name == null )
+ return MotionEvent.axisToString( axis ) + direction;
+ else
+ return name + " (" + MotionEvent.axisToString( axis ) + ")" + direction;
+ }
+ else
+ return "AXIS_" + axis + direction;
+ }
+ else
+ return "NULL";
+ }
+
+ /**
+ * Gets the human-readable name of the input, appended with strength information.
+ *
+ * @param inputCode The universal input code.
+ * @param strength The input strength, between 0 and 1, inclusive.
+ *
+ * @return The name of the input.
+ */
+ public static String getInputName( int inputCode, float strength )
+ {
+ return getInputName( inputCode ) + ( inputCode == 0
+ ? ""
+ : String.format( " %4.2f", strength ) );
+ }
+
+ /**
+ * Utility for child classes. Converts an Android axis code to a universal input code.
+ *
+ * @param axisCode The Android axis code.
+ * @param positiveDirection Set true for positive Android axis, false for negative Android axis.
+ *
+ * @return The corresponding universal input code.
+ */
+ protected static int axisToInputCode( int axisCode, boolean positiveDirection )
+ {
+ // Axis codes are encoded to negative values (versus buttons which are positive). Axis codes
+ // are bit shifted by one so that the lowest bit can encode axis direction.
+ return -( ( axisCode ) * 2 + ( positiveDirection ? 1 : 2 ) );
+ }
+
+ /**
+ * Utility for child classes. Converts a universal input code to an Android axis code.
+ *
+ * @param inputCode The universal input code.
+ *
+ * @return The corresponding Android axis code.
+ */
+ protected static int inputToAxisCode( int inputCode )
+ {
+ return ( -inputCode - 1 ) / 2;
+ }
+
+ /**
+ * Utility for child classes. Converts a universal input code to an Android axis direction.
+ *
+ * @param inputCode The universal input code.
+ *
+ * @return True if the input code represents positive Android axis direction, false otherwise.
+ */
+ protected static boolean inputToAxisDirection( int inputCode )
+ {
+ return ( ( -inputCode ) % 2 ) == 1;
+ }
+
+ /**
+ * Notifies listeners that a single input was dispatched. Subclasses should invoke this method
+ * to publish their input data.
+ *
+ * @param inputCode The universal input code that was dispatched.
+ * @param strength The input strength, between 0 and 1, inclusive.
+ * @param hardwareId The identifier of the source device.
+ */
+ protected void notifyListeners( int inputCode, float strength, int hardwareId )
+ {
+ for( OnInputListener listener : mPublisher )
+ {
+ listener.onInput( inputCode, strength, hardwareId );
+ }
+ }
+
+ /**
+ * Notifies listeners that multiple inputs were dispatched simultaneously. Subclasses should
+ * invoke this method to publish their input data.
+ *
+ * @param inputCodes The universal input codes that were dispatched.
+ * @param strengths The input strengths, between 0 and 1, inclusive.
+ * @param hardwareId The identifier of the source device.
+ */
+ protected void notifyListeners( int[] inputCodes, float[] strengths, int hardwareId )
+ {
+ for( OnInputListener listener : mPublisher )
+ {
+ listener.onInput( inputCodes.clone(), strengths.clone(), hardwareId );
+ }
+ }
+}
diff --git a/Android/src/emu/project64/input/provider/AxisProvider.java b/Android/src/emu/project64/input/provider/AxisProvider.java
new file mode 100644
index 000000000..424645290
--- /dev/null
+++ b/Android/src/emu/project64/input/provider/AxisProvider.java
@@ -0,0 +1,193 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2016 Project64. All rights reserved. *
+* Copyright (C) 2013 Paul Lamb, littleguy77
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.provider;
+
+import emu.project64.AndroidDevice;
+import emu.project64.input.map.AxisMap;
+import android.annotation.TargetApi;
+import android.view.InputDevice;
+import android.view.InputDevice.MotionRange;
+import android.view.MotionEvent;
+import android.view.View;
+
+/**
+ * A class for transforming Android MotionEvent inputs into a common format.
+ */
+public class AxisProvider extends AbstractProvider
+{
+ /** The input codes to listen for. */
+ private int[] mInputCodes;
+
+ /** The default number of input codes to listen for. */
+ private static final int DEFAULT_NUM_INPUTS = 128;
+
+ /**
+ * Instantiates a new axis provider.
+ */
+ @TargetApi( 12 )
+ public AxisProvider()
+ {
+ // By default, provide data from all possible axes
+ mInputCodes = new int[DEFAULT_NUM_INPUTS];
+ for( int i = 0; i < mInputCodes.length; i++ )
+ mInputCodes[i] = -( i + 1 );
+ }
+
+ /**
+ * Instantiates a new axis provider.
+ *
+ * @param view The view receiving MotionEvent data.
+ */
+ @TargetApi( 12 )
+ public AxisProvider( View view )
+ {
+ this();
+
+ // Connect the input source
+ view.setOnGenericMotionListener( new GenericMotionListener() );
+
+ // Request focus for proper listening
+ view.requestFocus();
+ }
+
+ /**
+ * Restricts listening to a set of universal input codes.
+ *
+ * @param inputCodeFilter The new input codes to listen for.
+ */
+ public void setInputCodeFilter( int[] inputCodeFilter )
+ {
+ mInputCodes = inputCodeFilter.clone();
+ }
+
+ /**
+ * Manually dispatches a MotionEvent through the provider's listening chain.
+ *
+ * @param event The MotionEvent object containing full information about the event.
+ *
+ * @return True if the listener has consumed the event, false otherwise.
+ */
+ public boolean onGenericMotion( MotionEvent event )
+ {
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ return new GenericMotionListener().onGenericMotion( null, event );
+ else
+ return false;
+ }
+
+ /**
+ * Just an indirection class that eliminates some logcat chatter about benign errors. If we make
+ * the parent class implement View.OnGenericMotionListener, then we get logcat error messages
+ * even if we conditionally exclude calls to the class based on API. These errors are not
+ * actually harmful, so the logcat messages are simply a nuisance during debugging.
+ *
+ * For a detailed explanation, see here.
+ */
+ @TargetApi( 12 )
+ public class GenericMotionListener implements View.OnGenericMotionListener
+ {
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View.OnGenericMotionListener#onGenericMotion(android.view.View,
+ * android.view.MotionEvent)
+ */
+ @Override
+ public boolean onGenericMotion( View v, MotionEvent event )
+ {
+ // Ignore motion events from non-joysticks (mice are a problem)
+ if( event.getSource() != InputDevice.SOURCE_JOYSTICK )
+ return false;
+
+ InputDevice device = event.getDevice();
+ AxisMap axisInfo = AxisMap.getMap( device );
+
+ // Read all the requested axes
+ float[] strengths = new float[mInputCodes.length];
+ for( int i = 0; i < mInputCodes.length; i++ )
+ {
+ int inputCode = mInputCodes[i];
+
+ // Compute the axis code from the input code
+ int axisCode = inputToAxisCode( inputCode );
+
+ // Get the analog value using the Android API
+ float strength = event.getAxisValue( axisCode );
+
+ // Modify strength if necessary
+ strength = normalizeStrength( strength, axisInfo, device, axisCode );
+
+ // If the strength points in the correct direction, record it
+ boolean direction1 = inputToAxisDirection( inputCode );
+ boolean direction2 = strength > 0;
+ if( direction1 == direction2 )
+ strengths[i] = Math.abs( strength );
+ else
+ strengths[i] = 0;
+ }
+
+ // Notify listeners about new input data
+ notifyListeners( mInputCodes, strengths, getHardwareId( event ) );
+
+ return true;
+ }
+
+ private float normalizeStrength( float strength, AxisMap axisInfo, InputDevice device,
+ int axisCode )
+ {
+ if( axisInfo != null )
+ {
+ int axisClass = axisInfo.getClass( axisCode );
+
+ if( axisClass == AxisMap.AXIS_CLASS_IGNORED )
+ {
+ // We should ignore this axis
+ strength = 0;
+ }
+ else if( device != null )
+ {
+ // We should normalize this axis
+ MotionRange motionRange = device.getMotionRange( axisCode, InputDevice.SOURCE_JOYSTICK );
+ if( motionRange != null )
+ {
+ switch( axisClass )
+ {
+ case AxisMap.AXIS_CLASS_STICK:
+ // Normalize to [-1,1]
+ strength = ( strength - motionRange.getMin() ) / motionRange.getRange() * 2f - 1f;
+ break;
+ case AxisMap.AXIS_CLASS_TRIGGER:
+ // Normalize to [0,1]
+ strength = ( strength - motionRange.getMin() ) / motionRange.getRange();
+ break;
+ case AxisMap.AXIS_CLASS_N64_USB_STICK:
+ // Normalize to [-1,1]
+ // The Raphnet adapters through v2.x and some other USB adapters assume the N64
+ // controller produces values in the range [-127,127]. However, the official N64 spec
+ // says that raw values of +/- 80 indicate full strength. Therefore we rescale by
+ // multiplying by 127/80 (dividing by 0.63).
+ // http://naesten.dyndns.org:8080/psyq/man/os/osContGetReadData.html
+ // http://raphnet-tech.com/products/gc_n64_usb_adapters/
+ strength = strength / 0.63f;
+ break;
+ case AxisMap.AXIS_CLASS_UNKNOWN:
+ default:
+ // Do nothing
+ }
+ }
+ }
+ }
+ return strength;
+ }
+ }
+}
diff --git a/Android/src/emu/project64/input/provider/KeyProvider.java b/Android/src/emu/project64/input/provider/KeyProvider.java
new file mode 100644
index 000000000..68903d357
--- /dev/null
+++ b/Android/src/emu/project64/input/provider/KeyProvider.java
@@ -0,0 +1,172 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2016 Project64. All rights reserved. *
+* Copyright (C) 2013 Paul Lamb, littleguy77
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.provider;
+
+import java.util.List;
+
+import android.app.AlertDialog.Builder;
+import android.content.DialogInterface;
+import android.view.KeyEvent;
+import android.view.View;
+
+/**
+ * A class for transforming Android KeyEvent inputs into a common format.
+ */
+public class KeyProvider extends AbstractProvider implements View.OnKeyListener,
+ DialogInterface.OnKeyListener
+{
+ /**
+ * The formula for decoding KeyEvent data for specific Android IMEs.
+ */
+ public enum ImeFormula
+ {
+ /** The default decoding formula. */
+ DEFAULT,
+ /** The formula for USB/BT Joystick Center, by Poke64738. */
+ USB_BT_JOYSTICK_CENTER,
+ /** The formula for BT Controller, by droidbean. */
+ BT_CONTROLLER,
+ /** An example decoding formula. */
+ EXAMPLE_IME
+ }
+
+ /** The IME formula for decoding KeyEvent data. */
+ private final ImeFormula mImeFormula;
+
+ /** The list of key codes that should be ignored. */
+ private final List mIgnoredCodes;
+
+ /**
+ * Instantiates a new key provider.
+ *
+ * @param formula The decoding formula to be used.
+ * @param ignoredCodes List of key codes that should be ignored.
+ */
+ public KeyProvider( ImeFormula formula, List ignoredCodes )
+ {
+ // Assign the fields
+ mImeFormula = formula;
+ mIgnoredCodes = ignoredCodes;
+ }
+
+ /**
+ * Instantiates a new key provider.
+ *
+ * @param view The view receiving KeyEvent data.
+ * @param formula The decoding formula to be used.
+ * @param ignoredCodes List of key codes that should be ignored.
+ */
+ public KeyProvider( View view, ImeFormula formula, List ignoredCodes )
+ {
+ this( formula, ignoredCodes );
+
+ // Connect the input source
+ view.setOnKeyListener( this );
+
+ // Request focus for proper listening
+ view.requestFocus();
+ }
+
+ /**
+ * Instantiates a new key provider.
+ *
+ * @param builder The builder for the dialog receiving KeyEvent data.
+ * @param formula The decoding formula to be used.
+ * @param ignoredCodes List of key codes that should be ignored.
+ */
+ public KeyProvider( Builder builder, ImeFormula formula, List ignoredCodes )
+ {
+ this( formula, ignoredCodes );
+
+ // Connect the input source
+ builder.setOnKeyListener( this );
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.view.View.OnKeyListener#onKey(android.view.View, int, android.view.KeyEvent)
+ */
+ @Override
+ public boolean onKey( View v, int keyCode, KeyEvent event )
+ {
+ return onKey( keyCode, event );
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see android.content.DialogInterface.OnKeyListener#onKey(android.content.DialogInterface,
+ * int, android.view.KeyEvent)
+ */
+ @Override
+ public boolean onKey( DialogInterface dialog, int keyCode, KeyEvent event )
+ {
+ return onKey( keyCode, event );
+ }
+
+ /**
+ * Manually dispatches a KeyEvent through the provider's listening chain.
+ *
+ * @param keyCode The code for the physical key that was pressed.
+ * @param event The KeyEvent object containing full information about the event.
+ *
+ * @return True if the listener has consumed the event, false otherwise.
+ */
+ public boolean onKey( int keyCode, KeyEvent event )
+ {
+ // Ignore specified key codes
+ if( mIgnoredCodes != null && mIgnoredCodes.contains( keyCode ) )
+ {
+ return false;
+ }
+
+ // Translate input code and analog strength (ranges between 0.0 and 1.0)
+ int inputCode;
+ float strength;
+ if( keyCode <= 0xFF )
+ {
+ // Ordinary key/button changed state
+ inputCode = keyCode;
+ strength = 1;
+ }
+ else
+ {
+ // Analog axis changed state, decode using IME-specific formula
+ switch( mImeFormula )
+ {
+ case DEFAULT:
+ case USB_BT_JOYSTICK_CENTER:
+ case BT_CONTROLLER:
+ default:
+ // Formula defined between paulscode and poke64738
+ inputCode = keyCode / 100;
+ strength = ( (float) keyCode % 100 ) / 64f;
+ break;
+ case EXAMPLE_IME:
+ // Low byte stores input code, high byte stores strength
+ inputCode = keyCode & 0xFF;
+ strength = ( (float) ( keyCode >> 8 ) ) / 0xFF;
+ break;
+ }
+ }
+
+ // Strength is zero when the button/axis is released
+ if( event.getAction() == KeyEvent.ACTION_UP )
+ strength = 0;
+
+ // Notify listeners about new input data
+ notifyListeners( inputCode, strength, getHardwareId( event ) );
+
+ return true;
+ }
+}
diff --git a/Android/src/emu/project64/input/provider/MogaProvider.java b/Android/src/emu/project64/input/provider/MogaProvider.java
new file mode 100644
index 000000000..7d1e13218
--- /dev/null
+++ b/Android/src/emu/project64/input/provider/MogaProvider.java
@@ -0,0 +1,97 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2016 Project64. All rights reserved. *
+* Copyright (C) 2013 Paul Lamb, littleguy77
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.input.provider;
+
+import android.os.Handler;
+
+import com.bda.controller.Controller;
+import com.bda.controller.ControllerListener;
+import com.bda.controller.KeyEvent;
+import com.bda.controller.MotionEvent;
+import com.bda.controller.StateEvent;
+
+/**
+ * A class for transforming MOGA input events into a common format.
+ */
+public class MogaProvider extends AbstractProvider implements ControllerListener
+{
+ private final Controller mController;
+ private final int[] mInputCodes;
+
+ /**
+ * Instantiates a new MOGA provider.
+ */
+ public MogaProvider( Controller controller )
+ {
+ mController = controller;
+ mController.setListener( this, new Handler() );
+
+ mInputCodes = new int[10];
+ //@formatter:off
+ mInputCodes[0] = axisToInputCode( MotionEvent.AXIS_X, true );
+ mInputCodes[1] = axisToInputCode( MotionEvent.AXIS_X, false );
+ mInputCodes[2] = axisToInputCode( MotionEvent.AXIS_Y, true );
+ mInputCodes[3] = axisToInputCode( MotionEvent.AXIS_Y, false );
+ mInputCodes[4] = axisToInputCode( MotionEvent.AXIS_Z, true );
+ mInputCodes[5] = axisToInputCode( MotionEvent.AXIS_Z, false );
+ mInputCodes[6] = axisToInputCode( MotionEvent.AXIS_RZ, true );
+ mInputCodes[7] = axisToInputCode( MotionEvent.AXIS_RZ, false );
+ mInputCodes[8] = axisToInputCode( MotionEvent.AXIS_LTRIGGER, true );
+ mInputCodes[9] = axisToInputCode( MotionEvent.AXIS_RTRIGGER, true );
+ //@formatter:on
+ }
+
+ @Override
+ public void onKeyEvent( KeyEvent event )
+ {
+ int inputCode = event.getKeyCode();
+ float strength = event.getAction() == KeyEvent.ACTION_DOWN ? 1 : 0;
+ int hardwareId = getHardwareId( event );
+
+ // Notify listeners about new input data
+ notifyListeners( inputCode, strength, hardwareId );
+ }
+
+ @Override
+ public void onMotionEvent( MotionEvent event )
+ {
+ // Read all the requested axes
+ float[] strengths = new float[mInputCodes.length];
+ for( int i = 0; i < mInputCodes.length; i++ )
+ {
+ int inputCode = mInputCodes[i];
+
+ // Compute the axis code from the input code
+ int axisCode = inputToAxisCode( inputCode );
+
+ // Get the analog value using the MOGA API
+ float strength = event.getAxisValue( axisCode );
+
+ // If the strength points in the correct direction, record it
+ boolean direction1 = inputToAxisDirection( inputCode );
+ boolean direction2 = strength > 0;
+ if( direction1 == direction2 )
+ strengths[i] = Math.abs( strength );
+ else
+ strengths[i] = 0;
+ }
+ int hardwareId = getHardwareId( event );
+
+ // Notify listeners about new input data
+ notifyListeners( mInputCodes, strengths, hardwareId );
+ }
+
+ @Override
+ public void onStateEvent( StateEvent arg0 )
+ {
+ }
+}
diff --git a/Android/src/emu/project64/jni/NativeConstants.java b/Android/src/emu/project64/jni/NativeConstants.java
new file mode 100644
index 000000000..e20da1250
--- /dev/null
+++ b/Android/src/emu/project64/jni/NativeConstants.java
@@ -0,0 +1,21 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+public class NativeConstants
+{
+ // @formatter:off
+ public static final int EMULATOR_STATE_UNKNOWN = 0;
+ public static final int EMULATOR_STATE_IDLE = 1;
+ public static final int EMULATOR_STATE_RUNNING = 2;
+ public static final int EMULATOR_STATE_PAUSED = 3;
+ // @formatter:on
+}
diff --git a/Android/src/emu/project64/jni/NativeExports.java b/Android/src/emu/project64/jni/NativeExports.java
new file mode 100644
index 000000000..e7962625d
--- /dev/null
+++ b/Android/src/emu/project64/jni/NativeExports.java
@@ -0,0 +1,54 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+import android.app.Activity;
+import emu.project64.game.GameSurface;
+
+public class NativeExports
+{
+ static
+ {
+ System.loadLibrary( "Project64-bridge" );
+ }
+
+ public static native void appInit (String BaseDir );
+ public static native String appVersion();
+ public static native void StopEmulation();
+ public static native void StartEmulation();
+ public static native void CloseSystem();
+ public static native void SettingsSaveBool(int type, boolean value);
+ public static native void SettingsSaveDword(int type, int value);
+ public static native void SettingsSaveString(int type, String value);
+ public static native boolean SettingsLoadBool(int type);
+ public static native int SettingsLoadDword(int type);
+ public static native String SettingsLoadString(int type);
+ public static native boolean IsSettingSet(int type);
+ public static native void LoadGame(String FileLoc);
+ public static native void StartGame(Activity activity, GameSurface.GLThread thread);
+ public static native void LoadRomList();
+ public static native void RefreshRomDir(String RomDir, boolean Recursive);
+ public static native void ExternalEvent(int Type);
+ public static native void ResetApplicationSettings();
+
+ public static native void onSurfaceCreated();
+ public static native void onSurfaceChanged(int width, int height);
+ public static native void onDrawFrame();
+
+ public static native void UISettingsSaveBool(int Type, boolean Value);
+ public static native void UISettingsSaveDword(int Type, int Value);
+ public static native void UISettingsSaveString(int type, String value);
+
+ public static native boolean UISettingsLoadBool(int Type);
+ public static native int UISettingsLoadDword(int Type);
+ public static native String UISettingsLoadString(int type);
+ public static native String UISettingsLoadStringIndex(int Type, int Index);
+}
diff --git a/Android/src/emu/project64/jni/NativeInput.java b/Android/src/emu/project64/jni/NativeInput.java
new file mode 100644
index 000000000..04b1884fc
--- /dev/null
+++ b/Android/src/emu/project64/jni/NativeInput.java
@@ -0,0 +1,36 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+/**
+ * Calls made between the native input-android library and Java. Any function names changed here
+ * should also be changed in the corresponding C code, and vice versa.
+ *
+ * @see /Source/Android/PluginInput/Main.cpp
+ * @see CoreInterface
+ */
+public class NativeInput
+{
+ static
+ {
+ System.loadLibrary( "Project64-input-android" );
+ }
+
+ /**
+ * Set the button/axis state of a controller.
+ *
+ * @param controllerNum Controller index, in the range [0,3].
+ * @param buttons The pressed state of the buttons.
+ * @param axisX The analog value of the x-axis, in the range [-80,80].
+ * @param axisY The analog value of the y-axis, in the range [-80,80].
+ */
+ public static native void setState( int controllerNum, boolean[] buttons, int axisX, int axisY );
+}
diff --git a/Android/src/emu/project64/jni/NativeXperiaTouchpad.java b/Android/src/emu/project64/jni/NativeXperiaTouchpad.java
new file mode 100644
index 000000000..a9bd219b1
--- /dev/null
+++ b/Android/src/emu/project64/jni/NativeXperiaTouchpad.java
@@ -0,0 +1,27 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+import android.content.Context;
+import android.view.View;
+
+public class NativeXperiaTouchpad extends View
+{
+ /**
+ * Instantiates a new native input source.
+ *
+ * @param context The context associated with the input events.
+ */
+ public NativeXperiaTouchpad( Context context )
+ {
+ super( context );
+ }
+}
diff --git a/Android/src/emu/project64/jni/SettingsID.java b/Android/src/emu/project64/jni/SettingsID.java
new file mode 100644
index 000000000..80d27bd5a
--- /dev/null
+++ b/Android/src/emu/project64/jni/SettingsID.java
@@ -0,0 +1,320 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+public enum SettingsID
+{
+ //Default values
+ Default_None,
+ Default_Constant,
+
+ //Command Settings
+ Cmd_BaseDirectory,
+ Cmd_RomFile,
+ Cmd_ShowHelp,
+
+ //Support Files
+ SupportFile_Settings,
+ SupportFile_SettingsDefault,
+ SupportFile_RomDatabase,
+ SupportFile_RomDatabaseDefault,
+ SupportFile_Glide64RDB,
+ SupportFile_Glide64RDBDefault,
+ SupportFile_Cheats,
+ SupportFile_CheatsDefault,
+ SupportFile_Notes,
+ SupportFile_NotesDefault,
+ SupportFile_ExtInfo,
+ SupportFile_ExtInfoDefault,
+
+ //Settings
+ Setting_ApplicationName,
+ Setting_UseFromRegistry,
+ Setting_RdbEditor,
+ Setting_CN64TimeCritical,
+ Setting_AutoStart,
+ Setting_CheckEmuRunning,
+ Setting_EraseGameDefaults,
+
+ Setting_AutoZipInstantSave,
+ Setting_RememberCheats,
+ Setting_UniqueSaveDir,
+ Setting_LanguageDir,
+ Setting_LanguageDirDefault,
+ Setting_CurrentLanguage,
+ Setting_EnableDisk,
+
+ //RDB Settings
+ Rdb_GoodName,
+ Rdb_SaveChip,
+ Rdb_CpuType,
+ Rdb_RDRamSize,
+ Rdb_CounterFactor,
+ Rdb_UseTlb,
+ Rdb_DelayDP,
+ Rdb_DelaySi,
+ Rdb_32Bit,
+ Rdb_FastSP,
+ Rdb_FixedAudio,
+ Rdb_SyncViaAudio,
+ Rdb_RspAudioSignal,
+ Rdb_TLB_VAddrStart,
+ Rdb_TLB_VAddrLen,
+ Rdb_TLB_PAddrStart,
+ Rdb_UseHleGfx,
+ Rdb_UseHleAudio,
+ Rdb_LoadRomToMemory,
+ Rdb_ScreenHertz,
+ Rdb_FuncLookupMode,
+ Rdb_RegCache,
+ Rdb_BlockLinking,
+ Rdb_SMM_StoreInstruc,
+ Rdb_SMM_Cache,
+ Rdb_SMM_PIDMA,
+ Rdb_SMM_TLB,
+ Rdb_SMM_Protect,
+ Rdb_SMM_ValidFunc,
+ Rdb_GameCheatFix,
+ Rdb_GameCheatFixPlugin,
+ Rdb_ViRefreshRate,
+ Rdb_AiCountPerBytes,
+ Rdb_AudioResetOnLoad,
+ Rdb_AllowROMWrites,
+ Rdb_CRC_Recalc,
+
+ //Individual Game Settings
+ Game_IniKey,
+ Game_File,
+ Game_UniqueSaveDir,
+ Game_GameName,
+ Game_GoodName,
+ Game_TempLoaded,
+ Game_SystemType,
+ Game_EditPlugin_Gfx,
+ Game_EditPlugin_Audio,
+ Game_EditPlugin_Contr,
+ Game_EditPlugin_RSP,
+ Game_Plugin_Gfx,
+ Game_Plugin_Audio,
+ Game_Plugin_Controller,
+ Game_Plugin_RSP,
+ Game_SaveChip,
+ Game_CpuType,
+ Game_LastSaveSlot,
+ Game_FixedAudio,
+ Game_SyncViaAudio,
+ Game_32Bit,
+ Game_SMM_Cache,
+ Game_SMM_Protect,
+ Game_SMM_ValidFunc,
+ Game_SMM_PIDMA,
+ Game_SMM_TLB,
+ Game_SMM_StoreInstruc,
+ Game_CurrentSaveState,
+ Game_LastSaveTime,
+ Game_RDRamSize,
+ Game_CounterFactor,
+ Game_UseTlb,
+ Game_DelayDP,
+ Game_DelaySI,
+ Game_FastSP,
+ Game_FuncLookupMode,
+ Game_RegCache,
+ Game_BlockLinking,
+ Game_ScreenHertz,
+ Game_RspAudioSignal,
+ Game_UseHleGfx,
+ Game_UseHleAudio,
+ Game_LoadRomToMemory,
+ Game_ViRefreshRate,
+ Game_AiCountPerBytes,
+ Game_AudioResetOnLoad,
+ Game_AllowROMWrites,
+ Game_CRC_Recalc,
+ Game_Transferpak_ROM,
+ Game_Transferpak_Sav,
+
+ // General Game running info
+ GameRunning_LoadingInProgress,
+ GameRunning_CPU_Running,
+ GameRunning_CPU_Paused,
+ GameRunning_CPU_PausedType,
+ GameRunning_InstantSaveFile,
+ GameRunning_LimitFPS,
+ GameRunning_ScreenHertz,
+ GameRunning_InReset,
+
+ //User Interface
+ UserInterface_BasicMode,
+ UserInterface_ShowCPUPer,
+ UserInterface_DisplayFrameRate,
+ UserInterface_FrameDisplayType,
+
+ //Directory Info
+ Directory_Plugin,
+ Directory_PluginInitial,
+ Directory_PluginSelected,
+ Directory_PluginUseSelected,
+ Directory_PluginSync,
+ Directory_PluginSyncInitial,
+ Directory_PluginSyncSelected,
+ Directory_PluginSyncUseSelected,
+ Directory_SnapShot,
+ Directory_SnapShotInitial,
+ Directory_SnapShotSelected,
+ Directory_SnapShotUseSelected,
+ Directory_NativeSave,
+ Directory_NativeSaveInitial,
+ Directory_NativeSaveSelected,
+ Directory_NativeSaveUseSelected,
+ Directory_InstantSave,
+ Directory_InstantSaveInitial,
+ Directory_InstantSaveSelected,
+ Directory_InstantSaveUseSelected,
+ Directory_Texture,
+ Directory_TextureInitial,
+ Directory_TextureSelected,
+ Directory_TextureUseSelected,
+ Directory_Log,
+ Directory_LogInitial,
+ Directory_LogSelected,
+ Directory_LogUseSelected,
+
+ //Rom List
+ RomList_RomListCache,
+ RomList_RomListCacheDefault,
+ RomList_GameDir,
+ RomList_GameDirInitial,
+ RomList_GameDirSelected,
+ RomList_GameDirUseSelected,
+ RomList_GameDirRecursive,
+ RomList_7zipCache,
+ RomList_7zipCacheDefault,
+
+ //File Info
+ File_DiskIPLPath,
+
+ //Debugger
+ Debugger_Enabled,
+ Debugger_ShowTLBMisses,
+ Debugger_ShowUnhandledMemory,
+ Debugger_ShowPifErrors,
+ Debugger_ShowDivByZero,
+ Debugger_GenerateLogFiles,
+ Debugger_DisableGameFixes,
+ Debugger_AppLogLevel,
+ Debugger_AppLogFlush,
+ Debugger_ShowDListAListCount,
+ Debugger_ShowRecompMemSize,
+ Debugger_DebugLanguage,
+ Debugger_RecordExecutionTimes,
+
+ //Trace
+ Debugger_TraceMD5,
+ Debugger_TraceThread,
+ Debugger_TracePath,
+ Debugger_TraceSettings,
+ Debugger_TraceUnknown,
+ Debugger_TraceAppInit,
+ Debugger_TraceAppCleanup,
+ Debugger_TraceN64System,
+ Debugger_TracePlugins,
+ Debugger_TraceGFXPlugin,
+ Debugger_TraceAudioPlugin,
+ Debugger_TraceControllerPlugin,
+ Debugger_TraceRSPPlugin,
+ Debugger_TraceRSP,
+ Debugger_TraceAudio,
+ Debugger_TraceRegisterCache,
+ Debugger_TraceRecompiler,
+ Debugger_TraceTLB,
+ Debugger_TraceProtectedMEM,
+ Debugger_TraceUserInterface,
+ Debugger_TraceRomList,
+ Debugger_TraceExceptionHandler,
+
+ //Plugins
+ Plugin_RSP_Current,
+ Plugin_RSP_CurVer,
+ Plugin_GFX_Current,
+ Plugin_GFX_CurVer,
+ Plugin_AUDIO_Current,
+ Plugin_AUDIO_CurVer,
+ Plugin_CONT_Current,
+ Plugin_CONT_CurVer,
+ Plugin_UseHleGfx,
+ Plugin_UseHleAudio,
+ Plugin_EnableAudio,
+ Plugin_ForceGfxReset,
+
+ Logging_GenerateLog,
+ Logging_LogRDRamRegisters,
+ Logging_LogSPRegisters,
+ Logging_LogDPCRegisters,
+ Logging_LogDPSRegisters,
+ Logging_LogMIPSInterface,
+ Logging_LogVideoInterface,
+ Logging_LogAudioInterface,
+ Logging_LogPerInterface,
+ Logging_LogRDRAMInterface,
+ Logging_LogSerialInterface,
+ Logging_LogPRDMAOperations,
+ Logging_LogPRDirectMemLoads,
+ Logging_LogPRDMAMemLoads,
+ Logging_LogPRDirectMemStores,
+ Logging_LogPRDMAMemStores,
+ Logging_LogControllerPak,
+ Logging_LogCP0changes,
+ Logging_LogCP0reads,
+ Logging_LogTLB,
+ Logging_LogExceptions,
+ Logging_NoInterrupts,
+ Logging_LogCache,
+ Logging_LogRomHeader,
+ Logging_LogUnknown,
+
+ //Cheats
+ Cheat_Entry,
+ Cheat_Active,
+ Cheat_Extension,
+ Cheat_Notes,
+ Cheat_Options,
+ Cheat_Range,
+ Cheat_RangeNotes,
+
+ /*, FirstUISettings, LastUISettings = FirstUISettings + MaxPluginSetting,
+ FirstRSPDefaultSet, LastRSPDefaultSet = FirstRSPDefaultSet + MaxPluginSetting,
+ FirstRSPSettings, LastRSPSettings = FirstRSPSettings + MaxPluginSetting,
+ FirstGfxDefaultSet, LastGfxDefaultSet = FirstGfxDefaultSet + MaxPluginSetting,
+ FirstGfxSettings, LastGfxSettings = FirstGfxSettings + MaxPluginSetting,
+ FirstAudioDefaultSet, LastAudioDefaultSet = FirstAudioDefaultSet + MaxPluginSetting,
+ FirstAudioSettings, LastAudioSettings = FirstAudioSettings + MaxPluginSetting,
+ FirstCtrlDefaultSet, LastCtrlDefaultSet = FirstCtrlDefaultSet + MaxPluginSetting,
+ FirstCtrlSettings, LastCtrlSettings = FirstCtrlSettings + MaxPluginSetting,
+ ;*/
+ ;
+ private int value;
+
+ public int getValue()
+ {
+ return this.value;
+ }
+ private static final class StaticFields
+ {
+ public static int Counter = 0;
+ }
+
+ private SettingsID()
+ {
+ this.value = StaticFields.Counter;
+ StaticFields.Counter += 1;
+ }
+}
\ No newline at end of file
diff --git a/Android/src/emu/project64/jni/SystemEvent.java b/Android/src/emu/project64/jni/SystemEvent.java
new file mode 100644
index 000000000..d216c8361
--- /dev/null
+++ b/Android/src/emu/project64/jni/SystemEvent.java
@@ -0,0 +1,70 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+public enum SystemEvent
+{
+ SysEvent_ExecuteInterrupt,
+ SysEvent_GSButtonPressed,
+ SysEvent_ResetCPU_Soft,
+ SysEvent_ResetCPU_SoftDone,
+ SysEvent_ResetCPU_Hard,
+ SysEvent_CloseCPU,
+ SysEvent_PauseCPU_FromMenu,
+ SysEvent_PauseCPU_AppLostActive,
+ SysEvent_PauseCPU_AppLostActiveDelay,
+ SysEvent_PauseCPU_AppLostFocus,
+ SysEvent_PauseCPU_SaveGame,
+ SysEvent_PauseCPU_LoadGame,
+ SysEvent_PauseCPU_DumpMemory,
+ SysEvent_PauseCPU_SearchMemory,
+ SysEvent_PauseCPU_Settings,
+ SysEvent_PauseCPU_Cheats,
+ SysEvent_ResumeCPU_FromMenu,
+ SysEvent_ResumeCPU_AppGainedActive,
+ SysEvent_ResumeCPU_AppGainedFocus,
+ SysEvent_ResumeCPU_SaveGame,
+ SysEvent_ResumeCPU_LoadGame,
+ SysEvent_ResumeCPU_DumpMemory,
+ SysEvent_ResumeCPU_SearchMemory,
+ SysEvent_ResumeCPU_Settings,
+ SysEvent_ResumeCPU_Cheats,
+ SysEvent_ChangingFullScreen,
+ SysEvent_ChangePlugins,
+ SysEvent_SaveMachineState,
+ SysEvent_LoadMachineState,
+ SysEvent_Interrupt_SP,
+ SysEvent_Interrupt_SI,
+ SysEvent_Interrupt_AI,
+ SysEvent_Interrupt_VI,
+ SysEvent_Interrupt_PI,
+ SysEvent_Interrupt_DP,
+ SysEvent_ResetFunctionTimes,
+ SysEvent_DumpFunctionTimes,
+ ;
+
+ private int value;
+
+ public int getValue()
+ {
+ return this.value;
+ }
+ private static final class StaticFields
+ {
+ public static int Counter = 0;
+ }
+
+ private SystemEvent()
+ {
+ this.value = StaticFields.Counter;
+ StaticFields.Counter += 1;
+ }
+}
diff --git a/Android/src/emu/project64/jni/UISettingID.java b/Android/src/emu/project64/jni/UISettingID.java
new file mode 100644
index 000000000..f498e1792
--- /dev/null
+++ b/Android/src/emu/project64/jni/UISettingID.java
@@ -0,0 +1,49 @@
+/****************************************************************************
+* *
+* Project 64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.jni;
+
+public enum UISettingID
+{
+ Asserts_Version,
+ Screen_Orientation,
+
+ //Recent Game
+ File_RecentGameFileCount,
+ File_RecentGameFileIndex,
+
+ //Touch Screen
+ TouchScreen_ButtonScale,
+ TouchScreen_Layout,
+
+ //Controller Config
+ Controller_ConfigFile,
+ Controller_CurrentProfile,
+ Controller_Deadzone,
+ Controller_Sensitivity,
+ ;
+
+ private int value;
+
+ public int getValue()
+ {
+ return this.value;
+ }
+ private static final class StaticFields
+ {
+ public static int Counter = 0;
+ }
+
+ private UISettingID()
+ {
+ this.value = StaticFields.Counter;
+ StaticFields.Counter += 1;
+ }
+}
diff --git a/Android/src/emu/project64/persistent/ConfigFile.java b/Android/src/emu/project64/persistent/ConfigFile.java
new file mode 100644
index 000000000..d1bbcbd88
--- /dev/null
+++ b/Android/src/emu/project64/persistent/ConfigFile.java
@@ -0,0 +1,534 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.persistent;
+
+import java.io.BufferedReader;
+import java.io.DataInputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Set;
+
+import android.text.TextUtils;
+import android.util.Log;
+
+public class ConfigFile
+{
+ /** Name of the config file. */
+ private final String mFilename;
+
+ /** Sections mapped by title for easy lookup, with insertion order retained. */
+ private final LinkedHashMap mConfigMap;
+
+ /**
+ * Reads the entire config file, and saves the data to internal collections for manipulation.
+ *
+ * @param filename The config file to read from.
+ */
+ public ConfigFile( String filename )
+ {
+ mFilename = filename;
+ mConfigMap = new LinkedHashMap();
+ reload();
+ }
+
+ /**
+ * Looks up a config section by its title.
+ *
+ * @param sectionTitle Title of the section containing the parameter.
+ *
+ * @return A ConfigSection containing parameters, or null if not found.
+ */
+ public ConfigSection get( String sectionTitle )
+ {
+ return mConfigMap.get( sectionTitle );
+ }
+
+ /**
+ * Looks up the specified parameter under the specified section title.
+ *
+ * @param sectionTitle Title of the section containing the parameter.
+ * @param parameter Name of the parameter.
+ *
+ * @return The value of the specified parameter, or null if not found.
+ */
+ public String get( String sectionTitle, String parameter )
+ {
+ ConfigSection section = mConfigMap.get( sectionTitle );
+
+ // The specified section doesn't exist or is empty.. quit
+ if( section == null || section.parameters == null )
+ return null;
+
+ ConfigParameter confParam = section.parameters.get( parameter );
+
+ // The specified parameter doesn't exist.. quit
+ if( confParam == null )
+ return null;
+
+ // Got it
+ return confParam.value;
+ }
+
+ /**
+ * Assigns the specified value to the specified parameter under the specified section.
+ *
+ * @param sectionTitle The title of the section to contain the parameter.
+ * @param parameter The name of the parameter.
+ * @param value The value to give the parameter.
+ */
+ public void put( String sectionTitle, String parameter, String value )
+ {
+ ConfigSection section = mConfigMap.get( sectionTitle );
+ if( section == null )
+ {
+ // Add a new section
+ section = new ConfigSection( sectionTitle );
+ mConfigMap.put( sectionTitle, section );
+ }
+ section.put( parameter, value );
+ }
+
+ /**
+ * Erases any previously loaded data.
+ */
+ public void clear()
+ {
+ mConfigMap.clear();
+ }
+
+ /**
+ * Re-loads the entire config file, overwriting any unsaved changes, and saves the data in
+ * 'configMap'.
+ *
+ * @return True if successful.
+ * @see #save()
+ */
+ public boolean reload()
+ {
+ // Make sure a file was actually specified
+ if( TextUtils.isEmpty( mFilename ) )
+ return false;
+
+ // Free any previously loaded data
+ clear();
+
+ FileInputStream fstream;
+ try
+ {
+ fstream = new FileInputStream( mFilename );
+ }
+ catch( FileNotFoundException fnfe )
+ {
+ // File not found... we can't continue
+ return false;
+ }
+
+ DataInputStream in = new DataInputStream( fstream );
+ BufferedReader br = new BufferedReader( new InputStreamReader( in ) );
+
+ ConfigSection section = new ConfigSection( "", br ); // section
+ // Loop through reading the remaining sections
+ while( !TextUtils.isEmpty( section.nextName ) )
+ {
+ // Get the next section name
+ String sectionName = section.nextName;
+
+ // Load the next section
+ section = new ConfigSection( sectionName, br );
+ mConfigMap.put( sectionName, section ); // Save the data to 'configMap'
+ }
+
+ try
+ {
+ // Finished. Close the file.
+ in.close();
+ br.close();
+ }
+ catch( IOException ioe )
+ {
+ // (Don't care)
+ }
+
+ // Success
+ return true;
+ }
+
+ /**
+ * Saves the data from 'configMap' back to the config file.
+ *
+ * @return True if successful. False otherwise.
+ * @see #reload()
+ */
+ public boolean save()
+ {
+ // No filename was specified.
+ if( TextUtils.isEmpty( mFilename ) )
+ {
+ Log.e( "ConfigFile", "Filename not specified in method save()" );
+ return false; // Quit
+ }
+
+ // Ensure parent directories exist before writing file
+ new File( mFilename ).getParentFile().mkdirs();
+
+ // Write data to file
+ FileWriter fw = null;
+ try
+ {
+ fw = new FileWriter( mFilename );
+
+ // Loop through the sections
+ for( ConfigSection section : mConfigMap.values() )
+ {
+ if( section != null )
+ section.save( fw );
+ }
+ }
+ catch( IOException ioe )
+ {
+ Log.e( "ConfigFile", "IOException creating file " + mFilename + ", error message: "
+ + ioe.getMessage() );
+ return false; // Some problem creating the file.. quit
+ }
+ finally
+ {
+ if( fw != null )
+ {
+ try
+ {
+ fw.close();
+ }
+ catch( IOException ignored )
+ {
+ }
+ }
+ }
+
+ // Success
+ return true;
+ }
+
+ /**
+ * Returns a handle to the configMap keyset.
+ *
+ * @return keyset containing all the config section titles.
+ */
+ public Set keySet()
+ {
+ return mConfigMap.keySet();
+ }
+
+ /**
+ * The ConfigSection class reads all the parameters in the next section of the config file.
+ * Saves the name of the next section (or null if end of file or error). Can also be used to add
+ * a new section to an existing configuration.
+ */
+ public static class ConfigSection
+ {
+ public String name; // Section name
+ private HashMap parameters; // Parameters sorted by name for easy
+ // lookup
+ private LinkedList lines; // All the lines in this section, including comments
+
+ // Name of the next section, or null if there are no sections left to read in the file:
+ private String nextName = null;
+
+ /**
+ * Constructor: Creates an empty config section
+ *
+ * @param sectionName The section title.
+ */
+ public ConfigSection( String sectionName )
+ {
+ parameters = new HashMap();
+ lines = new LinkedList();
+
+ if( !TextUtils.isEmpty( sectionName ))
+ {
+ lines.add( new ConfigLine( ConfigLine.LINE_SECTION, "[" + sectionName + "]\n", null ) );
+ }
+ name = sectionName;
+ }
+
+ /**
+ * Constructor: Reads the next section of the config file, and saves it in 'parameters'.
+ *
+ * @param sectionName The section title.
+ * @param br The config file to read from.
+ */
+ public ConfigSection( String sectionName, BufferedReader br )
+ {
+ String fullLine, strLine, p, v;
+ ConfigParameter confParam;
+ int x, y;
+
+ parameters = new HashMap();
+ lines = new LinkedList();
+
+ if( !TextUtils.isEmpty( sectionName ))
+ {
+ lines.add( new ConfigLine( ConfigLine.LINE_SECTION, "[" + sectionName + "]\n", null ) );
+ }
+ name = sectionName;
+
+ // No file to read from. Quit.
+ if( br == null )
+ return;
+
+ try
+ {
+ while( ( fullLine = br.readLine() ) != null )
+ {
+ strLine = fullLine.trim();
+ if( ( strLine.length() < 1 )
+ || ( strLine.substring( 0, 1 ).equals( "#" ) )
+ || ( strLine.substring( 0, 1 ).equals( ";" ) )
+ || ( ( strLine.length() > 1 ) && ( strLine.substring( 0, 2 )
+ .equals( "//" ) ) ) )
+
+ { // A comment or blank line.
+ lines.add( new ConfigLine( ConfigLine.LINE_GARBAGE, fullLine + "\n", null ) );
+ }
+ else if( strLine.contains( "=" ) )
+ {
+ // This should be a "parameter=value" pair:
+ x = strLine.indexOf( '=' );
+
+ if( x < 1 )
+ return; // This shouldn't happen (bad syntax). Quit.
+
+ if( x < ( strLine.length() - 1 ) )
+ {
+ p = strLine.substring( 0, x ).trim();
+ if( p.length() < 1 )
+ return; // This shouldn't happen (bad syntax). Quit.
+
+ v = strLine.substring( x + 1, strLine.length() ).trim();
+ // v = v.replace( "\"", "" ); // I'm doing this later, so I can save
+ // back without losing them
+
+ if( v.length() > 0 )
+ {
+ // Save the parameter=value pair
+ confParam = parameters.get( p );
+ if( confParam != null )
+ {
+ confParam.value = v;
+ }
+ else
+ {
+ confParam = new ConfigParameter( p, v );
+ lines.add( new ConfigLine( ConfigLine.LINE_PARAM, fullLine
+ + "\n", confParam ) );
+ parameters.put( p, confParam ); // Save the pair.
+ }
+ }
+ } // It's ok to have an empty assignment (such as "param=")
+ }
+ else if( strLine.contains( "[" ) )
+ {
+ // This should be the beginning of the next section
+ if( ( strLine.length() < 3 ) || ( !strLine.contains( "]" ) ) )
+ return; // This shouldn't happen (bad syntax). Quit.
+
+ x = strLine.indexOf( '[' );
+ y = strLine.indexOf( ']' );
+
+ if( ( y <= x + 1 ) || ( x == -1 ) || ( y == -1 ) )
+ return; // This shouldn't happen (bad syntax). Quit.
+
+ p = strLine.substring( x + 1, y ).trim();
+
+ // Save the name of the next section.
+ nextName = p;
+
+ // Done reading parameters. Return.
+ return;
+ }
+ else
+ {
+ // This shouldn't happen (bad syntax). Quit.
+ return;
+ }
+ }
+ }
+ catch( IOException ioe )
+ {
+ // (Don't care)
+ }
+
+ // Reached end of file or error.. either way, just quit
+ return;
+ }
+
+ /**
+ * Returns a handle to the parameter keyset.
+ *
+ * @return keyset containing all the parameters.
+ */
+ public Set keySet()
+ {
+ return parameters.keySet();
+ }
+
+ /**
+ * Returns the value of the specified parameter.
+ *
+ * @param parameter Name of the parameter.
+ *
+ * @return Parameter's value, or null if not found.
+ */
+ public String get( String parameter )
+ {
+ // Error: no parameters, or parameter was null
+ if( parameters == null || TextUtils.isEmpty( parameter ) )
+ return null;
+
+ ConfigParameter confParam = parameters.get( parameter );
+
+ // Parameter not found
+ if( confParam == null )
+ return null;
+
+ // Got it
+ return confParam.value;
+ }
+
+ /**
+ * Adds the specified parameter to this config section, updates the value if it already
+ * exists, or removes the parameter.
+ *
+ * @param parameter The name of the parameter.
+ * @param value The parameter's value, or null to remove.
+ */
+ public void put( String parameter, String value )
+ {
+ ConfigParameter confParam = parameters.get( parameter );
+ if( confParam == null ) // New parameter
+ {
+ if( !TextUtils.isEmpty( value ) )
+ {
+ confParam = new ConfigParameter( parameter, value );
+ lines.add( new ConfigLine( ConfigLine.LINE_PARAM, parameter + "=" + value
+ + "\n", confParam ) );
+ parameters.put( parameter, confParam );
+ }
+ }
+ else
+ {
+ // Change the parameter's value
+ confParam.value = value;
+ }
+ }
+
+ /**
+ * Writes the entire section to file.
+ *
+ * @param fw File to write to.
+ *
+ * @throws IOException if a writing error occurs.
+ */
+ public void save( FileWriter fw ) throws IOException
+ {
+ for( ConfigLine line : lines )
+ {
+ if( line != null )
+ line.save( fw );
+ }
+ }
+ }
+
+ /**
+ * The ConfigLine class stores each line of the config file (including comments).
+ */
+ private static class ConfigLine
+ {
+ public static final int LINE_GARBAGE = 0; // Comment, whitespace, or blank line
+ public static final int LINE_SECTION = 1; // Section title
+ public static final int LINE_PARAM = 2; // Parameter=value pair
+
+ public int lineType = 0; // LINE_GARBAGE, LINE_SECTION, or LINE_PARAM.
+ public String strLine = ""; // Actual line from the config file.
+ public ConfigParameter confParam = null; // Null unless this line has a parameter.
+
+ /**
+ * Constructor: Saves the relevant information about the line.
+ *
+ * @param type The type of line.
+ * @param line The line itself.
+ * @param param Config parameters pertaining to the line.
+ */
+ public ConfigLine( int type, String line, ConfigParameter param )
+ {
+ lineType = type;
+ strLine = line;
+ confParam = param;
+ }
+
+ /**
+ * Saves the ConfigLine.
+ *
+ * @param fw The file to save the ConfigLine to.
+ *
+ * @throws IOException If a writing error occurs.
+ */
+ public void save( FileWriter fw ) throws IOException
+ {
+ int x;
+ if( lineType == LINE_PARAM )
+ {
+ if( !strLine.contains( "=" ) || confParam == null )
+ return; // This shouldn't happen
+
+ x = strLine.indexOf( '=' );
+
+ if( x < 1 )
+ return; // This shouldn't happen either
+
+ if( x < strLine.length() )
+ fw.write( strLine.substring( 0, x + 1 ) + confParam.value + "\n" );
+ }
+ else
+ {
+ fw.write( strLine );
+ }
+ }
+ }
+
+ /**
+ * The ConfigParameter class associates a parameter with its value.
+ */
+ private static class ConfigParameter
+ {
+ @SuppressWarnings( "unused" )
+ public String parameter;
+ public String value;
+
+ /**
+ * Constructor: Associate the parameter and value
+ *
+ * @param parameter The name of the parameter.
+ * @param value The value of the parameter.
+ */
+ public ConfigParameter( String parameter, String value )
+ {
+ this.parameter = parameter;
+ this.value = value;
+ }
+ }
+}
diff --git a/Android/src/emu/project64/profile/ControllerProfileActivity.java b/Android/src/emu/project64/profile/ControllerProfileActivity.java
new file mode 100644
index 000000000..9ad834ae3
--- /dev/null
+++ b/Android/src/emu/project64/profile/ControllerProfileActivity.java
@@ -0,0 +1,510 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.profile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import emu.project64.AndroidDevice;
+import emu.project64.R;
+import emu.project64.hack.MogaHack;
+import emu.project64.input.AbstractController;
+import emu.project64.input.map.InputMap;
+import emu.project64.input.provider.AbstractProvider;
+import emu.project64.input.provider.AbstractProvider.OnInputListener;
+import emu.project64.input.provider.AxisProvider;
+import emu.project64.input.provider.KeyProvider;
+import emu.project64.input.provider.KeyProvider.ImeFormula;
+import emu.project64.input.provider.MogaProvider;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.UISettingID;
+import emu.project64.persistent.ConfigFile;
+import emu.project64.persistent.ConfigFile.ConfigSection;
+import android.app.AlertDialog;
+import android.app.AlertDialog.Builder;
+import android.annotation.TargetApi;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.graphics.PorterDuff;
+import android.os.Bundle;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.util.Log;
+import android.view.KeyEvent;
+import android.view.MenuItem;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.WindowManager;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.FrameLayout;
+import android.widget.TextView;
+
+import com.bda.controller.Controller;
+
+public class ControllerProfileActivity extends AppCompatActivity implements OnInputListener,
+ OnClickListener
+{
+ // Visual settings
+ private static final float UNMAPPED_BUTTON_ALPHA = 0.2f;
+ private static final int UNMAPPED_BUTTON_FILTER = 0x66FFFFFF;
+ private static final int MIN_LAYOUT_WIDTH_DP = 480;
+
+ // Controller profile objects
+ private ConfigFile mConfigFile;
+ private Profile mProfile;
+
+ // Input listening
+ private KeyProvider mKeyProvider;
+ private MogaProvider mMogaProvider;
+ private AxisProvider mAxisProvider;
+ private Controller mMogaController = Controller.getInstance( this );
+
+ // Widgets
+ private final Button[] mN64Buttons = new Button[InputMap.NUM_MAPPABLES];
+ private TextView mFeedbackText;
+
+ @Override
+ public void onCreate( Bundle savedInstanceState )
+ {
+ super.onCreate( savedInstanceState );
+
+ // Initialize MOGA controller API
+ // TODO: Remove hack after MOGA SDK is fixed
+ // mMogaController.init();
+ MogaHack.init( mMogaController, this );
+
+ // Load the profile; fail fast if there are any programmer usage errors
+ String name = NativeExports.UISettingsLoadString(UISettingID.Controller_CurrentProfile.getValue());
+ if( TextUtils.isEmpty( name ) )
+ throw new Error( "Invalid usage: profile name cannot be null or empty" );
+ mConfigFile = new ConfigFile(NativeExports.UISettingsLoadString(UISettingID.Controller_ConfigFile.getValue()));
+ ConfigSection section = mConfigFile.get( name );
+ if( section == null )
+ {
+ //profile not found create it
+ mConfigFile.put(name, "map", "-");
+ section = mConfigFile.get( name );
+ if( section == null )
+ {
+ throw new Error( "Invalid usage: profile name not found in config file" );
+ }
+ }
+ mProfile = new Profile( false, section );
+
+ // Set up input listeners
+ mKeyProvider = new KeyProvider( ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() );
+ mKeyProvider.registerListener( this );
+ mMogaProvider = new MogaProvider( mMogaController );
+ mMogaProvider.registerListener( this );
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ mAxisProvider = new AxisProvider();
+ mAxisProvider.registerListener( this );
+ }
+
+ // Initialize the layout
+ initLayoutDefault();
+
+ // Refresh everything
+ refreshAllButtons();
+ }
+
+ @Override
+ public void onResume()
+ {
+ super.onResume();
+ mMogaController.onResume();
+ }
+
+ @Override
+ public void onPause()
+ {
+ super.onPause();
+ mMogaController.onPause();
+
+ // Lazily persist the profile data; only need to do it on pause
+ mProfile.writeTo( mConfigFile );
+ mConfigFile.save();
+ }
+
+ @Override
+ public void onDestroy()
+ {
+ super.onDestroy();
+ mMogaController.exit();
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ switch (item.getItemId())
+ {
+ case android.R.id.home:
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onBackPressed()
+ {
+ finish();
+ }
+
+ private void initLayoutDefault()
+ {
+ WindowManager manager = (WindowManager) getSystemService( Context.WINDOW_SERVICE );
+ DisplayMetrics metrics = new DisplayMetrics();
+ manager.getDefaultDisplay().getMetrics( metrics );
+ float scalefactor = (float) DisplayMetrics.DENSITY_DEFAULT / (float) metrics.densityDpi;
+ int widthDp = Math.round( metrics.widthPixels * scalefactor );
+
+ // For narrow screens, use an alternate layout
+ if( widthDp < MIN_LAYOUT_WIDTH_DP )
+ {
+ setContentView( R.layout.controller_profile_activity_port );
+ }
+ else
+ {
+ setContentView( R.layout.controller_profile_activity );
+ }
+
+ // Add the tool bar to the activity (which supports the fancy menu/arrow animation)
+ Toolbar toolbar = (Toolbar) findViewById( R.id.toolbar );
+ toolbar.setTitle( getString(R.string.gamepad_title) );
+ setSupportActionBar( toolbar );
+ ActionBar actionbar = getSupportActionBar();
+
+ if (AndroidDevice.IS_ICE_CREAM_SANDWICH)
+ {
+ actionbar.setHomeButtonEnabled(true);
+ actionbar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ // Initialize and refresh the widgets
+ initWidgets();
+ }
+
+ private void initWidgets()
+ {
+ // Get the text view object
+ mFeedbackText = (TextView) findViewById( R.id.textFeedback );
+ mFeedbackText.setText( "" );
+
+ // Create a button list to simplify highlighting and mapping
+ setupButton( R.id.buttonDR, AbstractController.DPD_R );
+ setupButton( R.id.buttonDL, AbstractController.DPD_L );
+ setupButton( R.id.buttonDD, AbstractController.DPD_D );
+ setupButton( R.id.buttonDU, AbstractController.DPD_U );
+ setupButton( R.id.buttonS, AbstractController.START );
+ setupButton( R.id.buttonZ, AbstractController.BTN_Z );
+ setupButton( R.id.buttonB, AbstractController.BTN_B );
+ setupButton( R.id.buttonA, AbstractController.BTN_A );
+ setupButton( R.id.buttonCR, AbstractController.CPD_R );
+ setupButton( R.id.buttonCL, AbstractController.CPD_L );
+ setupButton( R.id.buttonCD, AbstractController.CPD_D );
+ setupButton( R.id.buttonCU, AbstractController.CPD_U );
+ setupButton( R.id.buttonR, AbstractController.BTN_R );
+ setupButton( R.id.buttonL, AbstractController.BTN_L );
+ setupButton( R.id.buttonAR, InputMap.AXIS_R );
+ setupButton( R.id.buttonAL, InputMap.AXIS_L );
+ setupButton( R.id.buttonAD, InputMap.AXIS_D );
+ setupButton( R.id.buttonAU, InputMap.AXIS_U );
+ }
+
+ private void setupButton( int resId, int index )
+ {
+ mN64Buttons[index] = (Button) findViewById( resId );
+ if( mN64Buttons[index] != null )
+ {
+ mN64Buttons[index].setOnClickListener( this );
+ }
+ }
+
+ @Override
+ public void onClick(View view)
+ {
+ // Handle button clicks in the mapping screen
+ for( int i = 0; i < mN64Buttons.length; i++ )
+ {
+ // Find the button that was pressed
+ if( view.equals( mN64Buttons[i] ) )
+ {
+ // Popup a dialog to listen to input codes from user
+ Button button = (Button) view;
+ popupListener( button.getText(), i );
+ }
+ }
+ }
+
+ private interface PromptInputCodeListener
+ {
+ public void onDialogClosed( int inputCode, int hardwareId, int which );
+ }
+
+ /**
+ * Open a dialog to prompt the user for an input code.
+ *
+ * @param context The activity context.
+ * @param moga The MOGA controller interface.
+ * @param title The title of the dialog.
+ * @param message The message to be shown inside the dialog.
+ * @param neutralButtonText The text to be shown on the neutral button, or null.
+ * @param ignoredKeyCodes The key codes to ignore.
+ * @param listener The listener to process the input code, when provided.
+ */
+ public static void promptInputCode( Context context, Controller moga, CharSequence title, CharSequence message,
+ CharSequence neutralButtonText, final PromptInputCodeListener listener )
+ {
+ final ArrayList providers = new ArrayList();
+
+ // Create a widget to dispatch key/motion event data
+ FrameLayout view = new FrameLayout( context );
+ EditText dummyImeListener = new EditText( context );
+ dummyImeListener.setVisibility( View.INVISIBLE );
+ dummyImeListener.setHeight( 0 );
+ view.addView( dummyImeListener );
+
+ // Set the focus parameters of the view so that it will dispatch events
+ view.setFocusable( true );
+ view.setFocusableInTouchMode( true );
+ view.requestFocus();
+
+ // Create the input event providers
+ providers.add( new KeyProvider( view, ImeFormula.DEFAULT, AndroidDevice.getUnmappableKeyCodes() ) );
+ providers.add( new MogaProvider( moga ) );
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ providers.add( new AxisProvider( view ) );
+ }
+
+ // Notify the client when the user clicks the dialog's positive button
+ DialogInterface.OnClickListener clickListener = new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick( DialogInterface dialog, int which )
+ {
+ for( AbstractProvider provider : providers )
+ provider.unregisterAllListeners();
+ listener.onDialogClosed( 0, 0, which );
+ }
+ };
+
+ final AlertDialog dialog = new Builder( context ).setTitle( title ).setMessage( message ).setCancelable( false )
+ .setNegativeButton( context.getString( android.R.string.cancel ), clickListener )
+ .setPositiveButton( context.getString( android.R.string.ok ), clickListener )
+ .setNeutralButton( neutralButtonText, clickListener ).setPositiveButton( null, null )
+ .setView( view ).create();
+
+ OnInputListener inputListener = new OnInputListener()
+ {
+ @Override
+ public void onInput( int[] inputCodes, float[] strengths, int hardwareId )
+ {
+ if( inputCodes == null || strengths == null )
+ return;
+
+ // Find the strongest input
+ float maxStrength = 0;
+ int strongestInputCode = 0;
+ for( int i = 0; i < inputCodes.length; i++ )
+ {
+ // Identify the strongest input
+ float strength = strengths[i];
+ if( strength > maxStrength )
+ {
+ maxStrength = strength;
+ strongestInputCode = inputCodes[i];
+ }
+ }
+
+ // Call the overloaded method with the strongest found
+ onInput( strongestInputCode, maxStrength, hardwareId );
+ }
+
+ @Override
+ public void onInput( int inputCode, float strength, int hardwareId )
+ {
+ if( inputCode != 0 && strength > AbstractProvider.STRENGTH_THRESHOLD )
+ {
+ for( AbstractProvider provider : providers )
+ provider.unregisterAllListeners();
+ listener.onDialogClosed( inputCode, hardwareId, DialogInterface.BUTTON_POSITIVE );
+ dialog.dismiss();
+ }
+ }
+ };
+
+ // Connect the upstream event listeners
+ for( AbstractProvider provider : providers )
+ {
+ provider.registerListener( inputListener );
+ }
+
+ // Launch the dialog
+ dialog.show();
+ }
+
+ private void popupListener( CharSequence title, final int index )
+ {
+ final InputMap map = new InputMap( mProfile.get( "map" ) );
+ String message = getString( R.string.inputMapActivity_popupMessage,map.getMappedCodeInfo( index ) );
+ String btnText = getString( R.string.inputMapActivity_popupUnmap );
+
+ PromptInputCodeListener listener = new PromptInputCodeListener()
+ {
+ @Override
+ public void onDialogClosed( int inputCode, int hardwareId, int which )
+ {
+ if( which != DialogInterface.BUTTON_NEGATIVE )
+ {
+ if( which == DialogInterface.BUTTON_POSITIVE )
+ {
+ map.map( inputCode, index );
+ }
+ else
+ {
+ map.unmapCommand( index );
+ }
+ mProfile.put( "map", map.serialize() );
+ refreshAllButtons();
+ }
+
+ // Refresh our MOGA provider since the prompt disconnected it
+ mMogaProvider = new MogaProvider( mMogaController );
+ mMogaProvider.registerListener( ControllerProfileActivity.this );
+ }
+ };
+ promptInputCode( this, mMogaController, title, message, btnText, listener);
+ }
+
+ @Override
+ public boolean onKeyDown( int keyCode, KeyEvent event )
+ {
+ return mKeyProvider.onKey( keyCode, event ) || super.onKeyDown( keyCode, event );
+ }
+
+ @Override
+ public boolean onKeyUp( int keyCode, KeyEvent event )
+ {
+ return mKeyProvider.onKey( keyCode, event ) || super.onKeyUp( keyCode, event );
+ }
+
+ @TargetApi( 12 )
+ @Override
+ public boolean onGenericMotionEvent( MotionEvent event )
+ {
+ if( !AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ return false;
+ }
+ return mAxisProvider.onGenericMotion( event ) || super.onGenericMotionEvent( event );
+ }
+
+ @Override
+ public void onInput(int inputCode, float strength, int hardwareId)
+ {
+ refreshButton( inputCode, strength );
+ refreshFeedbackText( inputCode, strength );
+ }
+
+ @Override
+ public void onInput(int[] inputCodes, float[] strengths, int hardwareId)
+ {
+ float maxStrength = AbstractProvider.STRENGTH_THRESHOLD;
+ int strongestInputCode = 0;
+ for( int i = 0; i < inputCodes.length; i++ )
+ {
+ int inputCode = inputCodes[i];
+ float strength = strengths[i];
+
+ // Cache the strongest input
+ if( strength > maxStrength )
+ {
+ maxStrength = strength;
+ strongestInputCode = inputCode;
+ }
+
+ refreshButton( inputCode, strength );
+ }
+ refreshFeedbackText( strongestInputCode, maxStrength );
+ }
+
+ private void refreshFeedbackText( int inputCode, float strength )
+ {
+ // Update the feedback text (not all layouts include this, so check null)
+ if( mFeedbackText != null )
+ {
+ mFeedbackText.setText( strength > AbstractProvider.STRENGTH_THRESHOLD ? AbstractProvider.getInputName( inputCode ) : "" );
+ }
+ }
+
+ private void refreshButton( int inputCode, float strength )
+ {
+ InputMap map = new InputMap( mProfile.get( "map" ) );
+ int command = map.get( inputCode );
+ if( command != InputMap.UNMAPPED )
+ {
+ Button button = mN64Buttons[command];
+ refreshButton( button, strength, true );
+ }
+ }
+
+ @TargetApi( 11 )
+ private void refreshButton( Button button, float strength, boolean isMapped )
+ {
+ if( button != null )
+ {
+ button.setPressed( strength > AbstractProvider.STRENGTH_THRESHOLD );
+
+ // Fade any buttons that aren't mapped
+ if( AndroidDevice.IS_HONEYCOMB )
+ {
+ if( isMapped )
+ {
+ button.setAlpha( 1 );
+ }
+ else
+ {
+ button.setAlpha( UNMAPPED_BUTTON_ALPHA );
+ }
+ }
+ else
+ {
+ // For older APIs try something similar (not quite the same)
+ if( isMapped )
+ {
+ button.getBackground().clearColorFilter();
+ }
+ else
+ {
+ button.getBackground().setColorFilter( UNMAPPED_BUTTON_FILTER, PorterDuff.Mode.MULTIPLY );
+ }
+ button.invalidate();
+ }
+ }
+ }
+
+ private void refreshAllButtons()
+ {
+ final InputMap map = new InputMap( mProfile.get( "map" ) );
+ for( int i = 0; i < mN64Buttons.length; i++ )
+ {
+ refreshButton( mN64Buttons[i], 0, map.isMapped( i ) );
+ }
+ }
+}
diff --git a/Android/src/emu/project64/profile/Profile.java b/Android/src/emu/project64/profile/Profile.java
new file mode 100644
index 000000000..6430a9a7f
--- /dev/null
+++ b/Android/src/emu/project64/profile/Profile.java
@@ -0,0 +1,234 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.profile;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+import emu.project64.persistent.ConfigFile;
+import emu.project64.persistent.ConfigFile.ConfigSection;
+import emu.project64.util.SafeMethods;
+import android.text.TextUtils;
+
+/**
+ * The base class for configuration profiles. Extend this class to encapsulate groups of settings.
+ */
+public class Profile implements Comparable
+{
+ /** The name of the profile, displayed in the UI and used as a unique identifier. */
+ public final String name;
+
+ /** An optional brief description of the profile. Shown in some locations in the UI. */
+ public final String comment;
+
+ /**
+ * Whether this profile is "built-in" to the app (vs. user defined). Built-in profiles are
+ * read-only and can only be copied. Non-built-in profiles can be copied, renamed, edited,
+ * created, and deleted. Built-in profiles are defined in the assets directory, and for all
+ * intents and purposes are guaranteed to exist. Defaults should always reference built-in
+ * profiles.
+ */
+ public final boolean isBuiltin;
+
+ private static final String KEY_COMMENT = "comment";
+
+ private final HashMap data = new HashMap();
+
+ public static List getProfiles( ConfigFile config, boolean isBuiltin )
+ {
+ List profiles = new ArrayList();
+ for( String name : config.keySet() )
+ {
+ profiles.add( new Profile( isBuiltin, config.get( name ) ) );
+ }
+ return profiles;
+ }
+
+ /**
+ * Instantiates an empty profile.
+ *
+ * @param isBuiltin true if the profile is built-in; false if the profile is user-defined
+ * @param name the unique name of the profile
+ * @param comment an optional brief description of the profile, shown in some of the UI
+ */
+ public Profile( boolean isBuiltin, String name, String comment )
+ {
+ this.isBuiltin = isBuiltin;
+ this.name = name;
+ this.comment = comment;
+ data.put( KEY_COMMENT, comment );
+ }
+
+ /**
+ * Instantiates a profile from a {@link ConfigSection}.
+ *
+ * @param isBuiltin true if the profile is built-in; false if the profile is user-defined
+ * @param section a back-end datastore for the profile
+ */
+ public Profile( boolean isBuiltin, ConfigSection section )
+ {
+ this.isBuiltin = isBuiltin;
+ this.name = section.name;
+ this.comment = section.get( KEY_COMMENT );
+ for( String key : section.keySet() )
+ this.data.put( key, section.get( key ) );
+ }
+
+ /**
+ * Gets the value mapped to the specified key.
+ *
+ * @param key the data key
+ * @return the value mapped to the key, or null if no mapping for the key exists
+ */
+ public String get( String key )
+ {
+ return data.get( key );
+ }
+
+ /**
+ * Gets the value mapped to the specified key.
+ *
+ * @param key the data key
+ * @param defaultValue the value to use if the key is not mapped
+ * @return the value mapped to the key, or defaultValue
if no mapping exists
+ */
+ public String get( String key, String defaultValue )
+ {
+ String value = data.get( key );
+ return value == null ? defaultValue : value;
+ }
+
+ /**
+ * @see #get(String, String)
+ */
+ public boolean getBoolean( String key, boolean defaultValue )
+ {
+ String value = data.get( key );
+ return SafeMethods.toBoolean( value, defaultValue );
+ }
+
+ /**
+ * @see #get(String, String)
+ */
+ public int getInt( String key, int defaultValue )
+ {
+ String value = data.get( key );
+ return SafeMethods.toInt( value, defaultValue );
+ }
+
+ /**
+ * @see #get(String, String)
+ */
+ public float getFloat( String key, int defaultValue )
+ {
+ String value = data.get( key );
+ return SafeMethods.toFloat( value, defaultValue );
+ }
+
+ /**
+ * Maps the specified value to the specified key.
+ *
+ * @param key the data key
+ * @param value the value to be mapped to the key
+ */
+ public void put( String key, String value )
+ {
+ data.put( key, value );
+ }
+
+ /**
+ * @see #put(String, String)
+ */
+ public void putBoolean( String key, boolean value )
+ {
+ put( key, String.valueOf( value ) );
+ }
+
+ /**
+ * @see #put(String, String)
+ */
+ public void putInt( String key, int value )
+ {
+ put( key, String.valueOf( value ) );
+ }
+
+ /**
+ * @see #put(String, String)
+ */
+ public void putFloat( String key, float value )
+ {
+ put( key, String.valueOf( value ) );
+ }
+
+ /**
+ * Reads key-value pairs from a given config file into the profile. Key-value pairs that already
+ * exist in the profile are overwritten.
+ *
+ * @param config the {@link ConfigFile} to read from
+ * @return true if the config file is non-null and the profile name is non-empty
+ */
+ public boolean readFrom( ConfigFile config )
+ {
+ if( config == null || TextUtils.isEmpty( name ) )
+ return false;
+
+ ConfigSection source = config.get( name );
+ if( source == null )
+ return false;
+
+ for( String key : source.keySet() )
+ data.put( key, source.get( key ) );
+ return true;
+ }
+
+ /**
+ * Writes key-value pairs from the profile into a given config file. Key-value pairs that
+ * already exist in the config file are overwritten.
+ *
+ * @param config the {@link ConfigFile} to write to
+ * @return true if the config file is non-null and the profile name is non-empty
+ */
+ public boolean writeTo( ConfigFile config )
+ {
+ if( config == null || TextUtils.isEmpty( name ) )
+ return false;
+
+ for( String key : data.keySet() )
+ config.put( name, key, data.get( key ) );
+ return true;
+ }
+
+ /**
+ * Copies a profile, changing only its name and comment.
+ *
+ * @param name the name of the copy
+ * @param comment the comment of the copy
+ * @return the copied profile
+ */
+ public Profile copy( String name, String comment )
+ {
+ if( TextUtils.isEmpty( name ) )
+ return null;
+
+ Profile newProfile = new Profile( false, name, comment );
+ for( String key : data.keySet() )
+ if( !KEY_COMMENT.equals( key ) )
+ newProfile.data.put( key, data.get( key ) );
+ return newProfile;
+ }
+
+ @Override
+ public int compareTo( Profile another )
+ {
+ return this.name.compareToIgnoreCase( another.name );
+ }
+}
\ No newline at end of file
diff --git a/Android/src/emu/project64/settings/AdvancedFragment.java b/Android/src/emu/project64/settings/AdvancedFragment.java
new file mode 100644
index 000000000..e81292865
--- /dev/null
+++ b/Android/src/emu/project64/settings/AdvancedFragment.java
@@ -0,0 +1,29 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+import android.support.v7.preference.Preference;
+
+public class AdvancedFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.settings_advanced;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.advanced_screen_title;
+ }
+}
diff --git a/Android/src/emu/project64/settings/AudioFragment.java b/Android/src/emu/project64/settings/AudioFragment.java
new file mode 100644
index 000000000..77f90b22d
--- /dev/null
+++ b/Android/src/emu/project64/settings/AudioFragment.java
@@ -0,0 +1,28 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+
+public class AudioFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.setting_audio;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.audio_screen_title;
+ }
+}
diff --git a/Android/src/emu/project64/settings/BaseSettingsFragment.java b/Android/src/emu/project64/settings/BaseSettingsFragment.java
new file mode 100644
index 000000000..80a41d69a
--- /dev/null
+++ b/Android/src/emu/project64/settings/BaseSettingsFragment.java
@@ -0,0 +1,159 @@
+/*
+ * *************************************************************************
+ * BasePreferenceFragment.java
+ * **************************************************************************
+ * Copyright © 2015 VLC authors and VideoLAN
+ * Author: Geoffrey Métais
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ * ***************************************************************************
+ */
+
+package emu.project64.settings;
+
+import emu.project64.R;
+import emu.project64.SplashActivity;
+import emu.project64.jni.NativeExports;
+import emu.project64.profile.ControllerProfileActivity;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.support.v4.app.Fragment;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceFragmentCompat;
+
+public abstract class BaseSettingsFragment extends PreferenceFragmentCompat
+{
+ private static final String DIALOG_FRAGMENT_TAG = "android.support.v7.preference.PreferenceFragment.DIALOG";
+
+ protected abstract int getXml();
+ protected abstract int getTitleId();
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s)
+ {
+ addPreferencesFromResource(getXml());
+ }
+
+ @Override
+ public void onStart()
+ {
+ super.onStart();
+ final AppCompatActivity activity = (AppCompatActivity)getActivity();
+ if (activity != null && activity.getSupportActionBar() != null)
+ {
+ activity.getSupportActionBar().setTitle(getString(getTitleId()));
+ }
+ }
+
+ protected void loadFragment(Fragment fragment)
+ {
+ getActivity().getSupportFragmentManager().beginTransaction()
+ .replace(R.id.fragment_placeholder, fragment)
+ .addToBackStack("main").commit();
+ }
+
+ @Override
+ public void onDisplayPreferenceDialog(Preference preference)
+ {
+ DialogFragment dialogFragment = null;
+ if (preference instanceof SeekBarPreference)
+ {
+ dialogFragment = SeekBarPreferencePreferenceDialogFragmentCompat.newInstance(preference.getKey());
+ }
+ else if (preference instanceof TwoLinesListPreference)
+ {
+ dialogFragment = TwoLinesListPreferenceDialogFragmentCompat.newInstance(preference.getKey());
+ }
+ else
+ {
+ super.onDisplayPreferenceDialog(preference);
+ }
+
+ if (dialogFragment != null)
+ {
+ dialogFragment.setTargetFragment(this, 0);
+ dialogFragment.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
+ }
+ }
+
+ @Override
+ public boolean onPreferenceTreeClick(Preference preference)
+ {
+ if (preference.getKey().equals("settings_input"))
+ {
+ loadFragment(new InputFragment());
+ }
+ else if (preference.getKey().equals("settings_touch_screen"))
+ {
+ loadFragment(new TouchScreenFragment());
+ }
+ else if (preference.getKey().equals("settings_gamepad_screen"))
+ {
+ final AppCompatActivity activity = (AppCompatActivity)getActivity();
+ Intent intent = new Intent( activity, ControllerProfileActivity.class );
+ activity.startActivity( intent );
+ }
+ else if (preference.getKey().equals("settings_video"))
+ {
+ loadFragment(new VideoFragment());
+ }
+ else if (preference.getKey().equals("settings_audio"))
+ {
+ loadFragment(new AudioFragment());
+ }
+ else if (preference.getKey().equals("settings_advanced"))
+ {
+ loadFragment(new AdvancedFragment());
+ }
+ else if (preference.getKey().equals("logging_core"))
+ {
+ loadFragment(new LoggingProject64Core());
+ }
+ else if (preference.getKey().equals("settings_reset"))
+ {
+ DialogInterface.OnClickListener internalListener = new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick( DialogInterface dialog, int which )
+ {
+ if( which == DialogInterface.BUTTON_POSITIVE )
+ {
+ NativeExports.ResetApplicationSettings();
+ SplashActivity.Reset();
+ Intent SplashIntent = new Intent(getActivity(), SplashActivity.class);
+ SplashIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ startActivity(SplashIntent);
+ }
+ }
+ };
+
+ String title = getString( R.string.settings_reset_title );
+ String message = getString( R.string.settings_reset_message );
+ AlertDialog.Builder builder = new AlertDialog.Builder( getActivity() ).setTitle( title ).setMessage( message ).setCancelable( false )
+ .setNegativeButton( getString( android.R.string.cancel ), internalListener )
+ .setPositiveButton( getString( android.R.string.ok ), internalListener );
+ builder.create().show();
+ }
+ else
+ {
+ return super.onPreferenceTreeClick(preference);
+ }
+ return true;
+ }
+}
diff --git a/Android/src/emu/project64/settings/GameSettingsActivity.java b/Android/src/emu/project64/settings/GameSettingsActivity.java
new file mode 100644
index 000000000..0ae26cf3c
--- /dev/null
+++ b/Android/src/emu/project64/settings/GameSettingsActivity.java
@@ -0,0 +1,87 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.AndroidDevice;
+import emu.project64.R;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.SettingsID;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+
+public class GameSettingsActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener
+{
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ setContentView(R.layout.settings_activity);
+
+ // Add the tool bar to the activity (which supports the fancy menu/arrow animation)
+ Toolbar toolbar = (Toolbar) findViewById( R.id.toolbar );
+ toolbar.setTitle( getString(R.string.settings_title) );
+ setSupportActionBar( toolbar );
+ ActionBar actionbar = getSupportActionBar();
+
+ if (AndroidDevice.IS_ICE_CREAM_SANDWICH)
+ {
+ actionbar.setHomeButtonEnabled(true);
+ actionbar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ sharedPrefs.edit().clear()
+ .putString("Game_CpuType",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Game_CpuType.getValue())))
+ .putBoolean("Game_BlockLinking",NativeExports.SettingsLoadBool(SettingsID.Game_BlockLinking.getValue()))
+ .apply();
+
+ sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+
+ if (savedInstanceState == null)
+ {
+ getSupportFragmentManager().beginTransaction().replace(R.id.fragment_placeholder, new GameSettingsFragment()).commit();
+ }
+ }
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ switch (item.getItemId())
+ {
+ case android.R.id.home:
+ if (!getSupportFragmentManager().popBackStackImmediate())
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
+ {
+ if (key.equals("Game_CpuType")) { NativeExports.SettingsSaveDword(SettingsID.Game_CpuType.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Game_BlockLinking")) { NativeExports.SettingsSaveBool(SettingsID.Game_BlockLinking.getValue(), sharedPreferences.getBoolean(key,false)); }
+ }
+}
diff --git a/Android/src/emu/project64/settings/GameSettingsFragment.java b/Android/src/emu/project64/settings/GameSettingsFragment.java
new file mode 100644
index 000000000..39df4f5cf
--- /dev/null
+++ b/Android/src/emu/project64/settings/GameSettingsFragment.java
@@ -0,0 +1,28 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+
+public class GameSettingsFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.game_settings;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.preferences;
+ }
+}
diff --git a/Android/src/emu/project64/settings/GamepadScreenFragment.java b/Android/src/emu/project64/settings/GamepadScreenFragment.java
new file mode 100644
index 000000000..d134bfec8
--- /dev/null
+++ b/Android/src/emu/project64/settings/GamepadScreenFragment.java
@@ -0,0 +1,57 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import android.os.Bundle;
+import emu.project64.R;
+
+public class GamepadScreenFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.setting_gamepad;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.gamepad_title;
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s)
+ {
+ super.onCreatePreferences(bundle, s);
+
+ /*String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
+ String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
+ ConfigFile touchscreenProfiles = new ConfigFile( touchscreenProfiles_cfg );
+ Set layoutsKeySet = touchscreenProfiles.keySet();
+ String[] layouts = layoutsKeySet.toArray(new String[layoutsKeySet.size()]);
+
+ CharSequence[] entries = new CharSequence[layouts.length];
+ String[] entryValues = new String[layouts.length];
+ String[] entrySubtitles = new String[layouts.length];
+
+ for( int i = 0; i < layouts.length; i++ )
+ {
+ entries[i] = layouts[i];
+ entryValues[i] = layouts[i];
+ entrySubtitles[i] = touchscreenProfiles.get(layouts[i]).get("comment");
+ }
+
+ final TwoLinesListPreference listPreference = (TwoLinesListPreference) findPreference("touchscreenLayout");
+ listPreference.setEntries(entries);
+ listPreference.setEntryValues(entryValues);
+ listPreference.setEntriesSubtitles(entrySubtitles);*/
+ }
+}
diff --git a/Android/src/emu/project64/settings/InputFragment.java b/Android/src/emu/project64/settings/InputFragment.java
new file mode 100644
index 000000000..fea3fb8dc
--- /dev/null
+++ b/Android/src/emu/project64/settings/InputFragment.java
@@ -0,0 +1,28 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+
+public class InputFragment extends SettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.setting_input;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.input_screen_title;
+ }
+}
diff --git a/Android/src/emu/project64/settings/LoggingProject64Core.java b/Android/src/emu/project64/settings/LoggingProject64Core.java
new file mode 100644
index 000000000..a34990c08
--- /dev/null
+++ b/Android/src/emu/project64/settings/LoggingProject64Core.java
@@ -0,0 +1,28 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+
+public class LoggingProject64Core extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.logging_project64core;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.logging_project64core;
+ }
+}
diff --git a/Android/src/emu/project64/settings/SeekBarPreference.java b/Android/src/emu/project64/settings/SeekBarPreference.java
new file mode 100644
index 000000000..978ccd742
--- /dev/null
+++ b/Android/src/emu/project64/settings/SeekBarPreference.java
@@ -0,0 +1,222 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.preference.DialogPreference;
+import android.util.AttributeSet;
+import android.widget.SeekBar;
+
+/**
+ * A type of {@link DialogPreference} that uses a {@link SeekBar} as a means of selecting a desired option.
+ */
+public class SeekBarPreference extends DialogPreference
+{
+ private static final int DEFAULT_VALUE = 50;
+ private static final int DEFAULT_MIN = 0;
+ private static final int DEFAULT_MAX = 100;
+ private static final int DEFAULT_STEP = 10;
+ private static final String DEFAULT_UNITS = "%";
+
+ private int mValue = DEFAULT_VALUE;
+ private int mMinValue = DEFAULT_MIN;
+ private int mMaxValue = DEFAULT_MAX;
+ private int mStepSize = DEFAULT_STEP;
+ private String mUnits = DEFAULT_UNITS;
+
+ /**
+ * Constructor
+ *
+ * @param context The {@link Context} this SeekBarPreference is being used in.
+ * @param attrs A collection of attributes, as found associated with a tag in an XML document.
+ */
+ public SeekBarPreference( Context context, AttributeSet attrs )
+ {
+ super( context, attrs );
+
+ // Get the attributes from the XML file, if provided
+ TypedArray a = context.obtainStyledAttributes( attrs, R.styleable.SeekBarPreference );
+ setMinValue( a.getInteger( R.styleable.SeekBarPreference_minimumValue, DEFAULT_MIN ) );
+ setMaxValue( a.getInteger( R.styleable.SeekBarPreference_maximumValue, DEFAULT_MAX ) );
+ setStepSize( a.getInteger( R.styleable.SeekBarPreference_stepSize, DEFAULT_STEP ) );
+ setUnits( a.getString( R.styleable.SeekBarPreference_units ) );
+ if (getUnits() == null)
+ {
+ setUnits(DEFAULT_UNITS);
+ }
+ a.recycle();
+
+ // Setup the layout
+ setDialogLayoutResource( R.layout.seek_bar_preference );
+ }
+
+ /**
+ * Constructor
+ *
+ * @param context The {@link Context} this SeekBarPreference will be used in.
+ */
+ public SeekBarPreference( Context context )
+ {
+ this( context, null );
+ }
+
+ /**
+ * Sets this SeekBarPreference to a specified value.
+ *
+ * @param value The value to set the SeekBarPreference to.
+ */
+ public void setValue( int value )
+ {
+ mValue = validate( value );
+ if( shouldPersist() )
+ persistInt( mValue );
+ setSummary( getValueString( mValue ) );
+ }
+
+ /**
+ * Sets the minimum value this SeekBarPreference may have.
+ *
+ * @param minValue The minimum value for this SeekBarPreference.
+ */
+ public void setMinValue( int minValue )
+ {
+ mMinValue = minValue;
+ }
+
+ /**
+ * Sets the maximum value this SeekBarPreference may have.
+ *
+ * @param maxValue The maximum value for this SeekBarPreference.
+ */
+ public void setMaxValue( int maxValue )
+ {
+ mMaxValue = maxValue;
+ }
+
+ /**
+ * Sets the size of each increment in this SeekBarPreference.
+ *
+ * @param stepSize The size of each increment.
+ */
+ public void setStepSize( int stepSize )
+ {
+ mStepSize = stepSize;
+ }
+
+ /**
+ * Sets the type of units this SeekBarPreference uses (e.g. "%").
+ *
+ * @param units The unit type for this SeekBarPreference to use.
+ */
+ public void setUnits( String units )
+ {
+ mUnits = units;
+ }
+
+ /**
+ * Gets the currently set value.
+ *
+ * @return The currently set value in this SeekBarPreference.
+ */
+ public int getValue()
+ {
+ return mValue;
+ }
+
+ /**
+ * Gets the currently set minimum value.
+ *
+ * @return The currently set minimum value for this SeekBarPreference.
+ */
+ public int getMinValue()
+ {
+ return mMinValue;
+ }
+
+ /**
+ * Gets the currently set maximum value.
+ *
+ * @return The currently set maximum value for this SeekBarPreference.
+ */
+ public int getMaxValue()
+ {
+ return mMaxValue;
+ }
+
+ /**
+ * Gets the currently set increment step size.
+ *
+ * @return The currently set increment step size for this SeekBarPreference.
+ */
+ public int getStepSize()
+ {
+ return mStepSize;
+ }
+
+ /**
+ * Gets the currently set units.
+ *
+ * @return The currently set unit type this SeekBarPreference uses.
+ */
+ public String getUnits()
+ {
+ return mUnits;
+ }
+
+ /**
+ * Gets the value as a string with units appended.
+ *
+ * @param value The value to use in the string.
+ *
+ * @return The value as a String.
+ */
+ public String getValueString( int value )
+ {
+ return getContext().getString( R.string.seekBarPreference_summary, value, mUnits );
+ }
+
+ @Override
+ protected Object onGetDefaultValue( TypedArray a, int index )
+ {
+ return a.getInteger( index, DEFAULT_VALUE );
+ }
+
+ @Override
+ protected void onSetInitialValue( boolean restorePersistedValue, Object defaultValue )
+ {
+ setValue( restorePersistedValue ? getPersistedInt( mValue ) : (Integer) defaultValue );
+ }
+
+ @Override
+ public void onAttached()
+ {
+ setSummary( getValueString( mValue ) );
+ super.onAttached();
+ }
+
+ public int validate( int value )
+ {
+ // Round to nearest integer multiple of mStepSize
+ int newValue = Math.round( value / (float)getStepSize() ) * getStepSize();
+
+ // Address issues when mStepSize is not an integral factor of mMaxValue
+ // e.g. mMaxValue = 100, mMinValue = 0, mStepSize = 9, progress = 100 --> newValue = 99 (should be 100)
+ // e.g. mMaxValue = 100, mMinValue = 0, mStepSize = 6, progress = 99 --> newValue = 102 (should be 100)
+ if( value == getMinValue() || newValue < getMinValue() )
+ newValue = getMinValue();
+ if( value == getMaxValue() || newValue > getMaxValue() )
+ newValue = getMaxValue();
+
+ return newValue;
+ }
+}
diff --git a/Android/src/emu/project64/settings/SeekBarPreferencePreferenceDialogFragmentCompat.java b/Android/src/emu/project64/settings/SeekBarPreferencePreferenceDialogFragmentCompat.java
new file mode 100644
index 000000000..92af133ae
--- /dev/null
+++ b/Android/src/emu/project64/settings/SeekBarPreferencePreferenceDialogFragmentCompat.java
@@ -0,0 +1,102 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.preference.DialogPreference;
+import android.support.v7.preference.Preference;
+import android.support.v7.preference.PreferenceDialogFragmentCompat;
+import android.view.View;
+import android.widget.SeekBar;
+import android.widget.TextView;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+
+public class SeekBarPreferencePreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat
+ implements DialogPreference.TargetFragment, OnSeekBarChangeListener
+{
+ private TextView mTextView;
+ private SeekBar mSeekBar;
+
+ public void onDialogClosed(boolean positiveResult)
+ {
+ if( positiveResult )
+ {
+ final SeekBarPreference preference = getSeekBarPreference();
+ int value = mSeekBar.getProgress() + preference.getMinValue();
+ preference.setValue( value );
+ }
+ }
+
+ public static SeekBarPreferencePreferenceDialogFragmentCompat newInstance(String key)
+ {
+ SeekBarPreferencePreferenceDialogFragmentCompat fragment = new SeekBarPreferencePreferenceDialogFragmentCompat();
+ Bundle b = new Bundle(1);
+ b.putString("key", key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ @Override
+ public Preference findPreference(CharSequence charSequence)
+ {
+ return getPreference();
+ }
+
+ private SeekBarPreference getSeekBarPreference()
+ {
+ return (SeekBarPreference)this.getPreference();
+ }
+
+ @Override
+ protected void onBindDialogView(View view)
+ {
+ super.onBindDialogView(view);
+
+ // Grab the widget references
+ mTextView = (TextView) view.findViewById( R.id.textFeedback );
+ mSeekBar = (SeekBar) view.findViewById( R.id.seekbar );
+ }
+
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder)
+ {
+ super.onPrepareDialogBuilder(builder);
+ final SeekBarPreference preference = getSeekBarPreference();
+
+ // Initialize and refresh the widgets
+ mSeekBar.setMax( preference.getMaxValue() - preference.getMinValue());
+ mSeekBar.setOnSeekBarChangeListener( this );
+ mSeekBar.setProgress( preference.getValue() - preference.getMinValue() );
+ mTextView.setText( preference.getValueString( preference.getValue() ) );
+ }
+
+ @Override
+ public void onStartTrackingTouch( SeekBar seekBar )
+ {
+ }
+
+ @Override
+ public void onStopTrackingTouch( SeekBar seekBar )
+ {
+ }
+
+ @Override
+ public void onProgressChanged( SeekBar seekBar, int progress, boolean fromUser )
+ {
+ final SeekBarPreference preference = getSeekBarPreference();
+
+ int value = preference.validate( progress + preference.getMinValue() );
+ if( value != ( progress + preference.getMinValue() ) )
+ seekBar.setProgress( value - preference.getMinValue() );
+ mTextView.setText( preference.getValueString( value ) );
+ }
+}
diff --git a/Android/src/emu/project64/settings/SettingsActivity.java b/Android/src/emu/project64/settings/SettingsActivity.java
new file mode 100644
index 000000000..37514020c
--- /dev/null
+++ b/Android/src/emu/project64/settings/SettingsActivity.java
@@ -0,0 +1,207 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.AndroidDevice;
+import emu.project64.R;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.SettingsID;
+import emu.project64.jni.SystemEvent;
+import emu.project64.jni.UISettingID;
+import android.content.SharedPreferences;
+import android.os.Bundle;
+import android.preference.PreferenceManager;
+import android.support.v7.app.ActionBar;
+import android.support.v7.app.AppCompatActivity;
+import android.support.v7.widget.Toolbar;
+import android.view.MenuItem;
+
+public class SettingsActivity extends AppCompatActivity implements SharedPreferences.OnSharedPreferenceChangeListener
+{
+ @Override
+ protected void onCreate(Bundle savedInstanceState)
+ {
+ super.onCreate(savedInstanceState);
+
+ if (NativeExports.SettingsLoadBool(SettingsID.GameRunning_CPU_Running.getValue()) == true)
+ {
+ NativeExports.ExternalEvent( SystemEvent.SysEvent_ResumeCPU_FromMenu.getValue());
+ }
+ setContentView(R.layout.settings_activity);
+
+ // Add the tool bar to the activity (which supports the fancy menu/arrow animation)
+ Toolbar toolbar = (Toolbar) findViewById( R.id.toolbar );
+ toolbar.setTitle( getString(R.string.settings_title) );
+ setSupportActionBar( toolbar );
+ ActionBar actionbar = getSupportActionBar();
+
+ if (AndroidDevice.IS_ICE_CREAM_SANDWICH)
+ {
+ actionbar.setHomeButtonEnabled(true);
+ actionbar.setDisplayHomeAsUpEnabled(true);
+ }
+
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ sharedPrefs.edit().clear()
+ .putInt("touchscreenScale",NativeExports.UISettingsLoadDword(UISettingID.TouchScreen_ButtonScale.getValue()))
+ .putString("touchscreenLayout",NativeExports.UISettingsLoadString(UISettingID.TouchScreen_Layout.getValue()))
+ .putBoolean("audio_Enabled",NativeExports.SettingsLoadBool(SettingsID.Plugin_EnableAudio.getValue()))
+ .putBoolean("Plugin_ForceGfxReset",NativeExports.SettingsLoadBool(SettingsID.Plugin_ForceGfxReset.getValue()))
+ .putBoolean("UserInterface_BasicMode",NativeExports.SettingsLoadBool(SettingsID.UserInterface_BasicMode.getValue()))
+ .putBoolean("Debugger_Enabled",NativeExports.SettingsLoadBool(SettingsID.Debugger_Enabled.getValue()))
+ .putBoolean("Debugger_GenerateLogFiles",NativeExports.SettingsLoadBool(SettingsID.Debugger_GenerateLogFiles.getValue()))
+ .putBoolean("Debugger_LimitFPS",NativeExports.SettingsLoadBool(SettingsID.GameRunning_LimitFPS.getValue()))
+ .putBoolean("Debugger_DisplaySpeed",NativeExports.SettingsLoadBool(SettingsID.UserInterface_DisplayFrameRate.getValue()))
+ .putBoolean("Debugger_CpuUsage",NativeExports.SettingsLoadBool(SettingsID.UserInterface_ShowCPUPer.getValue()))
+ .putBoolean("Debugger_RecordExecutionTimes",NativeExports.SettingsLoadBool(SettingsID.Debugger_RecordExecutionTimes.getValue()))
+ .putString("Debugger_DisplaySpeedType",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.UserInterface_FrameDisplayType.getValue())))
+ .putString("Debugger_TraceMD5",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceMD5.getValue())))
+ .putString("Debugger_TraceThread",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceThread.getValue())))
+ .putString("Debugger_TracePath",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TracePath.getValue())))
+ .putString("Debugger_TraceSettings",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceSettings.getValue())))
+ .putString("Debugger_TraceUnknown",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceUnknown.getValue())))
+ .putString("Debugger_TraceAppInit",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceAppInit.getValue())))
+ .putString("Debugger_TraceAppCleanup",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceAppCleanup.getValue())))
+ .putString("Debugger_TraceN64System",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceN64System.getValue())))
+ .putString("Debugger_TracePlugins",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TracePlugins.getValue())))
+ .putString("Debugger_TraceGFXPlugin",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceGFXPlugin.getValue())))
+ .putString("Debugger_TraceAudioPlugin",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceAudioPlugin.getValue())))
+ .putString("Debugger_TraceControllerPlugin",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceControllerPlugin.getValue())))
+ .putString("Debugger_TraceRSPPlugin",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceRSPPlugin.getValue())))
+ .putString("Debugger_TraceRSP",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceRSP.getValue())))
+ .putString("Debugger_TraceAudio",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceAudio.getValue())))
+ .putString("Debugger_TraceRegisterCache",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceRegisterCache.getValue())))
+ .putString("Debugger_TraceRecompiler",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceRecompiler.getValue())))
+ .putString("Debugger_TraceTLB",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceTLB.getValue())))
+ .putString("Debugger_TraceProtectedMEM",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceProtectedMEM.getValue())))
+ .putString("Debugger_TraceUserInterface",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceUserInterface.getValue())))
+ .putString("Debugger_TraceRomList",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceRomList.getValue())))
+ .putString("Debugger_TraceExceptionHandler",String.valueOf(NativeExports.SettingsLoadDword(SettingsID.Debugger_TraceExceptionHandler.getValue())))
+ .apply();
+
+ sharedPrefs.registerOnSharedPreferenceChangeListener(this);
+
+ if (savedInstanceState == null)
+ {
+ getSupportFragmentManager().beginTransaction().replace(R.id.fragment_placeholder, new SettingsFragment()).commit();
+ }
+ }
+
+ @Override
+ protected void onStop()
+ {
+ super.onStop();
+ SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
+ sharedPrefs.unregisterOnSharedPreferenceChangeListener(this);
+ }
+
+ @Override
+ public boolean onOptionsItemSelected(MenuItem item)
+ {
+ switch (item.getItemId())
+ {
+ case android.R.id.home:
+ if (!getSupportFragmentManager().popBackStackImmediate())
+ finish();
+ return true;
+ }
+ return super.onOptionsItemSelected(item);
+ }
+
+ @Override
+ public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
+ {
+ if (key.equals("UserInterface_BasicMode"))
+ {
+ NativeExports.SettingsSaveBool(SettingsID.UserInterface_BasicMode.getValue(), sharedPreferences.getBoolean(key,false));
+ getSupportFragmentManager().popBackStackImmediate();
+ getSupportFragmentManager().beginTransaction().replace(R.id.fragment_placeholder, new SettingsFragment()).commit();
+ }
+ else if (key.equals("touchscreenScale")) { NativeExports.UISettingsSaveDword(UISettingID.TouchScreen_ButtonScale.getValue(), sharedPreferences.getInt(key, 100)); }
+ else if (key.equals("touchscreenLayout")) { NativeExports.UISettingsSaveString(UISettingID.TouchScreen_Layout.getValue(), sharedPreferences.getString(key, "Analog")); }
+ else if (key.equals("audio_Enabled")) { NativeExports.SettingsSaveBool(SettingsID.Plugin_EnableAudio.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Plugin_ForceGfxReset")) { NativeExports.SettingsSaveBool(SettingsID.Plugin_ForceGfxReset.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_Enabled")) { NativeExports.SettingsSaveBool(SettingsID.Debugger_Enabled.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_GenerateLogFiles")) { NativeExports.SettingsSaveBool(SettingsID.Debugger_GenerateLogFiles.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_CpuUsage")) { NativeExports.SettingsSaveBool(SettingsID.UserInterface_ShowCPUPer.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_RecordExecutionTimes")) { NativeExports.SettingsSaveBool(SettingsID.Debugger_RecordExecutionTimes.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_LimitFPS")) { NativeExports.SettingsSaveBool(SettingsID.GameRunning_LimitFPS.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_DisplaySpeed")) { NativeExports.SettingsSaveBool(SettingsID.UserInterface_DisplayFrameRate.getValue(), sharedPreferences.getBoolean(key,false)); }
+ else if (key.equals("Debugger_DisplaySpeedType")) { NativeExports.SettingsSaveDword(SettingsID.UserInterface_FrameDisplayType.getValue(), Integer.valueOf(sharedPreferences.getString(key, "0"))); }
+ else if (key.equals("Debugger_TraceMD5")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceMD5.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TraceThread")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceThread.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TracePath")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TracePath.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TraceSettings")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceSettings.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TraceUnknown")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceUnknown.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TraceAppInit")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceAppInit.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TraceAppCleanup")) { NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceAppCleanup.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1"))); }
+ else if (key.equals("Debugger_TraceN64System"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceN64System.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TracePlugins"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TracePlugins.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceGFXPlugin"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceGFXPlugin.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceAudioPlugin"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceAudioPlugin.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceControllerPlugin"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceControllerPlugin.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceRSPPlugin"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceRSPPlugin.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceRSP"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceRSP.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceAudio"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceAudio.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceRegisterCache"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceRegisterCache.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceRecompiler"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceRecompiler.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceTLB"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceTLB.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceProtectedMEM"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceProtectedMEM.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceUserInterface"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceUserInterface.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceRomList"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceRomList.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ else if (key.equals("Debugger_TraceExceptionHandler"))
+ {
+ NativeExports.SettingsSaveDword(SettingsID.Debugger_TraceExceptionHandler.getValue(), Integer.valueOf(sharedPreferences.getString(key, "1")));
+ }
+ }
+}
diff --git a/Android/src/emu/project64/settings/SettingsFragment.java b/Android/src/emu/project64/settings/SettingsFragment.java
new file mode 100644
index 000000000..32d79f07b
--- /dev/null
+++ b/Android/src/emu/project64/settings/SettingsFragment.java
@@ -0,0 +1,34 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+import emu.project64.jni.NativeExports;
+import emu.project64.jni.SettingsID;
+
+public class SettingsFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ if (NativeExports.SettingsLoadBool(SettingsID.UserInterface_BasicMode.getValue()))
+ {
+ return R.xml.settings_basic;
+ }
+ return R.xml.settings;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.preferences;
+ }
+}
diff --git a/Android/src/emu/project64/settings/TouchScreenFragment.java b/Android/src/emu/project64/settings/TouchScreenFragment.java
new file mode 100644
index 000000000..655cac375
--- /dev/null
+++ b/Android/src/emu/project64/settings/TouchScreenFragment.java
@@ -0,0 +1,61 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import java.util.Set;
+
+import android.os.Bundle;
+import emu.project64.AndroidDevice;
+import emu.project64.R;
+import emu.project64.persistent.ConfigFile;
+
+public class TouchScreenFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.setting_touch_screen;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.touch_screen_title;
+ }
+
+ @Override
+ public void onCreatePreferences(Bundle bundle, String s)
+ {
+ super.onCreatePreferences(bundle, s);
+
+ String profilesDir = AndroidDevice.PACKAGE_DIRECTORY + "/profiles";
+ String touchscreenProfiles_cfg = profilesDir + "/touchscreen.cfg";
+ ConfigFile touchscreenProfiles = new ConfigFile( touchscreenProfiles_cfg );
+ Set layoutsKeySet = touchscreenProfiles.keySet();
+ String[] layouts = layoutsKeySet.toArray(new String[layoutsKeySet.size()]);
+
+ CharSequence[] entries = new CharSequence[layouts.length];
+ String[] entryValues = new String[layouts.length];
+ String[] entrySubtitles = new String[layouts.length];
+
+ for( int i = 0; i < layouts.length; i++ )
+ {
+ entries[i] = layouts[i];
+ entryValues[i] = layouts[i];
+ entrySubtitles[i] = touchscreenProfiles.get(layouts[i]).get("comment");
+ }
+
+ final TwoLinesListPreference listPreference = (TwoLinesListPreference) findPreference("touchscreenLayout");
+ listPreference.setEntries(entries);
+ listPreference.setEntryValues(entryValues);
+ listPreference.setEntriesSubtitles(entrySubtitles);
+ }
+}
diff --git a/Android/src/emu/project64/settings/TwoLinesListPreference.java b/Android/src/emu/project64/settings/TwoLinesListPreference.java
new file mode 100644
index 000000000..3a94707eb
--- /dev/null
+++ b/Android/src/emu/project64/settings/TwoLinesListPreference.java
@@ -0,0 +1,119 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.support.v7.preference.ListPreference;
+import android.util.AttributeSet;
+
+public class TwoLinesListPreference extends ListPreference
+{
+ private CharSequence[] mEntriesSubtitles;
+ private int mValueIndex;
+
+ public TwoLinesListPreference(Context context, AttributeSet attrs)
+ {
+ super(context, attrs);
+ TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.TwoLinesListPreference);
+ mEntriesSubtitles = a.getTextArray(R.styleable.TwoLinesListPreference_entriesSubtitles);
+ a.recycle();
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue)
+ {
+ super.onSetInitialValue(restoreValue, defaultValue);
+
+ mEntriesSubtitles = getEntriesSubtitles();
+ mValueIndex = getValueIndex();
+ }
+
+ @Override
+ public void setValue(String value)
+ {
+ super.setValue(value);
+ mValueIndex = getValueIndex();
+ updateSummary();
+ }
+ /**
+ * Returns the index of the given value (in the entry values array).
+ *
+ * @param value The value whose index should be returned.
+ * @return The index of the value, or -1 if not found.
+ */
+ public int findIndexOfValue(String value)
+ {
+ CharSequence[] EntryValues = getEntryValues();
+ if (value != null && EntryValues != null)
+ {
+ for (int i = EntryValues.length - 1; i >= 0; i--)
+ {
+ if (EntryValues[i].equals(value))
+ {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public int getValueIndex()
+ {
+ return findIndexOfValue(getValue());
+ }
+
+ public CharSequence[] getEntriesSubtitles()
+ {
+ return mEntriesSubtitles;
+ }
+
+ @Override
+ public void setEntries(CharSequence[] Entries)
+ {
+ super.setEntries(Entries);
+ updateSummary();
+ }
+
+ @Override
+ public void setEntryValues(CharSequence[] EntryValues)
+ {
+ super.setEntryValues(EntryValues);
+ mValueIndex = getValueIndex();
+ updateSummary();
+ }
+
+ public void setEntriesSubtitles(CharSequence[] mEntriesSubtitles)
+ {
+ this.mEntriesSubtitles = mEntriesSubtitles;
+ updateSummary();
+ }
+
+ private void updateSummary()
+ {
+ if (mValueIndex < 0)
+ {
+ return;
+ }
+ CharSequence[] Entries = getEntries();
+ String summary = Entries[mValueIndex].toString();
+ if (mEntriesSubtitles != null && mEntriesSubtitles.length > mValueIndex)
+ {
+ String subtitle = mEntriesSubtitles[mValueIndex].toString();
+ if (summary.length() > 0 && subtitle.length() > 0)
+ {
+ summary += " - " + subtitle;
+ }
+ }
+ setSummary( summary );
+ }
+}
\ No newline at end of file
diff --git a/Android/src/emu/project64/settings/TwoLinesListPreferenceDialogFragmentCompat.java b/Android/src/emu/project64/settings/TwoLinesListPreferenceDialogFragmentCompat.java
new file mode 100644
index 000000000..f69d47c3a
--- /dev/null
+++ b/Android/src/emu/project64/settings/TwoLinesListPreferenceDialogFragmentCompat.java
@@ -0,0 +1,133 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v7.app.AlertDialog;
+import android.support.v7.preference.PreferenceDialogFragmentCompat;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ListAdapter;
+import android.widget.RadioButton;
+import android.widget.TextView;
+
+public class TwoLinesListPreferenceDialogFragmentCompat extends PreferenceDialogFragmentCompat
+{
+ private TwoLinesListPreference getTwoLinesListPreference()
+ {
+ return (TwoLinesListPreference)this.getPreference();
+ }
+
+ class YourAdapter extends ArrayAdapter
+ {
+ public YourAdapter(Context context, String[] values)
+ {
+ super(context, R.layout.two_lines_list_preference_row, values);
+ }
+
+ class ViewHolder
+ {
+ TextView title;
+ TextView subTitle;
+ RadioButton radioBtn;
+ }
+
+ ViewHolder holder;
+ ViewHolderClickListener listener = new ViewHolderClickListener();
+
+ @Override
+ public View getView(int position, View convertView, ViewGroup parent)
+ {
+ final LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ if (convertView == null)
+ {
+ convertView = inflater.inflate(R.layout.two_lines_list_preference_row, null);
+ holder = new ViewHolder();
+ holder.title = (TextView) convertView.findViewById(R.id.two_lines_list_view_row_text);
+ holder.subTitle = (TextView) convertView.findViewById(R.id.two_lines_list_view_row_subtext);
+ holder.radioBtn = (RadioButton) convertView.findViewById(R.id.two_lines_list_view_row_radiobtn);
+ convertView.setTag(holder);
+
+ holder.title.setOnClickListener(listener);
+ holder.subTitle.setOnClickListener(listener);
+ holder.radioBtn.setOnClickListener(listener);
+ }
+ else
+ {
+ holder = (ViewHolder) convertView.getTag();
+ }
+ final TwoLinesListPreference preference = getTwoLinesListPreference();
+
+ holder.title.setText(preference.getEntries()[position]);
+ holder.title.setTag(position);
+ holder.subTitle.setText(preference.getEntriesSubtitles()[position]);
+ holder.subTitle.setTag(position);
+
+ holder.radioBtn.setChecked(preference.getValueIndex() == position);
+ holder.radioBtn.setTag(position);
+
+ return convertView;
+ }
+ }
+
+ @Override
+ protected void onPrepareDialogBuilder(AlertDialog.Builder builder)
+ {
+ super.onPrepareDialogBuilder(builder);
+ final TwoLinesListPreference preference = getTwoLinesListPreference();
+ CharSequence[] entries = preference.getEntries();
+ String[] values = new String[ entries.length ];
+ for (int i = 0; i < entries.length; i ++)
+ {
+ values[i] = entries[i].toString();
+ }
+
+ ListAdapter adapter = new YourAdapter(builder.getContext(), values);
+ builder.setAdapter(adapter, new DialogInterface.OnClickListener()
+ {
+ @Override
+ public void onClick(DialogInterface dialog, int which)
+ {
+ }
+ });
+ }
+
+ public static TwoLinesListPreferenceDialogFragmentCompat newInstance(String key)
+ {
+ TwoLinesListPreferenceDialogFragmentCompat fragment = new TwoLinesListPreferenceDialogFragmentCompat();
+ Bundle b = new Bundle(1);
+ b.putString("key", key);
+ fragment.setArguments(b);
+ return fragment;
+ }
+
+ public void onDialogClosed(boolean positiveResult)
+ {
+ }
+
+ private class ViewHolderClickListener implements OnClickListener
+ {
+ @Override
+ public void onClick(View v)
+ {
+ final TwoLinesListPreference preference = getTwoLinesListPreference();
+ int EntryIndex = (Integer) v.getTag();
+ preference.setValue(preference.getEntries()[EntryIndex].toString());
+ TwoLinesListPreferenceDialogFragmentCompat.this.getDialog().dismiss();
+ }
+ }
+}
diff --git a/Android/src/emu/project64/settings/VideoFragment.java b/Android/src/emu/project64/settings/VideoFragment.java
new file mode 100644
index 000000000..4db06a5f4
--- /dev/null
+++ b/Android/src/emu/project64/settings/VideoFragment.java
@@ -0,0 +1,28 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.settings;
+
+import emu.project64.R;
+
+public class VideoFragment extends BaseSettingsFragment
+{
+ @Override
+ protected int getXml()
+ {
+ return R.xml.setting_video;
+ }
+
+ @Override
+ protected int getTitleId()
+ {
+ return R.string.video_screen_title;
+ }
+}
diff --git a/Android/src/emu/project64/task/ExtractAssetsTask.java b/Android/src/emu/project64/task/ExtractAssetsTask.java
new file mode 100644
index 000000000..a49b750e6
--- /dev/null
+++ b/Android/src/emu/project64/task/ExtractAssetsTask.java
@@ -0,0 +1,323 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.task;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+import android.content.res.AssetManager;
+import android.os.AsyncTask;
+import android.text.TextUtils;
+import android.util.Log;
+
+public class ExtractAssetsTask extends AsyncTask>
+{
+ public interface ExtractAssetsListener
+ {
+ public void onExtractAssetsProgress( String nextFileToExtract );
+ public void onExtractAssetsFinished( List failures );
+ }
+
+ public ExtractAssetsTask( AssetManager assetManager, String srcPath, String dstPath, ExtractAssetsListener listener )
+ {
+ if (assetManager == null )
+ throw new IllegalArgumentException( "Asset manager cannot be null" );
+ if( TextUtils.isEmpty( srcPath ) )
+ throw new IllegalArgumentException( "Source path cannot be null or empty" );
+ if( TextUtils.isEmpty( dstPath ) )
+ throw new IllegalArgumentException( "Destination path cannot be null or empty" );
+ if( listener == null )
+ throw new IllegalArgumentException( "Listener cannot be null" );
+
+ mAssetManager = assetManager;
+ mSrcPath = srcPath;
+ mDstPath = dstPath;
+ mListener = listener;
+ }
+
+ private final AssetManager mAssetManager;
+ private final String mSrcPath;
+ private final String mDstPath;
+ private final ExtractAssetsListener mListener;
+
+ @Override
+ protected List doInBackground( Void... params )
+ {
+ return extractAssets( mSrcPath, mDstPath );
+ }
+
+ @Override
+ protected void onProgressUpdate( String... values )
+ {
+ mListener.onExtractAssetsProgress( values[0] );
+ }
+
+ @Override
+ protected void onPostExecute( List result )
+ {
+ mListener.onExtractAssetsFinished( result );
+ }
+
+ public static final class Failure
+ {
+ public enum Reason
+ {
+ FILE_UNWRITABLE,
+ FILE_UNCLOSABLE,
+ ASSET_UNCLOSABLE,
+ ASSET_IO_EXCEPTION,
+ FILE_IO_EXCEPTION,
+ }
+
+ public final String srcPath;
+ public final String dstPath;
+ public final Reason reason;
+ public Failure( String srcPath, String dstPath, Reason reason )
+ {
+ this.srcPath = srcPath;
+ this.dstPath = dstPath;
+ this.reason = reason;
+ }
+
+ @Override
+ public String toString()
+ {
+ switch( reason )
+ {
+ case FILE_UNWRITABLE:
+ return "Failed to open file " + dstPath;
+ case FILE_UNCLOSABLE:
+ return "Failed to close file " + dstPath;
+ case ASSET_UNCLOSABLE:
+ return "Failed to close asset " + srcPath;
+ case ASSET_IO_EXCEPTION:
+ return "Failed to extract asset " + srcPath + " to file " + dstPath;
+ case FILE_IO_EXCEPTION:
+ return "Failed to add file " + srcPath + " to file " + dstPath;
+ default:
+ return "Failed using source " + srcPath + " and destination " + dstPath;
+ }
+ }
+ }
+
+ private List extractAssets( String srcPath, String dstPath )
+ {
+ final List failures = new ArrayList();
+
+ if( srcPath.startsWith( "/" ) )
+ srcPath = srcPath.substring( 1 );
+
+ String[] srcSubPaths = getAssetList( mAssetManager, srcPath );
+
+ if( srcSubPaths.length > 0 )
+ {
+ // srcPath is a directory
+
+ // Ensure the parent directories exist
+ new File( dstPath ).mkdirs();
+
+ // Some files are too big for Android 2.2 and below, so we break them into parts.
+ // We use a simple naming scheme where we just append .part0, .part1, etc.
+ Pattern pattern = Pattern.compile( "(.+)\\.part(\\d+)$" );
+ HashMap fileParts = new HashMap();
+
+ // Recurse into each subdirectory
+ for( String srcSubPath : srcSubPaths )
+ {
+ Matcher matcher = pattern.matcher( srcSubPath );
+ if( matcher.matches() )
+ {
+ String name = matcher.group(1);
+ if( fileParts.containsKey( name ) )
+ fileParts.put( name, fileParts.get( name ) + 1 );
+ else
+ fileParts.put( name, 1 );
+ }
+ String suffix = "/" + srcSubPath;
+ failures.addAll( extractAssets( srcPath + suffix, dstPath + suffix ) );
+ }
+
+ // Combine the large broken files, if any
+ combineFileParts( fileParts, dstPath );
+ }
+ else // srcPath is a file.
+ {
+ // Call the progress listener before extracting
+ publishProgress( dstPath );
+
+ // IO objects, initialize null to eliminate lint error
+ OutputStream out = null;
+ InputStream in = null;
+
+ // Extract the file
+ try
+ {
+ out = new FileOutputStream( dstPath );
+ in = mAssetManager.open( srcPath );
+ byte[] buffer = new byte[1024];
+ int read;
+
+ while( ( read = in.read( buffer ) ) != -1 )
+ {
+ out.write( buffer, 0, read );
+ }
+ out.flush();
+ }
+ catch( FileNotFoundException e )
+ {
+ Failure failure = new Failure( srcPath, dstPath, Failure.Reason.FILE_UNWRITABLE );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ catch( IOException e )
+ {
+ Failure failure = new Failure( srcPath, dstPath, Failure.Reason.ASSET_IO_EXCEPTION );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ finally
+ {
+ if( out != null )
+ {
+ try
+ {
+ out.close();
+ }
+ catch( IOException e )
+ {
+ Failure failure = new Failure( srcPath, dstPath, Failure.Reason.FILE_UNCLOSABLE );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ }
+ if( in != null )
+ {
+ try
+ {
+ in.close();
+ }
+ catch( IOException e )
+ {
+ Failure failure = new Failure( srcPath, dstPath, Failure.Reason.ASSET_UNCLOSABLE );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ }
+ }
+ }
+
+ return failures;
+ }
+
+ private static String[] getAssetList( AssetManager assetManager, String srcPath )
+ {
+ String[] srcSubPaths = null;
+
+ try
+ {
+ srcSubPaths = assetManager.list( srcPath );
+ }
+ catch( IOException e )
+ {
+ Log.w( "ExtractAssetsTask", "Failed to get asset file list." );
+ }
+
+ return srcSubPaths;
+ }
+
+ private static List combineFileParts( Map filePieces, String dstPath )
+ {
+ List failures = new ArrayList();
+ for (String name : filePieces.keySet() )
+ {
+ String src = null;
+ String dst = dstPath + "/" + name;
+ OutputStream out = null;
+ InputStream in = null;
+ try
+ {
+ out = new FileOutputStream( dst );
+ byte[] buffer = new byte[1024];
+ int read;
+ for( int i = 0; i < filePieces.get( name ); i++ )
+ {
+ src = dst + ".part" + i;
+ try
+ {
+ in = new FileInputStream( src );
+ while( ( read = in.read( buffer ) ) != -1 )
+ {
+ out.write( buffer, 0, read );
+ }
+ out.flush();
+ }
+ catch( IOException e )
+ {
+ Failure failure = new Failure( src, dst, Failure.Reason.FILE_IO_EXCEPTION );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ finally
+ {
+ if( in != null )
+ {
+ try
+ {
+ in.close();
+ new File( src ).delete();
+ }
+ catch( IOException e )
+ {
+ Failure failure = new Failure( src, dst, Failure.Reason.FILE_UNCLOSABLE );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ }
+ }
+ }
+ }
+ catch( FileNotFoundException e )
+ {
+ Failure failure = new Failure( src, dst, Failure.Reason.FILE_UNWRITABLE );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ finally
+ {
+ if( out != null )
+ {
+ try
+ {
+ out.close();
+ }
+ catch( IOException e )
+ {
+ Failure failure = new Failure( src, dst, Failure.Reason.FILE_UNCLOSABLE );
+ Log.e( "ExtractAssetsTask", failure.toString() );
+ failures.add( failure );
+ }
+ }
+ }
+ }
+ return failures;
+ }
+}
diff --git a/Android/src/emu/project64/util/DeviceUtil.java b/Android/src/emu/project64/util/DeviceUtil.java
new file mode 100644
index 000000000..64cf520a7
--- /dev/null
+++ b/Android/src/emu/project64/util/DeviceUtil.java
@@ -0,0 +1,371 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+
+import emu.project64.AndroidDevice;
+import emu.project64.input.map.AxisMap;
+import android.annotation.SuppressLint;
+import android.annotation.TargetApi;
+import android.app.Activity;
+import android.content.Context;
+import android.os.Build;
+import android.text.TextUtils;
+import android.util.DisplayMetrics;
+import android.view.InputDevice;
+import android.view.InputDevice.MotionRange;
+import android.view.MotionEvent;
+import android.view.View;
+
+public final class DeviceUtil
+{
+ /**
+ * Gets the hardware information from /proc/cpuinfo.
+ *
+ * @return The hardware string.
+ */
+ public static String getCpuInfo()
+ {
+ // From http://android-er.blogspot.com/2009/09/read-android-cpu-info.html
+ String result = Utility.executeShellCommand( "/system/bin/cat", "/proc/cpuinfo" );
+
+ // Remove the serial number for privacy
+ Pattern pattern = Pattern.compile( "^serial\\s*?:.*?$", Pattern.CASE_INSENSITIVE
+ | Pattern.MULTILINE );
+ result = pattern.matcher( result ).replaceAll( "Serial : XXXX" );
+
+ // Additional information in android.os.Build may be useful
+ result += "\n";
+ result += "Board: " + Build.BOARD + "\n";
+ result += "Brand: " + Build.BRAND + "\n";
+ result += "Device: " + Build.DEVICE + "\n";
+ result += "Display: " + Build.DISPLAY + "\n";
+ result += "Host: " + Build.HOST + "\n";
+ result += "ID: " + Build.ID + "\n";
+ result += "Manufacturer: " + Build.MANUFACTURER + "\n";
+ result += "Model: " + Build.MODEL + "\n";
+ result += "Product: " + Build.PRODUCT + "\n";
+ return result;
+ }
+
+ public static String getLogCat()
+ {
+ return Utility.executeShellCommand( "logcat", "-d", "-v", "long" );
+ }
+
+ public static void clearLogCat()
+ {
+ Utility.executeShellCommand( "logcat", "-c" );
+ }
+
+ @TargetApi( 12 )
+ public static String getAxisInfo()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ int[] ids = InputDevice.getDeviceIds();
+ for( int i = 0; i < ids.length; i++ )
+ {
+ InputDevice device = InputDevice.getDevice( ids[i] );
+ AxisMap axisMap = AxisMap.getMap( device );
+ if( !TextUtils.isEmpty( axisMap.getSignature() ) )
+ {
+ builder.append( "Device: " + device.getName() + "\n" );
+ builder.append( "Type: " + axisMap.getSignatureName() + "\n" );
+ builder.append( "Signature: " + axisMap.getSignature() + "\n" );
+ builder.append( "Hash: " + axisMap.getSignature().hashCode() + "\n" );
+
+ List ranges = getPeripheralMotionRanges( device );
+ for( MotionRange range : ranges )
+ {
+ if( range.getSource() == InputDevice.SOURCE_JOYSTICK )
+ {
+ int axisCode = range.getAxis();
+ String axisName = MotionEvent.axisToString( axisCode );
+ String className = getAxisClassName( axisMap.getClass( axisCode ) );
+ builder.append( " " + axisName + ": " + className + "\n" );
+ }
+ }
+ builder.append( "\n" );
+ }
+ }
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets the peripheral information using the appropriate Android API.
+ *
+ * @return The peripheral info string.
+ */
+ @TargetApi( 16 )
+ public static String getPeripheralInfo()
+ {
+ StringBuilder builder = new StringBuilder();
+
+ if( AndroidDevice.IS_GINGERBREAD )
+ {
+ int[] ids = InputDevice.getDeviceIds();
+ for( int i = 0; i < ids.length; i++ )
+ {
+ InputDevice device = InputDevice.getDevice( ids[i] );
+ if( device != null )
+ {
+ if( 0 < ( device.getSources() & ( InputDevice.SOURCE_CLASS_BUTTON | InputDevice.SOURCE_CLASS_JOYSTICK ) ) )
+ {
+ builder.append( "Device: " + device.getName() + "\n" );
+ builder.append( "Id: " + device.getId() + "\n" );
+ if( AndroidDevice.IS_JELLY_BEAN )
+ {
+ builder.append( "Descriptor: " + device.getDescriptor() + "\n" );
+ if( device.getVibrator().hasVibrator() )
+ builder.append( "Vibrator: true\n" );
+ }
+ builder.append( "Class: " + getSourceClassesString( device.getSources() )
+ + "\n" );
+
+ List ranges = getPeripheralMotionRanges( device );
+ if( ranges.size() > 0 )
+ {
+ builder.append( "Axes: " + ranges.size() + "\n" );
+ for( MotionRange range : ranges )
+ {
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ String axisName = MotionEvent.axisToString( range.getAxis() );
+ String source = getSourceName( range.getSource() );
+ builder.append( " " + axisName + " (" + source + ")" );
+ }
+ else
+ {
+ builder.append( " Axis" );
+ }
+ builder.append( ": ( " + range.getMin() + " , " + range.getMax()
+ + " )\n" );
+ }
+ }
+ builder.append( "\n" );
+ }
+ }
+ }
+ }
+
+ return builder.toString();
+ }
+
+ /**
+ * Gets the motion ranges of a peripheral using the appropriate Android API.
+ *
+ * @return The motion ranges associated with the peripheral.
+ */
+ @TargetApi( 12 )
+ public static List getPeripheralMotionRanges( InputDevice device )
+ {
+ List ranges;
+ if( AndroidDevice.IS_HONEYCOMB_MR1 )
+ {
+ ranges = device.getMotionRanges();
+ }
+ else if( AndroidDevice.IS_GINGERBREAD )
+ {
+ // Earlier APIs we have to do it the hard way
+ ranges = new ArrayList();
+ boolean finished = false;
+ for( int j = 0; j < 256 && !finished; j++ )
+ {
+ // TODO: Eliminate reliance on try-catch
+ try
+ {
+ if( device.getMotionRange( j ) != null )
+ ranges.add( device.getMotionRange( j ) );
+ }
+ catch( Exception e )
+ {
+ finished = true;
+ }
+ }
+ }
+ else
+ {
+ ranges = new ArrayList();
+ }
+
+ return ranges;
+ }
+
+ /**
+ * Gets the name of an axis class.
+ *
+ * @param axisClass The axis class to get the name of.
+ *
+ * @return The name of the axis class.
+ */
+ public static String getAxisClassName( int axisClass )
+ {
+ switch( axisClass )
+ {
+ case AxisMap.AXIS_CLASS_UNKNOWN:
+ return "Unknown";
+ case AxisMap.AXIS_CLASS_IGNORED:
+ return "Ignored";
+ case AxisMap.AXIS_CLASS_STICK:
+ return "Stick";
+ case AxisMap.AXIS_CLASS_TRIGGER:
+ return "Trigger";
+ default:
+ return "";
+ }
+ }
+
+ /**
+ * Gets the name of an action.
+ *
+ * @param action The action being performed.
+ * @param isMotionEvent Whether or not the action is a motion event.
+ *
+ * @return The name of the action being performed.
+ */
+ public static String getActionName( int action, boolean isMotionEvent )
+ {
+ switch( action )
+ {
+ case MotionEvent.ACTION_DOWN:
+ return "DOWN";
+ case MotionEvent.ACTION_UP:
+ return "UP";
+ case MotionEvent.ACTION_MOVE:
+ return isMotionEvent ? "MOVE" : "MULTIPLE";
+ case MotionEvent.ACTION_CANCEL:
+ return "CANCEL";
+ case MotionEvent.ACTION_OUTSIDE:
+ return "OUTSIDE";
+ case MotionEvent.ACTION_POINTER_DOWN:
+ return "POINTER_DOWN";
+ case MotionEvent.ACTION_POINTER_UP:
+ return "POINTER_UP";
+ case MotionEvent.ACTION_HOVER_MOVE:
+ return "HOVER_MOVE";
+ case MotionEvent.ACTION_SCROLL:
+ return "SCROLL";
+ case MotionEvent.ACTION_HOVER_ENTER:
+ return "HOVER_ENTER";
+ case MotionEvent.ACTION_HOVER_EXIT:
+ return "HOVER_EXIT";
+ default:
+ return "ACTION_" + Integer.toString( action );
+ }
+ }
+
+ /**
+ * Gets the name of the source performing an action.
+ *
+ * @param source A number representing the source.
+ *
+ * @return The name of the source.
+ */
+ public static String getSourceName( int source )
+ {
+ switch( source )
+ {
+ case InputDevice.SOURCE_CLASS_BUTTON:
+ return "BUTTON";
+ case InputDevice.SOURCE_CLASS_POINTER:
+ return "POINTER";
+ case InputDevice.SOURCE_CLASS_TRACKBALL:
+ return "TRACKBALL";
+ case InputDevice.SOURCE_CLASS_POSITION:
+ return "POSITION";
+ case InputDevice.SOURCE_CLASS_JOYSTICK:
+ return "JOYSTICK";
+ case InputDevice.SOURCE_DPAD:
+ return "dpad";
+ case InputDevice.SOURCE_GAMEPAD:
+ return "gamepad";
+ case InputDevice.SOURCE_JOYSTICK:
+ return "joystick";
+ case InputDevice.SOURCE_KEYBOARD:
+ return "keyboard";
+ case InputDevice.SOURCE_MOUSE:
+ return "mouse";
+ case InputDevice.SOURCE_STYLUS:
+ return "stylus";
+ case InputDevice.SOURCE_TOUCHPAD:
+ return "touchpad";
+ case InputDevice.SOURCE_TOUCHSCREEN:
+ return "touchscreen";
+ case InputDevice.SOURCE_TRACKBALL:
+ return "trackball";
+ case InputDevice.SOURCE_UNKNOWN:
+ return "unknown";
+ default:
+ return "source_" + source;
+ }
+ }
+
+ @SuppressLint( "InlinedApi" )
+ public static String getSourcesString( int sources )
+ {
+ List names = new ArrayList();
+ addString( sources, InputDevice.SOURCE_KEYBOARD, names );
+ addString( sources, InputDevice.SOURCE_DPAD, names );
+ addString( sources, InputDevice.SOURCE_GAMEPAD, names );
+ addString( sources, InputDevice.SOURCE_TOUCHSCREEN, names );
+ addString( sources, InputDevice.SOURCE_MOUSE, names );
+ addString( sources, InputDevice.SOURCE_STYLUS, names );
+ addString( sources, InputDevice.SOURCE_TOUCHPAD, names );
+ addString( sources, InputDevice.SOURCE_JOYSTICK, names );
+ return TextUtils.join( ", ", names );
+ }
+
+ @SuppressLint( "InlinedApi" )
+ public static String getSourceClassesString( int sources )
+ {
+ List names = new ArrayList();
+ addString( sources, InputDevice.SOURCE_CLASS_BUTTON, names );
+ addString( sources, InputDevice.SOURCE_CLASS_POINTER, names );
+ addString( sources, InputDevice.SOURCE_CLASS_TRACKBALL, names );
+ addString( sources, InputDevice.SOURCE_CLASS_POSITION, names );
+ addString( sources, InputDevice.SOURCE_CLASS_JOYSTICK, names );
+ return TextUtils.join( ", ", names );
+ }
+
+ private static void addString( int sources, int sourceClass, List strings )
+ {
+ if( ( sources & sourceClass ) > 0 )
+ strings.add( getSourceName( sourceClass ) );
+ }
+
+ /**
+ * Returns display metrics for the specified view.
+ *
+ * @param view An instance of View (must be the child of an Activity).
+ *
+ * @return DisplayMetrics instance, or null if there was a problem.
+ */
+ public static DisplayMetrics getDisplayMetrics( View view )
+ {
+ if( view == null )
+ return null;
+
+ Context context = view.getContext();
+ if( !( context instanceof Activity ) )
+ return null;
+ DisplayMetrics metrics = new DisplayMetrics();
+ ((Activity) context).getWindowManager().getDefaultDisplay().getMetrics( metrics );
+ return metrics;
+ }
+}
diff --git a/Android/src/emu/project64/util/FileUtil.java b/Android/src/emu/project64/util/FileUtil.java
new file mode 100644
index 000000000..384f8e3f9
--- /dev/null
+++ b/Android/src/emu/project64/util/FileUtil.java
@@ -0,0 +1,168 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import java.io.File;
+import java.io.FileFilter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+
+import emu.project64.AndroidDevice;
+import android.text.Html;
+import android.text.TextUtils;
+
+/**
+ * Utility class that provides methods which simplify file I/O tasks.
+ */
+public final class FileUtil
+{
+ public static void populate( File startPath, boolean includeParent, boolean includeDirectories,
+ boolean includeFiles, List outNames, List outPaths )
+ {
+ if( !startPath.exists() )
+ return;
+
+ if( startPath.isFile() )
+ startPath = startPath.getParentFile();
+
+ if( startPath.getParentFile() == null )
+ includeParent = false;
+
+ outNames.clear();
+ outPaths.clear();
+
+ if( includeParent )
+ {
+
+ outNames.add( Html.fromHtml( ".." ) );
+ boolean BaseDir = false;
+ ArrayList StorageDirectories = AndroidDevice.getStorageDirectories();
+ for( String directory : StorageDirectories )
+ {
+ if (TextUtils.equals(startPath.getPath(), directory))
+ {
+ BaseDir = true;
+ break;
+ }
+ }
+
+ outPaths.add( BaseDir ? null : startPath.getParentFile().getPath() );
+ }
+
+ if( includeDirectories )
+ {
+ for( File directory : getContents( startPath, new VisibleDirectoryFilter() ) )
+ {
+ outNames.add( Html.fromHtml( "" + directory.getName() + "" ) );
+ outPaths.add( directory.getPath() );
+ }
+ }
+
+ if( includeFiles )
+ {
+ for( File file : getContents( startPath, new VisibleFileFilter() ) )
+ {
+ outNames.add( Html.fromHtml( file.getName() ) );
+ outPaths.add( file.getPath() );
+ }
+ }
+ }
+
+ public static List getContents( File startPath, FileFilter fileFilter )
+ {
+ // Get a filtered, sorted list of files
+ List results = new ArrayList();
+ File[] files = startPath.listFiles( fileFilter );
+
+ if( files != null )
+ {
+ Collections.addAll( results, files );
+ Collections.sort( results, new FileUtil.FileComparer() );
+ }
+
+ return results;
+ }
+
+ private static class FileComparer implements Comparator
+ {
+ // Compare files first by directory/file then alphabetically (case-insensitive)
+ @Override
+ public int compare( File lhs, File rhs )
+ {
+ if( lhs.isDirectory() && rhs.isFile() )
+ return -1;
+ else if( lhs.isFile() && rhs.isDirectory() )
+ return 1;
+ else
+ return lhs.getName().compareToIgnoreCase( rhs.getName() );
+ }
+ }
+
+ private static class VisibleFileFilter implements FileFilter
+ {
+ // Include only non-hidden files not starting with '.'
+ @Override
+ public boolean accept( File pathname )
+ {
+ return ( pathname != null ) && ( pathname.isFile() ) && ( !pathname.isHidden() )
+ && ( !pathname.getName().startsWith( "." ) );
+ }
+ }
+
+ private static class VisibleDirectoryFilter implements FileFilter
+ {
+ // Include only non-hidden directories not starting with '.'
+ @Override
+ public boolean accept( File pathname )
+ {
+ return ( pathname != null ) && ( pathname.isDirectory() ) && ( !pathname.isHidden() )
+ && ( !pathname.getName().startsWith( "." ) );
+ }
+ }
+
+ /**
+ * Deletes a given folder directory in the form of a {@link File}
+ *
+ * @param folder The folder to delete.
+ *
+ * @return True if the folder was deleted, false otherwise.
+ */
+ public static boolean deleteFolder( File folder )
+ {
+ if( folder.isDirectory() )
+ {
+ String[] children = folder.list();
+ if( children != null )
+ {
+ for( String child : children )
+ {
+ boolean success = deleteFolder( new File( folder, child ) );
+ if( !success )
+ return false;
+ }
+ }
+ }
+
+ return folder.delete();
+ }
+
+ public static String getFileNameFromPath(String path)
+ {
+ if (path == null)
+ {
+ return "";
+ }
+ int index = path.lastIndexOf('/');
+ return index > -1 ? path.substring(index+1) : path;
+ }
+}
diff --git a/Android/src/emu/project64/util/Image.java b/Android/src/emu/project64/util/Image.java
new file mode 100644
index 000000000..42d910a0d
--- /dev/null
+++ b/Android/src/emu/project64/util/Image.java
@@ -0,0 +1,203 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Rect;
+import android.graphics.drawable.BitmapDrawable;
+
+/**
+ * The Image class provides a simple interface to common image manipulation methods.
+ */
+public final class Image
+{
+ public final Bitmap image;
+ public final BitmapDrawable drawable;
+ public final int width;
+ public final int height;
+ public final int hWidth;
+ public final int hHeight;
+
+ public float scale = 1.0f;
+ public int x = 0;
+ public int y = 0;
+ public final Rect drawRect = new Rect();
+
+ /**
+ * Constructor: Loads an image file and sets the initial properties.
+ *
+ * @param res
+ * A handle to the app resources.
+ * @param filename
+ * The path to the image file.
+ */
+ public Image( Resources res, String filename )
+ {
+ image = BitmapFactory.decodeFile( filename );
+ drawable = new BitmapDrawable( res, image );
+
+ if( image == null )
+ {
+ width = 0;
+ height = 0;
+ }
+ else
+ {
+ width = image.getWidth();
+ height = image.getHeight();
+ }
+
+ hWidth = (int) ( width / 2.0f );
+ hHeight = (int) ( height / 2.0f );
+ }
+
+ /**
+ * Constructor: Creates a clone copy of a given Image.
+ *
+ * @param res
+ * A handle to the app resources.
+ * @param clone
+ * The Image to make a copy of.
+ */
+ public Image( Resources res, Image clone )
+ {
+ if( clone == null )
+ {
+ image = null;
+ drawable = null;
+ width = 0;
+ height = 0;
+ hWidth = 0;
+ hHeight = 0;
+ }
+ else
+ {
+ image = clone.image;
+ drawable = new BitmapDrawable( res, image );
+ width = clone.width;
+ height = clone.height;
+ hWidth = clone.hWidth;
+ hHeight = clone.hHeight;
+ scale = clone.scale;
+ }
+ }
+
+ /**
+ * Sets the scaling factor of the image.
+ *
+ * @param scale
+ * Factor to scale the image by.
+ */
+ public void setScale( float scale )
+ {
+ this.scale = scale;
+ setPos( x, y ); // Apply the new scaling factor
+ }
+
+ /**
+ * Sets the screen position of the image (in pixels).
+ *
+ * @param x
+ * X-coordinate.
+ * @param y
+ * Y-coordinate.
+ */
+ public void setPos( int x, int y )
+ {
+ this.x = x;
+ this.y = y;
+ drawRect.set( x, y, x + (int) ( width * scale ), y + (int) ( height * scale ) );
+ if( drawable != null )
+ drawable.setBounds( drawRect );
+ }
+
+ /**
+ * Places the image at the specified location in terms of percentage of screen size.
+ *
+ * @param percentX
+ * Percent of screen width to shift the image by.
+ * @param percentY
+ * Percent of screen height to shift the image by.
+ * @param screenW
+ * Horizontal screen dimension (in pixels).
+ * @param screenH
+ * Vertical screen dimension (in pixels).
+ */
+ public void fitPercent( float percentX, float percentY, int screenW, int screenH )
+ {
+ int px = (int) ( ( percentX / 100f ) * ( screenW - width * scale ) );
+ int py = (int) ( ( percentY / 100f ) * ( screenH - height * scale ) );
+ setPos( px, py );
+ }
+
+ /**
+ * Centers the image at the specified coordinates, without going beyond the edges of the
+ * specified rectangle.
+ *
+ * @param centerX
+ * X-coordinate to center the image at.
+ * @param centerY
+ * Y-coordinate to center the image at.
+ * @param rectX
+ * X-coordinate of the bounding rectangle.
+ * @param rectY
+ * Y-coordinate of the bounding rectangle.
+ * @param rectW
+ * Horizontal bounding rectangle dimension (in pixels).
+ * @param rectH
+ * Vertical bounding rectangle dimension (in pixels).
+ */
+ public void fitCenter( int centerX, int centerY, int rectX, int rectY, int rectW, int rectH )
+ {
+ float cx = centerX;
+ float cy = centerY;
+
+ if( cx < rectX + ( hWidth * scale ) )
+ cx = rectX + ( hWidth * scale );
+ if( cy < rectY + ( hHeight * scale ) )
+ cy = rectY + ( hHeight * scale );
+ if( cx + ( hWidth * scale ) > rectX + rectW )
+ cx = rectX + rectW - ( hWidth * scale );
+ if( cy + ( hHeight * scale ) > rectY + rectH )
+ cy = rectY + rectH - ( hHeight * scale );
+
+ int px = (int) ( cx - ( hWidth * scale ) );
+ int py = (int) ( cy - ( hHeight * scale ) );
+ setPos( px, py );
+ }
+
+ /**
+ * Draws the image.
+ *
+ * @param canvas
+ * Canvas to draw the image on.
+ */
+ public void draw( Canvas canvas )
+ {
+ if( drawable != null )
+ drawable.draw( canvas );
+ }
+
+ /**
+ * Sets the alpha value of the image.
+ *
+ * @param alpha
+ * Alpha value.
+ */
+ public void setAlpha( int alpha )
+ {
+ if( drawable != null )
+ drawable.setAlpha( alpha );
+ }
+}
diff --git a/Android/src/emu/project64/util/Notifier.java b/Android/src/emu/project64/util/Notifier.java
new file mode 100644
index 000000000..bfc7c1a59
--- /dev/null
+++ b/Android/src/emu/project64/util/Notifier.java
@@ -0,0 +1,135 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import emu.project64.game.GameOverlay;
+import emu.project64.R;
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.DialogInterface;
+import android.util.Log;
+
+/**
+ * A small class to encapsulate the notification process for Mupen64PlusAE.
+ */
+public final class Notifier
+{
+ private static Runnable sDisplayMessager = null;
+
+ /**
+ * Pop up a temporary message on the device.
+ *
+ * @param activity The activity to display from
+ * @param message The message string to display.
+ */
+ public static void DisplayError( Activity activity, String message )
+ {
+ if( activity == null )
+ return;
+
+ final String finalMessage = new String(message);
+ final Activity finalActivity = activity;
+
+ sDisplayMessager = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ new AlertDialog.Builder(finalActivity)
+ .setTitle("Error")
+ .setMessage(finalMessage)
+ .setPositiveButton("OK", new DialogInterface.OnClickListener()
+ {
+ public void onClick(DialogInterface dialog, int id)
+ {
+ // You don't have to do anything here if you just want it dismissed when clicked
+ synchronized(sDisplayMessager)
+ {
+ sDisplayMessager.notify();
+ };
+ }
+ })
+ .create()
+ .show();
+ }
+ };
+ activity.runOnUiThread( sDisplayMessager );
+ synchronized(sDisplayMessager)
+ {
+ try
+ {
+ sDisplayMessager.wait();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ catch (IllegalMonitorStateException e)
+ {
+ }
+ }
+ Log.d("DisplayError", "Done");
+ }
+
+ public static void showMessage( Activity activity, String message, int Duratation )
+ {
+ if( activity == null )
+ return;
+
+ GameOverlay overlay = (GameOverlay) activity.findViewById(R.id.gameOverlay);
+ if (overlay == null)
+ return;
+
+ overlay.SetDisplayMessage(message, Duratation);
+ }
+
+ public static void showMessage2( Activity activity, String message )
+ {
+ if( activity == null )
+ return;
+
+ GameOverlay overlay = (GameOverlay) activity.findViewById(R.id.gameOverlay);
+ overlay.SetDisplayMessage2(message);
+ }
+
+ private static Runnable runEmulationStopped = null;
+ public static void EmulationStopped (Activity activity)
+ {
+ final Activity finalActivity = activity;
+
+ runEmulationStopped = new Runnable()
+ {
+ @Override
+ public void run()
+ {
+ finalActivity.finish();
+ synchronized(runEmulationStopped)
+ {
+ runEmulationStopped.notify();
+ };
+ }
+ };
+ activity.runOnUiThread( runEmulationStopped );
+ synchronized(runEmulationStopped)
+ {
+ try
+ {
+ runEmulationStopped.wait();
+ }
+ catch (InterruptedException e)
+ {
+ }
+ catch (IllegalMonitorStateException e)
+ {
+ }
+ }
+ Log.d("EmulationStopped", "Done");
+ }
+}
diff --git a/Android/src/emu/project64/util/SafeMethods.java b/Android/src/emu/project64/util/SafeMethods.java
new file mode 100644
index 000000000..e3a03712e
--- /dev/null
+++ b/Android/src/emu/project64/util/SafeMethods.java
@@ -0,0 +1,176 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.LinkedList;
+
+import android.text.TextUtils;
+
+/**
+ * A boilerplate class for safely doing things, with simple exception handling.
+ */
+public final class SafeMethods
+{
+ /**
+ * Safely converts a string into a boolean.
+ *
+ * @param val String containing the boolean to convert.
+ * @param fail Value to use if unable to convert val to a boolean.
+ *
+ * @return The converted boolean, or the specified value if unsuccessful.
+ */
+ public static boolean toBoolean( String val, boolean fail )
+ {
+ if( TextUtils.isEmpty( val ) )
+ return fail; // Not a boolean
+
+ try
+ {
+ // Convert to boolean
+ return Boolean.parseBoolean( val );
+ }
+ catch( NumberFormatException nfe )
+ {
+ }
+ // Conversion failed
+ return fail;
+ }
+
+ /**
+ * Safely converts a string into an integer.
+ *
+ * @param val String containing the number to convert.
+ * @param fail Value to use if unable to convert val to an integer.
+ *
+ * @return The converted integer, or the specified value if unsuccessful.
+ */
+ public static int toInt( String val, int fail )
+ {
+ if( TextUtils.isEmpty( val ) )
+ return fail; // Not a number
+
+ try
+ {
+ // Convert to integer
+ return Integer.parseInt( val );
+ }
+ catch( NumberFormatException nfe )
+ {
+ }
+ // Conversion failed
+ return fail;
+ }
+
+ /**
+ * Safely converts a string into a float.
+ *
+ * @param val String containing the number to convert.
+ * @param fail Value to use if unable to convert val to a float.
+ *
+ * @return The converted float, or the specified value if unsuccessful.
+ */
+ public static float toFloat( String val, float fail )
+ {
+ if( TextUtils.isEmpty( val ) )
+ return fail; // Not a number
+
+ try
+ {
+ // Convert to float
+ return Float.parseFloat( val );
+ }
+ catch( NumberFormatException nfe )
+ {
+ }
+ // Conversion failed
+ return fail;
+ }
+
+ /**
+ * Safely sleep.
+ *
+ * @param milliseconds The sleep duration.
+ */
+ public static void sleep( int milliseconds )
+ {
+ try
+ {
+ Thread.sleep( milliseconds );
+ }
+ catch( InterruptedException e )
+ {
+ }
+ }
+
+ /**
+ * Safely wait for a thread to die.
+ *
+ * @param thread Thread to join.
+ * @param milliseconds Time to wait, in milliseconds (0 to wait indefinitely).
+ */
+ public static void join( Thread thread, int milliseconds )
+ {
+ if( thread == null || milliseconds < 0 )
+ return;
+
+ try
+ {
+ thread.join( milliseconds );
+ }
+ catch( InterruptedException e )
+ {
+ }
+ }
+
+ /**
+ * Safely executes a command and its arguments in a separate native process
+ *
+ * @param cmd Array containing the command and its arguments.
+ * @param wait Whether or not to wait for the command to finish executing.
+ *
+ * @return Array containing the output (if any), or null if wait was false.
+ */
+ public static String[] exec( String[] cmd, boolean wait )
+ {
+ try
+ {
+ Process process = Runtime.getRuntime().exec( cmd );
+ if( wait )
+ {
+ process.waitFor();
+ LinkedList output = new LinkedList();
+ BufferedReader buffer = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
+ String line;
+ while( ( line = buffer.readLine() ) != null )
+ {
+ output.add( line );
+ }
+
+ // Done with reading
+ buffer.close();
+
+ if( output.size() > 0 )
+ {
+ return output.toArray( new String[ output.size() ] );
+ }
+ }
+ }
+ catch( IOException ioe )
+ {}
+ catch( InterruptedException ie )
+ {}
+
+ return null;
+ }
+}
diff --git a/Android/src/emu/project64/util/Strings.java b/Android/src/emu/project64/util/Strings.java
new file mode 100644
index 000000000..01c171613
--- /dev/null
+++ b/Android/src/emu/project64/util/Strings.java
@@ -0,0 +1,40 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import java.util.List;
+
+public class Strings
+{
+ static public boolean startsWith(String[] array, String text)
+ {
+ for (String item : array)
+ {
+ if (text.startsWith(item))
+ {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static public int containsName(List array, String text)
+ {
+ for (int i = array.size()-1 ; i >= 0 ; --i)
+ {
+ if (array.get(i).endsWith(text))
+ {
+ return i;
+ }
+ }
+ return -1;
+ }
+}
diff --git a/Android/src/emu/project64/util/Utility.java b/Android/src/emu/project64/util/Utility.java
new file mode 100644
index 000000000..a4097224f
--- /dev/null
+++ b/Android/src/emu/project64/util/Utility.java
@@ -0,0 +1,122 @@
+/****************************************************************************
+* *
+* Project64 - A Nintendo 64 emulator. *
+* http://www.pj64-emu.com/ *
+* Copyright (C) 2012 Project64. All rights reserved. *
+* *
+* License: *
+* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
+* *
+****************************************************************************/
+package emu.project64.util;
+
+import java.io.BufferedReader;
+import java.io.Closeable;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import emu.project64.Project64Application;
+
+/**
+ * Utility class which collects a bunch of commonly used methods into one class.
+ */
+public final class Utility
+{
+
+ /**
+ * Clamps a value to the limit defined by min and max.
+ *
+ * @param val The value to clamp to min and max.
+ * @param min The lowest number val can be equal to.
+ * @param max The largest number val can be equal to.
+ *
+ * @return If the value is lower than min, min is returned.
+ * If the value is higher than max, max is returned.
+ */
+ public static> T clamp( T val, T min, T max )
+ {
+ final T temp;
+
+ // val < max
+ if ( val.compareTo(max) < 0 )
+ temp = val;
+ else
+ temp = max;
+
+ // temp > min
+ if ( temp.compareTo(min) > 0 )
+ return temp;
+ else
+ return min;
+ }
+
+ public static String executeShellCommand(String... args)
+ {
+ try
+ {
+ Process process = Runtime.getRuntime().exec( args );
+ BufferedReader reader = new BufferedReader( new InputStreamReader( process.getInputStream() ) );
+ StringBuilder result = new StringBuilder();
+ String line;
+ while( ( line = reader.readLine() ) != null )
+ {
+ result.append( line + "\n" );
+ }
+ return result.toString();
+ }
+ catch( IOException ignored )
+ {
+ }
+ return "";
+ }
+
+ public static boolean close(Closeable closeable)
+ {
+ if (closeable != null)
+ {
+ try
+ {
+ closeable.close();
+ return true;
+ }
+ catch (IOException e)
+ {
+ }
+ }
+ return false;
+ }
+
+ public static String readAsset(String assetName, String defaultS)
+ {
+ InputStream is = null;
+ BufferedReader r = null;
+ try
+ {
+ is = Project64Application.getAppResources().getAssets().open(assetName);
+ r = new BufferedReader(new InputStreamReader(is, "UTF8"));
+ StringBuilder sb = new StringBuilder();
+ String line = r.readLine();
+ if(line != null)
+ {
+ sb.append(line);
+ line = r.readLine();
+ while(line != null)
+ {
+ sb.append('\n');
+ sb.append(line);
+ line = r.readLine();
+ }
+ }
+ return sb.toString();
+ }
+ catch (IOException e)
+ {
+ return defaultS;
+ }
+ finally
+ {
+ close(is);
+ close(r);
+ }
+ }
+}
diff --git a/Source/Project64/UserInterface/Bitmaps/AboutScreen.psd b/Artwork/AboutScreen.psd
similarity index 100%
rename from Source/Project64/UserInterface/Bitmaps/AboutScreen.psd
rename to Artwork/AboutScreen.psd
diff --git a/Config/Glide64.rdb b/Config/Glide64.rdb
index f1aac62bc..ed6efb2eb 100644
--- a/Config/Glide64.rdb
+++ b/Config/Glide64.rdb
@@ -1946,6 +1946,12 @@ optimize_texrect=0
swapmode=2
useless_is_useless=1
+[27C985A8-ED7CE5C6-C:0]
+Good Name=Mega Man 64 (Proto)
+Internal Name=Megaman 64
+depthmode=1
+increase_texrect_edge=1
+
[0EC158F5-FB3E6896-C:45]
Good Name=Mega Man 64 (U)
Internal Name=Mega Man 64
diff --git a/Config/Project64.cfg.development b/Config/Project64.cfg.development
index df5b3e084..fa3563c36 100644
--- a/Config/Project64.cfg.development
+++ b/Config/Project64.cfg.development
@@ -13,14 +13,28 @@ ShortCuts=..\..\Config\Project64.sc3
[Debugger]
Debugger=1
-[Directory]
-Instant Save=..\..\Save\
-Instant Save - Use Selected=1
-Lang=..\..\Lang
-Plugin=..\..\Plugin\
-Plugin64=..\..\Plugin64\
-Plugin - Use Selected=1
-Save=..\..\Save\
-Save - Use Selected=1
-Texture Dir=..\..\Textures\
-Texture Dir - Use Selected=1
+[Plugin Directory]
+Directory=..\..\Plugin\
+Use Selected=1
+
+[Plugin64 Directory]
+Directory=..\..\Plugin64\
+Use Selected=1
+
+[Native Save Directory]
+Directory=..\..\Save\
+Use Selected=1
+
+[Instant Save Directory]
+Directory=..\..\Save\
+Use Selected=1
+
+[Lang Directory]
+Directory=..\..\Lang
+
+[Texture Directory]
+Directory=..\..\Textures\
+Use Selected=1
+
+[Support Project64]
+Run Count=-1
diff --git a/Config/Project64.rdb b/Config/Project64.rdb
index 9f0f04654..3b9a16b23 100644
--- a/Config/Project64.rdb
+++ b/Config/Project64.rdb
@@ -1,4 +1,4 @@
-// ============ RDB for PJ64 v2.2. GoodN64 v321 =====================================
+// ============ RDB for PJ64 v2.2. GoodN64 v321 =====================================
// PJ64 v2.2 Official RDB
// Not for use with PJ64 v1.6 or previous
//---- START OF RDB FILE HEADER ---------------------------------------------------------
@@ -1811,6 +1811,7 @@ Status=Compatible
Plugin Note=[Glide64] missing menu effects
32bit=No
Culling=1
+Fixed Audio=0
[B30ED978-3003C9F9-C:45]
Good Name=F-ZERO X (U)
@@ -2020,11 +2021,14 @@ RDRAM Size=8
Good Name=Ganbare Goemon - Derodero Douchuu Obake Tenkomori (J)
Internal Name=GOEMON2 DERODERO
Status=Compatible
+Counter Factor=1
+Culling=1
[832C168B-56A2CDAE-C:4A]
Good Name=Ganbare Goemon - Neo Momoyama Bakufu no Odori (J)
Internal Name=GANBAKE GOEMON
Status=Compatible
+Counter Factor=1
Culling=1
RDRAM Size=8
@@ -2041,6 +2045,7 @@ Internal Name=GAUNTLET LEGENDS
Status=Issues (mixed)
Plugin Note=[Glide64] missing:various
RDRAM Size=8
+RSP-Mfc0Count=10
[70B0260E-6716D04C-C:4A]
Good Name=Gauntlet Legends (J)
@@ -2048,6 +2053,7 @@ Internal Name=GAUNTLET LEGENDS
Status=Issues (mixed)
Plugin Note=[Glide64] missing:various
RDRAM Size=8
+RSP-Mfc0Count=10
[729B5E32-B728D980-C:45]
Good Name=Gauntlet Legends (U)
@@ -2056,6 +2062,7 @@ Status=Issues (mixed)
Plugin Note=[Glide64] missing:various
Culling=1
RDRAM Size=8
+RSP-Mfc0Count=10
[489C84E6-4C6E49F9-C:4A]
Good Name=Getter Love!! - Cho Ren-ai Party Game (J)
@@ -2125,6 +2132,8 @@ Status=Compatible
Good Name=Goemon's Great Adventure (U)
Internal Name=GOEMONS GREAT ADV
Status=Compatible
+Counter Factor=1
+Culling=1
[4690FB1C-4CD56D44-C:45]
Good Name=Golden Nugget 64 (U)
@@ -2466,7 +2475,7 @@ Good Name=Indiana Jones and the Infernal Machine (E) (Unreleased)
Internal Name=Indiana Jones
Status=Only intro/part OK
Core Note=Camera issue; can't play
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Plugin Note=[Glide64] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -2486,7 +2495,7 @@ Good Name=Indiana Jones and the Infernal Machine (U)
Internal Name=Indiana Jones
Status=Only intro/part OK
Core Note=Camera issue; can't play
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Plugin Note=[Glide64] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -3274,6 +3283,7 @@ Internal Name=ÃصÉÌ«ÄËß°
Status=Issues (plugin)
Plugin Note=[video] HLE not supported; errors:various
HLE GFX=No
+RSP-SemaphoreExit=1
[9C663069-80F24A80-C:50]
Good Name=Mario Party (E) (M3)
@@ -3371,6 +3381,11 @@ Plugin Note=[Glide64] errors:various
RDRAM Size=8
Save Type=16kbit Eeprom
+[27C985A8-ED7CE5C6-C:0]
+Good Name=Mega Man 64 (Proto)
+Internal Name=Megaman 64
+Status=Compatible
+
[0EC158F5-FB3E6896-C:45]
Good Name=Mega Man 64 (U)
Internal Name=Mega Man 64
@@ -3498,6 +3513,7 @@ Status=Compatible
Good Name=Monaco Grand Prix (U)
Internal Name=Monaco Grand Prix
Status=Compatible
+Counter Factor=1
Culling=1
RDRAM Size=8
@@ -3506,6 +3522,7 @@ Good Name=Monaco Grand Prix - Racing Simulation 2 (E) (M4)
Internal Name=Monaco GP Racing 2
Status=Compatible
Clear Frame=2
+Counter Factor=1
Culling=1
[5AC383E1-D712E387-C:45]
@@ -3602,17 +3619,22 @@ Good Name=Mystical Ninja 2 Starring Goemon (E) (M3)
Internal Name=MYSTICAL NINJA2 SG
Status=Compatible
Counter Factor=1
+Culling=1
[F5360FBE-2BF1691D-C:50]
Good Name=Mystical Ninja Starring Goemon (E)
Internal Name=MYSTICAL NINJA
Status=Compatible
+Counter Factor=1
+Culling=1
RDRAM Size=8
[FCBCCB21-72903C6B-C:45]
Good Name=Mystical Ninja Starring Goemon (U)
Internal Name=MYSTICAL NINJA
Status=Compatible
+Counter Factor=1
+Culling=1
RDRAM Size=8
//================ N ================
@@ -3739,12 +3761,14 @@ Status=Compatible
Good Name=NBA Live 2000 (E) (M4)
Internal Name=NBA LIVE 2000
Status=Compatible
+32bit=No
[5F25B0EE-6227C1DB-C:45]
Good Name=NBA Live 2000 (U) (M4)
Internal Name=NBA LIVE 2000
Status=Compatible
Culling=1
+32bit=No
[CF84F45F-00E4F6EB-C:50]
Good Name=NBA Live 99 (E) (M5)
@@ -3799,11 +3823,13 @@ Status=Compatible
Good Name=NFL Blitz 2000 (U) (V1.0)
Internal Name=blitz2k
Status=Compatible
+32bit=No
[5B755842-6CA39C7A-C:45]
Good Name=NFL Blitz 2000 (U) (V1.1)
Internal Name=blitz2k
Status=Compatible
+32bit=No
[36FA35EB-E85E2E36-C:45]
Good Name=NFL Blitz 2001 (U)
@@ -4436,6 +4462,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[AC5AA5C7-A9B0CDC3-C:46]
Good Name=Pokemon Stadium 2 (F)
@@ -4446,6 +4473,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[439B7E7E-C1A1495D-C:44]
Good Name=Pokemon Stadium 2 (G)
@@ -4456,6 +4484,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[EFCEAF00-22094848-C:49]
Good Name=Pokemon Stadium 2 (I)
@@ -4466,6 +4495,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[63775886-5FB80E7B-C:4A]
Good Name=Pokemon Stadium 2 (J)
@@ -4486,6 +4516,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[03571182-892FD06D-C:45]
Good Name=Pokemon Stadium 2 (U)
@@ -4496,6 +4527,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[EE4FD7C2-9CF1D938-C:4A]
Good Name=Pokemon Stadium Kin Gin (J)
@@ -4506,6 +4538,7 @@ Culling=1
Emulate Clear=1
Linking=Off
RDRAM Size=8
+RSP-Mfc0Count=10
[41380792-A167E045-C:45]
Good Name=Polaris SnoCross (U)
@@ -5268,8 +5301,8 @@ SMM-TLB=0
[7EE0E8BB-49E411AA-C:50]
Good Name=Star Wars - Rogue Squadron (E) (M3) (V1.0)
Internal Name=Rogue Squadron
-Status=Broken (plugin)
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Status=Issues (plugin)
+Plugin Note=[video] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -5280,8 +5313,8 @@ RSP-JumpTableSize=3584
[219191C1-33183C61-C:50]
Good Name=Star Wars - Rogue Squadron (E) (M3) (V1.1)
Internal Name=Rogue Squadron
-Status=Broken (plugin)
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Status=Issues (plugin)
+Plugin Note=[video] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -5292,8 +5325,8 @@ RSP-JumpTableSize=3584
[66A24BEC-2EADD94F-C:45]
Good Name=Star Wars - Rogue Squadron (U) (V1.0)
Internal Name=Rogue Squadron
-Status=Broken (plugin)
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Status=Issues (plugin)
+Plugin Note=[video] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -5304,8 +5337,8 @@ RSP-JumpTableSize=3584
[C7F30CFA-ECB0FA36-C:45]
Good Name=Star Wars - Rogue Squadron (U) (V1.1)
Internal Name=Rogue Squadron
-Status=Broken (plugin)
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Status=Issues (plugin)
+Plugin Note=[video] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -5349,8 +5382,8 @@ RDRAM Size=8
[827E4890-958468DC-C:4A]
Good Name=Star Wars - Shutsugeki! Rogue Chuutai (J)
Internal Name=rogue squadron
-Status=Broken (plugin)
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Status=Issues (plugin)
+Plugin Note=[video] errors:various
32bit=No
HLE GFX=No
RDRAM Size=8
@@ -5370,7 +5403,7 @@ Good Name=Star Wars Episode I - Battle for Naboo (E)
Internal Name=Battle for Naboo
Status=Only intro/part OK
Core Note=Camera issue; can't play
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Plugin Note=[Glide64] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -5383,7 +5416,7 @@ Good Name=Star Wars Episode I - Battle for Naboo (U)
Internal Name=Battle for Naboo
Status=Only intro/part OK
Core Note=Camera issue; can't play
-Plugin Note=[rsp] interpreter only [video] HLE not supported
+Plugin Note=[Glide64] errors:various
32bit=No
AudioResetOnLoad=Yes
Counter Factor=1
@@ -5480,6 +5513,7 @@ AudioResetOnLoad=Yes
HLE GFX=No
Fixed Audio=0
RDRAM Size=8
+RSP-Mfc0Count=10
[F4646B69-C5751095-C:4A]
Good Name=Super B-Daman - Battle Phoenix 64 (J)
@@ -6786,6 +6820,7 @@ Plugin Note=[video] HLE not supported [audio] needs audio plugin
AudioResetOnLoad=Yes
Fixed Audio=0
HLE GFX=No
+RSP-Mfc0Count=10
[308DFEC8-CE2EB5F6-C:45]
Good Name=World Driver Championship (U)
@@ -6796,6 +6831,7 @@ Plugin Note=[video] HLE not supported [audio] needs audio plugin
AudioResetOnLoad=Yes
Fixed Audio=0
HLE GFX=No
+RSP-Mfc0Count=10
[2D21C57B-8FE4C58C-C:50]
Good Name=Worms - Armageddon (E) (M6)
@@ -8121,3 +8157,10 @@ Fixed Audio=0
Good Name=64DD IPL (JPN)
RDRAM Size=8
Status=Compatible
+
+[00000000-00000000-C:45]
+32bit=No
+Fixed Audio=0
+Good Name=64DD IPL (USA)
+RDRAM Size=8
+Status=Compatible
diff --git a/Lang/Brazilian Portuguese.pj.Lang b/Lang/Brazilian Portuguese.pj.Lang
index 2fa053c87..0ec6e4b8f 100644
--- a/Lang/Brazilian Portuguese.pj.Lang
+++ b/Lang/Brazilian Portuguese.pj.Lang
@@ -4,8 +4,8 @@
//About DLL
#1 # "Português Brasileiro" // LANGUAGE ID
#2 # "Project64 team" // Author
-#3 # "2.2" // Version
-#4 # "Fevereiro, 2016" // Date
+#3 # "2.3" // Version
+#4 # "Junho, 2016" // Date
//About DLL Dialog
#5 # "Idioma Atual"
@@ -51,6 +51,7 @@
#132# "R&esumir"
#133# "&Resetar Software"
#134# "&Resetar Hardware"
+#135# "Trocar &Disco"
//Options Menu
#140# "&Opções"
@@ -234,6 +235,8 @@
#465# "Exibir a velocidade"
#466# "Display de velocidade:"
#467# "Verificar se o Project64 já está em execução"
+#468# "&Diretório de Saves Unificado"
+#469# "Caminho Para a ROM 64DD IPL:"
//ROM Browser Tab
#480# "Máx # de ROMs Lembradas (0-10):"
@@ -437,6 +440,22 @@
#1104# "Opções"
#1105# "Slots de Salvamento"
+/*********************************************************************************
+* Support Window *
+*********************************************************************************/
+#1200# "Apoie o Project64"
+#1201# "Project64 é um pacote de software projetado para emular o video game Nintendo64 em um PC com Microsoft Windows. Este permite que você jogue software de N64 da mesma forma que seria no hardware original.\n\nSe você gostou do Project64 e obteve algum valor através do mesmo, então por favor, apoie o project64 como um agradecimento, ou seu desejo de vê-lo continuamente melhorado.\n\nSe você apoiou o project64:"
+#1202# "Digite o código de notificação"
+#1203# "Apoie o Project64"
+#1204# "Continuar"
+#1205# "Por favor, insira o código de apoio"
+#1206# "Código de apoio incorreto"
+#1207# "Obrigado"
+#1208# "Digite o código"
+#1209# "Por favor, digite o código que esta no e-mail"
+#1210# "OK"
+#1211# "Cancelar"
+
/*********************************************************************************
* Messages *
*********************************************************************************/
diff --git a/Lang/Catalan.pj.Lang b/Lang/Catalan.pj.Lang
index 8b32cdbc6..746628c11 100644
--- a/Lang/Catalan.pj.Lang
+++ b/Lang/Catalan.pj.Lang
@@ -1,498 +1,498 @@
-/*********************************************************************************
-* Meta Information *
-*********************************************************************************/
-//About DLL
-#1 # "Català " // LANGUAGE ID
-#2 # "Hiro5" // Author
-#3 # "2.2" // Version
-#4 # "11 d'octubre de 2015" // Date
-
-//About DLL Dialog
-#5 # "Idioma actual"
-#6 # "Autor"
-#7 # "Versió"
-#8 # "Data"
-#9 # "Visiteu el lloc web"
-#10 # "Base de dades de ROMs (.RDB)"
-#11 # "Fitxer de Trucs (.CHT)"
-#12 # "Informació estesa de ROM (.RDX)"
-
-//About INI title
-#20 # "Quant als fitxers de configuració"
-
-/*********************************************************************************
-* Menu *
-*********************************************************************************/
-//File Menu
-#100# "&Fitxer"
-#101# "&Obre una ROM"
-#102# "&Informació de ROM...."
-#103# "Comença l'emulació"
-#104# "&Finalitza l'emulació"
-#105# "Tria directori de ROMs..."
-#106# "Actualitza llista de ROMs"
-#107# "ROMs recents"
-#108# "Directoris de ROMs recents"
-#109# "&Surt"
-
-//System Menu
-#120# "&Sistema"
-#121# "&Reinicia"
-#122# "&Pausa"
-#123# "Captura pantalla"
-#124# "Limitador de velocitat"
-#125# "&Desa"
-#126# "Anomena i desa..."
-#127# "&Restaura"
-#128# "Carrega..."
-#129# "&Estat desat actual"
-#130# "Trucs..."
-#131# "Botó de GameShark"
-#132# "Continua"
-#133# "Reinicia el &Programari"
-#134# "Reinicia el &Maquinari"
-
-//Options Menu
-#140# "&Opcions"
-#141# "&Pantalla completa"
-#142# "&Sempre a sobre"
-#143# "Configura el connector de vÃdeo..."
-#144# "Configura el connector d'Ã udio..."
-#145# "Configura el connector del controlador..."
-#146# "Configura el connector RSP..."
-#147# "Mostra % d'ús de CPU"
-#148# "&Parà metres..."
-
-//Debugger Menu
-#160# "&Depurador"
-
-//Language Menu
-#175# "&Idioma"
-
-//Help Menu
-#180# "&Ajuda"
-#181# "Quant als fitxers &INI"
-#182# "&Quant al Project 64"
-#183# "&Fòrum de suport"
-#184# "&Lloc web"
-
-//Current Save Slot menu
-#190# "Per defecte"
-#191# "Ranura 1"
-#192# "Ranura 2"
-#193# "Ranura 3"
-#194# "Ranura 4"
-#195# "Ranura 5"
-#196# "Ranura 6"
-#197# "Ranura 7"
-#198# "Ranura 8"
-#199# "Ranura 9"
-#200# "Ranura 10"
-
-//Pop up Menu
-#210# "Juga el joc"
-#211# "Informació de ROM"
-#212# "Edita els parà metres del joc"
-#213# "Edita els trucs"
-#214# "Connector de vÃdeo"
-
-//Alternate Name to save Slot
-#220# "Desa a la ranura per defecte"
-#221# "Desa a la ranura 1"
-#222# "Desa a la ranura 2"
-#223# "Desa a la ranura 3"
-#224# "Desa a la ranura 4"
-#225# "Desa a la ranura 5"
-#226# "Desa a la ranura 6"
-#227# "Desa a la ranura 7"
-#228# "Desa a la ranura 8"
-#229# "Desa a la ranura 9"
-#230# "Desa a la ranura 10"
-
-// Menu Descriptions
-#250# "Obre una imatge ROM de Nintendo 64"
-#251# "Mostra informació de la imatge carregada"
-#252# "Inicia l'emulació de la imatge ROM carregada"
-#253# "Atura l'emulació de la imatge ROM carregada"
-#254# "Selecciona el directori de ROMs"
-#255# "Actualitza la llista de ROMs en l'explorador de ROMs"
-#256# "Tanca aquesta aplicació"
-#257# "Recarrega la imatge ROM actual (recarrega qualsevol canvi de parà metres)"
-#258# "Pausa/Continua l'emulació de la ROM en execució actual"
-#259# "Genera una imatge Bitmap de la pantalla actual"
-#260# "Limita els quadres per segon a la velocitat correcta de la n64"
-#261# "Crea una instantà nia del sistema actual per un desat rà pid"
-#262# "Crea una instantà nia del sistema actual seleccionant la ubicació del fitxer"
-#263# "Carrega una instantà nia rà pida desada"
-#264# "Tria un fitxer d'instantà nia per carregar"
-#265# "Activa/Desactiva trucs del GameShark"
-#266# "El botó de GameShark s'utilitza amb trucs especÃfics"
-#267# "Canvia l'emulació de mode en finestra a pantalla completa"
-#268# "Fa que la finestra estigui per sobre de totes les altres"
-#269# "Canvia els parà metres dins del connector de vÃdeo"
-#270# "Canvia els parà metres dins del connector d'à udio"
-#271# "Canvia els parà metres dins del connector de controladors (i.e. assigna les tecles)"
-#272# "Canvia els parà metres dins del connector RSP"
-#273# "Mostra l'ús de CPU de l'emulador dividit en diferents recursos"
-#274# "Mostra/Canvia parà metres per aquesta aplicació"
-#275# "Mostra el Manual per l'aplicació"
-#276# "Mostra les PMF per l'aplicació"
-#278# "Quant a l'aplicació i als autors"
-#277# "Quant als autors dels fitxers de suport"
-#279# "Obre aquesta imatge de ROM oberta anteriorment"
-#280# "Tria aquest directori com el directori de ROMs"
-#281# "Canvia l'aplicació per utilitzar aquest idioma"
-#282# "Tria aquesta ubicació de desat rà pid"
-#283# "Comença el joc seleccionat"
-#284# "Informació del joc seleccionat"
-#285# "Edita els parà metres pel joc seleccionat"
-#286# "Edita els trucs per joc seleccionat"
-
-/*********************************************************************************
-* ROM Browser *
-*********************************************************************************/
-//ROM Browser Fields
-#300# "Nom de fitxer"
-#301# "Nom intern"
-#302# "Nom bo"
-#303# "Estat"
-#304# "Mida de ROM"
-#305# "Notes (Nucli)"
-#306# "Notes (complements per defecte)"
-#307# "Notes (Usuari)"
-#308# "ID de cartutx"
-#309# "Fabricant"
-#310# "PaÃs"
-#311# "Desenvolupador"
-#312# "CRC1"
-#313# "CRC2"
-#314# "Xip CIC"
-#315# "Data de sortida"
-#316# "Gènere"
-#317# "Jugadors"
-#318# "Força resposta"
-#319# "Format de fitxer"
-
-//Select ROM
-#320# "Selecciona directori de ROMs actual"
-
-//Messages
-#340# "ROM dolenta? Utilitza GoodN64 i cerca una RDB actualitzada"
-
-/*********************************************************************************
-* Options *
-*********************************************************************************/
-//Options Title
-#400# "Parà metres"
-
-//Tabs
-#401# "Connectors"
-#402# "Directoris"
-#403# "Opcions"
-#404# "Selecció de ROM"
-#405# "Avançat"
-#406# "Parà metres generals"
-#407# "Integració del sistema"
-#408# "Notes"
-#409# "Dreceres de teclat"
-#410# "Estat"
-#411# "Recompilador"
-
-//Plugin Dialog
-#420# "Quant a"
-#421# " Complement de processador de senyal de realitat: "
-#422# " Complement de vÃdeo (grà fics): "
-#423# " Complement d'Ã udio (so): "
-#424# " Complement d'entrada (controlador): "
-#425# "HLE de vÃdeo"
-#426# "HLE d'Ã udio"
-#427# "** Utilitza complement del sistema **"
-
-//Directory Dialog
-#440# " Directori de complements: "
-#441# " Directori de ROMs: "
-#442# " Autodesats de N64: "
-#443# " Instantà nies: "
-#444# " Captures de pantalla: "
-#445# "Carpeta des d'on es va obrir la darrera ROM."
-#446# "Seleccioneu directori de complements"
-#447# "Seleccioneu directori de ROMs"
-#448# "Seleccioneu directori d'autodesats"
-#449# "Seleccioneu directori de desats d'instantà nies"
-#450# "Seleccioneu directori d'imatges"
-#451# " Directori de paquets de textures: "
-#452# "Seleccioneu directori de paquets de textures"
-
-//Options Dialog
-#460# "Posa en pausa quan la finestra no està activa"
-#461# "Canvia a pantalla completa en carregar una ROM"
-#462# "Amaga els parà metres avançats"
-#463# "Recorda els trucs seleccionats"
-#464# "Desactiva l'estalvi de pantalla mentre s'executa una ROM"
-#465# "Mostra la velocitat"
-#466# "Mostra la velocitat:"
-#467# "Comprova si Project64 ja s'està executant"
-
-//ROM Browser Tab
-#480# "LÃmit de ROMs recordades (MÃ x 10):"
-#481# "ROMs"
-#482# "LÃmit de Dirs de ROMs recordades (MÃ x 10):"
-#483# "dirs"
-#484# "Empra explorador de ROMs"
-#485# "Cerca subdirectoris"
-#486# "Camps disponibles:"
-#487# "Mostra els camps en aquest ordre:"
-#488# "Afegeix ->"
-#489# "<- Esborra"
-#490# "Amunt"
-#491# "Avall"
-#492# "Refresca el navegador automà ticament"
-
-//Advanced Options
-#500# "La majoria d'aquests canvis no faran efecte fins que s'obri una nova ROM o fins a reiniciar l'actual ROM."
-#501# "Predeterminats de nucli"
-#502# "Estil de nucli de CPU:"
-#503# "Mètode de codi auto-mod:"
-#504# "Mida de memòria per defecte:"
-#505# "Enllaçat de bloc avançat:"
-#506# "Iniciar l'emulació quan s'obri la ROM"
-#507# "Sobreescriu sempre els parà metres per defecte amb els de l'INI"
-#508# "Comprimeix automà ticament els estats desats"
-#509# "Activa el depurador"
-#510# "Mem. cau"
-#511# "PI DMA"
-#512# "Inici canviat"
-#513# "Memòria protegida"
-#514# "Desmapat TLB"
-
-//ROM Options
-#520# "Estil de nucli de CPU:"
-#521# "Refresc d'entrada de vÃdeo:"
-#522# "Mida de memòria:"
-#523# "Enllaçat de blocs avançat:"
-#524# "Tipus de desat per defecte:"
-#525# "Factor de comptador:"
-#526# "Memòria de compilació més gran"
-#527# "Empra TLB"
-#528# "Registra la mem. cau"
-#529# "Retard d'interrupció SI"
-#530# "Modificació d'SP"
-#531# "Per defecte"
-#532# "Senyal d'Ã udio RSP"
-#533# "Sincr. d'Ã udio arreglada"
-#534# "Funció de mètode de cerca:"
-#535# "Mètode de codi auto-modificant"
-#536# "Sincr. utilitzant l'Ã udio"
-#537# "Compta AI per byte"
-#538# "MÃ quina 32-bit"
-#539# "Retard d'interrupció DP"
-
-//Core Styles
-#540# "Intèrpret"
-#541# "Recompilador"
-#542# "Sincronitza nuclis"
-
-//Self Mod Methods
-#560# "Cap"
-#561# "Mem. cau"
-#562# "Protegeix memòria"
-#563# "Comprova memòria i mem. cau"
-#564# "Canvia memòria i mem. cau"
-#565# "Comprova memòria avançada"
-#566# "Neteja codi en mem. cau"
-
-//Function Lookup method
-#570# "Taula de cerca fÃsica"
-#571# "Taula de cerca virtual"
-#572# "Canvia la memòria"
-
-//RDRAM Size
-#580# "4 MB"
-#581# "8 MB"
-
-//Advanced Block Linking
-#600# "Encès"
-#601# "Apagat"
-
-//Save Type
-#620# "Primer tipus de desat usat"
-#621# "EEPROM de 4 kbits"
-#622# "EEPROM de 16 kbits"
-#623# "SRAM"
-#624# "FlashRAM de 128kbytes"
-
-//Shell Integration Tab
-#640# "Associació d'extensions de fitxer:"
-
-//ROM Notes
-#660# "Estat de ROM:"
-#661# "Nota de nucli:"
-#662# "Nota de complement:"
-
-// Accelerator Selector
-#680# "Estat de CPU:"
-#681# "Element de menú:"
-#682# "Claus actuals:"
-#683# "Seleccioneu la nova clau de drecera:"
-#684# "Assignada actualment a:"
-#685# "Assigna"
-#686# "Esborra"
-#687# "Reinicia-ho tot"
-#688# "No s'està jugant"
-#689# "S'està jugant"
-#690# "S'està jugant en finestra"
-#691# "S'està jugant a pantalla completa"
-#692# "Detecta tecla"
-
-// Frame Rate Option
-#700# "Interrupcions vertical per segon"
-#701# "Mostra llistes per segon"
-#702# "% de velocitat completa"
-
-// Increase speed
-#710# "Augmenta velocitat de joc"
-#711# "Disminueix velocitat de joc"
-
-//Bottom page buttons
-#720# "Reinicia pà g."
-#721# "Reinicia tot"
-#722# "Aplica"
-#723# "Tanca"
-
-/*********************************************************************************
-* ROM Information *
-*********************************************************************************/
-//ROM Info Title
-#800# "Informació de ROM"
-
-//ROM Info Text
-#801# "Nom de ROM:"
-#802# "Nom de fitxer:"
-#803# "Ubicació:"
-#804# "Mida de ROM:"
-#805# "ID de cartutx:"
-#806# "Fabricant:"
-#807# "PaÃs:"
-#808# "CRC1:"
-#809# "CRC2:"
-#810# "Xip CIC:"
-#811# "MD5:"
-
-/*********************************************************************************
-* Cheats *
-*********************************************************************************/
-//Cheat List
-#1000# "Trucs"
-#1001# "Trucs:"
-#1002# " Notes: "
-#1003# "Marca-ho tot"
-#1004# "Desmarca-ho tot"
-
-//Add Cheat
-#1005# "Afegeix truc"
-#1006# "Nom:"
-#1007# "Codi:"
-#1008# "Insereix"
-#1009# "Neteja"
-#1010# " Notes del truc: "
-#1011# "Afegeix a la DB"
-
-//Code extension
-#1012# "Extensions de codi"
-#1013# "Trieu un valor per:"
-#1014# "D'acord"
-#1015# "Cancel·la"
-
-//Digital Value
-#1016# "DÃgit de quantitat"
-#1017# "Trieu un valor per:"
-#1018# "&Valor"
-#1019# "de"
-#1020# "a"
-#1021# "&Notes:"
-#1022# "Afegeix truc"
-#1023# "Nou truc"
-#1024# " "
-#1025# "Opcions:"
-#1026# " "
-
-//Edit Cheat
-#1027# "Edita el truc"
-#1028# "Actualitza el truc"
-#1029# "El truc s'ha modificat.\n\nVoleu actualitzar?"
-#1030# "Truc actualitzat"
-
-//Cheat Popup Menu
-#1040# "Afegeix nou truc..."
-#1041# "Edita"
-#1042# "Esborra"
-
-// short-cut editor
-#1100# "Reinicia dreceres"
-#1101# "Segur que voleu reiniciar les dreceres?\n\nAquesta acció no es podrà desfer."
-#1102# "Menú de Fitxer"
-#1103# "Menú de Sistema"
-#1104# "Opcions"
-#1105# "Ranures de desat"
-
-/*********************************************************************************
-* Messages *
-*********************************************************************************/
-#2000# "*** CPU EN PAUSA ***"
-#2001# "CPU continuat"
-#2002# "Es troba en un bucle permanent i no pot sortir.\nL'emulació s'aturarà ara.\n\nComproveu la ROM i els parà metres de ROM."
-#2003# "No s'ha pogut assignar memòria"
-#2004# "Ha desaparegut o no és và lid el complement de vÃdeo seleccionat o per defecte.\n\nComproveu que teniu com a mÃnim un fitxer de complement compatible en la carpeta de complements."
-#2005# "Ha desaparegut o no és và lid el complement d'à udio seleccionat o per defecte.\n\nComproveu que teniu com a mÃnim un fitxer de complement compatible en la carpeta de complements."
-#2006# "Ha desaparegut o no és và lid el complement d'RSP seleccionat o per defecte.\n\nComproveu que teniu Project64 instal·lat adequadament amb un camà de complements và lid."
-#2007# "Ha desaparegut o no és và lid el complement d'entrada seleccionat o per defecte.\n\nComproveu que teniu com a mÃnim un fitxer de complement compatible en la carpeta de complements."
-#2008# "No s'ha pogut carregar el complement:"
-#2009# "No s'ha pogut carregar la paraula\n\nComproveu la ROM i els parà metres de ROM."
-#2010# "No s'ha pogut obrir el fitxer de desat"
-#2011# "No s'ha pogut obrir l'EEPROM"
-#2012# "No s'ha pogut obrir el FlashRAM"
-#2013# "No s'ha pogut obrir el mempak"
-#2014# "Ha fallat l'intent d'obrir el fitxer zip.\nFitxer zip desaparegut o malmès - comproveu el camà i el fitxer.\n\nPotser necessitareu reiniciar l'aplicació."
-#2015# "Ha fallat l'intent d'obrir el fitxer."
-#2016# "S'ha produït un error en provar d'obrir el fitxer zip."
-#2017# "El fitxer carregat no sembla que sigui una ROM de Nintendo 64 và lida.\n\nVerifiqueu les ROMs amb GoodN64."
-#2018# "PaÃs desconegut"
-#2019# "Xip CIC desconegut"
-#2020# "Format de fitxer desconegut"
-#2021# "Acció de memòria desconeguda\n\nEmulació aturada"
-#2022# "OpCode R4300i no gestionat a"
-#2023# "Executant des d'un espai no-mapat.\n\nVerifiqueu la ROM i els parà metres de la ROM."
-#2024# "Sembla que l'estat desat no correspon a la ROM en execució.\n\nEls estats desats s'han de desar i carregar entre ROMs 100% idèntiques,\nen particular la REGIÓ i la VERSIÓ han de ser les mateixes.\nCarregant aquest estat és com provocar una fallida al joc o a l'emulador.\n\nSegur que voleu continuar carregant?"
-#2025# "Error"
-#2026# "No s'ha trobat la seqüència de copyright en el LUT. El joc deixarà de funcionar."
-#2027# "Fallida de protecció de còpia"
-#2028# "Canviar un complement cal que Project64 reinicii una ROM en execució.\nSi no vols perdre la teva posició, respon No i fes un desat d'estat primer.\n\nVoleu canviar els complements i reiniciar el joc ara?"
-#2029# "Canvia complements"
-#2030# "Emulació finalitzada"
-#2031# "Emulació iniciada"
-#2032# "No s'ha pogut carregar l'estat desat"
-#2033# "S'ha carregat l'estat desat"
-#2034# "S'ha desat l'estat actual a"
-#2035# "Ranura d'estat desat"
-#2036# "Imatge d'intercanvi d'octets"
-#2037# "Triant imatge de N64"
-#2038# "Carregat"
-#2039# "Carregant imatge"
-#2040# "No es pot obrir cap ROM perquè els complements no s'han iniciat correctament"
-#2041# "Esteu realment segur que voleu esborrar això?"
-#2042# "Esborra el truc"
-#2043# "El nom del truc ja es troba en ús"
-#2044# "Heu arribat al lÃmit mà xim de trucs per aquesta ROM"
-#2045# "Inicialitzant complement"
-#2046# "No heu seleccionat una clau virtual per assignar a l'element de menú."
-#2047# "Necessiteu seleccionar un element de menú per assignar a aquesta acció."
-#2048# "La drecera ja està assignada a un altre element de menú."
-#2049# "No s'ha seleccionat cap drecera per esborrar."
-#2050# "ROM carregada. Esperant per iniciar l'emulació."
-#2051# "La versió beta de Project64 només és pels membres.\n\nSi teniu un compte a pj64.net, no haurÃeu de veure aquest error!!\nContacteu amb nosaltres a la web."
-#2052# "Error del programa"
-#2053# "No s'ha pogut trobar el fitxer dins del fitxer 7z"
-#2054# "Emulació de baix nivell (LLE) de vÃdeo"
-#2055# "L'LLE de vÃdeo no és per un ús genèric!!!\nÉs aconsellable que només utilitzis això per fer proves i no per jugar.\n\nVoleu canviar a l'LLE de vÃdeo?"
-#2056# "Emulació d'alt nivell (HLE) d'à udio"
-#2057# "L'HLE d'à udio requereix un complement de tercers!!!\nSi s'utilitza cap complement de tercers que suporti HLE, no hi haurà cap so.\n\nVoleu canviar a l'HLE d'à udio?"
+/*********************************************************************************
+* Meta Information *
+*********************************************************************************/
+//About DLL
+#1 # "Català " // LANGUAGE ID
+#2 # "Hiro5" // Author
+#3 # "2.2" // Version
+#4 # "11 d'octubre de 2015" // Date
+
+//About DLL Dialog
+#5 # "Idioma actual"
+#6 # "Autor"
+#7 # "Versió"
+#8 # "Data"
+#9 # "Visiteu el lloc web"
+#10 # "Base de dades de ROMs (.RDB)"
+#11 # "Fitxer de Trucs (.CHT)"
+#12 # "Informació estesa de ROM (.RDX)"
+
+//About INI title
+#20 # "Quant als fitxers de configuració"
+
+/*********************************************************************************
+* Menu *
+*********************************************************************************/
+//File Menu
+#100# "&Fitxer"
+#101# "&Obre una ROM"
+#102# "&Informació de ROM...."
+#103# "Comença l'emulació"
+#104# "&Finalitza l'emulació"
+#105# "Tria directori de ROMs..."
+#106# "Actualitza llista de ROMs"
+#107# "ROMs recents"
+#108# "Directoris de ROMs recents"
+#109# "&Surt"
+
+//System Menu
+#120# "&Sistema"
+#121# "&Reinicia"
+#122# "&Pausa"
+#123# "Captura pantalla"
+#124# "Limitador de velocitat"
+#125# "&Desa"
+#126# "Anomena i desa..."
+#127# "&Restaura"
+#128# "Carrega..."
+#129# "&Estat desat actual"
+#130# "Trucs..."
+#131# "Botó de GameShark"
+#132# "Continua"
+#133# "Reinicia el &Programari"
+#134# "Reinicia el &Maquinari"
+
+//Options Menu
+#140# "&Opcions"
+#141# "&Pantalla completa"
+#142# "&Sempre a sobre"
+#143# "Configura el connector de vÃdeo..."
+#144# "Configura el connector d'Ã udio..."
+#145# "Configura el connector del controlador..."
+#146# "Configura el connector RSP..."
+#147# "Mostra % d'ús de CPU"
+#148# "&Parà metres..."
+
+//Debugger Menu
+#160# "&Depurador"
+
+//Language Menu
+#175# "&Idioma"
+
+//Help Menu
+#180# "&Ajuda"
+#181# "Quant als fitxers &INI"
+#182# "&Quant al Project 64"
+#183# "&Fòrum de suport"
+#184# "&Lloc web"
+
+//Current Save Slot menu
+#190# "Per defecte"
+#191# "Ranura 1"
+#192# "Ranura 2"
+#193# "Ranura 3"
+#194# "Ranura 4"
+#195# "Ranura 5"
+#196# "Ranura 6"
+#197# "Ranura 7"
+#198# "Ranura 8"
+#199# "Ranura 9"
+#200# "Ranura 10"
+
+//Pop up Menu
+#210# "Juga el joc"
+#211# "Informació de ROM"
+#212# "Edita els parà metres del joc"
+#213# "Edita els trucs"
+#214# "Connector de vÃdeo"
+
+//Alternate Name to save Slot
+#220# "Desa a la ranura per defecte"
+#221# "Desa a la ranura 1"
+#222# "Desa a la ranura 2"
+#223# "Desa a la ranura 3"
+#224# "Desa a la ranura 4"
+#225# "Desa a la ranura 5"
+#226# "Desa a la ranura 6"
+#227# "Desa a la ranura 7"
+#228# "Desa a la ranura 8"
+#229# "Desa a la ranura 9"
+#230# "Desa a la ranura 10"
+
+// Menu Descriptions
+#250# "Obre una imatge ROM de Nintendo 64"
+#251# "Mostra informació de la imatge carregada"
+#252# "Inicia l'emulació de la imatge ROM carregada"
+#253# "Atura l'emulació de la imatge ROM carregada"
+#254# "Selecciona el directori de ROMs"
+#255# "Actualitza la llista de ROMs en l'explorador de ROMs"
+#256# "Tanca aquesta aplicació"
+#257# "Recarrega la imatge ROM actual (recarrega qualsevol canvi de parà metres)"
+#258# "Pausa/Continua l'emulació de la ROM en execució actual"
+#259# "Genera una imatge Bitmap de la pantalla actual"
+#260# "Limita els quadres per segon a la velocitat correcta de la n64"
+#261# "Crea una instantà nia del sistema actual per un desat rà pid"
+#262# "Crea una instantà nia del sistema actual seleccionant la ubicació del fitxer"
+#263# "Carrega una instantà nia rà pida desada"
+#264# "Tria un fitxer d'instantà nia per carregar"
+#265# "Activa/Desactiva trucs del GameShark"
+#266# "El botó de GameShark s'utilitza amb trucs especÃfics"
+#267# "Canvia l'emulació de mode en finestra a pantalla completa"
+#268# "Fa que la finestra estigui per sobre de totes les altres"
+#269# "Canvia els parà metres dins del connector de vÃdeo"
+#270# "Canvia els parà metres dins del connector d'à udio"
+#271# "Canvia els parà metres dins del connector de controladors (i.e. assigna les tecles)"
+#272# "Canvia els parà metres dins del connector RSP"
+#273# "Mostra l'ús de CPU de l'emulador dividit en diferents recursos"
+#274# "Mostra/Canvia parà metres per aquesta aplicació"
+#275# "Mostra el Manual per l'aplicació"
+#276# "Mostra les PMF per l'aplicació"
+#278# "Quant a l'aplicació i als autors"
+#277# "Quant als autors dels fitxers de suport"
+#279# "Obre aquesta imatge de ROM oberta anteriorment"
+#280# "Tria aquest directori com el directori de ROMs"
+#281# "Canvia l'aplicació per utilitzar aquest idioma"
+#282# "Tria aquesta ubicació de desat rà pid"
+#283# "Comença el joc seleccionat"
+#284# "Informació del joc seleccionat"
+#285# "Edita els parà metres pel joc seleccionat"
+#286# "Edita els trucs per joc seleccionat"
+
+/*********************************************************************************
+* ROM Browser *
+*********************************************************************************/
+//ROM Browser Fields
+#300# "Nom de fitxer"
+#301# "Nom intern"
+#302# "Nom bo"
+#303# "Estat"
+#304# "Mida de ROM"
+#305# "Notes (Nucli)"
+#306# "Notes (complements per defecte)"
+#307# "Notes (Usuari)"
+#308# "ID de cartutx"
+#309# "Fabricant"
+#310# "PaÃs"
+#311# "Desenvolupador"
+#312# "CRC1"
+#313# "CRC2"
+#314# "Xip CIC"
+#315# "Data de sortida"
+#316# "Gènere"
+#317# "Jugadors"
+#318# "Força resposta"
+#319# "Format de fitxer"
+
+//Select ROM
+#320# "Selecciona directori de ROMs actual"
+
+//Messages
+#340# "ROM dolenta? Utilitza GoodN64 i cerca una RDB actualitzada"
+
+/*********************************************************************************
+* Options *
+*********************************************************************************/
+//Options Title
+#400# "Parà metres"
+
+//Tabs
+#401# "Connectors"
+#402# "Directoris"
+#403# "Opcions"
+#404# "Selecció de ROM"
+#405# "Avançat"
+#406# "Parà metres generals"
+#407# "Integració del sistema"
+#408# "Notes"
+#409# "Dreceres de teclat"
+#410# "Estat"
+#411# "Recompilador"
+
+//Plugin Dialog
+#420# "Quant a"
+#421# " Complement de processador de senyal de realitat: "
+#422# " Complement de vÃdeo (grà fics): "
+#423# " Complement d'Ã udio (so): "
+#424# " Complement d'entrada (controlador): "
+#425# "HLE de vÃdeo"
+#426# "HLE d'Ã udio"
+#427# "** Utilitza complement del sistema **"
+
+//Directory Dialog
+#440# " Directori de complements: "
+#441# " Directori de ROMs: "
+#442# " Autodesats de N64: "
+#443# " Instantà nies: "
+#444# " Captures de pantalla: "
+#445# "Carpeta des d'on es va obrir la darrera ROM."
+#446# "Seleccioneu directori de complements"
+#447# "Seleccioneu directori de ROMs"
+#448# "Seleccioneu directori d'autodesats"
+#449# "Seleccioneu directori de desats d'instantà nies"
+#450# "Seleccioneu directori d'imatges"
+#451# " Directori de paquets de textures: "
+#452# "Seleccioneu directori de paquets de textures"
+
+//Options Dialog
+#460# "Posa en pausa quan la finestra no està activa"
+#461# "Canvia a pantalla completa en carregar una ROM"
+#462# "Amaga els parà metres avançats"
+#463# "Recorda els trucs seleccionats"
+#464# "Desactiva l'estalvi de pantalla mentre s'executa una ROM"
+#465# "Mostra la velocitat"
+#466# "Mostra la velocitat:"
+#467# "Comprova si Project64 ja s'està executant"
+
+//ROM Browser Tab
+#480# "LÃmit de ROMs recordades (MÃ x 10):"
+#481# "ROMs"
+#482# "LÃmit de Dirs de ROMs recordades (MÃ x 10):"
+#483# "dirs"
+#484# "Empra explorador de ROMs"
+#485# "Cerca subdirectoris"
+#486# "Camps disponibles:"
+#487# "Mostra els camps en aquest ordre:"
+#488# "Afegeix ->"
+#489# "<- Esborra"
+#490# "Amunt"
+#491# "Avall"
+#492# "Refresca el navegador automà ticament"
+
+//Advanced Options
+#500# "La majoria d'aquests canvis no faran efecte fins que s'obri una nova ROM o fins a reiniciar l'actual ROM."
+#501# "Predeterminats de nucli"
+#502# "Estil de nucli de CPU:"
+#503# "Mètode de codi auto-mod:"
+#504# "Mida de memòria per defecte:"
+#505# "Enllaçat de bloc avançat:"
+#506# "Iniciar l'emulació quan s'obri la ROM"
+#507# "Sobreescriu sempre els parà metres per defecte amb els de l'INI"
+#508# "Comprimeix automà ticament els estats desats"
+#509# "Activa el depurador"
+#510# "Mem. cau"
+#511# "PI DMA"
+#512# "Inici canviat"
+#513# "Memòria protegida"
+#514# "Desmapat TLB"
+
+//ROM Options
+#520# "Estil de nucli de CPU:"
+#521# "Refresc d'entrada de vÃdeo:"
+#522# "Mida de memòria:"
+#523# "Enllaçat de blocs avançat:"
+#524# "Tipus de desat per defecte:"
+#525# "Factor de comptador:"
+#526# "Memòria de compilació més gran"
+#527# "Empra TLB"
+#528# "Registra la mem. cau"
+#529# "Retard d'interrupció SI"
+#530# "Modificació d'SP"
+#531# "Per defecte"
+#532# "Senyal d'Ã udio RSP"
+#533# "Sincr. d'Ã udio arreglada"
+#534# "Funció de mètode de cerca:"
+#535# "Mètode de codi auto-modificant"
+#536# "Sincr. utilitzant l'Ã udio"
+#537# "Compta AI per byte"
+#538# "MÃ quina 32-bit"
+#539# "Retard d'interrupció DP"
+
+//Core Styles
+#540# "Intèrpret"
+#541# "Recompilador"
+#542# "Sincronitza nuclis"
+
+//Self Mod Methods
+#560# "Cap"
+#561# "Mem. cau"
+#562# "Protegeix memòria"
+#563# "Comprova memòria i mem. cau"
+#564# "Canvia memòria i mem. cau"
+#565# "Comprova memòria avançada"
+#566# "Neteja codi en mem. cau"
+
+//Function Lookup method
+#570# "Taula de cerca fÃsica"
+#571# "Taula de cerca virtual"
+#572# "Canvia la memòria"
+
+//RDRAM Size
+#580# "4 MB"
+#581# "8 MB"
+
+//Advanced Block Linking
+#600# "Encès"
+#601# "Apagat"
+
+//Save Type
+#620# "Primer tipus de desat usat"
+#621# "EEPROM de 4 kbits"
+#622# "EEPROM de 16 kbits"
+#623# "SRAM"
+#624# "FlashRAM de 128kbytes"
+
+//Shell Integration Tab
+#640# "Associació d'extensions de fitxer:"
+
+//ROM Notes
+#660# "Estat de ROM:"
+#661# "Nota de nucli:"
+#662# "Nota de complement:"
+
+// Accelerator Selector
+#680# "Estat de CPU:"
+#681# "Element de menú:"
+#682# "Claus actuals:"
+#683# "Seleccioneu la nova clau de drecera:"
+#684# "Assignada actualment a:"
+#685# "Assigna"
+#686# "Esborra"
+#687# "Reinicia-ho tot"
+#688# "No s'està jugant"
+#689# "S'està jugant"
+#690# "S'està jugant en finestra"
+#691# "S'està jugant a pantalla completa"
+#692# "Detecta tecla"
+
+// Frame Rate Option
+#700# "Interrupcions vertical per segon"
+#701# "Mostra llistes per segon"
+#702# "% de velocitat completa"
+
+// Increase speed
+#710# "Augmenta velocitat de joc"
+#711# "Disminueix velocitat de joc"
+
+//Bottom page buttons
+#720# "Reinicia pà g."
+#721# "Reinicia tot"
+#722# "Aplica"
+#723# "Tanca"
+
+/*********************************************************************************
+* ROM Information *
+*********************************************************************************/
+//ROM Info Title
+#800# "Informació de ROM"
+
+//ROM Info Text
+#801# "Nom de ROM:"
+#802# "Nom de fitxer:"
+#803# "Ubicació:"
+#804# "Mida de ROM:"
+#805# "ID de cartutx:"
+#806# "Fabricant:"
+#807# "PaÃs:"
+#808# "CRC1:"
+#809# "CRC2:"
+#810# "Xip CIC:"
+#811# "MD5:"
+
+/*********************************************************************************
+* Cheats *
+*********************************************************************************/
+//Cheat List
+#1000# "Trucs"
+#1001# "Trucs:"
+#1002# " Notes: "
+#1003# "Marca-ho tot"
+#1004# "Desmarca-ho tot"
+
+//Add Cheat
+#1005# "Afegeix truc"
+#1006# "Nom:"
+#1007# "Codi:"
+#1008# "Insereix"
+#1009# "Neteja"
+#1010# " Notes del truc: "
+#1011# "Afegeix a la DB"
+
+//Code extension
+#1012# "Extensions de codi"
+#1013# "Trieu un valor per:"
+#1014# "D'acord"
+#1015# "Cancel·la"
+
+//Digital Value
+#1016# "DÃgit de quantitat"
+#1017# "Trieu un valor per:"
+#1018# "&Valor"
+#1019# "de"
+#1020# "a"
+#1021# "&Notes:"
+#1022# "Afegeix truc"
+#1023# "Nou truc"
+#1024# " "
+#1025# "Opcions:"
+#1026# " "
+
+//Edit Cheat
+#1027# "Edita el truc"
+#1028# "Actualitza el truc"
+#1029# "El truc s'ha modificat.\n\nVoleu actualitzar?"
+#1030# "Truc actualitzat"
+
+//Cheat Popup Menu
+#1040# "Afegeix nou truc..."
+#1041# "Edita"
+#1042# "Esborra"
+
+// short-cut editor
+#1100# "Reinicia dreceres"
+#1101# "Segur que voleu reiniciar les dreceres?\n\nAquesta acció no es podrà desfer."
+#1102# "Menú de Fitxer"
+#1103# "Menú de Sistema"
+#1104# "Opcions"
+#1105# "Ranures de desat"
+
+/*********************************************************************************
+* Messages *
+*********************************************************************************/
+#2000# "*** CPU EN PAUSA ***"
+#2001# "CPU continuat"
+#2002# "Es troba en un bucle permanent i no pot sortir.\nL'emulació s'aturarà ara.\n\nComproveu la ROM i els parà metres de ROM."
+#2003# "No s'ha pogut assignar memòria"
+#2004# "Ha desaparegut o no és và lid el complement de vÃdeo seleccionat o per defecte.\n\nComproveu que teniu com a mÃnim un fitxer de complement compatible en la carpeta de complements."
+#2005# "Ha desaparegut o no és và lid el complement d'à udio seleccionat o per defecte.\n\nComproveu que teniu com a mÃnim un fitxer de complement compatible en la carpeta de complements."
+#2006# "Ha desaparegut o no és và lid el complement d'RSP seleccionat o per defecte.\n\nComproveu que teniu Project64 instal·lat adequadament amb un camà de complements và lid."
+#2007# "Ha desaparegut o no és và lid el complement d'entrada seleccionat o per defecte.\n\nComproveu que teniu com a mÃnim un fitxer de complement compatible en la carpeta de complements."
+#2008# "No s'ha pogut carregar el complement:"
+#2009# "No s'ha pogut carregar la paraula\n\nComproveu la ROM i els parà metres de ROM."
+#2010# "No s'ha pogut obrir el fitxer de desat"
+#2011# "No s'ha pogut obrir l'EEPROM"
+#2012# "No s'ha pogut obrir el FlashRAM"
+#2013# "No s'ha pogut obrir el mempak"
+#2014# "Ha fallat l'intent d'obrir el fitxer zip.\nFitxer zip desaparegut o malmès - comproveu el camà i el fitxer.\n\nPotser necessitareu reiniciar l'aplicació."
+#2015# "Ha fallat l'intent d'obrir el fitxer."
+#2016# "S'ha produït un error en provar d'obrir el fitxer zip."
+#2017# "El fitxer carregat no sembla que sigui una ROM de Nintendo 64 và lida.\n\nVerifiqueu les ROMs amb GoodN64."
+#2018# "PaÃs desconegut"
+#2019# "Xip CIC desconegut"
+#2020# "Format de fitxer desconegut"
+#2021# "Acció de memòria desconeguda\n\nEmulació aturada"
+#2022# "OpCode R4300i no gestionat a"
+#2023# "Executant des d'un espai no-mapat.\n\nVerifiqueu la ROM i els parà metres de la ROM."
+#2024# "Sembla que l'estat desat no correspon a la ROM en execució.\n\nEls estats desats s'han de desar i carregar entre ROMs 100% idèntiques,\nen particular la REGIÓ i la VERSIÓ han de ser les mateixes.\nCarregant aquest estat és com provocar una fallida al joc o a l'emulador.\n\nSegur que voleu continuar carregant?"
+#2025# "Error"
+#2026# "No s'ha trobat la seqüència de copyright en el LUT. El joc deixarà de funcionar."
+#2027# "Fallida de protecció de còpia"
+#2028# "Canviar un complement cal que Project64 reinicii una ROM en execució.\nSi no vols perdre la teva posició, respon No i fes un desat d'estat primer.\n\nVoleu canviar els complements i reiniciar el joc ara?"
+#2029# "Canvia complements"
+#2030# "Emulació finalitzada"
+#2031# "Emulació iniciada"
+#2032# "No s'ha pogut carregar l'estat desat"
+#2033# "S'ha carregat l'estat desat"
+#2034# "S'ha desat l'estat actual a"
+#2035# "Ranura d'estat desat"
+#2036# "Imatge d'intercanvi d'octets"
+#2037# "Triant imatge de N64"
+#2038# "Carregat"
+#2039# "Carregant imatge"
+#2040# "No es pot obrir cap ROM perquè els complements no s'han iniciat correctament"
+#2041# "Esteu realment segur que voleu esborrar això?"
+#2042# "Esborra el truc"
+#2043# "El nom del truc ja es troba en ús"
+#2044# "Heu arribat al lÃmit mà xim de trucs per aquesta ROM"
+#2045# "Inicialitzant complement"
+#2046# "No heu seleccionat una clau virtual per assignar a l'element de menú."
+#2047# "Necessiteu seleccionar un element de menú per assignar a aquesta acció."
+#2048# "La drecera ja està assignada a un altre element de menú."
+#2049# "No s'ha seleccionat cap drecera per esborrar."
+#2050# "ROM carregada. Esperant per iniciar l'emulació."
+#2051# "La versió beta de Project64 només és pels membres.\n\nSi teniu un compte a pj64.net, no haurÃeu de veure aquest error!!\nContacteu amb nosaltres a la web."
+#2052# "Error del programa"
+#2053# "No s'ha pogut trobar el fitxer dins del fitxer 7z"
+#2054# "Emulació de baix nivell (LLE) de vÃdeo"
+#2055# "L'LLE de vÃdeo no és per un ús genèric!!!\nÉs aconsellable que només utilitzis això per fer proves i no per jugar.\n\nVoleu canviar a l'LLE de vÃdeo?"
+#2056# "Emulació d'alt nivell (HLE) d'à udio"
+#2057# "L'HLE d'à udio requereix un complement de tercers!!!\nSi s'utilitza cap complement de tercers que suporti HLE, no hi haurà cap so.\n\nVoleu canviar a l'HLE d'à udio?"
diff --git a/Lang/English.pj.Lang b/Lang/English.pj.Lang
index f17aa2489..57a1c8a5f 100644
--- a/Lang/English.pj.Lang
+++ b/Lang/English.pj.Lang
@@ -51,6 +51,7 @@
#132# "R&esume"
#133# "&Soft Reset"
#134# "&Hard Reset"
+#135# "Swap &Disk"
//Options Menu
#140# "&Options"
@@ -234,6 +235,8 @@
#465# "Display speed"
#466# "Speed display:"
#467# "Check if Project64 is already running"
+#468# "Unique Game Save Directory"
+#469# "64DD IPL ROM Path:"
//ROM Browser Tab
#480# "Max # of ROMs remembered (0-10):"
@@ -437,6 +440,22 @@
#1104# "Options"
#1105# "Save Slots"
+/*********************************************************************************
+* Support Window *
+*********************************************************************************/
+#1200# "Support Project64"
+#1201# "Project64 is a software package designed to emulate a Nintendo64 video game system on a Microsoft Windows based PC. This allows you to play real N64 software in much the same way as it would be on the original hardware system.\n\nIf you like Project64 and have gotten some value out of it then please support project64 as either a thank you, or your desire to see it continually improved.\n\nIf you have supported project64:"
+#1202# "Enter notification code"
+#1203# "Support Project64"
+#1204# "Continue"
+#1205# "Please enter the support code"
+#1206# "Incorrect support code"
+#1207# "Thank you"
+#1208# "Enter code"
+#1209# "Please enter the code in the email"
+#1210# "OK"
+#1211# "Cancel"
+
/*********************************************************************************
* Messages *
*********************************************************************************/
diff --git a/Lang/English_alternative.pj.Lang b/Lang/English_alternative.pj.Lang
index c9d7d8cf8..73acc7702 100644
--- a/Lang/English_alternative.pj.Lang
+++ b/Lang/English_alternative.pj.Lang
@@ -210,6 +210,7 @@
#465# "&Display speed"
#466# "Speed display:"
#467# "&Check if Project64 is already running"
+#468# "&Unique Game Save Directory"
//ROM Browser Tab
#480# "&Number of ROMs to remember (0-10)"
diff --git a/Lang/French.pj.Lang b/Lang/French.pj.Lang
index d9e7e1994..83e2aeb25 100644
--- a/Lang/French.pj.Lang
+++ b/Lang/French.pj.Lang
@@ -1,4 +1,4 @@
-/*********************************************************************************
+/*********************************************************************************
* Meta Information *
*********************************************************************************/
//About DLL
@@ -51,6 +51,7 @@
#132# "R&eprendre"
#133# "Redémarrage &logiciel"
#134# "Redémarrage &matériel"
+#135# "Changer &disque"
//Options Menu
#140# "&Options"
@@ -96,7 +97,7 @@
#212# "Éditer les paramètres du jeu"
#213# "Éditer les cheats"
#214# "Plugin graphique"
-#215# "Lancer le Jeu avec le Disque"
+#215# "Lancer le jeu avec un disque"
//Alternate Name to save Slot
#220# "Emplacement de sauvegarde - Défaut"
@@ -234,6 +235,8 @@
#465# "Afficher la vitesse"
#466# "Vitesse affichée :"
#467# "Vérifier si Project64 est déjà lancé"
+#468# "Répertoire de sauvegarde unique"
+#469# "Chemin vers 64DD IPL ROM:"
//ROM Browser Tab
#480# "Max de ROM Ã retenir (0-10) :"
@@ -437,6 +440,22 @@
#1104# "Options"
#1105# "Emplacements de sauvegarde"
+/*********************************************************************************
+* Support Window *
+*********************************************************************************/
+#1200# "Support Project64"
+#1201# "Project64 est un logiciel crée pour émuler le système de jeu vidéo Nintendo64 sur un PC basé sur Microsoft Windows. Ceci vous permet de jouer avec des jeux N64 comme vous le feriez sur avec une vrai console.\n\nSi vous appréciez Project64, alros veuillez supporter Project64 avec soit des remerciements soit en proposant des idées d'améliorations.\n\nSi vous avez supporté Project64 :"
+#1202# "Entrez un Code de Notification"
+#1203# "Supporter Project64"
+#1204# "Continuer"
+#1205# "Veuillez entrer un Code de Support"
+#1206# "Code de Support Incorrecte"
+#1207# "Remerciements"
+#1208# "Entrez un Code"
+#1209# "Veuillez entrer le code se trouvant dans l'email"
+#1210# "OK"
+#1211# "Annuler"
+
/*********************************************************************************
* Messages *
*********************************************************************************/
diff --git a/Lang/Japanese.pj.Lang b/Lang/Japanese.pj.Lang
index bd59acc57..208b46056 100644
--- a/Lang/Japanese.pj.Lang
+++ b/Lang/Japanese.pj.Lang
@@ -4,8 +4,8 @@
//About DLL
#1 # "Japanese" // LANGUAGE ID
#2 # "Nekokabu" // Author
-#3 # "2.2" // Version
-#4 # "2015/12/5" // Date
+#3 # "2.3.1" // Version
+#4 # "2016/10/11" // Date
//About DLL Dialog
#5 # "ç¾åœ¨ã®è¨€èªž"
@@ -65,6 +65,7 @@
#132# "å†é–‹(&U)"
#133# "ソフトリセット(&S)"
#134# "ãƒãƒ¼ãƒ‰ãƒªã‚»ãƒƒãƒˆ(&H)"
+#135# "ディスクã®å…¥æ›¿ãˆ(&D)"
//Options Menu
#140# "オプション(&O)"
@@ -246,8 +247,10 @@
#463# "å‰å›žä½¿ã£ãŸãƒãƒ¼ãƒˆã‚’記憶ã™ã‚‹(&R)"
#464# "ãƒãƒ ã®å®Ÿè¡Œä¸ã¯ã‚¹ã‚¯ãƒªãƒ¼ãƒ³ã‚»ãƒ¼ãƒãƒ¼ã‚’無効ã«ã™ã‚‹"
#465# "フレームレートを表示"
-#466# "表示形å¼ã«ã‚ˆã£ã¦ãƒ•レームレートを変更ã™ã‚‹:"
+#466# "フレームレート表示形å¼"
#467# "Project64ãŒã™ã§ã«èµ·å‹•ã—ã¦ã„ã‚‹ã‹ãƒã‚§ãƒƒã‚¯ã™ã‚‹"
+#468# "ゲーム毎ã«ã‚»ãƒ¼ãƒ–ディレクトリを作æˆã™ã‚‹"
+#469# "64DD IPLãƒãƒ パス:"
//ROM Browser Tab
#480# "最近開ã„ãŸãƒãƒ ファイルã®è¡¨ç¤ºã™ã‚‹æ•°(0~10):"
@@ -453,6 +456,22 @@
#1104# "オプション"
#1105# "セーブスãƒãƒƒãƒˆ"
+/*********************************************************************************
+* Support Window *
+*********************************************************************************/
+#1200# "Project64ã®ã‚µãƒãƒ¼ãƒˆ"
+#1201# "Project64ã¯ã€Microsoft WindowsãŒå‹•作ã™ã‚‹PC上ã§Nintendo64ビデオゲームシステムをエミュレートã™ã‚‹ã‚ˆã†ã«è¨è¨ˆã•れãŸã‚½ãƒ•トウェアパッケージã§ã™ã€‚オリジナルã®ãƒãƒ¼ãƒ‰ã‚¦ã‚§ã‚¢ã‚·ã‚¹ãƒ†ãƒ ã¨åŒã˜ã‚ˆã†ã«æœ¬ç‰©ã®N64ソフトウェアをプレイã™ã‚‹ã“ã¨ãŒã§ãã¾ã™ã€‚\n\nã‚‚ã—ã‚ãªãŸãŒProject64ãŒå¥½ãã§ã€æ—¥é ƒã®ãŠç¤¼ã‚’ã—ãŸã‹ã£ãŸã‚Šã€ã¾ãŸã¯ç¶™ç¶šçš„ãªæ”¹å–„ã‚’è¦æ±‚ã™ã‚‹ã®ã§ã‚れã°Project64ã®ã‚µãƒãƒ¼ãƒˆã‚’ãŠé¡˜ã„ã„ãŸã—ã¾ã™ã€‚\n\nProject64をサãƒãƒ¼ãƒˆã—ã¦ã„ã‚‹å ´åˆ:"
+#1202# "確èªã‚³ãƒ¼ãƒ‰ã®å…¥åŠ›"
+#1203# "Project64ã®ã‚µãƒãƒ¼ãƒˆ"
+#1204# "ç¶šã‘ã‚‹"
+#1205# "確èªã‚³ãƒ¼ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„"
+#1206# "確èªã‚³ãƒ¼ãƒ‰ãŒæ£ã—ãã‚りã¾ã›ã‚“"
+#1207# "ã‚りãŒã¨ã†ã”ã–ã„ã¾ã—ãŸï¼"
+#1208# "コードã®å…¥åŠ›"
+#1209# "Eメールã§å±Šã„ãŸã‚³ãƒ¼ãƒ‰ã‚’入力ã—ã¦ãã ã•ã„"
+#1210# "OK"
+#1211# "ã‚ャンセル"
+
/*********************************************************************************
* Messages *
*********************************************************************************/
diff --git a/Lang/Spanish.pj.Lang b/Lang/Spanish.pj.Lang
index 1579acced..b02615dce 100644
--- a/Lang/Spanish.pj.Lang
+++ b/Lang/Spanish.pj.Lang
@@ -4,8 +4,8 @@
//About DLL
#1 # "Español" // LANGUAGE ID
#2 # "MELERIX" // Author
-#3 # "2.2" // Version
-#4 # "12/02/2016" // Date
+#3 # "2.3.1" // Version
+#4 # "30/09/2016" // Date
//About DLL Dialog
#5 # "Lenguaje Actual"
@@ -51,6 +51,7 @@
#132# "C&ontinuar"
#133# "&Reinicio Simple"
#134# "&Reinicio Completo"
+#135# "Intercambiar &Disco"
//Options Menu
#140# "&Opciones"
@@ -234,6 +235,8 @@
#465# "Mostrar velocidad"
#466# "Velocidad de la pantalla:"
#467# "Comprobar si Project64 ya está en ejecución"
+#468# "Directorio Único de Guardados de Juego"
+#469# "Ruta de ROM 66DD IPL:"
//ROM Browser Tab
#480# "Máx # de ROMs recordadas (0-10):"
@@ -437,6 +440,22 @@
#1104# "Opciones"
#1105# "Ranuras de Guardado"
+/*********************************************************************************
+* Support Window *
+*********************************************************************************/
+#1200# "Apoya a Project64"
+#1201# "Project64 es un paquete de software diseñado para emular un sistema de videojuegos Nintendo64 en un PC basado en Microsoft Windows. Esto te permite jugar con software real de N64 de la misma manera como lo serÃa en el sistema de hardware original.\n\nSi te gusta Project64 y has conseguido algún valor fuera de este, entonces por favor apoya a project64 como muestra de agradecimiento, o tu deseo de ver que esto sea continuamente mejorado.\n\nSi has apoyado a project64:"
+#1202# "Introduce el código de notificación"
+#1203# "Apoya a Project64"
+#1204# "Continuar"
+#1205# "Por favor introduce el código de apoyo"
+#1206# "Código de apoyo incorrecto"
+#1207# "Gracias"
+#1208# "Introduce el código"
+#1209# "Por favor introduce el código del email"
+#1210# "Aceptar"
+#1211# "Cancelar"
+
/*********************************************************************************
* Messages *
*********************************************************************************/
diff --git a/Plugin/GFX/Jabo_Direct3D8.dll b/Plugin/GFX/Jabo_Direct3D8.dll
index a45c46e53..1f0dbec26 100644
Binary files a/Plugin/GFX/Jabo_Direct3D8.dll and b/Plugin/GFX/Jabo_Direct3D8.dll differ
diff --git a/Project64.sln b/Project64.sln
index a223e72c6..195212bbb 100644
--- a/Project64.sln
+++ b/Project64.sln
@@ -1,12 +1,9 @@
-
+
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 2013
-VisualStudioVersion = 12.0.31101.0
+# Visual Studio 2010 or later
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rd Party", "3rd Party", "{AA8F7F8E-5377-4911-859D-8A8817B0DB26}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wxWidgets", "wxWidgets", "{1379F817-7E3D-4F58-9C22-7E364E46E842}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Glide", "Glide", "{9FE699A5-41C3-4441-92AB-639B3D77DE26}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Source\Common\Common.vcxproj", "{B4A4B994-9111-42B1-93C2-6F1CA8BC4421}"
@@ -36,16 +33,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64Setup", "Source\In
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Glide64", "Source\Glide64\Glide64.vcxproj", "{A4D13408-A794-4199-8FC7-4A9A32505005}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "Source\3rdParty\wx\wx_core.vcxproj", "{93447136-FACD-4740-8F35-FC46FB4A9E82}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "Source\3rdParty\wx\wx_base.vcxproj", "{427F1DCD-3BED-4010-9322-077A4C06D871}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxjpeg", "Source\3rdParty\wx\wx_wxjpeg.vcxproj", "{93CFEDF3-9A75-4484-B169-D9D8074F5AC2}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxpng", "Source\3rdParty\wx\wx_wxpng.vcxproj", "{05B9CB11-12D1-47CD-8E4A-88E12162119B}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxzlib", "Source\3rdParty\wx\wx_wxzlib.vcxproj", "{25A25249-C284-4C5A-8DC2-26FC3EB13703}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Glitch64", "Source\Glitch64\Glitch64.vcxproj", "{462C2608-182F-452C-944F-AF201E19300B}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "GlideHQ", "Source\GlideHQ\GlideHQ.vcxproj", "{2DADDAA5-0F57-46ED-A974-747908DDC7F3}"
@@ -61,12 +48,20 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PropertySheets", "PropertyS
PropertySheets\Release.props = PropertySheets\Release.props
EndProjectSection
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2", "Source\3rdParty\sdl\sdl2.vcxproj", "{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64-core", "Source\Project64-core\Project64-core.vcxproj", "{00C7B43A-DED7-4DF0-B072-9A5783EF866D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "png", "Source\3rdParty\png\png.vcxproj", "{17836496-31B0-46F2-B1B1-366D7DF6F04C}"
EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Android", "Android", "{0E0FCAC2-E128-4886-8EE6-1BCA84551F58}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginAudio", "Source\Android\PluginAudio\PluginAudio.vcxproj", "{D233025A-231F-4A43-92B6-E87193C60ACC}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginInput", "Source\Android\PluginInput\PluginInput.vcxproj", "{1133A1CC-A9E5-4026-B20D-6A2987130D4E}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PluginRSP", "Source\Android\PluginRSP\PluginRSP.vcxproj", "{B685BB34-D700-4FCC-8503-9B6AA1A0C95D}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JniBridge", "Source\Android\Bridge\Bridge.vcxproj", "{593B00E6-1987-415D-A62C-26533FC3E95C}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
@@ -131,8 +126,8 @@ Global
{731BD205-2826-4631-B7AF-117658E88DBC}.Release|Win32.Build.0 = Release|Win32
{731BD205-2826-4631-B7AF-117658E88DBC}.Release|x64.ActiveCfg = Release|x64
{731BD205-2826-4631-B7AF-117658E88DBC}.Release|x64.Build.0 = Release|x64
- {360A34F3-3172-4B09-8BC9-B3FBEE677863}.Debug|Win32.ActiveCfg = Debug|Win32
- {360A34F3-3172-4B09-8BC9-B3FBEE677863}.Debug|x64.ActiveCfg = Debug|Win32
+ {360A34F3-3172-4B09-8BC9-B3FBEE677863}.Debug|Win32.ActiveCfg = Release|Win32
+ {360A34F3-3172-4B09-8BC9-B3FBEE677863}.Debug|x64.ActiveCfg = Release|Win32
{360A34F3-3172-4B09-8BC9-B3FBEE677863}.Release|Win32.ActiveCfg = Release|Win32
{360A34F3-3172-4B09-8BC9-B3FBEE677863}.Release|Win32.Build.0 = Release|Win32
{360A34F3-3172-4B09-8BC9-B3FBEE677863}.Release|x64.ActiveCfg = Release|Win32
@@ -144,46 +139,6 @@ Global
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.Build.0 = Release|Win32
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|x64.ActiveCfg = Release|x64
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|x64.Build.0 = Release|x64
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Debug|Win32.ActiveCfg = Debug|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Debug|Win32.Build.0 = Debug|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Debug|x64.ActiveCfg = Debug|x64
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Debug|x64.Build.0 = Debug|x64
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Release|Win32.ActiveCfg = Release|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Release|Win32.Build.0 = Release|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Release|x64.ActiveCfg = Release|x64
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Release|x64.Build.0 = Release|x64
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Debug|Win32.ActiveCfg = Debug|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Debug|Win32.Build.0 = Debug|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Debug|x64.ActiveCfg = Debug|x64
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Debug|x64.Build.0 = Debug|x64
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Release|Win32.ActiveCfg = Release|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Release|Win32.Build.0 = Release|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Release|x64.ActiveCfg = Release|x64
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Release|x64.Build.0 = Release|x64
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Debug|Win32.ActiveCfg = Debug|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Debug|Win32.Build.0 = Debug|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Debug|x64.ActiveCfg = Debug|x64
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Debug|x64.Build.0 = Debug|x64
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Release|Win32.ActiveCfg = Release|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Release|Win32.Build.0 = Release|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Release|x64.ActiveCfg = Release|x64
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Release|x64.Build.0 = Release|x64
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Debug|Win32.ActiveCfg = Debug|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Debug|Win32.Build.0 = Debug|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Debug|x64.ActiveCfg = Debug|x64
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Debug|x64.Build.0 = Debug|x64
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Release|Win32.ActiveCfg = Release|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Release|Win32.Build.0 = Release|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Release|x64.ActiveCfg = Release|x64
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Release|x64.Build.0 = Release|x64
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Debug|Win32.ActiveCfg = Debug|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Debug|Win32.Build.0 = Debug|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Debug|x64.ActiveCfg = Debug|x64
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Debug|x64.Build.0 = Debug|x64
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Release|Win32.ActiveCfg = Release|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Release|Win32.Build.0 = Release|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Release|x64.ActiveCfg = Release|x64
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Release|x64.Build.0 = Release|x64
{462C2608-182F-452C-944F-AF201E19300B}.Debug|Win32.ActiveCfg = Debug|Win32
{462C2608-182F-452C-944F-AF201E19300B}.Debug|Win32.Build.0 = Debug|Win32
{462C2608-182F-452C-944F-AF201E19300B}.Debug|x64.ActiveCfg = Debug|x64
@@ -208,14 +163,6 @@ Global
{FD617E80-9E40-4138-85DA-B94633972E6A}.Release|Win32.Build.0 = Release|Win32
{FD617E80-9E40-4138-85DA-B94633972E6A}.Release|x64.ActiveCfg = Release|x64
{FD617E80-9E40-4138-85DA-B94633972E6A}.Release|x64.Build.0 = Release|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.ActiveCfg = Debug|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.Build.0 = Debug|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|x64.ActiveCfg = Debug|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|x64.Build.0 = Debug|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.ActiveCfg = Release|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.Build.0 = Release|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|x64.ActiveCfg = Release|x64
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|x64.Build.0 = Release|x64
{00C7B43A-DED7-4DF0-B072-9A5783EF866D}.Debug|Win32.ActiveCfg = Debug|Win32
{00C7B43A-DED7-4DF0-B072-9A5783EF866D}.Debug|Win32.Build.0 = Debug|Win32
{00C7B43A-DED7-4DF0-B072-9A5783EF866D}.Debug|x64.ActiveCfg = Debug|x64
@@ -232,24 +179,45 @@ Global
{17836496-31B0-46F2-B1B1-366D7DF6F04C}.Release|Win32.Build.0 = Release|Win32
{17836496-31B0-46F2-B1B1-366D7DF6F04C}.Release|x64.ActiveCfg = Release|x64
{17836496-31B0-46F2-B1B1-366D7DF6F04C}.Release|x64.Build.0 = Release|x64
+ {D233025A-231F-4A43-92B6-E87193C60ACC}.Debug|Win32.ActiveCfg = Debug|Win32
+ {D233025A-231F-4A43-92B6-E87193C60ACC}.Debug|Win32.Build.0 = Debug|Win32
+ {D233025A-231F-4A43-92B6-E87193C60ACC}.Debug|x64.ActiveCfg = Debug|Win32
+ {D233025A-231F-4A43-92B6-E87193C60ACC}.Release|Win32.ActiveCfg = Release|Win32
+ {D233025A-231F-4A43-92B6-E87193C60ACC}.Release|Win32.Build.0 = Release|Win32
+ {D233025A-231F-4A43-92B6-E87193C60ACC}.Release|x64.ActiveCfg = Release|Win32
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E}.Debug|Win32.ActiveCfg = Debug|Win32
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E}.Debug|Win32.Build.0 = Debug|Win32
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E}.Debug|x64.ActiveCfg = Debug|Win32
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E}.Release|Win32.ActiveCfg = Release|Win32
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E}.Release|Win32.Build.0 = Release|Win32
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E}.Release|x64.ActiveCfg = Release|Win32
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D}.Debug|Win32.ActiveCfg = Debug|Win32
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D}.Debug|Win32.Build.0 = Debug|Win32
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D}.Debug|x64.ActiveCfg = Debug|Win32
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D}.Release|Win32.ActiveCfg = Release|Win32
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D}.Release|Win32.Build.0 = Release|Win32
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D}.Release|x64.ActiveCfg = Release|Win32
+ {593B00E6-1987-415D-A62C-26533FC3E95C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {593B00E6-1987-415D-A62C-26533FC3E95C}.Debug|Win32.Build.0 = Debug|Win32
+ {593B00E6-1987-415D-A62C-26533FC3E95C}.Debug|x64.ActiveCfg = Debug|Win32
+ {593B00E6-1987-415D-A62C-26533FC3E95C}.Release|Win32.ActiveCfg = Release|Win32
+ {593B00E6-1987-415D-A62C-26533FC3E95C}.Release|Win32.Build.0 = Release|Win32
+ {593B00E6-1987-415D-A62C-26533FC3E95C}.Release|x64.ActiveCfg = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
- {1379F817-7E3D-4F58-9C22-7E364E46E842} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{3326E128-33AF-422C-BB7C-67CC6B915610} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{4BC6906B-213E-40D7-9FC7-1A93E228393D} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{731BD205-2826-4631-B7AF-117658E88DBC} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{A4D13408-A794-4199-8FC7-4A9A32505005} = {9FE699A5-41C3-4441-92AB-639B3D77DE26}
- {93447136-FACD-4740-8F35-FC46FB4A9E82} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {427F1DCD-3BED-4010-9322-077A4C06D871} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {05B9CB11-12D1-47CD-8E4A-88E12162119B} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {25A25249-C284-4C5A-8DC2-26FC3EB13703} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
{462C2608-182F-452C-944F-AF201E19300B} = {9FE699A5-41C3-4441-92AB-639B3D77DE26}
{2DADDAA5-0F57-46ED-A974-747908DDC7F3} = {9FE699A5-41C3-4441-92AB-639B3D77DE26}
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{17836496-31B0-46F2-B1B1-366D7DF6F04C} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
+ {D233025A-231F-4A43-92B6-E87193C60ACC} = {0E0FCAC2-E128-4886-8EE6-1BCA84551F58}
+ {1133A1CC-A9E5-4026-B20D-6A2987130D4E} = {0E0FCAC2-E128-4886-8EE6-1BCA84551F58}
+ {B685BB34-D700-4FCC-8503-9B6AA1A0C95D} = {0E0FCAC2-E128-4886-8EE6-1BCA84551F58}
+ {593B00E6-1987-415D-A62C-26533FC3E95C} = {0E0FCAC2-E128-4886-8EE6-1BCA84551F58}
EndGlobalSection
EndGlobal
diff --git a/Project64.vs2008.sln b/Project64.vs2008.sln
index f8ef256b9..0c67cd36a 100644
--- a/Project64.vs2008.sln
+++ b/Project64.vs2008.sln
@@ -38,35 +38,14 @@ EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Glide64", "Source\Glide64\Glide64.vcproj", "{A4D13408-A794-4199-8FC7-4A9A32505005}"
ProjectSection(ProjectDependencies) = postProject
{462C2608-182F-452C-944F-AF201E19300B} = {462C2608-182F-452C-944F-AF201E19300B}
- {05B9CB11-12D1-47CD-8E4A-88E12162119B} = {05B9CB11-12D1-47CD-8E4A-88E12162119B}
- {93447136-FACD-4740-8F35-FC46FB4A9E82} = {93447136-FACD-4740-8F35-FC46FB4A9E82}
- {25A25249-C284-4C5A-8DC2-26FC3EB13703} = {25A25249-C284-4C5A-8DC2-26FC3EB13703}
{B4A4B994-9111-42B1-93C2-6F1CA8BC4421} = {B4A4B994-9111-42B1-93C2-6F1CA8BC4421}
{51A84197-56BA-4017-9C0C-43E7F285184A} = {51A84197-56BA-4017-9C0C-43E7F285184A}
{2DADDAA5-0F57-46ED-A974-747908DDC7F3} = {2DADDAA5-0F57-46ED-A974-747908DDC7F3}
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68} = {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}
{8B9961B1-88D9-4EA3-A752-507A00DD9F3D} = {8B9961B1-88D9-4EA3-A752-507A00DD9F3D}
- {427F1DCD-3BED-4010-9322-077A4C06D871} = {427F1DCD-3BED-4010-9322-077A4C06D871}
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2} = {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}
EndProjectSection
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "core", "Source\3rdParty\wx\wx_core.vcproj", "{93447136-FACD-4740-8F35-FC46FB4A9E82}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "3rdParty", "3rdParty", "{AA8F7F8E-5377-4911-859D-8A8817B0DB26}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "wxWidgets", "wxWidgets", "{1379F817-7E3D-4F58-9C22-7E364E46E842}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "base", "Source\3rdParty\wx\wx_base.vcproj", "{427F1DCD-3BED-4010-9322-077A4C06D871}"
- ProjectSection(ProjectDependencies) = postProject
- {93447136-FACD-4740-8F35-FC46FB4A9E82} = {93447136-FACD-4740-8F35-FC46FB4A9E82}
- EndProjectSection
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxjpeg", "Source\3rdParty\wx\wx_wxjpeg.vcproj", "{93CFEDF3-9A75-4484-B169-D9D8074F5AC2}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxpng", "Source\3rdParty\wx\wx_wxpng.vcproj", "{05B9CB11-12D1-47CD-8E4A-88E12162119B}"
-EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "wxzlib", "Source\3rdParty\wx\wx_wxzlib.vcproj", "{25A25249-C284-4C5A-8DC2-26FC3EB13703}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Glitch64", "Source\Glitch64\Glitch64.vcproj", "{462C2608-182F-452C-944F-AF201E19300B}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Glide", "Glide", "{9FE699A5-41C3-4441-92AB-639B3D77DE26}"
@@ -85,11 +64,12 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SortRdb", "Source\SortRdb\S
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "PJ64 NRage", "Source\nragev20\NRage_Input_V2.vcproj", "{FD617E80-9E40-4138-85DA-B94633972E6A}"
EndProject
-Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SDL2", "Source\3rdParty\sdl\sdl2.vcproj", "{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}"
-EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Project64-core", "Source\Project64-core\Project64-core.vcproj", "{00C7B43A-DED7-4DF0-B072-9A5783EF866D}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "png", "Source\3rdParty\png\png.vcproj", "{51A84197-56BA-4017-9C0C-43E7F285184A}"
+ ProjectSection(ProjectDependencies) = postProject
+ {731BD205-2826-4631-B7AF-117658E88DBC} = {731BD205-2826-4631-B7AF-117658E88DBC}
+ EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -132,26 +112,6 @@ Global
{A4D13408-A794-4199-8FC7-4A9A32505005}.Debug|Win32.Build.0 = Debug|Win32
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.ActiveCfg = Release|Win32
{A4D13408-A794-4199-8FC7-4A9A32505005}.Release|Win32.Build.0 = Release|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Debug|Win32.ActiveCfg = Debug|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Debug|Win32.Build.0 = Debug|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Release|Win32.ActiveCfg = Release|Win32
- {93447136-FACD-4740-8F35-FC46FB4A9E82}.Release|Win32.Build.0 = Release|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Debug|Win32.ActiveCfg = Debug|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Debug|Win32.Build.0 = Debug|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Release|Win32.ActiveCfg = Release|Win32
- {427F1DCD-3BED-4010-9322-077A4C06D871}.Release|Win32.Build.0 = Release|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Debug|Win32.ActiveCfg = Debug|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Debug|Win32.Build.0 = Debug|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Release|Win32.ActiveCfg = Release|Win32
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2}.Release|Win32.Build.0 = Release|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Debug|Win32.ActiveCfg = Debug|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Debug|Win32.Build.0 = Debug|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Release|Win32.ActiveCfg = Release|Win32
- {05B9CB11-12D1-47CD-8E4A-88E12162119B}.Release|Win32.Build.0 = Release|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Debug|Win32.ActiveCfg = Debug|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Debug|Win32.Build.0 = Debug|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Release|Win32.ActiveCfg = Release|Win32
- {25A25249-C284-4C5A-8DC2-26FC3EB13703}.Release|Win32.Build.0 = Release|Win32
{462C2608-182F-452C-944F-AF201E19300B}.Debug|Win32.ActiveCfg = Debug|Win32
{462C2608-182F-452C-944F-AF201E19300B}.Debug|Win32.Build.0 = Debug|Win32
{462C2608-182F-452C-944F-AF201E19300B}.Release|Win32.ActiveCfg = Release|Win32
@@ -168,10 +128,6 @@ Global
{FD617E80-9E40-4138-85DA-B94633972E6A}.Debug|Win32.Build.0 = Debug|Win32
{FD617E80-9E40-4138-85DA-B94633972E6A}.Release|Win32.ActiveCfg = Release|Win32
{FD617E80-9E40-4138-85DA-B94633972E6A}.Release|Win32.Build.0 = Release|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.ActiveCfg = Debug|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Debug|Win32.Build.0 = Debug|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.ActiveCfg = Release|Win32
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}.Release|Win32.Build.0 = Release|Win32
{00C7B43A-DED7-4DF0-B072-9A5783EF866D}.Debug|Win32.ActiveCfg = Debug|Win32
{00C7B43A-DED7-4DF0-B072-9A5783EF866D}.Debug|Win32.Build.0 = Debug|Win32
{00C7B43A-DED7-4DF0-B072-9A5783EF866D}.Release|Win32.ActiveCfg = Release|Win32
@@ -187,18 +143,11 @@ Global
GlobalSection(NestedProjects) = preSolution
{4BC6906B-213E-40D7-9FC7-1A93E228393D} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{731BD205-2826-4631-B7AF-117658E88DBC} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
- {1379F817-7E3D-4F58-9C22-7E364E46E842} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{3326E128-33AF-422C-BB7C-67CC6B915610} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
- {81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{51A84197-56BA-4017-9C0C-43E7F285184A} = {AA8F7F8E-5377-4911-859D-8A8817B0DB26}
{462C2608-182F-452C-944F-AF201E19300B} = {9FE699A5-41C3-4441-92AB-639B3D77DE26}
{A4D13408-A794-4199-8FC7-4A9A32505005} = {9FE699A5-41C3-4441-92AB-639B3D77DE26}
{2DADDAA5-0F57-46ED-A974-747908DDC7F3} = {9FE699A5-41C3-4441-92AB-639B3D77DE26}
- {93447136-FACD-4740-8F35-FC46FB4A9E82} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {427F1DCD-3BED-4010-9322-077A4C06D871} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {93CFEDF3-9A75-4484-B169-D9D8074F5AC2} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {05B9CB11-12D1-47CD-8E4A-88E12162119B} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
- {25A25249-C284-4C5A-8DC2-26FC3EB13703} = {1379F817-7E3D-4F58-9C22-7E364E46E842}
{5788717F-E3D4-40CF-9637-3A2AEE85BB81} = {3768C4C9-9E32-4EA6-99FD-FCE72C34B27F}
EndGlobalSection
EndGlobal
diff --git a/PropertySheets/Debug.props b/PropertySheets/Debug.props
index 9aabfaa47..920f34506 100644
--- a/PropertySheets/Debug.props
+++ b/PropertySheets/Debug.props
@@ -11,7 +11,7 @@
false
false
EnableFastChecks
- true
+ true
MultiThreadedDebug
diff --git a/PropertySheets/Platform.props b/PropertySheets/Platform.props
index ad5f29b22..3195fec8b 100644
--- a/PropertySheets/Platform.props
+++ b/PropertySheets/Platform.props
@@ -62,12 +62,11 @@
true
Async
Default
- false
Default
false
true
NoExtensions
- NotSet
+ NotSet
Precise
false
false
diff --git a/PropertySheets/Release.props b/PropertySheets/Release.props
index 5476e48fd..3872a41ff 100644
--- a/PropertySheets/Release.props
+++ b/PropertySheets/Release.props
@@ -2,15 +2,14 @@
+ NDEBUG;%(PreprocessorDefinitions)
MinSpace
Default
- false
+ true
Size
false
false
false
- NDEBUG;%(PreprocessorDefinitions)
- false
MultiThreaded
diff --git a/PropertySheets/Release.vsprops b/PropertySheets/Release.vsprops
index 3cd19af07..bf238fd47 100644
--- a/PropertySheets/Release.vsprops
+++ b/PropertySheets/Release.vsprops
@@ -9,7 +9,7 @@
Name="VCCLCompilerTool"
Optimization="1"
InlineFunctionExpansion="0"
- EnableIntrinsicFunctions="false"
+ EnableIntrinsicFunctions="true"
FavorSizeOrSpeed="2"
OmitFramePointers="false"
EnableFiberSafeOptimizations="false"
diff --git a/Source/3rdParty/sdl/include/SDL.h b/Source/3rdParty/sdl/include/SDL.h
deleted file mode 100644
index a9077095f..000000000
--- a/Source/3rdParty/sdl/include/SDL.h
+++ /dev/null
@@ -1,163 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL.h
- *
- * Main include header for the SDL library
- */
-
-/**
- * \mainpage Simple DirectMedia Layer (SDL)
- *
- * http://www.libsdl.org/
- *
- * \section intro_sec Introduction
- *
- * Simple DirectMedia Layer is a cross-platform development library designed
- * to provide low level access to audio, keyboard, mouse, joystick, and
- * graphics hardware via OpenGL and Direct3D. It is used by video playback
- * software, emulators, and popular games including Valve's award winning
- * catalog and many Humble Bundle games.
- *
- * SDL officially supports Windows, Mac OS X, Linux, iOS, and Android.
- * Support for other platforms may be found in the source code.
- *
- * SDL is written in C, works natively with C++, and there are bindings
- * available for several other languages, including C# and Python.
- *
- * This library is distributed under the zlib license, which can be found
- * in the file "COPYING.txt".
- *
- * The best way to learn how to use SDL is to check out the header files in
- * the "include" subdirectory and the programs in the "test" subdirectory.
- * The header files and test programs are well commented and always up to date.
- * More documentation and FAQs are available online at:
- * http://wiki.libsdl.org/
- *
- * If you need help with the library, or just want to discuss SDL related
- * issues, you can join the developers mailing list:
- * http://www.libsdl.org/mailing-list.php
- *
- * Enjoy!
- * Sam Lantinga (slouken@libsdl.org)
- */
-
-#ifndef _SDL_H
-#define _SDL_H
-
-#include "SDL_main.h"
-#include "SDL_stdinc.h"
-#include "SDL_assert.h"
-#include "SDL_atomic.h"
-#include "SDL_audio.h"
-#include "SDL_clipboard.h"
-#include "SDL_cpuinfo.h"
-#include "SDL_endian.h"
-#include "SDL_error.h"
-#include "SDL_events.h"
-#include "SDL_filesystem.h"
-#include "SDL_joystick.h"
-#include "SDL_gamecontroller.h"
-#include "SDL_haptic.h"
-#include "SDL_hints.h"
-#include "SDL_loadso.h"
-#include "SDL_log.h"
-#include "SDL_messagebox.h"
-#include "SDL_mutex.h"
-#include "SDL_power.h"
-#include "SDL_render.h"
-#include "SDL_rwops.h"
-#include "SDL_system.h"
-#include "SDL_thread.h"
-#include "SDL_timer.h"
-#include "SDL_version.h"
-#include "SDL_video.h"
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* As of version 0.5, SDL is loaded dynamically into the application */
-
-/**
- * \name SDL_INIT_*
- *
- * These are the flags which may be passed to SDL_Init(). You should
- * specify the subsystems which you will be using in your application.
- */
-/* @{ */
-#define SDL_INIT_TIMER 0x00000001
-#define SDL_INIT_AUDIO 0x00000010
-#define SDL_INIT_VIDEO 0x00000020 /**< SDL_INIT_VIDEO implies SDL_INIT_EVENTS */
-#define SDL_INIT_JOYSTICK 0x00000200 /**< SDL_INIT_JOYSTICK implies SDL_INIT_EVENTS */
-#define SDL_INIT_HAPTIC 0x00001000
-#define SDL_INIT_GAMECONTROLLER 0x00002000 /**< SDL_INIT_GAMECONTROLLER implies SDL_INIT_JOYSTICK */
-#define SDL_INIT_EVENTS 0x00004000
-#define SDL_INIT_NOPARACHUTE 0x00100000 /**< Don't catch fatal signals */
-#define SDL_INIT_EVERYTHING ( \
- SDL_INIT_TIMER | SDL_INIT_AUDIO | SDL_INIT_VIDEO | SDL_INIT_EVENTS | \
- SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC | SDL_INIT_GAMECONTROLLER \
- )
-/* @} */
-
-/**
- * This function initializes the subsystems specified by \c flags
- * Unless the ::SDL_INIT_NOPARACHUTE flag is set, it will install cleanup
- * signal handlers for some commonly ignored fatal signals (like SIGSEGV).
- */
-extern DECLSPEC int SDLCALL SDL_Init(Uint32 flags);
-
-/**
- * This function initializes specific SDL subsystems
- */
-extern DECLSPEC int SDLCALL SDL_InitSubSystem(Uint32 flags);
-
-/**
- * This function cleans up specific SDL subsystems
- */
-extern DECLSPEC void SDLCALL SDL_QuitSubSystem(Uint32 flags);
-
-/**
- * This function returns a mask of the specified subsystems which have
- * previously been initialized.
- *
- * If \c flags is 0, it returns a mask of all initialized subsystems.
- */
-extern DECLSPEC Uint32 SDLCALL SDL_WasInit(Uint32 flags);
-
-/**
- * This function cleans up all initialized subsystems. You should
- * call it upon all exit conditions.
- */
-extern DECLSPEC void SDLCALL SDL_Quit(void);
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_H */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_assert.h b/Source/3rdParty/sdl/include/SDL_assert.h
deleted file mode 100644
index 42348f7d1..000000000
--- a/Source/3rdParty/sdl/include/SDL_assert.h
+++ /dev/null
@@ -1,284 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_assert_h
-#define _SDL_assert_h
-
-#include "SDL_config.h"
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#ifndef SDL_ASSERT_LEVEL
-#ifdef SDL_DEFAULT_ASSERT_LEVEL
-#define SDL_ASSERT_LEVEL SDL_DEFAULT_ASSERT_LEVEL
-#elif defined(_DEBUG) || defined(DEBUG) || \
- (defined(__GNUC__) && !defined(__OPTIMIZE__))
-#define SDL_ASSERT_LEVEL 2
-#else
-#define SDL_ASSERT_LEVEL 1
-#endif
-#endif /* SDL_ASSERT_LEVEL */
-
-/*
-These are macros and not first class functions so that the debugger breaks
-on the assertion line and not in some random guts of SDL, and so each
-assert can have unique static variables associated with it.
-*/
-
-#if defined(_MSC_VER)
-/* Don't include intrin.h here because it contains C++ code */
- extern void __cdecl __debugbreak(void);
- #define SDL_TriggerBreakpoint() __debugbreak()
-#elif (defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)))
- #define SDL_TriggerBreakpoint() __asm__ __volatile__ ( "int $3\n\t" )
-#elif defined(HAVE_SIGNAL_H)
- #include
- #define SDL_TriggerBreakpoint() raise(SIGTRAP)
-#else
- /* How do we trigger breakpoints on this platform? */
- #define SDL_TriggerBreakpoint()
-#endif
-
-#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 supports __func__ as a standard. */
-# define SDL_FUNCTION __func__
-#elif ((__GNUC__ >= 2) || defined(_MSC_VER))
-# define SDL_FUNCTION __FUNCTION__
-#else
-# define SDL_FUNCTION "???"
-#endif
-#define SDL_FILE __FILE__
-#define SDL_LINE __LINE__
-
-/*
-sizeof (x) makes the compiler still parse the expression even without
-assertions enabled, so the code is always checked at compile time, but
-doesn't actually generate code for it, so there are no side effects or
-expensive checks at run time, just the constant size of what x WOULD be,
-which presumably gets optimized out as unused.
-This also solves the problem of...
-
- int somevalue = blah();
- SDL_assert(somevalue == 1);
-
-...which would cause compiles to complain that somevalue is unused if we
-disable assertions.
-*/
-
-#ifdef _MSC_VER /* stupid /W4 warnings. */
-#define SDL_NULL_WHILE_LOOP_CONDITION (-1 == __LINE__)
-#else
-#define SDL_NULL_WHILE_LOOP_CONDITION (0)
-#endif
-
-#define SDL_disabled_assert(condition) \
- do { (void) sizeof ((condition)); } while (SDL_NULL_WHILE_LOOP_CONDITION)
-
-typedef enum
-{
- SDL_ASSERTION_RETRY, /**< Retry the assert immediately. */
- SDL_ASSERTION_BREAK, /**< Make the debugger trigger a breakpoint. */
- SDL_ASSERTION_ABORT, /**< Terminate the program. */
- SDL_ASSERTION_IGNORE, /**< Ignore the assert. */
- SDL_ASSERTION_ALWAYS_IGNORE /**< Ignore the assert from now on. */
-} SDL_assert_state;
-
-typedef struct SDL_assert_data
-{
- int always_ignore;
- unsigned int trigger_count;
- const char *condition;
- const char *filename;
- int linenum;
- const char *function;
- const struct SDL_assert_data *next;
-} SDL_assert_data;
-
-#if (SDL_ASSERT_LEVEL > 0)
-
-/* Never call this directly. Use the SDL_assert* macros. */
-extern DECLSPEC SDL_assert_state SDLCALL SDL_ReportAssertion(SDL_assert_data *,
- const char *,
- const char *, int)
-#if defined(__clang__)
-#if __has_feature(attribute_analyzer_noreturn)
-/* this tells Clang's static analysis that we're a custom assert function,
- and that the analyzer should assume the condition was always true past this
- SDL_assert test. */
- __attribute__((analyzer_noreturn))
-#endif
-#endif
-;
-
-/* the do {} while(0) avoids dangling else problems:
- if (x) SDL_assert(y); else blah();
- ... without the do/while, the "else" could attach to this macro's "if".
- We try to handle just the minimum we need here in a macro...the loop,
- the static vars, and break points. The heavy lifting is handled in
- SDL_ReportAssertion(), in SDL_assert.c.
-*/
-#define SDL_enabled_assert(condition) \
- do { \
- while ( !(condition) ) { \
- static struct SDL_assert_data assert_data = { \
- 0, 0, #condition, 0, 0, 0, 0 \
- }; \
- const SDL_assert_state state = SDL_ReportAssertion(&assert_data, \
- SDL_FUNCTION, \
- SDL_FILE, \
- SDL_LINE); \
- if (state == SDL_ASSERTION_RETRY) { \
- continue; /* go again. */ \
- } else if (state == SDL_ASSERTION_BREAK) { \
- SDL_TriggerBreakpoint(); \
- } \
- break; /* not retrying. */ \
- } \
- } while (SDL_NULL_WHILE_LOOP_CONDITION)
-
-#endif /* enabled assertions support code */
-
-/* Enable various levels of assertions. */
-#if SDL_ASSERT_LEVEL == 0 /* assertions disabled */
-# define SDL_assert(condition) SDL_disabled_assert(condition)
-# define SDL_assert_release(condition) SDL_disabled_assert(condition)
-# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
-#elif SDL_ASSERT_LEVEL == 1 /* release settings. */
-# define SDL_assert(condition) SDL_disabled_assert(condition)
-# define SDL_assert_release(condition) SDL_enabled_assert(condition)
-# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
-#elif SDL_ASSERT_LEVEL == 2 /* normal settings. */
-# define SDL_assert(condition) SDL_enabled_assert(condition)
-# define SDL_assert_release(condition) SDL_enabled_assert(condition)
-# define SDL_assert_paranoid(condition) SDL_disabled_assert(condition)
-#elif SDL_ASSERT_LEVEL == 3 /* paranoid settings. */
-# define SDL_assert(condition) SDL_enabled_assert(condition)
-# define SDL_assert_release(condition) SDL_enabled_assert(condition)
-# define SDL_assert_paranoid(condition) SDL_enabled_assert(condition)
-#else
-# error Unknown assertion level.
-#endif
-
-/* this assertion is never disabled at any level. */
-#define SDL_assert_always(condition) SDL_enabled_assert(condition)
-
-
-typedef SDL_assert_state (SDLCALL *SDL_AssertionHandler)(
- const SDL_assert_data* data, void* userdata);
-
-/**
- * \brief Set an application-defined assertion handler.
- *
- * This allows an app to show its own assertion UI and/or force the
- * response to an assertion failure. If the app doesn't provide this, SDL
- * will try to do the right thing, popping up a system-specific GUI dialog,
- * and probably minimizing any fullscreen windows.
- *
- * This callback may fire from any thread, but it runs wrapped in a mutex, so
- * it will only fire from one thread at a time.
- *
- * Setting the callback to NULL restores SDL's original internal handler.
- *
- * This callback is NOT reset to SDL's internal handler upon SDL_Quit()!
- *
- * \return SDL_assert_state value of how to handle the assertion failure.
- *
- * \param handler Callback function, called when an assertion fails.
- * \param userdata A pointer passed to the callback as-is.
- */
-extern DECLSPEC void SDLCALL SDL_SetAssertionHandler(
- SDL_AssertionHandler handler,
- void *userdata);
-
-/**
- * \brief Get the default assertion handler.
- *
- * This returns the function pointer that is called by default when an
- * assertion is triggered. This is an internal function provided by SDL,
- * that is used for assertions when SDL_SetAssertionHandler() hasn't been
- * used to provide a different function.
- *
- * \return The default SDL_AssertionHandler that is called when an assert triggers.
- */
-extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetDefaultAssertionHandler(void);
-
-/**
- * \brief Get the current assertion handler.
- *
- * This returns the function pointer that is called when an assertion is
- * triggered. This is either the value last passed to
- * SDL_SetAssertionHandler(), or if no application-specified function is
- * set, is equivalent to calling SDL_GetDefaultAssertionHandler().
- *
- * \param puserdata Pointer to a void*, which will store the "userdata"
- * pointer that was passed to SDL_SetAssertionHandler().
- * This value will always be NULL for the default handler.
- * If you don't care about this data, it is safe to pass
- * a NULL pointer to this function to ignore it.
- * \return The SDL_AssertionHandler that is called when an assert triggers.
- */
-extern DECLSPEC SDL_AssertionHandler SDLCALL SDL_GetAssertionHandler(void **puserdata);
-
-/**
- * \brief Get a list of all assertion failures.
- *
- * Get all assertions triggered since last call to SDL_ResetAssertionReport(),
- * or the start of the program.
- *
- * The proper way to examine this data looks something like this:
- *
- *
- * const SDL_assert_data *item = SDL_GetAssertionReport();
- * while (item) {
- * printf("'%s', %s (%s:%d), triggered %u times, always ignore: %s.\n",
- * item->condition, item->function, item->filename,
- * item->linenum, item->trigger_count,
- * item->always_ignore ? "yes" : "no");
- * item = item->next;
- * }
- *
- *
- * \return List of all assertions.
- * \sa SDL_ResetAssertionReport
- */
-extern DECLSPEC const SDL_assert_data * SDLCALL SDL_GetAssertionReport(void);
-
-/**
- * \brief Reset the list of all assertion failures.
- *
- * Reset list of all assertions triggered.
- *
- * \sa SDL_GetAssertionReport
- */
-extern DECLSPEC void SDLCALL SDL_ResetAssertionReport(void);
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_assert_h */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_atomic.h b/Source/3rdParty/sdl/include/SDL_atomic.h
deleted file mode 100644
index bb3a9b657..000000000
--- a/Source/3rdParty/sdl/include/SDL_atomic.h
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_atomic.h
- *
- * Atomic operations.
- *
- * IMPORTANT:
- * If you are not an expert in concurrent lockless programming, you should
- * only be using the atomic lock and reference counting functions in this
- * file. In all other cases you should be protecting your data structures
- * with full mutexes.
- *
- * The list of "safe" functions to use are:
- * SDL_AtomicLock()
- * SDL_AtomicUnlock()
- * SDL_AtomicIncRef()
- * SDL_AtomicDecRef()
- *
- * Seriously, here be dragons!
- * ^^^^^^^^^^^^^^^^^^^^^^^^^^^
- *
- * You can find out a little more about lockless programming and the
- * subtle issues that can arise here:
- * http://msdn.microsoft.com/en-us/library/ee418650%28v=vs.85%29.aspx
- *
- * There's also lots of good information here:
- * http://www.1024cores.net/home/lock-free-algorithms
- * http://preshing.com/
- *
- * These operations may or may not actually be implemented using
- * processor specific atomic operations. When possible they are
- * implemented as true processor specific atomic operations. When that
- * is not possible the are implemented using locks that *do* use the
- * available atomic operations.
- *
- * All of the atomic operations that modify memory are full memory barriers.
- */
-
-#ifndef _SDL_atomic_h_
-#define _SDL_atomic_h_
-
-#include "SDL_stdinc.h"
-#include "SDL_platform.h"
-
-#include "begin_code.h"
-
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \name SDL AtomicLock
- *
- * The atomic locks are efficient spinlocks using CPU instructions,
- * but are vulnerable to starvation and can spin forever if a thread
- * holding a lock has been terminated. For this reason you should
- * minimize the code executed inside an atomic lock and never do
- * expensive things like API or system calls while holding them.
- *
- * The atomic locks are not safe to lock recursively.
- *
- * Porting Note:
- * The spin lock functions and type are required and can not be
- * emulated because they are used in the atomic emulation code.
- */
-/* @{ */
-
-typedef int SDL_SpinLock;
-
-/**
- * \brief Try to lock a spin lock by setting it to a non-zero value.
- *
- * \param lock Points to the lock.
- *
- * \return SDL_TRUE if the lock succeeded, SDL_FALSE if the lock is already held.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_AtomicTryLock(SDL_SpinLock *lock);
-
-/**
- * \brief Lock a spin lock by setting it to a non-zero value.
- *
- * \param lock Points to the lock.
- */
-extern DECLSPEC void SDLCALL SDL_AtomicLock(SDL_SpinLock *lock);
-
-/**
- * \brief Unlock a spin lock by setting it to 0. Always returns immediately
- *
- * \param lock Points to the lock.
- */
-extern DECLSPEC void SDLCALL SDL_AtomicUnlock(SDL_SpinLock *lock);
-
-/* @} *//* SDL AtomicLock */
-
-
-/**
- * The compiler barrier prevents the compiler from reordering
- * reads and writes to globally visible variables across the call.
- */
-#if defined(_MSC_VER) && (_MSC_VER > 1200)
-void _ReadWriteBarrier(void);
-#pragma intrinsic(_ReadWriteBarrier)
-#define SDL_CompilerBarrier() _ReadWriteBarrier()
-#elif defined(__GNUC__)
-#define SDL_CompilerBarrier() __asm__ __volatile__ ("" : : : "memory")
-#else
-#define SDL_CompilerBarrier() \
-{ SDL_SpinLock _tmp = 0; SDL_AtomicLock(&_tmp); SDL_AtomicUnlock(&_tmp); }
-#endif
-
-/**
- * Memory barriers are designed to prevent reads and writes from being
- * reordered by the compiler and being seen out of order on multi-core CPUs.
- *
- * A typical pattern would be for thread A to write some data and a flag,
- * and for thread B to read the flag and get the data. In this case you
- * would insert a release barrier between writing the data and the flag,
- * guaranteeing that the data write completes no later than the flag is
- * written, and you would insert an acquire barrier between reading the
- * flag and reading the data, to ensure that all the reads associated
- * with the flag have completed.
- *
- * In this pattern you should always see a release barrier paired with
- * an acquire barrier and you should gate the data reads/writes with a
- * single flag variable.
- *
- * For more information on these semantics, take a look at the blog post:
- * http://preshing.com/20120913/acquire-and-release-semantics
- */
-#if defined(__GNUC__) && (defined(__powerpc__) || defined(__ppc__))
-#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("lwsync" : : : "memory")
-#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("lwsync" : : : "memory")
-#elif defined(__GNUC__) && defined(__arm__)
-#if defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7EM__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
-#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("dmb ish" : : : "memory")
-#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("dmb ish" : : : "memory")
-#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__)
-#ifdef __thumb__
-/* The mcr instruction isn't available in thumb mode, use real functions */
-extern DECLSPEC void SDLCALL SDL_MemoryBarrierRelease();
-extern DECLSPEC void SDLCALL SDL_MemoryBarrierAcquire();
-#else
-#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
-#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("mcr p15, 0, %0, c7, c10, 5" : : "r"(0) : "memory")
-#endif /* __thumb__ */
-#else
-#define SDL_MemoryBarrierRelease() __asm__ __volatile__ ("" : : : "memory")
-#define SDL_MemoryBarrierAcquire() __asm__ __volatile__ ("" : : : "memory")
-#endif /* __GNUC__ && __arm__ */
-#else
-/* This is correct for the x86 and x64 CPUs, and we'll expand this over time. */
-#define SDL_MemoryBarrierRelease() SDL_CompilerBarrier()
-#define SDL_MemoryBarrierAcquire() SDL_CompilerBarrier()
-#endif
-
-/**
- * \brief A type representing an atomic integer value. It is a struct
- * so people don't accidentally use numeric operations on it.
- */
-typedef struct { int value; } SDL_atomic_t;
-
-/**
- * \brief Set an atomic variable to a new value if it is currently an old value.
- *
- * \return SDL_TRUE if the atomic variable was set, SDL_FALSE otherwise.
- *
- * \note If you don't know what this function is for, you shouldn't use it!
-*/
-extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCAS(SDL_atomic_t *a, int oldval, int newval);
-
-/**
- * \brief Set an atomic variable to a value.
- *
- * \return The previous value of the atomic variable.
- */
-extern DECLSPEC int SDLCALL SDL_AtomicSet(SDL_atomic_t *a, int v);
-
-/**
- * \brief Get the value of an atomic variable
- */
-extern DECLSPEC int SDLCALL SDL_AtomicGet(SDL_atomic_t *a);
-
-/**
- * \brief Add to an atomic variable.
- *
- * \return The previous value of the atomic variable.
- *
- * \note This same style can be used for any number operation
- */
-extern DECLSPEC int SDLCALL SDL_AtomicAdd(SDL_atomic_t *a, int v);
-
-/**
- * \brief Increment an atomic variable used as a reference count.
- */
-#ifndef SDL_AtomicIncRef
-#define SDL_AtomicIncRef(a) SDL_AtomicAdd(a, 1)
-#endif
-
-/**
- * \brief Decrement an atomic variable used as a reference count.
- *
- * \return SDL_TRUE if the variable reached zero after decrementing,
- * SDL_FALSE otherwise
- */
-#ifndef SDL_AtomicDecRef
-#define SDL_AtomicDecRef(a) (SDL_AtomicAdd(a, -1) == 1)
-#endif
-
-/**
- * \brief Set a pointer to a new value if it is currently an old value.
- *
- * \return SDL_TRUE if the pointer was set, SDL_FALSE otherwise.
- *
- * \note If you don't know what this function is for, you shouldn't use it!
-*/
-extern DECLSPEC SDL_bool SDLCALL SDL_AtomicCASPtr(void **a, void *oldval, void *newval);
-
-/**
- * \brief Set a pointer to a value atomically.
- *
- * \return The previous value of the pointer.
- */
-extern DECLSPEC void* SDLCALL SDL_AtomicSetPtr(void **a, void* v);
-
-/**
- * \brief Get the value of a pointer atomically.
- */
-extern DECLSPEC void* SDLCALL SDL_AtomicGetPtr(void **a);
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-
-#include "close_code.h"
-
-#endif /* _SDL_atomic_h_ */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_audio.h b/Source/3rdParty/sdl/include/SDL_audio.h
deleted file mode 100644
index 4c987d511..000000000
--- a/Source/3rdParty/sdl/include/SDL_audio.h
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_audio.h
- *
- * Access to the raw audio mixing buffer for the SDL library.
- */
-
-#ifndef _SDL_audio_h
-#define _SDL_audio_h
-
-#include "SDL_stdinc.h"
-#include "SDL_error.h"
-#include "SDL_endian.h"
-#include "SDL_mutex.h"
-#include "SDL_thread.h"
-#include "SDL_rwops.h"
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief Audio format flags.
- *
- * These are what the 16 bits in SDL_AudioFormat currently mean...
- * (Unspecified bits are always zero).
- *
- * \verbatim
- ++-----------------------sample is signed if set
- ||
- || ++-----------sample is bigendian if set
- || ||
- || || ++---sample is float if set
- || || ||
- || || || +---sample bit size---+
- || || || | |
- 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
- \endverbatim
- *
- * There are macros in SDL 2.0 and later to query these bits.
- */
-typedef Uint16 SDL_AudioFormat;
-
-/**
- * \name Audio flags
- */
-/* @{ */
-
-#define SDL_AUDIO_MASK_BITSIZE (0xFF)
-#define SDL_AUDIO_MASK_DATATYPE (1<<8)
-#define SDL_AUDIO_MASK_ENDIAN (1<<12)
-#define SDL_AUDIO_MASK_SIGNED (1<<15)
-#define SDL_AUDIO_BITSIZE(x) (x & SDL_AUDIO_MASK_BITSIZE)
-#define SDL_AUDIO_ISFLOAT(x) (x & SDL_AUDIO_MASK_DATATYPE)
-#define SDL_AUDIO_ISBIGENDIAN(x) (x & SDL_AUDIO_MASK_ENDIAN)
-#define SDL_AUDIO_ISSIGNED(x) (x & SDL_AUDIO_MASK_SIGNED)
-#define SDL_AUDIO_ISINT(x) (!SDL_AUDIO_ISFLOAT(x))
-#define SDL_AUDIO_ISLITTLEENDIAN(x) (!SDL_AUDIO_ISBIGENDIAN(x))
-#define SDL_AUDIO_ISUNSIGNED(x) (!SDL_AUDIO_ISSIGNED(x))
-
-/**
- * \name Audio format flags
- *
- * Defaults to LSB byte order.
- */
-/* @{ */
-#define AUDIO_U8 0x0008 /**< Unsigned 8-bit samples */
-#define AUDIO_S8 0x8008 /**< Signed 8-bit samples */
-#define AUDIO_U16LSB 0x0010 /**< Unsigned 16-bit samples */
-#define AUDIO_S16LSB 0x8010 /**< Signed 16-bit samples */
-#define AUDIO_U16MSB 0x1010 /**< As above, but big-endian byte order */
-#define AUDIO_S16MSB 0x9010 /**< As above, but big-endian byte order */
-#define AUDIO_U16 AUDIO_U16LSB
-#define AUDIO_S16 AUDIO_S16LSB
-/* @} */
-
-/**
- * \name int32 support
- */
-/* @{ */
-#define AUDIO_S32LSB 0x8020 /**< 32-bit integer samples */
-#define AUDIO_S32MSB 0x9020 /**< As above, but big-endian byte order */
-#define AUDIO_S32 AUDIO_S32LSB
-/* @} */
-
-/**
- * \name float32 support
- */
-/* @{ */
-#define AUDIO_F32LSB 0x8120 /**< 32-bit floating point samples */
-#define AUDIO_F32MSB 0x9120 /**< As above, but big-endian byte order */
-#define AUDIO_F32 AUDIO_F32LSB
-/* @} */
-
-/**
- * \name Native audio byte ordering
- */
-/* @{ */
-#if SDL_BYTEORDER == SDL_LIL_ENDIAN
-#define AUDIO_U16SYS AUDIO_U16LSB
-#define AUDIO_S16SYS AUDIO_S16LSB
-#define AUDIO_S32SYS AUDIO_S32LSB
-#define AUDIO_F32SYS AUDIO_F32LSB
-#else
-#define AUDIO_U16SYS AUDIO_U16MSB
-#define AUDIO_S16SYS AUDIO_S16MSB
-#define AUDIO_S32SYS AUDIO_S32MSB
-#define AUDIO_F32SYS AUDIO_F32MSB
-#endif
-/* @} */
-
-/**
- * \name Allow change flags
- *
- * Which audio format changes are allowed when opening a device.
- */
-/* @{ */
-#define SDL_AUDIO_ALLOW_FREQUENCY_CHANGE 0x00000001
-#define SDL_AUDIO_ALLOW_FORMAT_CHANGE 0x00000002
-#define SDL_AUDIO_ALLOW_CHANNELS_CHANGE 0x00000004
-#define SDL_AUDIO_ALLOW_ANY_CHANGE (SDL_AUDIO_ALLOW_FREQUENCY_CHANGE|SDL_AUDIO_ALLOW_FORMAT_CHANGE|SDL_AUDIO_ALLOW_CHANNELS_CHANGE)
-/* @} */
-
-/* @} *//* Audio flags */
-
-/**
- * This function is called when the audio device needs more data.
- *
- * \param userdata An application-specific parameter saved in
- * the SDL_AudioSpec structure
- * \param stream A pointer to the audio data buffer.
- * \param len The length of that buffer in bytes.
- *
- * Once the callback returns, the buffer will no longer be valid.
- * Stereo samples are stored in a LRLRLR ordering.
- */
-typedef void (SDLCALL * SDL_AudioCallback) (void *userdata, Uint8 * stream,
- int len);
-
-/**
- * The calculated values in this structure are calculated by SDL_OpenAudio().
- */
-typedef struct SDL_AudioSpec
-{
- int freq; /**< DSP frequency -- samples per second */
- SDL_AudioFormat format; /**< Audio data format */
- Uint8 channels; /**< Number of channels: 1 mono, 2 stereo */
- Uint8 silence; /**< Audio buffer silence value (calculated) */
- Uint16 samples; /**< Audio buffer size in samples (power of 2) */
- Uint16 padding; /**< Necessary for some compile environments */
- Uint32 size; /**< Audio buffer size in bytes (calculated) */
- SDL_AudioCallback callback;
- void *userdata;
-} SDL_AudioSpec;
-
-
-struct SDL_AudioCVT;
-typedef void (SDLCALL * SDL_AudioFilter) (struct SDL_AudioCVT * cvt,
- SDL_AudioFormat format);
-
-/**
- * A structure to hold a set of audio conversion filters and buffers.
- */
-#ifdef __GNUC__
-/* This structure is 84 bytes on 32-bit architectures, make sure GCC doesn't
- pad it out to 88 bytes to guarantee ABI compatibility between compilers.
- vvv
- The next time we rev the ABI, make sure to size the ints and add padding.
-*/
-#define SDL_AUDIOCVT_PACKED __attribute__((packed))
-#else
-#define SDL_AUDIOCVT_PACKED
-#endif
-/* */
-typedef struct SDL_AudioCVT
-{
- int needed; /**< Set to 1 if conversion possible */
- SDL_AudioFormat src_format; /**< Source audio format */
- SDL_AudioFormat dst_format; /**< Target audio format */
- double rate_incr; /**< Rate conversion increment */
- Uint8 *buf; /**< Buffer to hold entire audio data */
- int len; /**< Length of original audio buffer */
- int len_cvt; /**< Length of converted audio buffer */
- int len_mult; /**< buffer must be len*len_mult big */
- double len_ratio; /**< Given len, final size is len*len_ratio */
- SDL_AudioFilter filters[10]; /**< Filter list */
- int filter_index; /**< Current audio conversion function */
-} SDL_AUDIOCVT_PACKED SDL_AudioCVT;
-
-
-/* Function prototypes */
-
-/**
- * \name Driver discovery functions
- *
- * These functions return the list of built in audio drivers, in the
- * order that they are normally initialized by default.
- */
-/* @{ */
-extern DECLSPEC int SDLCALL SDL_GetNumAudioDrivers(void);
-extern DECLSPEC const char *SDLCALL SDL_GetAudioDriver(int index);
-/* @} */
-
-/**
- * \name Initialization and cleanup
- *
- * \internal These functions are used internally, and should not be used unless
- * you have a specific need to specify the audio driver you want to
- * use. You should normally use SDL_Init() or SDL_InitSubSystem().
- */
-/* @{ */
-extern DECLSPEC int SDLCALL SDL_AudioInit(const char *driver_name);
-extern DECLSPEC void SDLCALL SDL_AudioQuit(void);
-/* @} */
-
-/**
- * This function returns the name of the current audio driver, or NULL
- * if no driver has been initialized.
- */
-extern DECLSPEC const char *SDLCALL SDL_GetCurrentAudioDriver(void);
-
-/**
- * This function opens the audio device with the desired parameters, and
- * returns 0 if successful, placing the actual hardware parameters in the
- * structure pointed to by \c obtained. If \c obtained is NULL, the audio
- * data passed to the callback function will be guaranteed to be in the
- * requested format, and will be automatically converted to the hardware
- * audio format if necessary. This function returns -1 if it failed
- * to open the audio device, or couldn't set up the audio thread.
- *
- * When filling in the desired audio spec structure,
- * - \c desired->freq should be the desired audio frequency in samples-per-
- * second.
- * - \c desired->format should be the desired audio format.
- * - \c desired->samples is the desired size of the audio buffer, in
- * samples. This number should be a power of two, and may be adjusted by
- * the audio driver to a value more suitable for the hardware. Good values
- * seem to range between 512 and 8096 inclusive, depending on the
- * application and CPU speed. Smaller values yield faster response time,
- * but can lead to underflow if the application is doing heavy processing
- * and cannot fill the audio buffer in time. A stereo sample consists of
- * both right and left channels in LR ordering.
- * Note that the number of samples is directly related to time by the
- * following formula: \code ms = (samples*1000)/freq \endcode
- * - \c desired->size is the size in bytes of the audio buffer, and is
- * calculated by SDL_OpenAudio().
- * - \c desired->silence is the value used to set the buffer to silence,
- * and is calculated by SDL_OpenAudio().
- * - \c desired->callback should be set to a function that will be called
- * when the audio device is ready for more data. It is passed a pointer
- * to the audio buffer, and the length in bytes of the audio buffer.
- * This function usually runs in a separate thread, and so you should
- * protect data structures that it accesses by calling SDL_LockAudio()
- * and SDL_UnlockAudio() in your code.
- * - \c desired->userdata is passed as the first parameter to your callback
- * function.
- *
- * The audio device starts out playing silence when it's opened, and should
- * be enabled for playing by calling \c SDL_PauseAudio(0) when you are ready
- * for your audio callback function to be called. Since the audio driver
- * may modify the requested size of the audio buffer, you should allocate
- * any local mixing buffers after you open the audio device.
- */
-extern DECLSPEC int SDLCALL SDL_OpenAudio(SDL_AudioSpec * desired,
- SDL_AudioSpec * obtained);
-
-/**
- * SDL Audio Device IDs.
- *
- * A successful call to SDL_OpenAudio() is always device id 1, and legacy
- * SDL audio APIs assume you want this device ID. SDL_OpenAudioDevice() calls
- * always returns devices >= 2 on success. The legacy calls are good both
- * for backwards compatibility and when you don't care about multiple,
- * specific, or capture devices.
- */
-typedef Uint32 SDL_AudioDeviceID;
-
-/**
- * Get the number of available devices exposed by the current driver.
- * Only valid after a successfully initializing the audio subsystem.
- * Returns -1 if an explicit list of devices can't be determined; this is
- * not an error. For example, if SDL is set up to talk to a remote audio
- * server, it can't list every one available on the Internet, but it will
- * still allow a specific host to be specified to SDL_OpenAudioDevice().
- *
- * In many common cases, when this function returns a value <= 0, it can still
- * successfully open the default device (NULL for first argument of
- * SDL_OpenAudioDevice()).
- */
-extern DECLSPEC int SDLCALL SDL_GetNumAudioDevices(int iscapture);
-
-/**
- * Get the human-readable name of a specific audio device.
- * Must be a value between 0 and (number of audio devices-1).
- * Only valid after a successfully initializing the audio subsystem.
- * The values returned by this function reflect the latest call to
- * SDL_GetNumAudioDevices(); recall that function to redetect available
- * hardware.
- *
- * The string returned by this function is UTF-8 encoded, read-only, and
- * managed internally. You are not to free it. If you need to keep the
- * string for any length of time, you should make your own copy of it, as it
- * will be invalid next time any of several other SDL functions is called.
- */
-extern DECLSPEC const char *SDLCALL SDL_GetAudioDeviceName(int index,
- int iscapture);
-
-
-/**
- * Open a specific audio device. Passing in a device name of NULL requests
- * the most reasonable default (and is equivalent to calling SDL_OpenAudio()).
- *
- * The device name is a UTF-8 string reported by SDL_GetAudioDeviceName(), but
- * some drivers allow arbitrary and driver-specific strings, such as a
- * hostname/IP address for a remote audio server, or a filename in the
- * diskaudio driver.
- *
- * \return 0 on error, a valid device ID that is >= 2 on success.
- *
- * SDL_OpenAudio(), unlike this function, always acts on device ID 1.
- */
-extern DECLSPEC SDL_AudioDeviceID SDLCALL SDL_OpenAudioDevice(const char
- *device,
- int iscapture,
- const
- SDL_AudioSpec *
- desired,
- SDL_AudioSpec *
- obtained,
- int
- allowed_changes);
-
-
-
-/**
- * \name Audio state
- *
- * Get the current audio state.
- */
-/* @{ */
-typedef enum
-{
- SDL_AUDIO_STOPPED = 0,
- SDL_AUDIO_PLAYING,
- SDL_AUDIO_PAUSED
-} SDL_AudioStatus;
-extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioStatus(void);
-
-extern DECLSPEC SDL_AudioStatus SDLCALL
-SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
-/* @} *//* Audio State */
-
-/**
- * \name Pause audio functions
- *
- * These functions pause and unpause the audio callback processing.
- * They should be called with a parameter of 0 after opening the audio
- * device to start playing sound. This is so you can safely initialize
- * data for your callback function after opening the audio device.
- * Silence will be written to the audio device during the pause.
- */
-/* @{ */
-extern DECLSPEC void SDLCALL SDL_PauseAudio(int pause_on);
-extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
- int pause_on);
-/* @} *//* Pause audio functions */
-
-/**
- * This function loads a WAVE from the data source, automatically freeing
- * that source if \c freesrc is non-zero. For example, to load a WAVE file,
- * you could do:
- * \code
- * SDL_LoadWAV_RW(SDL_RWFromFile("sample.wav", "rb"), 1, ...);
- * \endcode
- *
- * If this function succeeds, it returns the given SDL_AudioSpec,
- * filled with the audio data format of the wave data, and sets
- * \c *audio_buf to a malloc()'d buffer containing the audio data,
- * and sets \c *audio_len to the length of that audio buffer, in bytes.
- * You need to free the audio buffer with SDL_FreeWAV() when you are
- * done with it.
- *
- * This function returns NULL and sets the SDL error message if the
- * wave file cannot be opened, uses an unknown data format, or is
- * corrupt. Currently raw and MS-ADPCM WAVE files are supported.
- */
-extern DECLSPEC SDL_AudioSpec *SDLCALL SDL_LoadWAV_RW(SDL_RWops * src,
- int freesrc,
- SDL_AudioSpec * spec,
- Uint8 ** audio_buf,
- Uint32 * audio_len);
-
-/**
- * Loads a WAV from a file.
- * Compatibility convenience function.
- */
-#define SDL_LoadWAV(file, spec, audio_buf, audio_len) \
- SDL_LoadWAV_RW(SDL_RWFromFile(file, "rb"),1, spec,audio_buf,audio_len)
-
-/**
- * This function frees data previously allocated with SDL_LoadWAV_RW()
- */
-extern DECLSPEC void SDLCALL SDL_FreeWAV(Uint8 * audio_buf);
-
-/**
- * This function takes a source format and rate and a destination format
- * and rate, and initializes the \c cvt structure with information needed
- * by SDL_ConvertAudio() to convert a buffer of audio data from one format
- * to the other.
- *
- * \return -1 if the format conversion is not supported, 0 if there's
- * no conversion needed, or 1 if the audio filter is set up.
- */
-extern DECLSPEC int SDLCALL SDL_BuildAudioCVT(SDL_AudioCVT * cvt,
- SDL_AudioFormat src_format,
- Uint8 src_channels,
- int src_rate,
- SDL_AudioFormat dst_format,
- Uint8 dst_channels,
- int dst_rate);
-
-/**
- * Once you have initialized the \c cvt structure using SDL_BuildAudioCVT(),
- * created an audio buffer \c cvt->buf, and filled it with \c cvt->len bytes of
- * audio data in the source format, this function will convert it in-place
- * to the desired format.
- *
- * The data conversion may expand the size of the audio data, so the buffer
- * \c cvt->buf should be allocated after the \c cvt structure is initialized by
- * SDL_BuildAudioCVT(), and should be \c cvt->len*cvt->len_mult bytes long.
- */
-extern DECLSPEC int SDLCALL SDL_ConvertAudio(SDL_AudioCVT * cvt);
-
-#define SDL_MIX_MAXVOLUME 128
-/**
- * This takes two audio buffers of the playing audio format and mixes
- * them, performing addition, volume adjustment, and overflow clipping.
- * The volume ranges from 0 - 128, and should be set to ::SDL_MIX_MAXVOLUME
- * for full audio volume. Note this does not change hardware volume.
- * This is provided for convenience -- you can mix your own audio data.
- */
-extern DECLSPEC void SDLCALL SDL_MixAudio(Uint8 * dst, const Uint8 * src,
- Uint32 len, int volume);
-
-/**
- * This works like SDL_MixAudio(), but you specify the audio format instead of
- * using the format of audio device 1. Thus it can be used when no audio
- * device is open at all.
- */
-extern DECLSPEC void SDLCALL SDL_MixAudioFormat(Uint8 * dst,
- const Uint8 * src,
- SDL_AudioFormat format,
- Uint32 len, int volume);
-
-/**
- * \name Audio lock functions
- *
- * The lock manipulated by these functions protects the callback function.
- * During a SDL_LockAudio()/SDL_UnlockAudio() pair, you can be guaranteed that
- * the callback function is not running. Do not call these from the callback
- * function or you will cause deadlock.
- */
-/* @{ */
-extern DECLSPEC void SDLCALL SDL_LockAudio(void);
-extern DECLSPEC void SDLCALL SDL_LockAudioDevice(SDL_AudioDeviceID dev);
-extern DECLSPEC void SDLCALL SDL_UnlockAudio(void);
-extern DECLSPEC void SDLCALL SDL_UnlockAudioDevice(SDL_AudioDeviceID dev);
-/* @} *//* Audio lock functions */
-
-/**
- * This function shuts down audio processing and closes the audio device.
- */
-extern DECLSPEC void SDLCALL SDL_CloseAudio(void);
-extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_audio_h */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_bits.h b/Source/3rdParty/sdl/include/SDL_bits.h
deleted file mode 100644
index 341524fd9..000000000
--- a/Source/3rdParty/sdl/include/SDL_bits.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_bits.h
- *
- * Functions for fiddling with bits and bitmasks.
- */
-
-#ifndef _SDL_bits_h
-#define _SDL_bits_h
-
-#include "SDL_stdinc.h"
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \file SDL_bits.h
- */
-
-/**
- * Get the index of the most significant bit. Result is undefined when called
- * with 0. This operation can also be stated as "count leading zeroes" and
- * "log base 2".
- *
- * \return Index of the most significant bit, or -1 if the value is 0.
- */
-SDL_FORCE_INLINE int
-SDL_MostSignificantBitIndex32(Uint32 x)
-{
-#if defined(__GNUC__) && __GNUC__ >= 4
- /* Count Leading Zeroes builtin in GCC.
- * http://gcc.gnu.org/onlinedocs/gcc-4.3.4/gcc/Other-Builtins.html
- */
- if (x == 0) {
- return -1;
- }
- return 31 - __builtin_clz(x);
-#else
- /* Based off of Bit Twiddling Hacks by Sean Eron Anderson
- * , released in the public domain.
- * http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog
- */
- const Uint32 b[] = {0x2, 0xC, 0xF0, 0xFF00, 0xFFFF0000};
- const int S[] = {1, 2, 4, 8, 16};
-
- int msbIndex = 0;
- int i;
-
- if (x == 0) {
- return -1;
- }
-
- for (i = 4; i >= 0; i--)
- {
- if (x & b[i])
- {
- x >>= S[i];
- msbIndex |= S[i];
- }
- }
-
- return msbIndex;
-#endif
-}
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_bits_h */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_blendmode.h b/Source/3rdParty/sdl/include/SDL_blendmode.h
deleted file mode 100644
index 8c257be9c..000000000
--- a/Source/3rdParty/sdl/include/SDL_blendmode.h
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_blendmode.h
- *
- * Header file declaring the SDL_BlendMode enumeration
- */
-
-#ifndef _SDL_blendmode_h
-#define _SDL_blendmode_h
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/**
- * \brief The blend mode used in SDL_RenderCopy() and drawing operations.
- */
-typedef enum
-{
- SDL_BLENDMODE_NONE = 0x00000000, /**< no blending
- dstRGBA = srcRGBA */
- SDL_BLENDMODE_BLEND = 0x00000001, /**< alpha blending
- dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
- dstA = srcA + (dstA * (1-srcA)) */
- SDL_BLENDMODE_ADD = 0x00000002, /**< additive blending
- dstRGB = (srcRGB * srcA) + dstRGB
- dstA = dstA */
- SDL_BLENDMODE_MOD = 0x00000004 /**< color modulate
- dstRGB = srcRGB * dstRGB
- dstA = dstA */
-} SDL_BlendMode;
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_video_h */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_clipboard.h b/Source/3rdParty/sdl/include/SDL_clipboard.h
deleted file mode 100644
index 74e2b32fe..000000000
--- a/Source/3rdParty/sdl/include/SDL_clipboard.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_clipboard.h
- *
- * Include file for SDL clipboard handling
- */
-
-#ifndef _SDL_clipboard_h
-#define _SDL_clipboard_h
-
-#include "SDL_stdinc.h"
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* Function prototypes */
-
-/**
- * \brief Put UTF-8 text into the clipboard
- *
- * \sa SDL_GetClipboardText()
- */
-extern DECLSPEC int SDLCALL SDL_SetClipboardText(const char *text);
-
-/**
- * \brief Get UTF-8 text from the clipboard, which must be freed with SDL_free()
- *
- * \sa SDL_SetClipboardText()
- */
-extern DECLSPEC char * SDLCALL SDL_GetClipboardText(void);
-
-/**
- * \brief Returns a flag indicating whether the clipboard exists and contains a text string that is non-empty
- *
- * \sa SDL_GetClipboardText()
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasClipboardText(void);
-
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_clipboard_h */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_config.h b/Source/3rdParty/sdl/include/SDL_config.h
deleted file mode 100644
index 9a2e51c55..000000000
--- a/Source/3rdParty/sdl/include/SDL_config.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_h
-#define _SDL_config_h
-
-#include "SDL_platform.h"
-
-/**
- * \file SDL_config.h
- */
-
-/* Add any platform that doesn't build using the configure system. */
-#ifdef USING_PREMAKE_CONFIG_H
-#include "SDL_config_premake.h"
-#elif defined(__WIN32__)
-#include "SDL_config_windows.h"
-#elif defined(__WINRT__)
-#include "SDL_config_winrt.h"
-#elif defined(__MACOSX__)
-#include "SDL_config_macosx.h"
-#elif defined(__IPHONEOS__)
-#include "SDL_config_iphoneos.h"
-#elif defined(__ANDROID__)
-#include "SDL_config_android.h"
-#elif defined(__PSP__)
-#include "SDL_config_psp.h"
-#else
-/* This is a minimal configuration just to get SDL running on new platforms */
-#include "SDL_config_minimal.h"
-#endif /* platform config */
-
-#ifdef USING_GENERATED_CONFIG_H
-#error Wrong SDL_config.h, check your include path?
-#endif
-
-#endif /* _SDL_config_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config.h.cmake b/Source/3rdParty/sdl/include/SDL_config.h.cmake
deleted file mode 100644
index b6fb53aa2..000000000
--- a/Source/3rdParty/sdl/include/SDL_config.h.cmake
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_h
-#define _SDL_config_h
-
-/**
- * \file SDL_config.h.in
- *
- * This is a set of defines to configure the SDL features
- */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-/* C language features */
-#cmakedefine const @HAVE_CONST@
-#cmakedefine inline @HAVE_INLINE@
-#cmakedefine volatile @HAVE_VOLATILE@
-
-/* C datatypes */
-/* Define SIZEOF_VOIDP for 64/32 architectures */
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-
-#cmakedefine HAVE_GCC_ATOMICS @HAVE_GCC_ATOMICS@
-#cmakedefine HAVE_GCC_SYNC_LOCK_TEST_AND_SET @HAVE_GCC_SYNC_LOCK_TEST_AND_SET@
-#cmakedefine HAVE_PTHREAD_SPINLOCK @HAVE_PTHREAD_SPINLOCK@
-
-/* Comment this if you want to build without any C library requirements */
-#cmakedefine HAVE_LIBC 1
-#if HAVE_LIBC
-
-/* Useful headers */
-#cmakedefine HAVE_ALLOCA_H 1
-#cmakedefine HAVE_SYS_TYPES_H 1
-#cmakedefine HAVE_STDIO_H 1
-#cmakedefine STDC_HEADERS 1
-#cmakedefine HAVE_STDLIB_H 1
-#cmakedefine HAVE_STDARG_H 1
-#cmakedefine HAVE_MALLOC_H 1
-#cmakedefine HAVE_MEMORY_H 1
-#cmakedefine HAVE_STRING_H 1
-#cmakedefine HAVE_STRINGS_H 1
-#cmakedefine HAVE_INTTYPES_H 1
-#cmakedefine HAVE_STDINT_H 1
-#cmakedefine HAVE_CTYPE_H 1
-#cmakedefine HAVE_MATH_H 1
-#cmakedefine HAVE_ICONV_H 1
-#cmakedefine HAVE_SIGNAL_H 1
-#cmakedefine HAVE_ALTIVEC_H 1
-#cmakedefine HAVE_PTHREAD_NP_H 1
-#cmakedefine HAVE_LIBUDEV_H 1
-#cmakedefine HAVE_DBUS_DBUS_H 1
-
-/* C library functions */
-#cmakedefine HAVE_MALLOC 1
-#cmakedefine HAVE_CALLOC 1
-#cmakedefine HAVE_REALLOC 1
-#cmakedefine HAVE_FREE 1
-#cmakedefine HAVE_ALLOCA 1
-#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
-#cmakedefine HAVE_GETENV 1
-#cmakedefine HAVE_SETENV 1
-#cmakedefine HAVE_PUTENV 1
-#cmakedefine HAVE_UNSETENV 1
-#endif
-#cmakedefine HAVE_QSORT 1
-#cmakedefine HAVE_ABS 1
-#cmakedefine HAVE_BCOPY 1
-#cmakedefine HAVE_MEMSET 1
-#cmakedefine HAVE_MEMCPY 1
-#cmakedefine HAVE_MEMMOVE 1
-#cmakedefine HAVE_MEMCMP 1
-#cmakedefine HAVE_STRLEN 1
-#cmakedefine HAVE_STRLCPY 1
-#cmakedefine HAVE_STRLCAT 1
-#cmakedefine HAVE_STRDUP 1
-#cmakedefine HAVE__STRREV 1
-#cmakedefine HAVE__STRUPR 1
-#cmakedefine HAVE__STRLWR 1
-#cmakedefine HAVE_INDEX 1
-#cmakedefine HAVE_RINDEX 1
-#cmakedefine HAVE_STRCHR 1
-#cmakedefine HAVE_STRRCHR 1
-#cmakedefine HAVE_STRSTR 1
-#cmakedefine HAVE_ITOA 1
-#cmakedefine HAVE__LTOA 1
-#cmakedefine HAVE__UITOA 1
-#cmakedefine HAVE__ULTOA 1
-#cmakedefine HAVE_STRTOL 1
-#cmakedefine HAVE_STRTOUL 1
-#cmakedefine HAVE__I64TOA 1
-#cmakedefine HAVE__UI64TOA 1
-#cmakedefine HAVE_STRTOLL 1
-#cmakedefine HAVE_STRTOULL 1
-#cmakedefine HAVE_STRTOD 1
-#cmakedefine HAVE_ATOI 1
-#cmakedefine HAVE_ATOF 1
-#cmakedefine HAVE_STRCMP 1
-#cmakedefine HAVE_STRNCMP 1
-#cmakedefine HAVE__STRICMP 1
-#cmakedefine HAVE_STRCASECMP 1
-#cmakedefine HAVE__STRNICMP 1
-#cmakedefine HAVE_STRNCASECMP 1
-#cmakedefine HAVE_VSSCANF 1
-#cmakedefine HAVE_VSNPRINTF 1
-#cmakedefine HAVE_M_PI 1
-#cmakedefine HAVE_ATAN 1
-#cmakedefine HAVE_ATAN2 1
-#cmakedefine HAVE_ACOS 1
-#cmakedefine HAVE_ASIN 1
-#cmakedefine HAVE_CEIL 1
-#cmakedefine HAVE_COPYSIGN 1
-#cmakedefine HAVE_COS 1
-#cmakedefine HAVE_COSF 1
-#cmakedefine HAVE_FABS 1
-#cmakedefine HAVE_FLOOR 1
-#cmakedefine HAVE_LOG 1
-#cmakedefine HAVE_POW 1
-#cmakedefine HAVE_SCALBN 1
-#cmakedefine HAVE_SIN 1
-#cmakedefine HAVE_SINF 1
-#cmakedefine HAVE_SQRT 1
-#cmakedefine HAVE_FSEEKO 1
-#cmakedefine HAVE_FSEEKO64 1
-#cmakedefine HAVE_SIGACTION 1
-#cmakedefine HAVE_SA_SIGACTION 1
-#cmakedefine HAVE_SETJMP 1
-#cmakedefine HAVE_NANOSLEEP 1
-#cmakedefine HAVE_SYSCONF 1
-#cmakedefine HAVE_SYSCTLBYNAME 1
-#cmakedefine HAVE_CLOCK_GETTIME 1
-#cmakedefine HAVE_GETPAGESIZE 1
-#cmakedefine HAVE_MPROTECT 1
-#cmakedefine HAVE_ICONV 1
-#cmakedefine HAVE_PTHREAD_SETNAME_NP 1
-#cmakedefine HAVE_PTHREAD_SET_NAME_NP 1
-#cmakedefine HAVE_SEM_TIMEDWAIT 1
-#elif __WIN32__
-#cmakedefine HAVE_STDARG_H 1
-#cmakedefine HAVE_STDDEF_H 1
-#else
-/* We may need some replacement for stdarg.h here */
-#include
-#endif /* HAVE_LIBC */
-
-/* SDL internal assertion support */
-#cmakedefine SDL_DEFAULT_ASSERT_LEVEL @SDL_DEFAULT_ASSERT_LEVEL@
-
-/* Allow disabling of core subsystems */
-#cmakedefine SDL_ATOMIC_DISABLED @SDL_ATOMIC_DISABLED@
-#cmakedefine SDL_AUDIO_DISABLED @SDL_AUDIO_DISABLED@
-#cmakedefine SDL_CPUINFO_DISABLED @SDL_CPUINFO_DISABLED@
-#cmakedefine SDL_EVENTS_DISABLED @SDL_EVENTS_DISABLED@
-#cmakedefine SDL_FILE_DISABLED @SDL_FILE_DISABLED@
-#cmakedefine SDL_JOYSTICK_DISABLED @SDL_JOYSTICK_DISABLED@
-#cmakedefine SDL_HAPTIC_DISABLED @SDL_HAPTIC_DISABLED@
-#cmakedefine SDL_LOADSO_DISABLED @SDL_LOADSO_DISABLED@
-#cmakedefine SDL_RENDER_DISABLED @SDL_RENDER_DISABLED@
-#cmakedefine SDL_THREADS_DISABLED @SDL_THREADS_DISABLED@
-#cmakedefine SDL_TIMERS_DISABLED @SDL_TIMERS_DISABLED@
-#cmakedefine SDL_VIDEO_DISABLED @SDL_VIDEO_DISABLED@
-#cmakedefine SDL_POWER_DISABLED @SDL_POWER_DISABLED@
-#cmakedefine SDL_FILESYSTEM_DISABLED @SDL_FILESYSTEM_DISABLED@
-
-/* Enable various audio drivers */
-#cmakedefine SDL_AUDIO_DRIVER_ALSA @SDL_AUDIO_DRIVER_ALSA@
-#cmakedefine SDL_AUDIO_DRIVER_ALSA_DYNAMIC @SDL_AUDIO_DRIVER_ALSA_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_ARTS @SDL_AUDIO_DRIVER_ARTS@
-#cmakedefine SDL_AUDIO_DRIVER_ARTS_DYNAMIC @SDL_AUDIO_DRIVER_ARTS_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO @SDL_AUDIO_DRIVER_PULSEAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC @SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_HAIKU @SDL_AUDIO_DRIVER_HAIKU@
-#cmakedefine SDL_AUDIO_DRIVER_BSD @SDL_AUDIO_DRIVER_BSD@
-#cmakedefine SDL_AUDIO_DRIVER_COREAUDIO @SDL_AUDIO_DRIVER_COREAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_DISK @SDL_AUDIO_DRIVER_DISK@
-#cmakedefine SDL_AUDIO_DRIVER_DUMMY @SDL_AUDIO_DRIVER_DUMMY@
-#cmakedefine SDL_AUDIO_DRIVER_XAUDIO2 @SDL_AUDIO_DRIVER_XAUDIO2@
-#cmakedefine SDL_AUDIO_DRIVER_DSOUND @SDL_AUDIO_DRIVER_DSOUND@
-#cmakedefine SDL_AUDIO_DRIVER_ESD @SDL_AUDIO_DRIVER_ESD@
-#cmakedefine SDL_AUDIO_DRIVER_ESD_DYNAMIC @SDL_AUDIO_DRIVER_ESD_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_NAS @SDL_AUDIO_DRIVER_NAS@
-#cmakedefine SDL_AUDIO_DRIVER_NAS_DYNAMIC @SDL_AUDIO_DRIVER_NAS_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_SNDIO @SDL_AUDIO_DRIVER_SNDIO@
-#cmakedefine SDL_AUDIO_DRIVER_SNDIO_DYNAMIC @SDL_AUDIO_DRIVER_SNDIO_DYNAMIC@
-#cmakedefine SDL_AUDIO_DRIVER_OSS @SDL_AUDIO_DRIVER_OSS@
-#cmakedefine SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H @SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H@
-#cmakedefine SDL_AUDIO_DRIVER_PAUDIO @SDL_AUDIO_DRIVER_PAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_QSA @SDL_AUDIO_DRIVER_QSA@
-#cmakedefine SDL_AUDIO_DRIVER_SUNAUDIO @SDL_AUDIO_DRIVER_SUNAUDIO@
-#cmakedefine SDL_AUDIO_DRIVER_WINMM @SDL_AUDIO_DRIVER_WINMM@
-#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND @SDL_AUDIO_DRIVER_FUSIONSOUND@
-#cmakedefine SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC @SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC@
-
-/* Enable various input drivers */
-#cmakedefine SDL_INPUT_LINUXEV @SDL_INPUT_LINUXEV@
-#cmakedefine SDL_INPUT_LINUXKD @SDL_INPUT_LINUXKD@
-#cmakedefine SDL_INPUT_TSLIB @SDL_INPUT_TSLIB@
-#cmakedefine SDL_JOYSTICK_HAIKU @SDL_JOYSTICK_HAIKU@
-#cmakedefine SDL_JOYSTICK_DINPUT @SDL_JOYSTICK_DINPUT@
-#cmakedefine SDL_JOYSTICK_DUMMY @SDL_JOYSTICK_DUMMY@
-#cmakedefine SDL_JOYSTICK_IOKIT @SDL_JOYSTICK_IOKIT@
-#cmakedefine SDL_JOYSTICK_LINUX @SDL_JOYSTICK_LINUX@
-#cmakedefine SDL_JOYSTICK_WINMM @SDL_JOYSTICK_WINMM@
-#cmakedefine SDL_JOYSTICK_USBHID @SDL_JOYSTICK_USBHID@
-#cmakedefine SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H @SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H@
-#cmakedefine SDL_HAPTIC_DUMMY @SDL_HAPTIC_DUMMY@
-#cmakedefine SDL_HAPTIC_LINUX @SDL_HAPTIC_LINUX@
-#cmakedefine SDL_HAPTIC_IOKIT @SDL_HAPTIC_IOKIT@
-#cmakedefine SDL_HAPTIC_DINPUT @SDL_HAPTIC_DINPUT@
-
-/* Enable various shared object loading systems */
-#cmakedefine SDL_LOADSO_HAIKU @SDL_LOADSO_HAIKU@
-#cmakedefine SDL_LOADSO_DLOPEN @SDL_LOADSO_DLOPEN@
-#cmakedefine SDL_LOADSO_DUMMY @SDL_LOADSO_DUMMY@
-#cmakedefine SDL_LOADSO_LDG @SDL_LOADSO_LDG@
-#cmakedefine SDL_LOADSO_WINDOWS @SDL_LOADSO_WINDOWS@
-
-/* Enable various threading systems */
-#cmakedefine SDL_THREAD_PTHREAD @SDL_THREAD_PTHREAD@
-#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX@
-#cmakedefine SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP @SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP@
-#cmakedefine SDL_THREAD_WINDOWS @SDL_THREAD_WINDOWS@
-
-/* Enable various timer systems */
-#cmakedefine SDL_TIMER_HAIKU @SDL_TIMER_HAIKU@
-#cmakedefine SDL_TIMER_DUMMY @SDL_TIMER_DUMMY@
-#cmakedefine SDL_TIMER_UNIX @SDL_TIMER_UNIX@
-#cmakedefine SDL_TIMER_WINDOWS @SDL_TIMER_WINDOWS@
-#cmakedefine SDL_TIMER_WINCE @SDL_TIMER_WINCE@
-
-/* Enable various video drivers */
-#cmakedefine SDL_VIDEO_DRIVER_HAIKU @SDL_VIDEO_DRIVER_HAIKU@
-#cmakedefine SDL_VIDEO_DRIVER_COCOA @SDL_VIDEO_DRIVER_COCOA@
-#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB @SDL_VIDEO_DRIVER_DIRECTFB@
-#cmakedefine SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC @SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_DUMMY @SDL_VIDEO_DRIVER_DUMMY@
-#cmakedefine SDL_VIDEO_DRIVER_WINDOWS @SDL_VIDEO_DRIVER_WINDOWS@
-#cmakedefine SDL_VIDEO_DRIVER_WAYLAND @SDL_VIDEO_DRIVER_WAYLAND@
-
-#if 0
-/* !!! FIXME: in configure script version, missing here: */
-#undef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
-#endif
-
-#cmakedefine SDL_VIDEO_DRIVER_MIR @SDL_VIDEO_DRIVER_MIR@
-#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC @SDL_VIDEO_DRIVER_MIR_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON @SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON@
-#cmakedefine SDL_VIDEO_DRIVER_X11 @SDL_VIDEO_DRIVER_X11@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC @SDL_VIDEO_DRIVER_X11_DYNAMIC@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT @SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 @SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR @SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS @SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS@
-#cmakedefine SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE @SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XCURSOR @SDL_VIDEO_DRIVER_X11_XCURSOR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XINERAMA @SDL_VIDEO_DRIVER_X11_XINERAMA@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2 @SDL_VIDEO_DRIVER_X11_XINPUT2@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH @SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XRANDR @SDL_VIDEO_DRIVER_X11_XRANDR@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XSCRNSAVER @SDL_VIDEO_DRIVER_X11_XSCRNSAVER@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XSHAPE @SDL_VIDEO_DRIVER_X11_XSHAPE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_XVIDMODE @SDL_VIDEO_DRIVER_X11_XVIDMODE@
-#cmakedefine SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS @SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS@
-#cmakedefine SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32 @SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32@
-#cmakedefine SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY @SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY@
-#cmakedefine SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM @SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM@
-
-#cmakedefine SDL_VIDEO_RENDER_D3D @SDL_VIDEO_RENDER_D3D@
-#cmakedefine SDL_VIDEO_RENDER_D3D11 @SDL_VIDEO_RENDER_D3D11@
-#cmakedefine SDL_VIDEO_RENDER_OGL @SDL_VIDEO_RENDER_OGL@
-#cmakedefine SDL_VIDEO_RENDER_OGL_ES @SDL_VIDEO_RENDER_OGL_ES@
-#cmakedefine SDL_VIDEO_RENDER_OGL_ES2 @SDL_VIDEO_RENDER_OGL_ES2@
-#cmakedefine SDL_VIDEO_RENDER_DIRECTFB @SDL_VIDEO_RENDER_DIRECTFB@
-
-/* Enable OpenGL support */
-#cmakedefine SDL_VIDEO_OPENGL @SDL_VIDEO_OPENGL@
-#cmakedefine SDL_VIDEO_OPENGL_ES @SDL_VIDEO_OPENGL_ES@
-#cmakedefine SDL_VIDEO_OPENGL_ES2 @SDL_VIDEO_OPENGL_ES2@
-#cmakedefine SDL_VIDEO_OPENGL_BGL @SDL_VIDEO_OPENGL_BGL@
-#cmakedefine SDL_VIDEO_OPENGL_CGL @SDL_VIDEO_OPENGL_CGL@
-#cmakedefine SDL_VIDEO_OPENGL_GLX @SDL_VIDEO_OPENGL_GLX@
-#cmakedefine SDL_VIDEO_OPENGL_WGL @SDL_VIDEO_OPENGL_WGL@
-#cmakedefine SDL_VIDEO_OPENGL_EGL @SDL_VIDEO_OPENGL_EGL@
-#cmakedefine SDL_VIDEO_OPENGL_OSMESA @SDL_VIDEO_OPENGL_OSMESA@
-#cmakedefine SDL_VIDEO_OPENGL_OSMESA_DYNAMIC @SDL_VIDEO_OPENGL_OSMESA_DYNAMIC@
-
-/* Enable system power support */
-#cmakedefine SDL_POWER_LINUX @SDL_POWER_LINUX@
-#cmakedefine SDL_POWER_WINDOWS @SDL_POWER_WINDOWS@
-#cmakedefine SDL_POWER_MACOSX @SDL_POWER_MACOSX@
-#cmakedefine SDL_POWER_HAIKU @SDL_POWER_HAIKU@
-#cmakedefine SDL_POWER_HARDWIRED @SDL_POWER_HARDWIRED@
-
-/* Enable system filesystem support */
-#cmakedefine SDL_FILESYSTEM_HAIKU @SDL_FILESYSTEM_HAIKU@
-#cmakedefine SDL_FILESYSTEM_COCOA @SDL_FILESYSTEM_COCOA@
-#cmakedefine SDL_FILESYSTEM_DUMMY @SDL_FILESYSTEM_DUMMY@
-#cmakedefine SDL_FILESYSTEM_UNIX @SDL_FILESYSTEM_UNIX@
-#cmakedefine SDL_FILESYSTEM_WINDOWS @SDL_FILESYSTEM_WINDOWS@
-
-/* Enable assembly routines */
-#cmakedefine SDL_ASSEMBLY_ROUTINES @SDL_ASSEMBLY_ROUTINES@
-#cmakedefine SDL_ALTIVEC_BLITTERS @SDL_ALTIVEC_BLITTERS@
-
-
-/* Platform specific definitions */
-#if !defined(__WIN32__)
-# if !defined(_STDINT_H_) && !defined(_STDINT_H) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
-typedef unsigned int size_t;
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-typedef unsigned long uintptr_t;
-# endif /* if (stdint.h isn't available) */
-#else /* __WIN32__ */
-# if !defined(_STDINT_H_) && !defined(HAVE_STDINT_H) && !defined(_HAVE_STDINT_H)
-# if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
-#define HAVE_STDINT_H 1
-# elif defined(_MSC_VER)
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-# ifndef _UINTPTR_T_DEFINED
-# ifdef _WIN64
-typedef unsigned __int64 uintptr_t;
-# else
-typedef unsigned int uintptr_t;
-# endif
-#define _UINTPTR_T_DEFINED
-# endif
-/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
-# if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
-#define DWORD_PTR DWORD
-# endif
-# if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
-#define LONG_PTR LONG
-# endif
-# else /* !__GNUC__ && !_MSC_VER */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-# ifndef _SIZE_T_DEFINED_
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-# endif
-typedef unsigned int uintptr_t;
-# endif /* __GNUC__ || _MSC_VER */
-# endif /* !_STDINT_H_ && !HAVE_STDINT_H */
-#endif /* __WIN32__ */
-
-#endif /* _SDL_config_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config.h.in b/Source/3rdParty/sdl/include/SDL_config.h.in
deleted file mode 100644
index 689dcf839..000000000
--- a/Source/3rdParty/sdl/include/SDL_config.h.in
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_h
-#define _SDL_config_h
-
-/**
- * \file SDL_config.h.in
- *
- * This is a set of defines to configure the SDL features
- */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-/* Make sure that this isn't included by Visual C++ */
-#ifdef _MSC_VER
-#error You should run hg revert SDL_config.h
-#endif
-
-/* C language features */
-#undef const
-#undef inline
-#undef volatile
-
-/* C datatypes */
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-#undef HAVE_GCC_ATOMICS
-#undef HAVE_GCC_SYNC_LOCK_TEST_AND_SET
-#undef HAVE_PTHREAD_SPINLOCK
-
-/* Comment this if you want to build without any C library requirements */
-#undef HAVE_LIBC
-#if HAVE_LIBC
-
-/* Useful headers */
-#undef HAVE_ALLOCA_H
-#undef HAVE_SYS_TYPES_H
-#undef HAVE_STDIO_H
-#undef STDC_HEADERS
-#undef HAVE_STDLIB_H
-#undef HAVE_STDARG_H
-#undef HAVE_MALLOC_H
-#undef HAVE_MEMORY_H
-#undef HAVE_STRING_H
-#undef HAVE_STRINGS_H
-#undef HAVE_INTTYPES_H
-#undef HAVE_STDINT_H
-#undef HAVE_CTYPE_H
-#undef HAVE_MATH_H
-#undef HAVE_ICONV_H
-#undef HAVE_SIGNAL_H
-#undef HAVE_ALTIVEC_H
-#undef HAVE_PTHREAD_NP_H
-#undef HAVE_LIBUDEV_H
-#undef HAVE_DBUS_DBUS_H
-
-/* C library functions */
-#undef HAVE_MALLOC
-#undef HAVE_CALLOC
-#undef HAVE_REALLOC
-#undef HAVE_FREE
-#undef HAVE_ALLOCA
-#ifndef __WIN32__ /* Don't use C runtime versions of these on Windows */
-#undef HAVE_GETENV
-#undef HAVE_SETENV
-#undef HAVE_PUTENV
-#undef HAVE_UNSETENV
-#endif
-#undef HAVE_QSORT
-#undef HAVE_ABS
-#undef HAVE_BCOPY
-#undef HAVE_MEMSET
-#undef HAVE_MEMCPY
-#undef HAVE_MEMMOVE
-#undef HAVE_MEMCMP
-#undef HAVE_STRLEN
-#undef HAVE_STRLCPY
-#undef HAVE_STRLCAT
-#undef HAVE_STRDUP
-#undef HAVE__STRREV
-#undef HAVE__STRUPR
-#undef HAVE__STRLWR
-#undef HAVE_INDEX
-#undef HAVE_RINDEX
-#undef HAVE_STRCHR
-#undef HAVE_STRRCHR
-#undef HAVE_STRSTR
-#undef HAVE_ITOA
-#undef HAVE__LTOA
-#undef HAVE__UITOA
-#undef HAVE__ULTOA
-#undef HAVE_STRTOL
-#undef HAVE_STRTOUL
-#undef HAVE__I64TOA
-#undef HAVE__UI64TOA
-#undef HAVE_STRTOLL
-#undef HAVE_STRTOULL
-#undef HAVE_STRTOD
-#undef HAVE_ATOI
-#undef HAVE_ATOF
-#undef HAVE_STRCMP
-#undef HAVE_STRNCMP
-#undef HAVE__STRICMP
-#undef HAVE_STRCASECMP
-#undef HAVE__STRNICMP
-#undef HAVE_STRNCASECMP
-#undef HAVE_SSCANF
-#undef HAVE_VSSCANF
-#undef HAVE_SNPRINTF
-#undef HAVE_VSNPRINTF
-#undef HAVE_M_PI
-#undef HAVE_ATAN
-#undef HAVE_ATAN2
-#undef HAVE_ACOS
-#undef HAVE_ASIN
-#undef HAVE_CEIL
-#undef HAVE_COPYSIGN
-#undef HAVE_COS
-#undef HAVE_COSF
-#undef HAVE_FABS
-#undef HAVE_FLOOR
-#undef HAVE_LOG
-#undef HAVE_POW
-#undef HAVE_SCALBN
-#undef HAVE_SIN
-#undef HAVE_SINF
-#undef HAVE_SQRT
-#undef HAVE_FSEEKO
-#undef HAVE_FSEEKO64
-#undef HAVE_SIGACTION
-#undef HAVE_SA_SIGACTION
-#undef HAVE_SETJMP
-#undef HAVE_NANOSLEEP
-#undef HAVE_SYSCONF
-#undef HAVE_SYSCTLBYNAME
-#undef HAVE_CLOCK_GETTIME
-#undef HAVE_GETPAGESIZE
-#undef HAVE_MPROTECT
-#undef HAVE_ICONV
-#undef HAVE_PTHREAD_SETNAME_NP
-#undef HAVE_PTHREAD_SET_NAME_NP
-#undef HAVE_SEM_TIMEDWAIT
-
-#else
-#define HAVE_STDARG_H 1
-#define HAVE_STDDEF_H 1
-#define HAVE_STDINT_H 1
-#endif /* HAVE_LIBC */
-
-/* SDL internal assertion support */
-#undef SDL_DEFAULT_ASSERT_LEVEL
-
-/* Allow disabling of core subsystems */
-#undef SDL_ATOMIC_DISABLED
-#undef SDL_AUDIO_DISABLED
-#undef SDL_CPUINFO_DISABLED
-#undef SDL_EVENTS_DISABLED
-#undef SDL_FILE_DISABLED
-#undef SDL_JOYSTICK_DISABLED
-#undef SDL_HAPTIC_DISABLED
-#undef SDL_LOADSO_DISABLED
-#undef SDL_RENDER_DISABLED
-#undef SDL_THREADS_DISABLED
-#undef SDL_TIMERS_DISABLED
-#undef SDL_VIDEO_DISABLED
-#undef SDL_POWER_DISABLED
-#undef SDL_FILESYSTEM_DISABLED
-
-/* Enable various audio drivers */
-#undef SDL_AUDIO_DRIVER_ALSA
-#undef SDL_AUDIO_DRIVER_ALSA_DYNAMIC
-#undef SDL_AUDIO_DRIVER_ARTS
-#undef SDL_AUDIO_DRIVER_ARTS_DYNAMIC
-#undef SDL_AUDIO_DRIVER_PULSEAUDIO
-#undef SDL_AUDIO_DRIVER_PULSEAUDIO_DYNAMIC
-#undef SDL_AUDIO_DRIVER_HAIKU
-#undef SDL_AUDIO_DRIVER_BSD
-#undef SDL_AUDIO_DRIVER_COREAUDIO
-#undef SDL_AUDIO_DRIVER_DISK
-#undef SDL_AUDIO_DRIVER_DUMMY
-#undef SDL_AUDIO_DRIVER_XAUDIO2
-#undef SDL_AUDIO_DRIVER_DSOUND
-#undef SDL_AUDIO_DRIVER_ESD
-#undef SDL_AUDIO_DRIVER_ESD_DYNAMIC
-#undef SDL_AUDIO_DRIVER_NAS
-#undef SDL_AUDIO_DRIVER_NAS_DYNAMIC
-#undef SDL_AUDIO_DRIVER_SNDIO
-#undef SDL_AUDIO_DRIVER_SNDIO_DYNAMIC
-#undef SDL_AUDIO_DRIVER_OSS
-#undef SDL_AUDIO_DRIVER_OSS_SOUNDCARD_H
-#undef SDL_AUDIO_DRIVER_PAUDIO
-#undef SDL_AUDIO_DRIVER_QSA
-#undef SDL_AUDIO_DRIVER_SUNAUDIO
-#undef SDL_AUDIO_DRIVER_WINMM
-#undef SDL_AUDIO_DRIVER_FUSIONSOUND
-#undef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
-
-/* Enable various input drivers */
-#undef SDL_INPUT_LINUXEV
-#undef SDL_INPUT_LINUXKD
-#undef SDL_INPUT_TSLIB
-#undef SDL_JOYSTICK_HAIKU
-#undef SDL_JOYSTICK_DINPUT
-#undef SDL_JOYSTICK_DUMMY
-#undef SDL_JOYSTICK_IOKIT
-#undef SDL_JOYSTICK_LINUX
-#undef SDL_JOYSTICK_WINMM
-#undef SDL_JOYSTICK_USBHID
-#undef SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
-#undef SDL_HAPTIC_DUMMY
-#undef SDL_HAPTIC_LINUX
-#undef SDL_HAPTIC_IOKIT
-#undef SDL_HAPTIC_DINPUT
-
-/* Enable various shared object loading systems */
-#undef SDL_LOADSO_HAIKU
-#undef SDL_LOADSO_DLOPEN
-#undef SDL_LOADSO_DUMMY
-#undef SDL_LOADSO_LDG
-#undef SDL_LOADSO_WINDOWS
-
-/* Enable various threading systems */
-#undef SDL_THREAD_PTHREAD
-#undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX
-#undef SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP
-#undef SDL_THREAD_WINDOWS
-
-/* Enable various timer systems */
-#undef SDL_TIMER_HAIKU
-#undef SDL_TIMER_DUMMY
-#undef SDL_TIMER_UNIX
-#undef SDL_TIMER_WINDOWS
-
-/* Enable various video drivers */
-#undef SDL_VIDEO_DRIVER_HAIKU
-#undef SDL_VIDEO_DRIVER_COCOA
-#undef SDL_VIDEO_DRIVER_DIRECTFB
-#undef SDL_VIDEO_DRIVER_DIRECTFB_DYNAMIC
-#undef SDL_VIDEO_DRIVER_DUMMY
-#undef SDL_VIDEO_DRIVER_WINDOWS
-#undef SDL_VIDEO_DRIVER_WAYLAND
-#undef SDL_VIDEO_DRIVER_WAYLAND_QT_TOUCH
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_EGL
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_CURSOR
-#undef SDL_VIDEO_DRIVER_WAYLAND_DYNAMIC_XKBCOMMON
-#undef SDL_VIDEO_DRIVER_MIR
-#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC
-#undef SDL_VIDEO_DRIVER_MIR_DYNAMIC_XKBCOMMON
-#undef SDL_VIDEO_DRIVER_X11
-#undef SDL_VIDEO_DRIVER_RPI
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XCURSOR
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS
-#undef SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE
-#undef SDL_VIDEO_DRIVER_X11_XCURSOR
-#undef SDL_VIDEO_DRIVER_X11_XINERAMA
-#undef SDL_VIDEO_DRIVER_X11_XINPUT2
-#undef SDL_VIDEO_DRIVER_X11_XINPUT2_SUPPORTS_MULTITOUCH
-#undef SDL_VIDEO_DRIVER_X11_XRANDR
-#undef SDL_VIDEO_DRIVER_X11_XSCRNSAVER
-#undef SDL_VIDEO_DRIVER_X11_XSHAPE
-#undef SDL_VIDEO_DRIVER_X11_XVIDMODE
-#undef SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS
-#undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XDATA32
-#undef SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY
-#undef SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM
-
-#undef SDL_VIDEO_RENDER_D3D
-#undef SDL_VIDEO_RENDER_D3D11
-#undef SDL_VIDEO_RENDER_OGL
-#undef SDL_VIDEO_RENDER_OGL_ES
-#undef SDL_VIDEO_RENDER_OGL_ES2
-#undef SDL_VIDEO_RENDER_DIRECTFB
-
-/* Enable OpenGL support */
-#undef SDL_VIDEO_OPENGL
-#undef SDL_VIDEO_OPENGL_ES
-#undef SDL_VIDEO_OPENGL_ES2
-#undef SDL_VIDEO_OPENGL_BGL
-#undef SDL_VIDEO_OPENGL_CGL
-#undef SDL_VIDEO_OPENGL_EGL
-#undef SDL_VIDEO_OPENGL_GLX
-#undef SDL_VIDEO_OPENGL_WGL
-#undef SDL_VIDEO_OPENGL_OSMESA
-#undef SDL_VIDEO_OPENGL_OSMESA_DYNAMIC
-
-/* Enable system power support */
-#undef SDL_POWER_LINUX
-#undef SDL_POWER_WINDOWS
-#undef SDL_POWER_MACOSX
-#undef SDL_POWER_HAIKU
-#undef SDL_POWER_HARDWIRED
-
-/* Enable system filesystem support */
-#undef SDL_FILESYSTEM_HAIKU
-#undef SDL_FILESYSTEM_COCOA
-#undef SDL_FILESYSTEM_DUMMY
-#undef SDL_FILESYSTEM_UNIX
-#undef SDL_FILESYSTEM_WINDOWS
-
-/* Enable assembly routines */
-#undef SDL_ASSEMBLY_ROUTINES
-#undef SDL_ALTIVEC_BLITTERS
-
-#endif /* _SDL_config_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_android.h b/Source/3rdParty/sdl/include/SDL_config_android.h
deleted file mode 100644
index 738dd94cc..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_android.h
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_android_h
-#define _SDL_config_android_h
-
-#include "SDL_platform.h"
-
-/**
- * \file SDL_config_android.h
- *
- * This is a configuration that can be used to build SDL for Android
- */
-
-#include
-
-#define HAVE_GCC_ATOMICS 1
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_SETENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY 1
-#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-#define HAVE_SYSCONF 1
-
-#define SIZEOF_VOIDP 4
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_ANDROID 1
-#define SDL_AUDIO_DRIVER_DUMMY 1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_ANDROID 1
-#define SDL_HAPTIC_DUMMY 1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_DLOPEN 1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX 1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_ANDROID 1
-
-/* Enable OpenGL ES */
-#define SDL_VIDEO_OPENGL_ES 1
-#define SDL_VIDEO_OPENGL_ES2 1
-#define SDL_VIDEO_OPENGL_EGL 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_RENDER_OGL_ES2 1
-
-/* Enable system power support */
-#define SDL_POWER_ANDROID 1
-
-/* !!! FIXME: what does Android do for filesystem stuff? */
-#define SDL_FILESYSTEM_DUMMY 1
-
-#endif /* _SDL_config_android_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_iphoneos.h b/Source/3rdParty/sdl/include/SDL_config_iphoneos.h
deleted file mode 100644
index a0f55b6a7..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_iphoneos.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_iphoneos_h
-#define _SDL_config_iphoneos_h
-
-#include "SDL_platform.h"
-
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-
-#define HAVE_GCC_ATOMICS 1
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_SETENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY 1
-#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-#define HAVE_SYSCONF 1
-#define HAVE_SYSCTLBYNAME 1
-
-/* enable iPhone version of Core Audio driver */
-#define SDL_AUDIO_DRIVER_COREAUDIO 1
-/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
-#define SDL_AUDIO_DRIVER_DUMMY 1
-
-/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
-#define SDL_HAPTIC_DISABLED 1
-
-/* Enable Unix style SO loading */
-/* Technically this works, but it violates the iPhone developer agreement */
-/* #define SDL_LOADSO_DLOPEN 1 */
-
-/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
-#define SDL_LOADSO_DISABLED 1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX 1
-
-/* Supported video drivers */
-#define SDL_VIDEO_DRIVER_UIKIT 1
-#define SDL_VIDEO_DRIVER_DUMMY 1
-
-/* enable OpenGL ES */
-#define SDL_VIDEO_OPENGL_ES 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_RENDER_OGL_ES2 1
-
-/* Enable system power support */
-#define SDL_POWER_UIKIT 1
-
-/* enable iPhone keyboard support */
-#define SDL_IPHONE_KEYBOARD 1
-
-/* enable joystick subsystem */
-#define SDL_JOYSTICK_DISABLED 0
-
-/* Set max recognized G-force from accelerometer
- See src/joystick/uikit/SDLUIAccelerationDelegate.m for notes on why this is needed
- */
-#define SDL_IPHONE_MAX_GFORCE 5.0
-
-/* enable filesystem support */
-#define SDL_FILESYSTEM_COCOA 1
-
-#endif /* _SDL_config_iphoneos_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_macosx.h b/Source/3rdParty/sdl/include/SDL_config_macosx.h
deleted file mode 100644
index e627aef26..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_macosx.h
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_macosx_h
-#define _SDL_config_macosx_h
-
-#include "SDL_platform.h"
-
-/* This gets us MAC_OS_X_VERSION_MIN_REQUIRED... */
-#include
-
-/* This is a set of defines to configure the SDL features */
-
-#ifdef __LP64__
- #define SIZEOF_VOIDP 8
-#else
- #define SIZEOF_VOIDP 4
-#endif
-
-/* Useful headers */
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY 1
-#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-#define HAVE_SYSCONF 1
-#define HAVE_SYSCTLBYNAME 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_COREAUDIO 1
-#define SDL_AUDIO_DRIVER_DISK 1
-#define SDL_AUDIO_DRIVER_DUMMY 1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_IOKIT 1
-#define SDL_HAPTIC_IOKIT 1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_DLOPEN 1
-
-/* Enable various threading systems */
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX 1
-
-/* Enable various timer systems */
-#define SDL_TIMER_UNIX 1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_COCOA 1
-#define SDL_VIDEO_DRIVER_DUMMY 1
-#undef SDL_VIDEO_DRIVER_X11
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC "/usr/X11R6/lib/libX11.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XEXT "/usr/X11R6/lib/libXext.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINERAMA "/usr/X11R6/lib/libXinerama.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XINPUT2 "/usr/X11R6/lib/libXi.6.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XRANDR "/usr/X11R6/lib/libXrandr.2.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XSS "/usr/X11R6/lib/libXss.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_DYNAMIC_XVIDMODE "/usr/X11R6/lib/libXxf86vm.1.dylib"
-#define SDL_VIDEO_DRIVER_X11_XINERAMA 1
-#define SDL_VIDEO_DRIVER_X11_XRANDR 1
-#define SDL_VIDEO_DRIVER_X11_XSCRNSAVER 1
-#define SDL_VIDEO_DRIVER_X11_XSHAPE 1
-#define SDL_VIDEO_DRIVER_X11_XVIDMODE 1
-#define SDL_VIDEO_DRIVER_X11_HAS_XKBKEYCODETOKEYSYM 1
-
-#ifdef MAC_OS_X_VERSION_10_8
-/*
- * No matter the versions targeted, this is the 10.8 or later SDK, so you have
- * to use the external Xquartz, which is a more modern Xlib. Previous SDKs
- * used an older Xlib.
- */
-#define SDL_VIDEO_DRIVER_X11_XINPUT2 1
-#define SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS 1
-#define SDL_VIDEO_DRIVER_X11_CONST_PARAM_XEXTADDDISPLAY 1
-#endif
-
-#ifndef SDL_VIDEO_RENDER_OGL
-#define SDL_VIDEO_RENDER_OGL 1
-#endif
-
-/* Enable OpenGL support */
-#ifndef SDL_VIDEO_OPENGL
-#define SDL_VIDEO_OPENGL 1
-#endif
-#ifndef SDL_VIDEO_OPENGL_CGL
-#define SDL_VIDEO_OPENGL_CGL 1
-#endif
-#ifndef SDL_VIDEO_OPENGL_GLX
-#define SDL_VIDEO_OPENGL_GLX 1
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_MACOSX 1
-
-/* enable filesystem support */
-#define SDL_FILESYSTEM_COCOA 1
-
-/* Enable assembly routines */
-#define SDL_ASSEMBLY_ROUTINES 1
-#ifdef __ppc__
-#define SDL_ALTIVEC_BLITTERS 1
-#endif
-
-#endif /* _SDL_config_macosx_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_minimal.h b/Source/3rdParty/sdl/include/SDL_config_minimal.h
deleted file mode 100644
index 1bddafea7..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_minimal.h
+++ /dev/null
@@ -1,81 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_minimal_h
-#define _SDL_config_minimal_h
-
-#include "SDL_platform.h"
-
-/**
- * \file SDL_config_minimal.h
- *
- * This is the minimal configuration that can be used to build SDL.
- */
-
-#define HAVE_STDARG_H 1
-#define HAVE_STDDEF_H 1
-
-/* Most everything except Visual Studio 2008 and earlier has stdint.h now */
-#if defined(_MSC_VER) && (_MSC_VER < 1600)
-/* Here are some reasonable defaults */
-typedef unsigned int size_t;
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-typedef unsigned long uintptr_t;
-#else
-#define HAVE_STDINT_H 1
-#endif /* Visual Studio 2008 */
-
-#ifdef __GNUC__
-#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
-#endif
-
-/* Enable the dummy audio driver (src/audio/dummy/\*.c) */
-#define SDL_AUDIO_DRIVER_DUMMY 1
-
-/* Enable the stub joystick driver (src/joystick/dummy/\*.c) */
-#define SDL_JOYSTICK_DISABLED 1
-
-/* Enable the stub haptic driver (src/haptic/dummy/\*.c) */
-#define SDL_HAPTIC_DISABLED 1
-
-/* Enable the stub shared object loader (src/loadso/dummy/\*.c) */
-#define SDL_LOADSO_DISABLED 1
-
-/* Enable the stub thread support (src/thread/generic/\*.c) */
-#define SDL_THREADS_DISABLED 1
-
-/* Enable the stub timer support (src/timer/dummy/\*.c) */
-#define SDL_TIMERS_DISABLED 1
-
-/* Enable the dummy video driver (src/video/dummy/\*.c) */
-#define SDL_VIDEO_DRIVER_DUMMY 1
-
-/* Enable the dummy filesystem driver (src/filesystem/dummy/\*.c) */
-#define SDL_FILESYSTEM_DUMMY 1
-
-#endif /* _SDL_config_minimal_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_pandora.h b/Source/3rdParty/sdl/include/SDL_config_pandora.h
deleted file mode 100644
index ac8b08508..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_pandora.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_h
-#define _SDL_config_h
-
-/* This is a set of defines to configure the SDL features */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-#ifdef __LP64__
-#define SIZEOF_VOIDP 8
-#else
-#define SIZEOF_VOIDP 4
-#endif
-
-#define SDL_BYTEORDER 1234
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STDARG_H 1
-#define HAVE_MALLOC_H 1
-#define HAVE_MEMORY_H 1
-#define HAVE_STRING_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_ICONV_H 1
-#define HAVE_SIGNAL_H 1
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_STRLEN 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-
-#define SDL_AUDIO_DRIVER_DUMMY 1
-#define SDL_AUDIO_DRIVER_OSS 1
-
-#define SDL_INPUT_LINUXEV 1
-#define SDL_INPUT_TSLIB 1
-#define SDL_JOYSTICK_LINUX 1
-#define SDL_HAPTIC_LINUX 1
-
-#define SDL_LOADSO_DLOPEN 1
-
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1
-
-#define SDL_TIMER_UNIX 1
-#define SDL_FILESYSTEM_UNIX 1
-
-#define SDL_VIDEO_DRIVER_DUMMY 1
-#define SDL_VIDEO_DRIVER_X11 1
-#define SDL_VIDEO_DRIVER_PANDORA 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_OPENGL_ES 1
-
-#endif /* _SDL_config_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_psp.h b/Source/3rdParty/sdl/include/SDL_config_psp.h
deleted file mode 100644
index 2f9d023c5..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_psp.h
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_psp_h
-#define _SDL_config_psp_h
-
-#include "SDL_platform.h"
-
-
-
-#ifdef __GNUC__
-#define HAVE_GCC_SYNC_LOCK_TEST_AND_SET 1
-#endif
-
-#define HAVE_GCC_ATOMICS 1
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_SETENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE_STRLCPY 1
-#define HAVE_STRLCAT 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-/* #define HAVE_SYSCONF 1 */
-/* #define HAVE_SIGACTION 1 */
-
-
-/* PSP isn't that sophisticated */
-#define LACKS_SYS_MMAN_H 1
-
-/* Enable the stub thread support (src/thread/psp/\*.c) */
-#define SDL_THREAD_PSP 1
-
-/* Enable the stub timer support (src/timer/psp/\*.c) */
-#define SDL_TIMERS_PSP 1
-
-/* Enable the stub joystick driver (src/joystick/psp/\*.c) */
-#define SDL_JOYSTICK_PSP 1
-
-/* Enable the stub audio driver (src/audio/psp/\*.c) */
-#define SDL_AUDIO_DRIVER_PSP 1
-
-/* PSP video dirver */
-#define SDL_VIDEO_DRIVER_PSP 1
-
-/* PSP render dirver */
-#define SDL_VIDEO_RENDER_PSP 1
-
-#define SDL_POWER_PSP 1
-
-/* !!! FIXME: what does PSP do for filesystem stuff? */
-#define SDL_FILESYSTEM_DUMMY 1
-
-/* PSP doesn't have haptic device (src/haptic/dummy/\*.c) */
-#define SDL_HAPTIC_DISABLED 1
-
-/* PSP can't load shared object (src/loadso/dummy/\*.c) */
-#define SDL_LOADSO_DISABLED 1
-
-
-#endif /* _SDL_config_psp_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_windows.h b/Source/3rdParty/sdl/include/SDL_config_windows.h
deleted file mode 100644
index 35eda4653..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_windows.h
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_windows_h
-#define _SDL_config_windows_h
-
-#include "SDL_platform.h"
-
-/* This is a set of defines to configure the SDL features */
-
-#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
-#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
-#define HAVE_STDINT_H 1
-#elif defined(_MSC_VER)
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#ifndef _UINTPTR_T_DEFINED
-#ifdef _WIN64
-typedef unsigned __int64 uintptr_t;
-#else
-typedef unsigned int uintptr_t;
-#endif
-#define _UINTPTR_T_DEFINED
-#endif
-/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
-#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
-#define DWORD_PTR DWORD
-#endif
-#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
-#define LONG_PTR LONG
-#endif
-#else /* !__GNUC__ && !_MSC_VER */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#ifndef _SIZE_T_DEFINED_
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-#endif
-typedef unsigned int uintptr_t;
-#endif /* __GNUC__ || _MSC_VER */
-#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
-
-#ifdef _WIN64
-# define SIZEOF_VOIDP 8
-#else
-# define SIZEOF_VOIDP 4
-#endif
-
-/* This is disabled by default to avoid C runtime dependencies and manifest requirements */
-#ifdef HAVE_LIBC
-/* Useful headers */
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-#define HAVE__STRLWR 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE__LTOA 1
-#define HAVE__ULTOA 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE__STRICMP 1
-#define HAVE__STRNICMP 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_ACOS 1
-#define HAVE_ASIN 1
-#define HAVE_CEIL 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#if _MSC_VER >= 1800
-#define HAVE_STRTOLL 1
-#define HAVE_VSSCANF 1
-#define HAVE_COPYSIGN 1
-#define HAVE_SCALBN 1
-#endif
-#if !defined(_MSC_VER) || defined(_USE_MATH_DEFINES)
-#define HAVE_M_PI 1
-#endif
-#else
-#define HAVE_STDARG_H 1
-#define HAVE_STDDEF_H 1
-#endif
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_DSOUND 1
-#define SDL_AUDIO_DRIVER_XAUDIO2 1
-#define SDL_AUDIO_DRIVER_WINMM 1
-#define SDL_AUDIO_DRIVER_DISK 1
-#define SDL_AUDIO_DRIVER_DUMMY 1
-
-/* Enable various input drivers */
-#define SDL_JOYSTICK_DINPUT 1
-#define SDL_HAPTIC_DINPUT 1
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_WINDOWS 1
-
-/* Enable various threading systems */
-#define SDL_THREAD_WINDOWS 1
-
-/* Enable various timer systems */
-#define SDL_TIMER_WINDOWS 1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_DUMMY 1
-#define SDL_VIDEO_DRIVER_WINDOWS 1
-
-#ifndef SDL_VIDEO_RENDER_D3D
-#define SDL_VIDEO_RENDER_D3D 1
-#endif
-#ifndef SDL_VIDEO_RENDER_D3D11
-#define SDL_VIDEO_RENDER_D3D11 0
-#endif
-
-/* Enable OpenGL support */
-#ifndef SDL_VIDEO_OPENGL
-#define SDL_VIDEO_OPENGL 1
-#endif
-#ifndef SDL_VIDEO_OPENGL_WGL
-#define SDL_VIDEO_OPENGL_WGL 1
-#endif
-#ifndef SDL_VIDEO_RENDER_OGL
-#define SDL_VIDEO_RENDER_OGL 1
-#endif
-#ifndef SDL_VIDEO_RENDER_OGL_ES2
-#define SDL_VIDEO_RENDER_OGL_ES2 1
-#endif
-#ifndef SDL_VIDEO_OPENGL_ES2
-#define SDL_VIDEO_OPENGL_ES2 1
-#endif
-#ifndef SDL_VIDEO_OPENGL_EGL
-#define SDL_VIDEO_OPENGL_EGL 1
-#endif
-
-
-/* Enable system power support */
-#define SDL_POWER_WINDOWS 1
-
-/* Enable filesystem support */
-#define SDL_FILESYSTEM_WINDOWS 1
-
-/* Enable assembly routines (Win64 doesn't have inline asm) */
-#ifndef _WIN64
-#define SDL_ASSEMBLY_ROUTINES 1
-#endif
-
-#endif /* _SDL_config_windows_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_winrt.h b/Source/3rdParty/sdl/include/SDL_config_winrt.h
deleted file mode 100644
index 78b43ab64..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_winrt.h
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2012 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_windows_h
-#define _SDL_config_windows_h
-
-#include "SDL_platform.h"
-
-/* This is a set of defines to configure the SDL features */
-
-#if !defined(_STDINT_H_) && (!defined(HAVE_STDINT_H) || !_HAVE_STDINT_H)
-#if defined(__GNUC__) || defined(__DMC__) || defined(__WATCOMC__)
-#define HAVE_STDINT_H 1
-#elif defined(_MSC_VER)
-typedef signed __int8 int8_t;
-typedef unsigned __int8 uint8_t;
-typedef signed __int16 int16_t;
-typedef unsigned __int16 uint16_t;
-typedef signed __int32 int32_t;
-typedef unsigned __int32 uint32_t;
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-#ifndef _UINTPTR_T_DEFINED
-#ifdef _WIN64
-typedef unsigned __int64 uintptr_t;
-#else
-typedef unsigned int uintptr_t;
-#endif
-#define _UINTPTR_T_DEFINED
-#endif
-/* Older Visual C++ headers don't have the Win64-compatible typedefs... */
-#if ((_MSC_VER <= 1200) && (!defined(DWORD_PTR)))
-#define DWORD_PTR DWORD
-#endif
-#if ((_MSC_VER <= 1200) && (!defined(LONG_PTR)))
-#define LONG_PTR LONG
-#endif
-#else /* !__GNUC__ && !_MSC_VER */
-typedef signed char int8_t;
-typedef unsigned char uint8_t;
-typedef signed short int16_t;
-typedef unsigned short uint16_t;
-typedef signed int int32_t;
-typedef unsigned int uint32_t;
-typedef signed long long int64_t;
-typedef unsigned long long uint64_t;
-#ifndef _SIZE_T_DEFINED_
-#define _SIZE_T_DEFINED_
-typedef unsigned int size_t;
-#endif
-typedef unsigned int uintptr_t;
-#endif /* __GNUC__ || _MSC_VER */
-#endif /* !_STDINT_H_ && !HAVE_STDINT_H */
-
-#ifdef _WIN64
-# define SIZEOF_VOIDP 8
-#else
-# define SIZEOF_VOIDP 4
-#endif
-
-/* Useful headers */
-#define HAVE_LIBC 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STRING_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_FLOAT_H 1
-#define HAVE_SIGNAL_H 1
-
-/* C library functions */
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_MEMCMP 1
-#define HAVE_STRLEN 1
-#define HAVE__STRREV 1
-#define HAVE__STRUPR 1
-//#define HAVE__STRLWR 1 // TODO, WinRT: consider using _strlwr_s instead
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-//#define HAVE_ITOA 1 // TODO, WinRT: consider using _itoa_s instead
-//#define HAVE__LTOA 1 // TODO, WinRT: consider using _ltoa_s instead
-//#define HAVE__ULTOA 1 // TODO, WinRT: consider using _ultoa_s instead
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-//#define HAVE_STRTOLL 1
-#define HAVE_STRTOD 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE__STRICMP 1
-#define HAVE__STRNICMP 1
-#define HAVE_VSNPRINTF 1
-//#define HAVE_SSCANF 1 // TODO, WinRT: consider using sscanf_s instead
-#define HAVE_M_PI 1
-#define HAVE_ATAN 1
-#define HAVE_ATAN2 1
-#define HAVE_CEIL 1
-#define HAVE__COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_POW 1
-//#define HAVE_SCALBN 1
-#define HAVE__SCALB 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE__FSEEKI64 1
-
-/* Enable various audio drivers */
-#define SDL_AUDIO_DRIVER_XAUDIO2 1
-#define SDL_AUDIO_DRIVER_DISK 1
-#define SDL_AUDIO_DRIVER_DUMMY 1
-
-/* Enable various input drivers */
-// TODO, WinRT: Get haptic support working
-#define SDL_HAPTIC_DISABLED 1
-
-#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
-#define SDL_JOYSTICK_DISABLED 1
-#else
-#define SDL_JOYSTICK_XINPUT 1
-#endif
-
-/* Enable various shared object loading systems */
-#define SDL_LOADSO_WINDOWS 1
-
-/* Enable various threading systems */
-#define SDL_THREAD_STDCPP 1
-
-/* Enable various timer systems */
-#define SDL_TIMER_WINDOWS 1
-
-/* Enable various video drivers */
-#define SDL_VIDEO_DRIVER_WINRT 1
-#define SDL_VIDEO_DRIVER_DUMMY 1
-
-/* Enable OpenGL ES 2.0 (via a modified ANGLE library) */
-#if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP /* TODO, WinRT: try adding OpenGL ES 2 support for Windows Phone 8 */
-#define SDL_VIDEO_OPENGL_ES2 1
-#define SDL_VIDEO_OPENGL_EGL 1
-#endif
-
-/* Enable appropriate renderer(s) */
-#define SDL_VIDEO_RENDER_D3D11 1
-
-#if SDL_VIDEO_OPENGL_ES2
-#define SDL_VIDEO_RENDER_OGL_ES2 1
-#endif
-
-/* Enable system power support */
-#define SDL_POWER_WINRT 1
-
-/* Enable assembly routines (Win64 doesn't have inline asm) */
-#ifndef _WIN64
-#define SDL_ASSEMBLY_ROUTINES 1
-#endif
-
-#endif /* _SDL_config_windows_h */
diff --git a/Source/3rdParty/sdl/include/SDL_config_wiz.h b/Source/3rdParty/sdl/include/SDL_config_wiz.h
deleted file mode 100644
index 7efc20bc9..000000000
--- a/Source/3rdParty/sdl/include/SDL_config_wiz.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-#ifndef _SDL_config_h
-#define _SDL_config_h
-
-/* This is a set of defines to configure the SDL features */
-
-/* General platform specific identifiers */
-#include "SDL_platform.h"
-
-#define SDL_BYTEORDER 1234
-
-#define HAVE_ALLOCA_H 1
-#define HAVE_SYS_TYPES_H 1
-#define HAVE_STDIO_H 1
-#define STDC_HEADERS 1
-#define HAVE_STDLIB_H 1
-#define HAVE_STDARG_H 1
-#define HAVE_MALLOC_H 1
-#define HAVE_MEMORY_H 1
-#define HAVE_STRING_H 1
-#define HAVE_STRINGS_H 1
-#define HAVE_INTTYPES_H 1
-#define HAVE_STDINT_H 1
-#define HAVE_CTYPE_H 1
-#define HAVE_MATH_H 1
-#define HAVE_ICONV_H 1
-#define HAVE_SIGNAL_H 1
-#define HAVE_MALLOC 1
-#define HAVE_CALLOC 1
-#define HAVE_REALLOC 1
-#define HAVE_FREE 1
-#define HAVE_ALLOCA 1
-#define HAVE_GETENV 1
-#define HAVE_SETENV 1
-#define HAVE_PUTENV 1
-#define HAVE_UNSETENV 1
-#define HAVE_QSORT 1
-#define HAVE_ABS 1
-#define HAVE_BCOPY 1
-#define HAVE_MEMSET 1
-#define HAVE_MEMCPY 1
-#define HAVE_MEMMOVE 1
-#define HAVE_STRLEN 1
-#define HAVE_STRDUP 1
-#define HAVE_STRCHR 1
-#define HAVE_STRRCHR 1
-#define HAVE_STRSTR 1
-#define HAVE_STRTOL 1
-#define HAVE_STRTOUL 1
-#define HAVE_STRTOLL 1
-#define HAVE_STRTOULL 1
-#define HAVE_ATOI 1
-#define HAVE_ATOF 1
-#define HAVE_STRCMP 1
-#define HAVE_STRNCMP 1
-#define HAVE_STRCASECMP 1
-#define HAVE_STRNCASECMP 1
-#define HAVE_VSSCANF 1
-#define HAVE_VSNPRINTF 1
-#define HAVE_M_PI 1
-#define HAVE_CEIL 1
-#define HAVE_COPYSIGN 1
-#define HAVE_COS 1
-#define HAVE_COSF 1
-#define HAVE_FABS 1
-#define HAVE_FLOOR 1
-#define HAVE_LOG 1
-#define HAVE_SCALBN 1
-#define HAVE_SIN 1
-#define HAVE_SINF 1
-#define HAVE_SQRT 1
-#define HAVE_SIGACTION 1
-#define HAVE_SETJMP 1
-#define HAVE_NANOSLEEP 1
-#define HAVE_POW 1
-
-#define SDL_CDROM_DISABLED 1
-#define SDL_AUDIO_DRIVER_DUMMY 1
-#define SDL_AUDIO_DRIVER_OSS 1
-
-#define SDL_INPUT_LINUXEV 1
-#define SDL_INPUT_TSLIB 1
-#define SDL_JOYSTICK_LINUX 1
-#define SDL_HAPTIC_LINUX 1
-
-#define SDL_LOADSO_DLOPEN 1
-
-#define SDL_THREAD_PTHREAD 1
-#define SDL_THREAD_PTHREAD_RECURSIVE_MUTEX_NP 1
-
-#define SDL_TIMER_UNIX 1
-
-#define SDL_VIDEO_DRIVER_DUMMY 1
-#define SDL_VIDEO_DRIVER_PANDORA 1
-#define SDL_VIDEO_RENDER_OGL_ES 1
-#define SDL_VIDEO_OPENGL_ES 1
-
-#endif /* _SDL_config_h */
diff --git a/Source/3rdParty/sdl/include/SDL_copying.h b/Source/3rdParty/sdl/include/SDL_copying.h
deleted file mode 100644
index 0964da84f..000000000
--- a/Source/3rdParty/sdl/include/SDL_copying.h
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
diff --git a/Source/3rdParty/sdl/include/SDL_cpuinfo.h b/Source/3rdParty/sdl/include/SDL_cpuinfo.h
deleted file mode 100644
index 1f6efd384..000000000
--- a/Source/3rdParty/sdl/include/SDL_cpuinfo.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_cpuinfo.h
- *
- * CPU feature detection for SDL.
- */
-
-#ifndef _SDL_cpuinfo_h
-#define _SDL_cpuinfo_h
-
-#include "SDL_stdinc.h"
-
-/* Need to do this here because intrin.h has C++ code in it */
-/* Visual Studio 2005 has a bug where intrin.h conflicts with winnt.h */
-#if defined(_MSC_VER) && (_MSC_VER >= 1500) && (defined(_M_IX86) || defined(_M_X64))
-#include
-#ifndef _WIN64
-#define __MMX__
-#define __3dNOW__
-#endif
-#define __SSE__
-#define __SSE2__
-#elif defined(__MINGW64_VERSION_MAJOR)
-#include
-#else
-#ifdef __ALTIVEC__
-#if HAVE_ALTIVEC_H && !defined(__APPLE_ALTIVEC__)
-#include
-#undef pixel
-#endif
-#endif
-#ifdef __MMX__
-#include
-#endif
-#ifdef __3dNOW__
-#include
-#endif
-#ifdef __SSE__
-#include
-#endif
-#ifdef __SSE2__
-#include
-#endif
-#endif
-
-#include "begin_code.h"
-/* Set up for C function definitions, even when using C++ */
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/* This is a guess for the cacheline size used for padding.
- * Most x86 processors have a 64 byte cache line.
- * The 64-bit PowerPC processors have a 128 byte cache line.
- * We'll use the larger value to be generally safe.
- */
-#define SDL_CACHELINE_SIZE 128
-
-/**
- * This function returns the number of CPU cores available.
- */
-extern DECLSPEC int SDLCALL SDL_GetCPUCount(void);
-
-/**
- * This function returns the L1 cache line size of the CPU
- *
- * This is useful for determining multi-threaded structure padding
- * or SIMD prefetch sizes.
- */
-extern DECLSPEC int SDLCALL SDL_GetCPUCacheLineSize(void);
-
-/**
- * This function returns true if the CPU has the RDTSC instruction.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasRDTSC(void);
-
-/**
- * This function returns true if the CPU has AltiVec features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasAltiVec(void);
-
-/**
- * This function returns true if the CPU has MMX features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasMMX(void);
-
-/**
- * This function returns true if the CPU has 3DNow! features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_Has3DNow(void);
-
-/**
- * This function returns true if the CPU has SSE features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE(void);
-
-/**
- * This function returns true if the CPU has SSE2 features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE2(void);
-
-/**
- * This function returns true if the CPU has SSE3 features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE3(void);
-
-/**
- * This function returns true if the CPU has SSE4.1 features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE41(void);
-
-/**
- * This function returns true if the CPU has SSE4.2 features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasSSE42(void);
-
-/**
- * This function returns true if the CPU has AVX features.
- */
-extern DECLSPEC SDL_bool SDLCALL SDL_HasAVX(void);
-
-/**
- * This function returns the amount of RAM configured in the system, in MB.
- */
-extern DECLSPEC int SDLCALL SDL_GetSystemRAM(void);
-
-
-/* Ends C function definitions when using C++ */
-#ifdef __cplusplus
-}
-#endif
-#include "close_code.h"
-
-#endif /* _SDL_cpuinfo_h */
-
-/* vi: set ts=4 sw=4 expandtab: */
diff --git a/Source/3rdParty/sdl/include/SDL_egl.h b/Source/3rdParty/sdl/include/SDL_egl.h
deleted file mode 100644
index d312f0425..000000000
--- a/Source/3rdParty/sdl/include/SDL_egl.h
+++ /dev/null
@@ -1,1396 +0,0 @@
-/*
- Simple DirectMedia Layer
- Copyright (C) 1997-2014 Sam Lantinga
-
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source distribution.
-*/
-
-/**
- * \file SDL_opengles.h
- *
- * This is a simple file to encapsulate the OpenGL ES 2.0 API headers.
- */
-#ifndef _MSC_VER
-
-#include
-
-#else /* _MSC_VER */
-
-/* EGL headers for Visual Studio */
-
-#ifndef __khrplatform_h_
-#define __khrplatform_h_
-
-/*
-** Copyright (c) 2008-2009 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/* Khronos platform-specific types and definitions.
-*
-* $Revision: 23298 $ on $Date: 2013-09-30 17:07:13 -0700 (Mon, 30 Sep 2013) $
-*
-* Adopters may modify this file to suit their platform. Adopters are
-* encouraged to submit platform specific modifications to the Khronos
-* group so that they can be included in future versions of this file.
-* Please submit changes by sending them to the public Khronos Bugzilla
-* (http://khronos.org/bugzilla) by filing a bug against product
-* "Khronos (general)" component "Registry".
-*
-* A predefined template which fills in some of the bug fields can be
-* reached using http://tinyurl.com/khrplatform-h-bugreport, but you
-* must create a Bugzilla login first.
-*
-*
-* See the Implementer's Guidelines for information about where this file
-* should be located on your system and for more details of its use:
-* http://www.khronos.org/registry/implementers_guide.pdf
-*
-* This file should be included as
-* #include
-* by Khronos client API header files that use its types and defines.
-*
-* The types in khrplatform.h should only be used to define API-specific types.
-*
-* Types defined in khrplatform.h:
-* khronos_int8_t signed 8 bit
-* khronos_uint8_t unsigned 8 bit
-* khronos_int16_t signed 16 bit
-* khronos_uint16_t unsigned 16 bit
-* khronos_int32_t signed 32 bit
-* khronos_uint32_t unsigned 32 bit
-* khronos_int64_t signed 64 bit
-* khronos_uint64_t unsigned 64 bit
-* khronos_intptr_t signed same number of bits as a pointer
-* khronos_uintptr_t unsigned same number of bits as a pointer
-* khronos_ssize_t signed size
-* khronos_usize_t unsigned size
-* khronos_float_t signed 32 bit floating point
-* khronos_time_ns_t unsigned 64 bit time in nanoseconds
-* khronos_utime_nanoseconds_t unsigned time interval or absolute time in
-* nanoseconds
-* khronos_stime_nanoseconds_t signed time interval in nanoseconds
-* khronos_boolean_enum_t enumerated boolean type. This should
-* only be used as a base type when a client API's boolean type is
-* an enum. Client APIs which use an integer or other type for
-* booleans cannot use this as the base type for their boolean.
-*
-* Tokens defined in khrplatform.h:
-*
-* KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
-*
-* KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
-* KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
-*
-* Calling convention macros defined in this file:
-* KHRONOS_APICALL
-* KHRONOS_APIENTRY
-* KHRONOS_APIATTRIBUTES
-*
-* These may be used in function prototypes as:
-*
-* KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
-* int arg1,
-* int arg2) KHRONOS_APIATTRIBUTES;
-*/
-
-/*-------------------------------------------------------------------------
-* Definition of KHRONOS_APICALL
-*-------------------------------------------------------------------------
-* This precedes the return type of the function in the function prototype.
-*/
-#if defined(_WIN32) && !defined(__SCITECH_SNAP__)
-# define KHRONOS_APICALL __declspec(dllimport)
-#elif defined (__SYMBIAN32__)
-# define KHRONOS_APICALL IMPORT_C
-#else
-# define KHRONOS_APICALL
-#endif
-
-/*-------------------------------------------------------------------------
-* Definition of KHRONOS_APIENTRY
-*-------------------------------------------------------------------------
-* This follows the return type of the function and precedes the function
-* name in the function prototype.
-*/
-#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
-/* Win32 but not WinCE */
-# define KHRONOS_APIENTRY __stdcall
-#else
-# define KHRONOS_APIENTRY
-#endif
-
-/*-------------------------------------------------------------------------
-* Definition of KHRONOS_APIATTRIBUTES
-*-------------------------------------------------------------------------
-* This follows the closing parenthesis of the function prototype arguments.
-*/
-#if defined (__ARMCC_2__)
-#define KHRONOS_APIATTRIBUTES __softfp
-#else
-#define KHRONOS_APIATTRIBUTES
-#endif
-
-/*-------------------------------------------------------------------------
-* basic type definitions
-*-----------------------------------------------------------------------*/
-#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
-
-
-/*
-* Using
-*/
-#include
-typedef int32_t khronos_int32_t;
-typedef uint32_t khronos_uint32_t;
-typedef int64_t khronos_int64_t;
-typedef uint64_t khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif defined(__VMS ) || defined(__sgi)
-
-/*
-* Using
-*/
-#include
-typedef int32_t khronos_int32_t;
-typedef uint32_t khronos_uint32_t;
-typedef int64_t khronos_int64_t;
-typedef uint64_t khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
-
-/*
-* Win32
-*/
-typedef __int32 khronos_int32_t;
-typedef unsigned __int32 khronos_uint32_t;
-typedef __int64 khronos_int64_t;
-typedef unsigned __int64 khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif defined(__sun__) || defined(__digital__)
-
-/*
-* Sun or Digital
-*/
-typedef int khronos_int32_t;
-typedef unsigned int khronos_uint32_t;
-#if defined(__arch64__) || defined(_LP64)
-typedef long int khronos_int64_t;
-typedef unsigned long int khronos_uint64_t;
-#else
-typedef long long int khronos_int64_t;
-typedef unsigned long long int khronos_uint64_t;
-#endif /* __arch64__ */
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#elif 0
-
-/*
-* Hypothetical platform with no float or int64 support
-*/
-typedef int khronos_int32_t;
-typedef unsigned int khronos_uint32_t;
-#define KHRONOS_SUPPORT_INT64 0
-#define KHRONOS_SUPPORT_FLOAT 0
-
-#else
-
-/*
-* Generic fallback
-*/
-#include
-typedef int32_t khronos_int32_t;
-typedef uint32_t khronos_uint32_t;
-typedef int64_t khronos_int64_t;
-typedef uint64_t khronos_uint64_t;
-#define KHRONOS_SUPPORT_INT64 1
-#define KHRONOS_SUPPORT_FLOAT 1
-
-#endif
-
-
-/*
-* Types that are (so far) the same on all platforms
-*/
-typedef signed char khronos_int8_t;
-typedef unsigned char khronos_uint8_t;
-typedef signed short int khronos_int16_t;
-typedef unsigned short int khronos_uint16_t;
-
-/*
-* Types that differ between LLP64 and LP64 architectures - in LLP64,
-* pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
-* to be the only LLP64 architecture in current use.
-*/
-#ifdef _WIN64
-typedef signed long long int khronos_intptr_t;
-typedef unsigned long long int khronos_uintptr_t;
-typedef signed long long int khronos_ssize_t;
-typedef unsigned long long int khronos_usize_t;
-#else
-typedef signed long int khronos_intptr_t;
-typedef unsigned long int khronos_uintptr_t;
-typedef signed long int khronos_ssize_t;
-typedef unsigned long int khronos_usize_t;
-#endif
-
-#if KHRONOS_SUPPORT_FLOAT
-/*
-* Float type
-*/
-typedef float khronos_float_t;
-#endif
-
-#if KHRONOS_SUPPORT_INT64
-/* Time types
-*
-* These types can be used to represent a time interval in nanoseconds or
-* an absolute Unadjusted System Time. Unadjusted System Time is the number
-* of nanoseconds since some arbitrary system event (e.g. since the last
-* time the system booted). The Unadjusted System Time is an unsigned
-* 64 bit value that wraps back to 0 every 584 years. Time intervals
-* may be either signed or unsigned.
-*/
-typedef khronos_uint64_t khronos_utime_nanoseconds_t;
-typedef khronos_int64_t khronos_stime_nanoseconds_t;
-#endif
-
-/*
-* Dummy value used to pad enum types to 32 bits.
-*/
-#ifndef KHRONOS_MAX_ENUM
-#define KHRONOS_MAX_ENUM 0x7FFFFFFF
-#endif
-
-/*
-* Enumerated boolean type
-*
-* Values other than zero should be considered to be true. Therefore
-* comparisons should not be made against KHRONOS_TRUE.
-*/
-typedef enum {
- KHRONOS_FALSE = 0,
- KHRONOS_TRUE = 1,
- KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
-} khronos_boolean_enum_t;
-
-#endif /* __khrplatform_h_ */
-
-
-#ifndef __eglplatform_h_
-#define __eglplatform_h_
-
-/*
-** Copyright (c) 2007-2009 The Khronos Group Inc.
-**
-** Permission is hereby granted, free of charge, to any person obtaining a
-** copy of this software and/or associated documentation files (the
-** "Materials"), to deal in the Materials without restriction, including
-** without limitation the rights to use, copy, modify, merge, publish,
-** distribute, sublicense, and/or sell copies of the Materials, and to
-** permit persons to whom the Materials are furnished to do so, subject to
-** the following conditions:
-**
-** The above copyright notice and this permission notice shall be included
-** in all copies or substantial portions of the Materials.
-**
-** THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-** EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-** MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-** IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
-** CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
-** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
-** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
-*/
-
-/* Platform-specific types and definitions for egl.h
-* $Revision: 12306 $ on $Date: 2010-08-25 09:51:28 -0700 (Wed, 25 Aug 2010) $
-*
-* Adopters may modify khrplatform.h and this file to suit their platform.
-* You are encouraged to submit all modifications to the Khronos group so that
-* they can be included in future versions of this file. Please submit changes
-* by sending them to the public Khronos Bugzilla (http://khronos.org/bugzilla)
-* by filing a bug against product "EGL" component "Registry".
-*/
-
-/*#include