Merge branch 'master' into wii-network

Conflicts:
	Source/Core/Core/Core.vcxproj
	Source/Core/Core/Core.vcxproj.filters
	Source/Core/Core/Src/CoreParameter.cpp
	Source/Core/DolphinWX/Dolphin.vcxproj
	Source/Core/DolphinWX/Dolphin.vcxproj.filters
This commit is contained in:
Matthew Parlane
2013-08-23 00:51:12 +12:00
1697 changed files with 64354 additions and 72384 deletions

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.ANDROID_FRAMEWORK"/>
<classpathentry kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry exported="true" kind="con" path="com.android.ide.eclipse.adt.LIBRARIES"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="gen"/>
<classpathentry kind="output" path="bin/classes"/>

View File

@ -1,4 +1,4 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.5
org.eclipse.jdt.core.compiler.compliance=1.5
org.eclipse.jdt.core.compiler.source=1.5
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
org.eclipse.jdt.core.compiler.compliance=1.6
org.eclipse.jdt.core.compiler.source=1.6

View File

@ -2,47 +2,40 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.dolphinemu.dolphinemu"
android:versionCode="10"
android:versionName="0.10" >
android:versionName="0.10"
android:installLocation="auto">
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14"/>
<uses-feature android:glEsVersion="0x00020000"></uses-feature>
<uses-feature android:name="android.hardware.screen.landscape" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<application
<uses-sdk
android:minSdkVersion="14"
android:targetSdkVersion="14" />
<uses-feature android:glEsVersion="0x00020000" >
</uses-feature>
<uses-feature android:name="android.hardware.screen.landscape" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application
android:icon="@drawable/launcher"
android:label="@string/app_name">
android:label="@string/app_name" >
<activity
android:name=".DolphinEmulator"
android:name="org.dolphinemu.dolphinemu.DolphinEmulator"
android:configChanges="locale|keyboard|keyboardHidden|navigation|fontScale|uiMode"
android:label="@string/app_name"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
android:screenOrientation="landscape"
android:configChanges="locale|keyboard|keyboardHidden|navigation|fontScale|uiMode" >
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="org.dolphinemu.dolphinemu.FolderBrowser"
android:label="@string/app_name"
android:configChanges="orientation|locale|keyboard|keyboardHidden|navigation|fontScale|uiMode" >
<activity android:name="org.dolphinemu.dolphinemu.gamelist.GameListActivity" >
</activity>
<activity
android:name=".InputConfigFragment"
android:label="@string/app_name"
android:configChanges="orientation|locale|keyboard|keyboardHidden|navigation|fontScale|uiMode" >
</activity>
<activity
android:name=".PrefsFragment" >
</activity>
<activity
android:name=".GameListActivity" >
</activity>
<activity
android:name=".AboutFragment" >
android:name="org.dolphinemu.dolphinemu.settings.PrefsActivity"
android:label="@string/settings" >
</activity>
</application>

View File

@ -8,7 +8,7 @@
<copy todir="${jar.libs.dir}/armeabi-v7a">
<fileset
dir="../../libs/armeabi-v7a"
includes="libdolphin-emu-nogui.so" />
includes="libmain.so" />
</copy>
</target>
<target name="clean" depends="android_rules.clean">

Binary file not shown.

After

Width:  |  Height:  |  Size: 510 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 580 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/FolderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:singleLine="true"
android:textStyle="bold" />
<TextView
android:id="@+id/FolderSubTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip" />
</LinearLayout>

View File

@ -1,29 +1,53 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="3dip">
<ImageView
android:id="@+id/ImageIcon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="6dip"/>
<TextView
android:id="@+id/FolderTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:singleLine="true"
android:text="Title"
android:textStyle="bold" />
<TextView
android:id="@+id/FolderSubTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="Subtitle" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/FolderSubTitle"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_toRightOf="@id/ImageIcon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:singleLine="true"
android:ellipsize="marquee"
android:text="Subtitle" />
<TextView
android:id="@+id/FolderTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/ImageIcon"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="@id/FolderSubTitle"
android:layout_alignWithParentIfMissing="true"
android:gravity="center_vertical"
android:text="Title"
android:textStyle="bold" />
<ImageView
android:src="@android:drawable/divider_horizontal_dark"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="2dp"
android:paddingTop="2dp" />
</RelativeLayout>

View File

@ -1,43 +1,54 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="3dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<ImageView
android:id="@+id/GameItemIcon"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_alignParentTop="true"
android:layout_alignParentBottom="true"
android:layout_marginRight="6dip" />
<ImageView
android:id="@+id/GameItemIcon"
android:layout_width="96dp"
android:layout_height="match_parent" />
<TextView
android:id="@+id/GameItemSubText"
android:layout_width="fill_parent"
android:layout_height="26dip"
android:layout_toRightOf="@id/GameItemIcon"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:singleLine="true"
android:ellipsize="marquee"/>
<TextView
android:id="@+id/GameItemTitle"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="@id/GameItemIcon"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="@id/GameItemSubText"
android:layout_alignWithParentIfMissing="true"
android:gravity="center_vertical"
android:textStyle="bold" />
<ImageView
android:src="@android:drawable/divider_horizontal_dark"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:paddingLeft="5dp"
android:paddingRight="5dp"
android:paddingBottom="2dp"
android:paddingTop="2dp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/GameItemTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:singleLine="true"
android:text="@+id/TextView01"
android:textStyle="bold" />
<TextView
android:id="@+id/GameItemSubText"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dip"
android:text="@+id/TextView02" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
>
<PreferenceCategory
android:summary="Settings"
android:title="CPU Settings"
android:key="cpuprefcat">
<CheckBoxPreference
android:key="dualcorepref"
android:summary="On/Off"
android:title="Dual Core" />
</PreferenceCategory>
<PreferenceCategory
android:summary="Settings"
android:title="Video Settings"
android:key="videoprefcat">
<ListPreference
android:entries="@array/gpuOptions"
android:entryValues="@array/gpuValues"
android:key="gpupref"
android:summary="Video backend to use"
android:title="Video Backend" />
</PreferenceCategory>
</PreferenceScreen>

View File

@ -0,0 +1,6 @@
<android.support.v4.view.ViewPager xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".PrefsActivity" />

View File

@ -1,31 +1,19 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="left"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/SideMenuTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:singleLine="true"
android:text="@+id/TextView01"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold" />
</LinearLayout>
</LinearLayout>
<TextView
android:id="@+id/SideMenuTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="5dip"
android:layout_marginTop="5dip"
android:singleLine="true"
android:text="@+id/TextView01"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textStyle="bold" />
</LinearLayout>

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Title of the app -->
<string name="app_name">Dolphin Emulator</string>
<!-- Navigation-related Strings -->
<string name="drawer_open">ナビゲーションウィンドウを開く</string>
<string name="drawer_close">ナビゲーションウィンドウを閉じる</string>
<!-- About Fragment -->
<string name="build_revision">ビルドのバージョン:</string>
<string name="supports_gles3">サポートのOpenGL ES 3</string>
<!-- Folder Browser -->
<string name="current_dir">現在のディレクトリ: </string>
<string name="parent_directory">親ディレクトリ</string>
<string name="folder">フォルダ</string>
<string name="file_size">ファイルサイズ: </string>
<string name="cant_use_compressed_filetypes">圧縮ファイル形式はサポートされていません</string>
<!-- Game List Activity -->
<string name="game_list">ゲームリスト</string>
<string name="browse_folder">フォルダの参照</string>
<string name="settings">設定</string>
<string name="gamepad_config">ゲームパッド設定</string>
<string name="about">について</string>
<!-- Game List Fragment -->
<string name="file_clicked">クリックされたファイル: </string>
<!-- Input Config Fragment -->
<string name="button_a">Aボタン</string>
<string name="button_b">Bボタン</string>
<string name="button_start">スタートボタン</string>
<string name="button_x">Xボタン</string>
<string name="button_y">Yボタン</string>
<string name="button_z">Zボタン</string>
<string name="dpad_up">D-Pad: ↑</string>
<string name="dpad_down">D-Pad: ↓</string>
<string name="dpad_left">D-Pad: ←</string>
<string name="dpad_right">D-Pad: →</string>
<string name="main_stick_up">コントロールスティック: ↑</string>
<string name="main_stick_down">コントロールスティック: ↓</string>
<string name="main_stick_left">コントロールスティック: ←</string>
<string name="main_stick_right">コントロールスティック: →</string>
<string name="c_stick_up">C-スティック: ↑</string>
<string name="c_stick_down">C-スティック: ↓</string>
<string name="c_stick_left">C-スティック: ←</string>
<string name="c_stick_right">C-スティック: →</string>
<string name="trigger_left">左のトリガー</string>
<string name="trigger_right">右のトリガー</string>
<string name="press_button_to_config">%1$sを設定するにはボタンを押して</string>
<!-- Prefs Fragment -->
<string name="interpreter">Interpreter</string>
<string name="jit64_recompiler">JIT64 Recompiler</string>
<string name="jitil_recompiler">JITIL Recompiler</string>
<string name="jit_arm_recompiler">JIT ARM Recompiler</string>
<string name="cpu_core">CPUコア</string>
<string name="cpu_settings">CPU設定</string>
<string name="emu_core_to_use">使用するエミュレーションコア</string>
<string name="dual_core">デュアルコア</string>
<string name="on_off">有効/無効</string>
<string name="video_settings">ビデオ設定</string>
<string name="software_renderer">Software Renderer</string>
<string name="opengl_es3">OpenGL ES 3</string>
<string name="video_backend">ビデオレンダラ</string>
<string name="video_backend_to_use">使用するビデオレンダラー</string>
<string name="draw_onscreen_controls">画面上のコントロールを描画</string>
<string name="enhancements">画質向上の設定</string>
<string name="internal_resolution">内部解像度の変更</string>
<string name="internal_resolution_descrip">内部解像度の計算方式を設定します。高解像度に設定することで大きく 画質が向上します。 しかし、ゲームによっては非常に重くなったり描画バグの原因となります。 【ゲーム解像度の倍数】は【ウィンドウサイズに拡大】より少し重くなり ますが、描画バグは発生しにくくなります。 また一般的に内部解像度が低いほど、動作速度は向上します。</string>
<string name="anisotropic_filtering">異方性フィルタリング</string>
<string name="anisotropic_filtering_descrip">異方性フィルタリングを適用します。 奥行きのあるテクスチャをより精細に描画することが出来ます。 特定のゲームでは描画バグの原因になることがあります。</string>
<string name="scaled_efb_copy">Scaled EFB Copy</string>
<string name="scaled_efb_copy_descrip">テクスチャエフェクトを表示するために作成されたテクスチャの品質を著しく向上させます。 特に高解像度出力時に効果が大きく出ます。 動作速度は少々低下し、まれに描画バグの原因にもなることもあります。</string>
<string name="per_pixel_lighting">Per-Pixel Lighting</string>
<string name="per_pixel_lighting_descrip">ピクセル単位での光源処理を行います。 GPUの性能にもよりますが、数パーセント程度、動作速度が低下します。 このオプションは通常安全ですが、時に描画バグを引き起こすこともあります</string>
<string name="force_texture_filtering">Force Texture Filtering</string>
<string name="force_texture_filtering_descrip">ゲーム側でフィルタ無効を明示している場面でも、強制的にフィルタリングを行います。 特に高解像度出力時にテクスチャが綺麗になりますが、いくつかのゲームで描画バグを引き起こします。</string>
<string name="disable_fog">霧を無効</string>
<string name="disable_fog_descrip">フォグ処理を無効化します。これにより遠景の高精細化が期待できます。いくつかのタイトルではフォグ処理に頼った画面効果が正しく表示 されなくなります。</string>
<string name="hacks">高速化(Hacks)</string>
<string name="embedded_frame_buffer">内蔵フレームバッファ</string>
<string name="skip_efb_access">CPUからEFBアクセスをスキップ</string>
<string name="skip_efb_access_descrip">EFBへの読み取り/書き込みにCPUから作られたすべての要求を無視。</string>
<string name="ignore_format_changes">フォーマットの変更を無視</string>
<string name="ignore_format_changes_descrip">EFB形式への変更を無視。</string>
<string name="efb_copy_method">EFBコピー方法</string>
<string name="efb_copy_method_descrip">EFBコピーをエミュレート方法を決定。</string>
<string name="efb_copy_texture">テクスチャ</string>
<string name="efb_copy_ram_uncached">RAM (キャッシュない)</string>
<string name="efb_copy_ram_cached">RAM (キャッシュ)</string>
<string name="texture_cache">テクスチャキャッシュ</string>
<string name="texture_cache_accuracy">テクスチャキャッシュ確度</string>
<string name="texture_cache_accuracy_descrip">この選択をSafe設定しておくと、RAMからのテクスチャ更新に 失敗しにくなります。</string>
<string name="texture_cache_accuracy_low"></string>
<string name="texture_cache_accuracy_medium"></string>
<string name="texture_cache_accuracy_high"></string>
<string name="external_frame_buffer">外部フレームバッファ</string>
<string name="external_frame_buffer_descrip">XFBをエミュレート方法を決定。</string>
<string name="external_frame_buffer_virtual">バーチャル</string>
<string name="external_frame_buffer_real">実機</string>
<string name="cache_display_lists">Cache Display Lists</string>
<string name="cache_display_lists_descrip">ディスプレイリストをキャッシュすることによりエミュレーション速度を向上。</string>
<string name="disable_destination_alpha">Disable Destination Alpha</string>
<string name="disable_destination_alpha_descrip">多くのタイトルで画面効果に使用されている、アルファ透過処理をスキップ 。</string>
<string name="fast_depth_calculation">高速奥行き計算</string>
<string name="fast_depth_calculation_descrip">深度値を計算するために精度の低いアルゴリズムを使用します。</string>
<!-- Miscellaneous -->
<string name="yes">はい</string>
<string name="no">いいえ</string>
<string name="disabled">無効</string>
<string name="other">その他</string>
</resources>

View File

@ -0,0 +1,128 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- All lists for ListPreference keys/values are placed here -->
<resources>
<!-- CPU core selection - X86 -->
<string-array name="emuCoreEntriesX86" translatable="false">
<item>@string/interpreter</item>
<item>@string/jit64_recompiler</item>
<item>@string/jitil_recompiler</item>
</string-array>
<string-array name="emuCoreValuesX86" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<!-- CPU core selection - ARM -->
<string-array name="emuCoreEntriesARM" translatable="false">
<item>@string/interpreter</item>
<item>@string/jit_arm_recompiler</item>
</string-array>
<string-array name="emuCoreValuesARM" translatable="false">
<item>0</item>
<item>3</item>
</string-array>
<!-- CPU core selection - Other -->
<string-array name="emuCoreEntriesOther" translatable="false">
<item>@string/interpreter</item>
</string-array>
<string-array name="emuCoreValuesOther" translatable="false">
<item>0</item>
</string-array>
<!-- Video Backend Selection - Supports OpenGL ES 3 -->
<string-array name="videoBackendEntriesGLES3" translatable="false">
<item>@string/software_renderer</item>
<item>@string/opengl_es3</item>
</string-array>
<string-array name="videoBackendValuesGLES3" translatable="false">
<item>Software Renderer</item>
<item>OGL</item>
</string-array>
<!-- Video Backend Selection - No OpenGL ES 3 support -->
<string-array name="videoBackendEntriesNoGLES3" translatable="false">
<item>@string/software_renderer</item>
</string-array>
<string-array name="videoBackendValuesNoGLES3" translatable="false">
<item>Software Renderer</item>
</string-array>
<!-- EFB Copy Method Preference -->
<string-array name="efbCopyMethodEntries" translatable="false">
<item>@string/disabled</item>
<item>@string/efb_copy_texture</item>
<item>@string/efb_copy_ram_uncached</item>
<item>@string/efb_copy_ram_cached</item>
</string-array>
<string-array name="efbCopyMethodValues" translatable="false">
<item>Off</item>
<item>Texture</item>
<item>RAM (cached)</item>
<item>RAM (uncached)</item>
</string-array>
<!-- Texture Cache Accuracy Preference -->
<string-array name="textureCacheAccuracyEntries" translatable="false">
<item>@string/texture_cache_accuracy_low</item>
<item>@string/texture_cache_accuracy_medium</item>
<item>@string/texture_cache_accuracy_high</item>
</string-array>
<string-array name="textureCacheAccuracyValues" translatable="false">
<item>128</item>
<item>512</item>
<item>0</item>
</string-array>
<!-- External Frame Buffer Preference -->
<string-array name="externalFrameBufferEntries" translatable="false">
<item>@string/disabled</item>
<item>@string/external_frame_buffer_virtual</item>
<item>@string/external_frame_buffer_real</item>
</string-array>
<string-array name="externalFrameBufferValues" translatable="false">
<item>Disabled</item>
<item>Virtual</item>
<item>Real</item>
</string-array>
<!-- Internal Resolution Preference -->
<string-array name="internalResolutionEntries" translatable="false">
<item>1x Native (640x528)</item>
<item>1.5x Native (960x792)</item>
<item>2x Native (1280x1056)</item>
<item>2.5x Native (1600x1320)</item>
<item>3x Native (1920x1584)</item>
<item>4x Native (2560x2112)</item>
</string-array>
<string-array name="internalResolutionValues" translatable="false">
<item>2</item>
<item>3</item>
<item>4</item>
<item>5</item>
<item>6</item>
<item>7</item>
</string-array>
<!-- Anisotropic Filtering Preference -->
<string-array name="anisotropicFilteringEntries" translatable="false">
<item>1x</item>
<item>2x</item>
<item>4x</item>
<item>8x</item>
<item>16x</item>
</string-array>
<string-array name="anisotropicFilteringValues" translatable="false">
<item>0</item>
<item>1</item>
<item>2</item>
<item>3</item>
<item>4</item>
</string-array>
</resources>

View File

@ -1,12 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="gpuOptions">
<item>Software Renderer</item>
<item>OpenGL ES 3</item>
</string-array>
<string-array name="gpuValues">
<item>Software Renderer</item>
<item>OGL</item>
</string-array>
</resources>

View File

@ -1,8 +1,121 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Title of the app -->
<string name="app_name">Dolphin Emulator</string>
<!-- Navigation-related Strings -->
<string name="drawer_open">Open navigation drawer</string>
<string name="drawer_close">Close navigation drawer</string>
<!-- About Fragment -->
<string name="build_revision">Build Revision:</string>
<string name="supports_gles3">Supports OpenGL ES 3:</string>
<!-- Folder Browser -->
<string name="current_dir">Current Dir: </string>
<string name="parent_directory">Parent Directory</string>
<string name="folder">Folder</string>
<string name="file_size">File Size: </string>
<string name="cant_use_compressed_filetypes">Can not use compressed file types</string>
<!-- Game List Activity -->
<string name="game_list">Game List</string>
<string name="browse_folder">Browse Folder</string>
<string name="settings">Settings</string>
<string name="gamepad_config">Gamepad Config</string>
<string name="about">About</string>
<!-- Game List Fragment -->
<string name="file_clicked">File clicked: </string>
<!-- Input Config Fragment -->
<string name="button_a">Button A</string>
<string name="button_b">Button B</string>
<string name="button_start">Button Start</string>
<string name="button_x">Button X</string>
<string name="button_y">Button Y</string>
<string name="button_z">Button Z</string>
<string name="dpad_up">D-Pad Up</string>
<string name="dpad_down">D-Pad Down</string>
<string name="dpad_left">D-Pad Left</string>
<string name="dpad_right">D-Pad Right</string>
<string name="main_stick_up">Main Stick Up</string>
<string name="main_stick_down">Main Stick Down</string>
<string name="main_stick_left">Main Stick Left</string>
<string name="main_stick_right">Main Stick Right</string>
<string name="c_stick_up">C Stick Up</string>
<string name="c_stick_down">C Stick Down</string>
<string name="c_stick_left">C Stick Left</string>
<string name="c_stick_right">C Stick Right</string>
<string name="trigger_left">Trigger L</string>
<string name="trigger_right">Trigger R</string>
<string name="press_button_to_config">Press button to configure %1$s</string>
<!-- Preference Related -->
<string name="interpreter">Interpreter</string>
<string name="jit64_recompiler">JIT64 Recompiler</string>
<string name="jitil_recompiler">JITIL Recompiler</string>
<string name="jit_arm_recompiler">JIT ARM Recompiler</string>
<string name="cpu_core">CPU Core</string>
<string name="cpu_settings">CPU Settings</string>
<string name="emu_core_to_use">Emulation core to use</string>
<string name="dual_core">Dual Core</string>
<string name="on_off">On/Off</string>
<string name="video_settings">Video Settings</string>
<string name="software_renderer">Software Renderer</string>
<string name="opengl_es3">OpenGL ES 3</string>
<string name="video_backend">Video Backend</string>
<string name="video_backend_to_use">Video backend to use</string>
<string name="draw_onscreen_controls">Draw on-screen controls</string>
<string name="enhancements">Enhancements</string>
<string name="internal_resolution">Internal Resolution</string>
<string name="internal_resolution_descrip">Specifies the resolution used to render at. A high resolution will improve visual quality a lot but is also quite heavy on performance and might cause glitches in certain games.</string>
<string name="anisotropic_filtering">Anisotropic Filtering</string>
<string name="anisotropic_filtering_descrip">Enhances visual quality of textures that are at oblique viewing angles. Might cause issues in a small number of games.</string>
<string name="scaled_efb_copy">Scaled EFB Copy</string>
<string name="scaled_efb_copy_descrip">Greatly increases quality of textures generated using render to texture effects. Raising the internal resolution will improve the effect of this setting. Slightly decreases performance and possibly causes issues (although unlikely).</string>
<string name="per_pixel_lighting">Per-Pixel Lighting</string>
<string name="per_pixel_lighting_descrip">Calculate lighting of 3D graphics per-pixel rather than per vertex. Decreases emulation speed by some percent (depending on your GPU). This usually is a safe enhancement, but might cause issues sometimes.</string>
<string name="force_texture_filtering">Force Texture Filtering</string>
<string name="force_texture_filtering_descrip">Force texture filtering even if the emulated game explicitly disabled it. Improves texture quality slightly but causes glitches in some games.</string>
<string name="disable_fog">Disable Fog</string>
<string name="disable_fog_descrip">Makes distant objects more visible by removing fog, thus increasing the overall detail. Disabling fog will break some games which rely on proper fog emulation.</string>
<string name="hacks">Hacks</string>
<string name="embedded_frame_buffer">Embedded Frame Buffer</string>
<string name="skip_efb_access">Skip EFB Access from CPU</string>
<string name="skip_efb_access_descrip">Ignore any requests from the CPU to read/write to the EFB.</string>
<string name="ignore_format_changes">Ignore Format Changes</string>
<string name="ignore_format_changes_descrip">Ignore any changes to the EFB format.</string>
<string name="efb_copy_method">EFB Copy Method</string>
<string name="efb_copy_method_descrip">Determines how EFB copies will be emulated.</string>
<string name="efb_copy_texture">Texture</string>
<string name="efb_copy_ram_uncached">RAM (uncached)</string>
<string name="efb_copy_ram_cached">RAM (cached)</string>
<string name="texture_cache">Texture Cache</string>
<string name="texture_cache_accuracy">Texture Cache Accuracy</string>
<string name="texture_cache_accuracy_descrip">The safer the selection, the less likely the emulator will be missing any texture updates from RAM.</string>
<string name="texture_cache_accuracy_low">Low</string>
<string name="texture_cache_accuracy_medium">Medium</string>
<string name="texture_cache_accuracy_high">High</string>
<string name="external_frame_buffer">External Frame Buffer</string>
<string name="external_frame_buffer_descrip">Determines how the XFB will be emulated.</string>
<string name="external_frame_buffer_virtual">Virtual</string>
<string name="external_frame_buffer_real">Real</string>
<string name="cache_display_lists">Cache Display Lists</string>
<string name="cache_display_lists_descrip">Speeds up emulation a bit by caching display lists.</string>
<string name="disable_destination_alpha">Disable Destination Alpha</string>
<string name="disable_destination_alpha_descrip">Disables emulation of a hardware feature called destination alpha, which is used in many games for various effects.</string>
<string name="fast_depth_calculation">Fast Depth Calculation</string>
<string name="fast_depth_calculation_descrip">Uses a less accurate algorithm to calculate depth values.</string>
<!-- Miscellaneous -->
<string name="yes">Yes</string>
<string name="no">No</string>
<string name="disabled">Disabled</string>
<string name="other">Other</string>
</resources>

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- CPU Settings -->
<CheckBoxPreference
android:key="dualCorePref"
android:summary="@string/on_off"
android:title="@string/dual_core" />
<ListPreference
android:key="cpuCorePref"
android:summary="@string/emu_core_to_use"
android:title="@string/cpu_core" />
</PreferenceScreen>

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Video Settings -->
<!-- Video Enhancements -->
<PreferenceScreen android:title="@string/enhancements">
<ListPreference
android:entries="@array/internalResolutionEntries"
android:entryValues="@array/internalResolutionValues"
android:key="internalResolution"
android:summary="@string/internal_resolution_descrip"
android:title="@string/internal_resolution"/>
<ListPreference
android:entries="@array/anisotropicFilteringEntries"
android:entryValues="@array/anisotropicFilteringValues"
android:key="anisotropicFiltering"
android:summary="@string/anisotropic_filtering_descrip"
android:title="@string/anisotropic_filtering"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="scaledEFBCopy"
android:summary="@string/scaled_efb_copy_descrip"
android:title="@string/scaled_efb_copy"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="perPixelLighting"
android:summary="@string/per_pixel_lighting_descrip"
android:title="@string/per_pixel_lighting"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="forceTextureFiltering"
android:summary="@string/force_texture_filtering_descrip"
android:title="@string/force_texture_filtering"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="disableFog"
android:summary="@string/disable_fog_descrip"
android:title="@string/disable_fog"/>
</PreferenceScreen>
<!-- Video Hacks -->
<PreferenceScreen android:title="@string/hacks">
<PreferenceCategory android:title="@string/embedded_frame_buffer">
<CheckBoxPreference
android:defaultValue="false"
android:key="skipEFBAccess"
android:summary="@string/skip_efb_access_descrip"
android:title="@string/skip_efb_access"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="ignoreFormatChanges"
android:summary="@string/ignore_format_changes_descrip"
android:title="@string/ignore_format_changes"/>
<ListPreference
android:defaultValue="Texture"
android:entries="@array/efbCopyMethodEntries"
android:entryValues="@array/efbCopyMethodValues"
android:key="efbCopyMethod"
android:summary="@string/efb_copy_method_descrip"
android:title="@string/efb_copy_method"/>
</PreferenceCategory>
<!-- Texture Cache -->
<PreferenceCategory android:title="@string/texture_cache">
<ListPreference
android:defaultValue="Low"
android:entries="@array/textureCacheAccuracyEntries"
android:entryValues="@array/textureCacheAccuracyValues"
android:key="textureCacheAccuracy"
android:summary="@string/texture_cache_accuracy_descrip"
android:title="@string/texture_cache_accuracy"/>
</PreferenceCategory>
<!-- External Frame Buffer -->
<PreferenceCategory android:title="@string/external_frame_buffer">
<ListPreference
android:defaultValue="Disabled"
android:entries="@array/externalFrameBufferEntries"
android:entryValues="@array/externalFrameBufferValues"
android:key="externalFrameBuffer"
android:summary="@string/external_frame_buffer_descrip"
android:title="@string/external_frame_buffer"/>
</PreferenceCategory>
<!-- Other Hacks -->
<PreferenceCategory android:title="@string/other">
<CheckBoxPreference
android:defaultValue="false"
android:key="cacheDisplayLists"
android:summary="@string/cache_display_lists_descrip"
android:title="@string/cache_display_lists"/>
<CheckBoxPreference
android:defaultValue="false"
android:key="disableDestinationAlpha"
android:summary="@string/disable_destination_alpha_descrip"
android:title="@string/disable_destination_alpha"/>
<CheckBoxPreference
android:defaultValue="true"
android:key="fastDepthCalculation"
android:summary="@string/fast_depth_calculation_descrip"
android:title="@string/fast_depth_calculation"/>
</PreferenceCategory>
</PreferenceScreen>
<ListPreference
android:key="gpuPref"
android:summary="@string/video_backend_to_use"
android:title="@string/video_backend" />
<CheckBoxPreference
android:defaultValue="true"
android:key="drawOnscreenControls"
android:title="@string/draw_onscreen_controls"/>
</PreferenceScreen>

View File

@ -11,50 +11,53 @@ import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
import org.dolphinemu.dolphinemu.folderbrowser.FolderBrowserAdapter;
import org.dolphinemu.dolphinemu.folderbrowser.FolderBrowserItem;
import org.dolphinemu.dolphinemu.settings.VideoSettingsFragment;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
public class AboutFragment extends Fragment {
public final class AboutFragment extends Fragment
{
private static Activity m_activity;
private ListView mMainList;
private FolderBrowserAdapter adapter;
private int configPosition = 0;
boolean Configuring = false;
boolean firstEvent = true;
public AboutFragment() {
// Empty constructor required for fragment subclasses
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
mMainList = (ListView) rootView.findViewById(R.id.gamelist);
String yes = getString(R.string.yes);
String no = getString(R.string.no);
List<GameListItem> Input = new ArrayList<GameListItem>();
int a = 0;
List<FolderBrowserItem> Input = new ArrayList<FolderBrowserItem>();
Input.add(new FolderBrowserItem(getString(R.string.build_revision), NativeLibrary.GetVersionString(), "", true));
Input.add(new FolderBrowserItem(getString(R.string.supports_gles3), VideoSettingsFragment.SupportsGLES3() ? yes : no, "", true));
Input.add(a++, new GameListItem(m_activity, "Build Revision", NativeLibrary.GetVersionString(), "", true));
Input.add(a++, new GameListItem(m_activity, "Supports OpenGL ES 3", PrefsFragment.SupportsGLES3() ? "Yes" : "No", "", true));
adapter = new FolderBrowserAdapter(m_activity, R.layout.folderbrowser, Input);
adapter = new FolderBrowserAdapter(m_activity, R.layout.about_layout, Input);
mMainList.setAdapter(adapter);
return mMainList;
}
@Override
public void onAttach(Activity activity) {
public void onAttach(Activity activity)
{
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
try
{
m_activity = activity;
} catch (ClassCastException e) {
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString()
+ " must implement OnGameListZeroListener");
}

View File

@ -3,10 +3,8 @@ package org.dolphinemu.dolphinemu;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.InputDevice;
@ -17,39 +15,48 @@ import android.view.WindowManager;
import java.io.*;
import java.util.List;
public class DolphinEmulator<MainActivity> extends Activity
{
static private NativeGLSurfaceView GLview = null;
static private boolean Running = false;
import org.dolphinemu.dolphinemu.gamelist.GameListActivity;
import org.dolphinemu.dolphinemu.inputconfig.InputConfigFragment;
import org.dolphinemu.dolphinemu.settings.UserPreferences;
public final class DolphinEmulator<MainActivity> extends Activity
{
private static NativeGLSurfaceView GLview = null;
private static boolean Running = false;
private float screenWidth;
private float screenHeight;
private void CopyAsset(String asset, String output) {
InputStream in = null;
OutputStream out = null;
try {
in = getAssets().open(asset);
out = new FileOutputStream(output);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch(IOException e) {
Log.e("tag", "Failed to copy asset file: " + asset, e);
}
private void CopyAsset(String asset, String output)
{
InputStream in = null;
OutputStream out = null;
try
{
in = getAssets().open(asset);
out = new FileOutputStream(output);
copyFile(in, out);
in.close();
out.close();
}
catch (IOException e)
{
Log.e("DolphinEmulator", "Failed to copy asset file: " + asset, e);
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while((read = in.read(buffer)) != -1){
out.write(buffer, 0, read);
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}
@Override
public void onStop()
{
@ -57,6 +64,7 @@ public class DolphinEmulator<MainActivity> extends Activity
if (Running)
NativeLibrary.StopEmulation();
}
@Override
public void onPause()
{
@ -64,6 +72,7 @@ public class DolphinEmulator<MainActivity> extends Activity
if (Running)
NativeLibrary.PauseEmulation();
}
@Override
public void onResume()
{
@ -72,21 +81,21 @@ public class DolphinEmulator<MainActivity> extends Activity
NativeLibrary.UnPauseEmulation();
}
/** Called when the activity is first created. */
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
{
Intent ListIntent = new Intent(this, GameListActivity.class);
startActivityForResult(ListIntent, 1);
// Make the assets directory
String BaseDir = Environment.getExternalStorageDirectory()+File.separator+"dolphin-emu";
File directory = new File(BaseDir);
directory.mkdirs();
String ConfigDir = BaseDir + File.separator + "Config";
directory = new File(ConfigDir);
directory.mkdirs();
@ -95,50 +104,31 @@ public class DolphinEmulator<MainActivity> extends Activity
directory = new File(GCDir);
directory.mkdirs();
String WiiDir = BaseDir + File.separator + "Wii";
directory = new File(WiiDir);
directory.mkdirs();
// Copy assets if needed
java.io.File file = new java.io.File(
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "GC" + File.separator + "dsp_coef.bin");
File file = new File(WiiDir + File.separator + "setting-usa.txt");
if(!file.exists())
{
CopyAsset("ButtonA.png",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "ButtonA.png");
CopyAsset("ButtonB.png",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "ButtonB.png");
CopyAsset("ButtonStart.png",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "ButtonStart.png");
CopyAsset("NoBanner.png",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "NoBanner.png");
CopyAsset("GCPadNew.ini",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "Config" + File.separator + "GCPadNew.ini");
CopyAsset("Dolphin.ini",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "Config" + File.separator + "Dolphin.ini");
CopyAsset("dsp_coef.bin",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "GC" + File.separator + "dsp_coef.bin");
CopyAsset("dsp_rom.bin",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "GC" + File.separator + "dsp_rom.bin");
CopyAsset("font_ansi.bin",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "GC" + File.separator + "font_ansi.bin");
CopyAsset("font_sjis.bin",
Environment.getExternalStorageDirectory()+File.separator+
"dolphin-emu" + File.separator + "GC" + File.separator + "font_sjis.bin");
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = prefs.edit();
editor.putString("cpupref", NativeLibrary.GetConfig("Dolphin.ini", "Core", "CPUCore", "3"));
editor.putBoolean("dualcorepref", NativeLibrary.GetConfig("Dolphin.ini", "Core", "CPUThread", "False").equals("True") ? true : false);
editor.putString("gpupref", NativeLibrary.GetConfig("Dolphin.ini", "Core", "GFXBackend ", "Software Renderer"));
editor.commit();
CopyAsset("ButtonA.png", BaseDir + File.separator + "ButtonA.png");
CopyAsset("ButtonB.png", BaseDir + File.separator + "ButtonB.png");
CopyAsset("ButtonStart.png", BaseDir + File.separator + "ButtonStart.png");
CopyAsset("NoBanner.png", BaseDir + File.separator + "NoBanner.png");
CopyAsset("GCPadNew.ini", ConfigDir + File.separator + "GCPadNew.ini");
CopyAsset("Dolphin.ini", ConfigDir + File.separator + "Dolphin.ini");
CopyAsset("dsp_coef.bin", GCDir + File.separator + "dsp_coef.bin");
CopyAsset("dsp_rom.bin", GCDir + File.separator + "dsp_rom.bin");
CopyAsset("font_ansi.bin", GCDir + File.separator + "font_ansi.bin");
CopyAsset("font_sjis.bin", GCDir + File.separator + "font_sjis.bin");
CopyAsset("setting-eur.txt", WiiDir + File.separator + "setting-eur.txt");
CopyAsset("setting-jpn.txt", WiiDir + File.separator + "setting-jpn.txt");
CopyAsset("setting-kor.txt", WiiDir + File.separator + "setting-kor.txt");
CopyAsset("setting-usa.txt", WiiDir + File.separator + "setting-usa.txt");
}
UserPreferences.LoadDolphinConfigToPrefs(this);
}
}
@ -154,30 +144,25 @@ public class DolphinEmulator<MainActivity> extends Activity
wm.getDefaultDisplay().getMetrics(displayMetrics);
screenWidth = displayMetrics.widthPixels;
screenHeight = displayMetrics.heightPixels;
String FileName = data.getStringExtra("Select");
GLview = new NativeGLSurfaceView(this);
this.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
String backend = NativeLibrary.GetConfig("Dolphin.ini", "Core", "GFXBackend", "Software Renderer");
if (backend.equals("OGL"))
GLview.SetDimensions(screenHeight, screenWidth);
else
GLview.SetDimensions(screenWidth, screenHeight);
GLview.SetFileName(FileName);
NativeLibrary.SetDimensions((int)screenWidth, (int)screenHeight);
NativeLibrary.SetFilename(FileName);
setContentView(GLview);
Running = true;
}
}
@Override
public boolean onTouchEvent(MotionEvent event)
{
float X, Y;
int Action;
X = event.getX();
Y = event.getY();
Action = event.getActionMasked();
float X = event.getX();
float Y = event.getY();
int Action = event.getActionMasked();
// Converts button locations 0 - 1 to OGL screen coords -1.0 - 1.0
float ScreenX = ((X / screenWidth) * 2.0f) - 1.0f;
float ScreenY = ((Y / screenHeight) * -2.0f) + 1.0f;
@ -189,7 +174,8 @@ public class DolphinEmulator<MainActivity> extends Activity
// Gets button presses
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
public boolean dispatchKeyEvent(KeyEvent event)
{
int action = 0;
// Special catch for the back key
@ -211,7 +197,8 @@ public class DolphinEmulator<MainActivity> extends Activity
if (Running)
{
switch (event.getAction()) {
switch (event.getAction())
{
case KeyEvent.ACTION_DOWN:
action = 0;
break;
@ -229,21 +216,21 @@ public class DolphinEmulator<MainActivity> extends Activity
}
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) || !Running) {
public boolean dispatchGenericMotionEvent(MotionEvent event)
{
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0) || !Running)
{
return super.dispatchGenericMotionEvent(event);
}
InputDevice input = event.getDevice();
List<InputDevice.MotionRange> motions = input.getMotionRanges();
for (int a = 0; a < motions.size(); ++a)
for (InputDevice.MotionRange range : motions)
{
InputDevice.MotionRange range;
range = motions.get(a);
NativeLibrary.onGamePadMoveEvent(InputConfigFragment.getInputDesc(input), range.getAxis(), event.getAxisValue(range.getAxis()));
}
return true;
}
}
}

View File

@ -1,58 +0,0 @@
package org.dolphinemu.dolphinemu;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
public class FolderBrowserAdapter extends ArrayAdapter<GameListItem>{
private Context c;
private int id;
private List<GameListItem>items;
public FolderBrowserAdapter(Context context, int textViewResourceId,
List<GameListItem> objects) {
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
public GameListItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
final GameListItem o = items.get(position);
if (o != null) {
TextView t1 = (TextView) v.findViewById(R.id.FolderTitle);
TextView t2 = (TextView) v.findViewById(R.id.FolderSubTitle);
if(t1!=null)
{
t1.setText(o.getName());
if (!o.isValid())
t1.setTextColor(0xFFFF0000);
}
if(t2!=null)
t2.setText(o.getData());
}
return v;
}
}

View File

@ -1,55 +0,0 @@
package org.dolphinemu.dolphinemu;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
public class GameListAdapter extends ArrayAdapter<GameListItem>{
private Context c;
private int id;
private List<GameListItem>items;
public GameListAdapter(Context context, int textViewResourceId, List<GameListItem> objects) {
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
public GameListItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
final GameListItem o = items.get(position);
if (o != null) {
TextView t1 = (TextView) v.findViewById(R.id.GameItemTitle);
TextView t2 = (TextView) v.findViewById(R.id.GameItemSubText);
ImageView v1 = (ImageView) v.findViewById(R.id.GameItemIcon);
if(t1!=null)
t1.setText(o.getName());
if(t2!=null)
t2.setText(o.getData());
if(v1!=null)
v1.setImageBitmap(o.getImage());
}
return v;
}
}

View File

@ -1,76 +0,0 @@
package org.dolphinemu.dolphinemu;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
public class GameListItem implements Comparable<GameListItem>{
private String name;
private String data;
private String path;
private Bitmap image;
private boolean m_valid;
public GameListItem(Context ctx, String n,String d,String p, boolean valid)
{
name = n;
data = d;
path = p;
m_valid = valid;
File file = new File(path);
if (!file.isDirectory() && !path.equals(""))
{
int[] Banner = NativeLibrary.GetBanner(path);
if (Banner[0] == 0)
{
try {
InputStream path = ctx.getAssets().open("NoBanner.png");
image = BitmapFactory.decodeStream(path);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
else
image = Bitmap.createBitmap(Banner, 96, 32, Bitmap.Config.ARGB_8888);
name = NativeLibrary.GetTitle(path);
}
}
public String getName()
{
return name;
}
public String getData()
{
return data;
}
public String getPath()
{
return path;
}
public Bitmap getImage()
{
return image;
}
public boolean isValid()
{
return m_valid;
}
public int compareTo(GameListItem o)
{
if(this.name != null)
return this.name.toLowerCase().compareTo(o.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -1,56 +0,0 @@
package org.dolphinemu.dolphinemu;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
public class InputConfigAdapter extends ArrayAdapter<InputConfigItem> {
private Context c;
private int id;
private List<InputConfigItem> items;
public InputConfigAdapter(Context context, int textViewResourceId,
List<InputConfigItem> objects) {
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
public InputConfigItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
final InputConfigItem o = items.get(position);
if (o != null) {
TextView t1 = (TextView) v.findViewById(R.id.FolderTitle);
TextView t2 = (TextView) v.findViewById(R.id.FolderSubTitle);
if(t1!=null)
t1.setText(o.getName());
if(t2!=null)
t2.setText(o.getBind());
}
return v;
}
}

View File

@ -1,56 +0,0 @@
package org.dolphinemu.dolphinemu;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
public class InputConfigItem implements Comparable<InputConfigItem>{
private String m_name;
private String m_Config;
private String m_bind;
private void Init(String n, String c, String d)
{
m_name = n;
m_Config = c;
String ConfigValues[] = m_Config.split("-");
String Key = ConfigValues[0];
String Value = ConfigValues[1];
m_bind = NativeLibrary.GetConfig("Dolphin.ini", Key, Value, d);
}
public InputConfigItem(String n, String c, String d)
{
Init(n, c, d);
}
public InputConfigItem(String n, String c)
{
Init(n, c, "None");
}
public String getName()
{
return m_name;
}
public String getConfig()
{
return m_Config;
}
public String getBind()
{
return m_bind;
}
public void setBind(String b)
{
m_bind = b;
}
public int compareTo(InputConfigItem o)
{
if(this.m_name != null)
return this.m_name.toLowerCase().compareTo(o.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -4,58 +4,57 @@ import android.content.Context;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
public class NativeGLSurfaceView extends SurfaceView {
static private String FileName;
static private Thread myRun;
static private boolean Running = false;
static private boolean Created = false;
static private float width;
static private float height;
/**
* The surface that rendering is done to.
*/
public final class NativeGLSurfaceView extends SurfaceView
{
private static Thread myRun;
private static boolean Running = false;
private static boolean Created = false;
public NativeGLSurfaceView(Context context) {
/**
* Constructor.
*
* @param context The current {@link Context}.
*/
public NativeGLSurfaceView(Context context)
{
super(context);
if (!Created)
{
myRun = new Thread()
{
@Override
public void run() {
NativeLibrary.Run(FileName, getHolder().getSurface(), (int)width, (int)height);
}
public void run() {
NativeLibrary.Run(getHolder().getSurface());
}
};
getHolder().addCallback(new SurfaceHolder.Callback() {
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
if (!Running)
{
myRun.start();
Running = true;
}
}
public void surfaceChanged(SurfaceHolder arg0, int arg1,
int arg2, int arg3) {
getHolder().addCallback(new SurfaceHolder.Callback()
{
public void surfaceCreated(SurfaceHolder holder)
{
// TODO Auto-generated method stub
if (!Running)
{
myRun.start();
Running = true;
}
}
public void surfaceDestroyed(SurfaceHolder arg0) {
public void surfaceChanged(SurfaceHolder arg0, int arg1, int arg2, int arg3)
{
// TODO Auto-generated method stub
}
public void surfaceDestroyed(SurfaceHolder arg0)
{
// TODO Auto-generated method stub
}
});
Created = true;
}
}
public void SetFileName(String file)
{
FileName = file;
}
public void SetDimensions(float screenWidth, float screenHeight)
{
width = screenWidth;
height = screenHeight;
}
}

View File

@ -1,24 +1,32 @@
/*
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu;
import android.util.Log;
import android.view.Surface;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
* Class which contains methods that interact
* with the native side of the Dolphin code.
*/
public class NativeLibrary {
public final class NativeLibrary
{
public static native void onTouchEvent(int Action, float X, float Y);
public static native void onGamePadEvent(String Device, int Button, int Action);
public static native void onGamePadMoveEvent(String Device, int Axis, float Value);
public static native String GetConfig(String configFile, String Key, String Value, String Default);
public static native void SetConfig(String configFile, String Key, String Value, String Default);
public static native void SetFilename(String filename);
public static native void SetDimensions(int width, int height);
public static native int[] GetBanner(String filename);
public static native String GetTitle(String filename);
public static native String GetVersionString();
public static native void Run(String File, Surface surf, int width, int height);
public static native void Run(Surface surf);
public static native void UnPauseEmulation();
public static native void PauseEmulation();
public static native void StopEmulation();
@ -27,11 +35,11 @@ public class NativeLibrary {
{
try
{
System.loadLibrary("dolphin-emu-nogui");
System.loadLibrary("main");
}
catch (Exception ex)
catch (UnsatisfiedLinkError ex)
{
Log.w("me", ex.toString());
Log.w("NativeLibrary", ex.toString());
}
}
}

View File

@ -1,211 +0,0 @@
package org.dolphinemu.dolphinemu;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceCategory;
import android.preference.PreferenceFragment;
import javax.microedition.khronos.egl.*;
import javax.microedition.khronos.opengles.GL10;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
public class PrefsFragment extends PreferenceFragment {
private Activity m_activity;
static public class VersionCheck {
EGL10 mEGL;
EGLDisplay mEGLDisplay;
EGLConfig[] mEGLConfigs;
EGLConfig mEGLConfig;
EGLContext mEGLContext;
EGLSurface mEGLSurface;
GL10 mGL;
String mThreadOwner;
public VersionCheck() {
int[] version = new int[2];
int[] attribList = new int[] {
EGL10.EGL_WIDTH, 1,
EGL10.EGL_HEIGHT, 1,
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_NONE
};
// No error checking performed, minimum required code to elucidate logic
mEGL = (EGL10) EGLContext.getEGL();
mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
mEGL.eglInitialize(mEGLDisplay, version);
mEGLConfig = chooseConfig(); // Choosing a config is a little more complicated
mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT, null);
mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, attribList);
mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
mGL = (GL10) mEGLContext.getGL();
// Record thread owner of OpenGL context
mThreadOwner = Thread.currentThread().getName();
}
public String getVersion()
{
return mGL.glGetString(GL10.GL_VERSION);
}
public String getVendor()
{
return mGL.glGetString(GL10.GL_VENDOR);
}
public String getRenderer()
{
return mGL.glGetString(GL10.GL_RENDERER);
}
private EGLConfig chooseConfig() {
int[] attribList = new int[] {
EGL10.EGL_DEPTH_SIZE, 0,
EGL10.EGL_STENCIL_SIZE, 0,
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_NONE
};
// No error checking performed, minimum required code to elucidate logic
// Expand on this logic to be more selective in choosing a configuration
int[] numConfig = new int[1];
mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig);
int configSize = numConfig[0];
mEGLConfigs = new EGLConfig[configSize];
mEGL.eglChooseConfig(mEGLDisplay, attribList, mEGLConfigs, configSize, numConfig);
return mEGLConfigs[0]; // Best match is probably the first configuration
}
}
static public boolean SupportsGLES3()
{
String m_GLVersion;
String m_GLVendor;
String m_GLRenderer;
VersionCheck mbuffer = new VersionCheck();
m_GLVersion = mbuffer.getVersion();
m_GLVendor = mbuffer.getVendor();
m_GLRenderer = mbuffer.getRenderer();
boolean mSupportsGLES3 = false;
if (m_GLVersion.contains("OpenGL ES 3.0")) // 3.0 support
mSupportsGLES3 = true;
if (!mSupportsGLES3 && m_GLVendor.equals("Qualcomm"))
{
if (m_GLRenderer.contains("Adreno (TM) 3"))
{
int mVStart, mVEnd = 0;
float mVersion;
mVStart = m_GLVersion.indexOf("V@") + 2;
for (int a = mVStart; a < m_GLVersion.length(); ++a)
if (m_GLVersion.charAt(a) == ' ')
{
mVEnd = a;
break;
}
mVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd));
if (mVersion >= 14.0f)
mSupportsGLES3 = true;
}
}
return mSupportsGLES3;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.layout.prefs);
final ListPreference etp = new ListPreference(m_activity);
CharSequence[] _entries;
CharSequence[] _entryvalues;
if (Build.CPU_ABI.contains("x86"))
{
_entries = new CharSequence[] {
"Interpreter",
"JIT64 Recompiler",
"JITIL Recompiler",
};
_entryvalues = new CharSequence[] {"0", "1", "2"};
}
else if (Build.CPU_ABI.contains("arm"))
{
_entries = new CharSequence[] {
"Interpreter",
"JIT ARM Recompiler",
};
_entryvalues = new CharSequence[] {"0", "3"};
}
else
{
_entries = new CharSequence[] {
"Interpreter",
};
_entryvalues = new CharSequence[] {"0"};
}
etp.setEntries(_entries);
etp.setEntryValues(_entryvalues);
etp.setKey("cpupref");
etp.setTitle("CPU Core");
etp.setSummary("Emulation core to use");
PreferenceCategory mCategory = (PreferenceCategory) findPreference("cpuprefcat");
mCategory.addPreference(etp);
boolean mSupportsGLES3 = SupportsGLES3();
if (!mSupportsGLES3)
{
mCategory = (PreferenceCategory) findPreference("videoprefcat");
ListPreference mPref = (ListPreference) findPreference("gpupref");
mCategory.removePreference(mPref);
final ListPreference videobackend = new ListPreference(m_activity);
_entries = new CharSequence[] {
"Software Renderer",
};
_entryvalues = new CharSequence[] {"Software Renderer"};
videobackend.setKey("gpupref");
videobackend.setTitle("Video Backend");
videobackend.setSummary("Video backend to use");
videobackend.setEntries(_entries);
videobackend.setEntryValues(_entryvalues);
mCategory.addPreference(videobackend);
}
}
@Override
public void onAttach(Activity activity) {
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
m_activity = activity;
} catch (ClassCastException e) {
throw new ClassCastException(activity.toString()
+ " must implement OnGameListZeroListener");
}
}
}

View File

@ -1,49 +0,0 @@
package org.dolphinemu.dolphinemu;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
public class SideMenuAdapter extends ArrayAdapter<SideMenuItem>{
private Context c;
private int id;
private List<SideMenuItem>items;
public SideMenuAdapter(Context context, int textViewResourceId,
List<SideMenuItem> objects) {
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
public SideMenuItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View v = convertView;
if (v == null) {
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
final SideMenuItem o = items.get(position);
if (o != null) {
TextView t1 = (TextView) v.findViewById(R.id.SideMenuTitle);
if(t1!=null)
t1.setText(o.getName());
}
return v;
}
}

View File

@ -1,36 +0,0 @@
package org.dolphinemu.dolphinemu;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
public class SideMenuItem implements Comparable<SideMenuItem>{
private String m_name;
private int m_id;
public SideMenuItem(String n, int id)
{
m_name = n;
m_id = id;
}
public String getName()
{
return m_name;
}
public int getID()
{
return m_id;
}
public int compareTo(SideMenuItem o)
{
if(this.m_name != null)
return this.m_name.toLowerCase().compareTo(o.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -1,9 +1,10 @@
package org.dolphinemu.dolphinemu;
package org.dolphinemu.dolphinemu.folderbrowser;
import android.app.Activity;
import android.app.Fragment;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -14,7 +15,25 @@ import android.widget.Toast;
import java.io.File;
import java.util.*;
public class FolderBrowser extends Fragment {
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.gamelist.GameListActivity;
/**
* A basic folder browser {@link Fragment} that allows
* the user to select ISOs/ROMs for playing within the
* emulator.
* <p>
* Any valid ISO/ROM selected in this will be added to
* the game list for easy browsing the next time the
* application is used.
* <p>
* Note that invalid items will be shown in the color red. <br/>
* Also note that this file browser does not display files
* or directories that are hidden
*/
public final class FolderBrowser extends Fragment
{
private Activity m_activity;
private FolderBrowserAdapter adapter;
private ListView mDrawerList;
@ -23,45 +42,48 @@ public class FolderBrowser extends Fragment {
// Populates the FolderView with the given currDir's contents.
private void Fill(File currDir)
{
m_activity.setTitle("Current Dir: " + currDir.getName());
{
m_activity.setTitle(getString(R.string.current_dir) + currDir.getName());
File[] dirs = currDir.listFiles();
List<GameListItem>dir = new ArrayList<GameListItem>();
List<GameListItem>fls = new ArrayList<GameListItem>();
List<FolderBrowserItem>dir = new ArrayList<FolderBrowserItem>();
List<FolderBrowserItem>fls = new ArrayList<FolderBrowserItem>();
// Supported extensions to filter by
Set<String> validExts = new HashSet<String>(Arrays.asList(".gcm", ".iso", ".wbfs", ".gcz", ".dol", ".elf", ".dff"));
Set<String> archiveExts = new HashSet<String>(Arrays.asList(".zip", ".rar", ".7z"));
Set<String> invalidExts = new HashSet<String>(Arrays.asList(".zip", ".rar", ".7z"));
// Search for any directories or supported files within the current dir.
try
// Search for any directories or files within the current dir.
for(File entry : dirs)
{
for(File entry : dirs)
try
{
String entryName = entry.getName();
boolean hasExtension = (entryName.lastIndexOf(".") != -1);
// Skip hidden folders/files.
if (entryName.charAt(0) != '.')
{
if(entry.isDirectory())
{
dir.add(new GameListItem(m_activity, entryName,"Folder",entry.getAbsolutePath(), true));
dir.add(new FolderBrowserItem(entryName, entry.getAbsolutePath(), true));
}
else
else if (entry.isFile() && hasExtension)
{
if (validExts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
{
fls.add(new GameListItem(m_activity, entryName,"File Size: "+entry.length(),entry.getAbsolutePath(), true));
fls.add(new FolderBrowserItem(entryName, getString(R.string.file_size)+entry.length(), entry.getAbsolutePath(), true));
}
else if (archiveExts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
else if (invalidExts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
{
fls.add(new GameListItem(m_activity, entryName,"File Size: "+entry.length(),entry.getAbsolutePath(), false));
fls.add(new FolderBrowserItem(entryName, getString(R.string.file_size)+entry.length(), entry.getAbsolutePath(), false));
}
}
}
}
}
catch(Exception ignored)
{
catch (Exception ex)
{
Log.e("Exception-FolderBrowser", ex.toString());
}
}
Collections.sort(dir);
@ -70,16 +92,16 @@ public class FolderBrowser extends Fragment {
// Check for a parent directory to the one we're currently in.
if (!currDir.getPath().equalsIgnoreCase("/"))
dir.add(0, new GameListItem(m_activity, "..", "Parent Directory", currDir.getParent(), true));
dir.add(0, new FolderBrowserItem("..", getString(R.string.parent_directory), currDir.getParent(), true));
adapter = new FolderBrowserAdapter(m_activity, R.layout.folderbrowser, dir);
mDrawerList = (ListView) rootView.findViewById(R.id.gamelist);
mDrawerList.setAdapter(adapter);
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
}
mDrawerList = (ListView) rootView.findViewById(R.id.gamelist);
mDrawerList.setAdapter(adapter);
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(currentDir == null)
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
@ -94,33 +116,41 @@ public class FolderBrowser extends Fragment {
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
GameListItem o = adapter.getItem(position);
if(o.getData().equalsIgnoreCase("folder") || o.getData().equalsIgnoreCase("parent directory"))
FolderBrowserItem item = adapter.getItem(position);
if(item.isDirectory())
{
currentDir = new File(o.getPath());
currentDir = new File(item.getPath());
Fill(currentDir);
}
else
if (o.isValid())
{
if (item.isValid())
FolderSelected();
else
Toast.makeText(m_activity, "Can not use compressed file types.", Toast.LENGTH_LONG).show();
Toast.makeText(m_activity, getString(R.string.cant_use_compressed_filetypes), Toast.LENGTH_LONG).show();
}
}
};
@Override
public void onAttach(Activity activity) {
public void onAttach(Activity activity)
{
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
try
{
m_activity = activity;
} catch (ClassCastException e) {
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString()
+ " must implement OnGameListZeroListener");
}
}
private void FolderSelected()
{
String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPathes", "0");

View File

@ -0,0 +1,95 @@
package org.dolphinemu.dolphinemu.folderbrowser;
import java.util.List;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import org.dolphinemu.dolphinemu.R;
/**
* The {@link ArrayAdapter} that backs the file browser.
* <p>
* This is responsible for correctly handling the display
* of the items for the UI.
*/
public final class FolderBrowserAdapter extends ArrayAdapter<FolderBrowserItem>
{
private final Context c;
private final int id;
private final List<FolderBrowserItem> items;
public FolderBrowserAdapter(Context context, int textViewResourceId, List<FolderBrowserItem> objects)
{
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
@Override
public FolderBrowserItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater) c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, parent, false);
}
final FolderBrowserItem item = items.get(position);
if (item != null)
{
ImageView iconView = (ImageView) v.findViewById(R.id.ImageIcon);
TextView mainText = (TextView) v.findViewById(R.id.FolderTitle);
TextView subtitleText = (TextView) v.findViewById(R.id.FolderSubTitle);
if(mainText != null)
{
mainText.setText(item.getName());
if (!item.isValid())
{
mainText.setTextColor(0xFFFF0000);
}
}
if(subtitleText != null)
{
// Remove the subtitle for all folders, except for the parent directory folder.
if (item.isDirectory() && !item.getSubtitle().equals(c.getResources().getString(R.string.parent_directory)))
{
subtitleText.setVisibility(View.GONE);
}
else
{
subtitleText.setText(item.getSubtitle());
}
}
if (iconView != null)
{
if (item.isDirectory())
{
iconView.setImageResource(R.drawable.ic_menu_folder);
}
else
{
iconView.setImageResource(R.drawable.ic_menu_file);
}
}
}
return v;
}
}

View File

@ -0,0 +1,122 @@
package org.dolphinemu.dolphinemu.folderbrowser;
import java.io.File;
/**
* Represents an item in the folder browser list.
*/
public final class FolderBrowserItem implements Comparable<FolderBrowserItem>
{
private final String name;
private final String subtitle;
private final String path;
private final boolean isValid;
private final File underlyingFile;
/**
* Constructor
*
* @param name The name of the file/folder represented by this item.
* @param subtitle The subtitle of this FolderBrowserItem to display.
* @param path The path of the file/folder represented by this item.
* @param isValid Whether or not this item represents a file type that can be handled.
*/
public FolderBrowserItem(String name, String subtitle, String path, boolean isValid)
{
this.name = name;
this.subtitle = subtitle;
this.path = path;
this.isValid = isValid;
this.underlyingFile = new File(path);
}
/**
* Constructor. Initializes a FolderBrowserItem with an empty subtitle.
*
* @param name The name of the file/folder represented by this item.
* @param path The path of the file/folder represented by this item.
* @param isValid Whether or not this item represents a file type that can be handled.
*/
public FolderBrowserItem(String name, String path, boolean isValid)
{
this.name = name;
this.subtitle = "";
this.path = path;
this.isValid = isValid;
this.underlyingFile = new File(path);
}
/**
* Gets the name of the file/folder represented by this FolderBrowserItem.
*
* @return the name of the file/folder represented by this FolderBrowserItem.
*/
public String getName()
{
return name;
}
/**
* Gets the subtitle text of this FolderBrowserItem.
*
* @return the subtitle text of this FolderBrowserItem.
*/
public String getSubtitle()
{
return subtitle;
}
/**
* Gets the path of the file/folder represented by this FolderBrowserItem.
*
* @return the path of the file/folder represented by this FolderBrowserItem.
*/
public String getPath()
{
return path;
}
/**
* Gets whether or not the file represented
* by this FolderBrowserItem is supported
* and can be handled correctly.
*
* @return whether or not the file represented
* by this FolderBrowserItem is supported
* and can be handled correctly.
*/
public boolean isValid()
{
return isValid;
}
/**
* Gets the {@link File} representation of the underlying file/folder
* represented by this FolderBrowserItem.
*
* @return the {@link File} representation of the underlying file/folder
* represented by this FolderBrowserItem.
*/
public File getUnderlyingFile()
{
return underlyingFile;
}
/**
* Gets whether or not this FolderBrowserItem represents a directory.
*
* @return true if this FolderBrowserItem represents a directory, false otherwise.
*/
public boolean isDirectory()
{
return underlyingFile.isDirectory();
}
public int compareTo(FolderBrowserItem other)
{
if(this.name != null)
return this.name.toLowerCase().compareTo(other.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -1,62 +1,88 @@
package org.dolphinemu.dolphinemu;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.SharedPreferences;
import android.content.res.Configuration;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.*;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
public class GameListActivity extends Activity
implements GameListFragment.OnGameListZeroListener{
package org.dolphinemu.dolphinemu.gamelist;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.content.Intent;
import android.content.res.Configuration;
import android.os.Bundle;
import android.support.v4.app.ActionBarDrawerToggle;
import android.support.v4.widget.DrawerLayout;
import android.view.*;
import android.widget.AdapterView;
import android.widget.ListView;
import java.util.ArrayList;
import java.util.List;
import org.dolphinemu.dolphinemu.AboutFragment;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.folderbrowser.FolderBrowser;
import org.dolphinemu.dolphinemu.inputconfig.InputConfigAdapter;
import org.dolphinemu.dolphinemu.inputconfig.InputConfigFragment;
import org.dolphinemu.dolphinemu.inputconfig.InputConfigItem;
import org.dolphinemu.dolphinemu.settings.PrefsActivity;
import org.dolphinemu.dolphinemu.sidemenu.SideMenuAdapter;
import org.dolphinemu.dolphinemu.sidemenu.SideMenuItem;
/**
* The activity that implements all of the functions
* for the game list.
*/
public final class GameListActivity extends Activity
implements GameListFragment.OnGameListZeroListener
{
private int mCurFragmentNum = 0;
private Fragment mCurFragment;
enum keyTypes {TYPE_STRING, TYPE_BOOL};
private ActionBarDrawerToggle mDrawerToggle;
private DrawerLayout mDrawerLayout;
private SideMenuAdapter mDrawerAdapter;
private ListView mDrawerList;
/**
* Interface defining methods which handle
* the binding of specific key presses within
* the input mapping settings.
*/
public interface OnGameConfigListener
{
boolean onMotionEvent(MotionEvent event);
boolean onKeyEvent(KeyEvent event);
}
private static GameListActivity mMe;
// Called from the game list fragment
/**
* Called from the {@link GameListFragment}.
* <p>
* This is called when there are no games
* currently present within the game list.
*/
public void onZeroFiles()
{
mDrawerLayout.openDrawer(mDrawerList);
}
@Override
protected void onCreate(Bundle savedInstanceState) {
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.gamelist_activity);
mMe = this;
mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
mDrawerList = (ListView) findViewById(R.id.left_drawer);
List<SideMenuItem> dir = new ArrayList<SideMenuItem>();
dir.add(new SideMenuItem("Game List", 0));
dir.add(new SideMenuItem("Browse Folder", 1));
dir.add(new SideMenuItem("Settings", 2));
dir.add(new SideMenuItem("Gamepad Config", 3));
dir.add(new SideMenuItem("About", 4));
dir.add(new SideMenuItem(getString(R.string.game_list), 0));
dir.add(new SideMenuItem(getString(R.string.browse_folder), 1));
dir.add(new SideMenuItem(getString(R.string.settings), 2));
dir.add(new SideMenuItem(getString(R.string.gamepad_config), 3));
dir.add(new SideMenuItem(getString(R.string.about), 4));
mDrawerAdapter = new SideMenuAdapter(this, R.layout.sidemenu, dir);
mDrawerList.setAdapter(mDrawerAdapter);
@ -94,59 +120,25 @@ public class GameListActivity extends Activity
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
}
/**
* Switches to the {@link Fragment} represented
* by the given ID number.
*
* @param toPage the number representing the {@link Fragment} to switch to.l
*/
public void SwitchPage(int toPage)
{
if (mCurFragmentNum == toPage)
return;
switch (mCurFragmentNum)
{
// Folder browser
case 1:
recreateFragment();
break;
// Settings
case 2:
{
String Keys[] = {
"cpupref",
"dualcorepref",
"gpupref",
};
String ConfigKeys[] = {
"Core-CPUCore",
"Core-CPUThread",
"Core-GFXBackend",
};
break;
keyTypes KeysTypes[] = {
keyTypes.TYPE_STRING,
keyTypes.TYPE_BOOL,
keyTypes.TYPE_STRING,
};
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getApplicationContext());
// Set our preferences here
for (int a = 0; a < Keys.length; ++a)
{
String ConfigValues[] = ConfigKeys[a].split("-");
String Key = ConfigValues[0];
String Value = ConfigValues[1];
switch(KeysTypes[a])
{
case TYPE_STRING:
String strPref = prefs.getString(Keys[a], "");
NativeLibrary.SetConfig("Dolphin.ini", Key, Value, strPref);
break;
case TYPE_BOOL:
boolean boolPref = prefs.getBoolean(Keys[a], true);
NativeLibrary.SetConfig("Dolphin.ini", Key, Value, boolPref ? "True" : "False");
break;
}
}
}
break;
case 3: // Gamepad settings
{
InputConfigAdapter adapter = ((InputConfigFragment)mCurFragment).getAdapter();
@ -162,11 +154,14 @@ public class GameListActivity extends Activity
}
}
break;
case 0: // Game List
case 2: // Settings
case 4: // About
/* Do Nothing */
/* Do Nothing */
break;
}
switch(toPage)
{
case 0:
@ -177,46 +172,46 @@ public class GameListActivity extends Activity
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
}
break;
case 1:
{
Toast.makeText(mMe, "Loading up the browser", Toast.LENGTH_SHORT).show();
mCurFragmentNum = 1;
mCurFragment = new FolderBrowser();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
}
break;
case 2:
{
Toast.makeText(mMe, "Loading up settings", Toast.LENGTH_SHORT).show();
mCurFragmentNum = 2;
mCurFragment = new PrefsFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
Intent intent = new Intent(this, PrefsActivity.class);
startActivity(intent);
}
break;
case 3:
{
Toast.makeText(mMe, "Loading up gamepad config", Toast.LENGTH_SHORT).show();
mCurFragmentNum = 3;
mCurFragment = new InputConfigFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
}
break;
case 4:
{
Toast.makeText(mMe, "Loading up About", Toast.LENGTH_SHORT).show();
mCurFragmentNum = 4;
mCurFragment = new AboutFragment();
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
}
break;
default:
break;
}
}
private AdapterView.OnItemClickListener mMenuItemClickListener = new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
@ -226,64 +221,76 @@ public class GameListActivity extends Activity
SwitchPage(o.getID());
}
};
/**
* When using the ActionBarDrawerToggle, you must call it during
* onPostCreate() and onConfigurationChanged()...
*/
@Override
protected void onPostCreate(Bundle savedInstanceState) {
protected void onPostCreate(Bundle savedInstanceState)
{
super.onPostCreate(savedInstanceState);
// Sync the toggle state after onRestoreInstanceState has occurred.
mDrawerToggle.syncState();
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
public void onConfigurationChanged(Configuration newConfig)
{
super.onConfigurationChanged(newConfig);
// Pass any configuration change to the drawer toggls
// Pass any configuration change to the drawer toggle
mDrawerToggle.onConfigurationChanged(newConfig);
}
/* Called whenever we call invalidateOptionsMenu() */
@Override
public boolean onPrepareOptionsMenu(Menu menu) {
public boolean onPrepareOptionsMenu(Menu menu)
{
return super.onPrepareOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
public boolean onOptionsItemSelected(MenuItem item)
{
// The action bar home/up action should open or close the drawer.
// ActionBarDrawerToggle will take care of this.
if (mDrawerToggle.onOptionsItemSelected(item)) {
if (mDrawerToggle.onOptionsItemSelected(item))
{
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed()
{
SwitchPage(0);
}
public interface OnGameConfigListener {
public boolean onMotionEvent(MotionEvent event);
public boolean onKeyEvent(KeyEvent event);
}
// Gets move(triggers, joystick) events
@Override
public boolean dispatchGenericMotionEvent(MotionEvent event) {
public boolean dispatchGenericMotionEvent(MotionEvent event)
{
if (mCurFragmentNum == 3)
{
if (((OnGameConfigListener)mCurFragment).onMotionEvent(event))
return true;
}
return super.dispatchGenericMotionEvent(event);
}
// Gets button presses
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
public boolean dispatchKeyEvent(KeyEvent event)
{
if (mCurFragmentNum == 3)
{
if (((OnGameConfigListener)mCurFragment).onKeyEvent(event))
return true;
}
return super.dispatchKeyEvent(event);
}
}

View File

@ -0,0 +1,80 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.gamelist;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ImageView;
import android.widget.TextView;
import java.util.List;
import org.dolphinemu.dolphinemu.R;
/**
* The adapter backing the game list.
* <p>
* Responsible for handling each game list item individually.
*/
public final class GameListAdapter extends ArrayAdapter<GameListItem>
{
private final Context c;
private final int id;
private final List<GameListItem>items;
public GameListAdapter(Context context, int textViewResourceId, List<GameListItem> objects)
{
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
@Override
public GameListItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, parent, false);
}
final GameListItem item = items.get(position);
if (item != null)
{
TextView title = (TextView) v.findViewById(R.id.GameItemTitle);
TextView subtitle = (TextView) v.findViewById(R.id.GameItemSubText);
ImageView icon = (ImageView) v.findViewById(R.id.GameItemIcon);
if (title != null)
title.setText(item.getName());
if (subtitle != null)
subtitle.setText(item.getData());
if (icon != null)
{
icon.setImageBitmap(item.getImage());
icon.getLayoutParams().width = (int) ((860 / c.getResources().getDisplayMetrics().density) + 0.5);
icon.getLayoutParams().height = (int)((340 / c.getResources().getDisplayMetrics().density) + 0.5);
}
}
return v;
}
}

View File

@ -1,4 +1,10 @@
package org.dolphinemu.dolphinemu;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.gamelist;
import android.app.Activity;
import android.app.Fragment;
@ -19,25 +25,33 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.dolphinemu.dolphinemu.NativeLibrary;
import org.dolphinemu.dolphinemu.R;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
* The {@link Fragment} responsible for displaying the game list.
*/
public class GameListFragment extends Fragment
public final class GameListFragment extends Fragment
{
private ListView mMainList;
private GameListAdapter mGameAdapter;
private static GameListActivity mMe;
OnGameListZeroListener mCallback;
private OnGameListZeroListener mCallback;
public interface OnGameListZeroListener {
public void onZeroFiles();
/**
* Interface that defines how to handle the case
* when there are zero game.
*/
public interface OnGameListZeroListener
{
/**
* This is called when there are no games
* currently present within the game list.
*/
void onZeroFiles();
}
public GameListFragment() {
// Empty constructor required for fragment subclasses
}
private void Fill()
{
List<GameListItem> fls = new ArrayList<GameListItem>();
@ -49,40 +63,58 @@ public class GameListFragment extends Fragment
for (int a = 0; a < intDirectories; ++a)
{
String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPath" + Integer.toString(a), "");
String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPath" + a, "");
File currentDir = new File(BrowseDir);
File[]dirs = currentDir.listFiles();
File[] dirs = currentDir.listFiles();
try
{
for(File entry : dirs)
for (File entry : dirs)
{
String entryName = entry.getName();
if (entryName.charAt(0) != '.')
{
if(!entry.isDirectory())
if (!entry.isDirectory())
{
if (exts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
fls.add(new GameListItem(mMe.getApplicationContext(), entryName,"File Size: "+entry.length(),entry.getAbsolutePath(), true));
fls.add(new GameListItem(mMe.getApplicationContext(), entryName, getString(R.string.file_size)+entry.length(),entry.getAbsolutePath(), true));
}
}
}
}
catch(Exception ignored)
catch (Exception ignored)
{
}
}
Collections.sort(fls);
// Remove any duplicate items from the list.
// We don't need to index these in the game list more than once.
//
// This works by comparing the paths of items in the file list for equality,
// so there should be no worries about accidentally removing a valid game.
for (int i = 0; i < fls.size(); i++)
{
int indexNext = i+1;
if (indexNext < fls.size() && fls.get(indexNext).getPath().contains(fls.get(i).getPath()))
{
fls.remove(indexNext);
}
}
mGameAdapter = new GameListAdapter(mMe, R.layout.gamelist_layout, fls);
mMainList.setAdapter(mGameAdapter);
if (fls.size() == 0)
if (fls.isEmpty())
{
mCallback.onZeroFiles();
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
mMainList = (ListView) rootView.findViewById(R.id.gamelist);
mMainList.setOnItemClickListener(mGameItemClickListener);
@ -91,36 +123,43 @@ public class GameListFragment extends Fragment
return mMainList;
}
private AdapterView.OnItemClickListener mGameItemClickListener = new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
GameListItem o = mGameAdapter.getItem(position);
if(!(o.getData().equalsIgnoreCase("folder")||o.getData().equalsIgnoreCase("parent directory")))
if (!(o.getData().equalsIgnoreCase(getString(R.string.folder))||o.getData().equalsIgnoreCase(getString(R.string.parent_directory))))
{
onFileClick(o.getPath());
}
}
};
private void onFileClick(String o)
{
Toast.makeText(mMe, "File Clicked: " + o, Toast.LENGTH_SHORT).show();
Toast.makeText(mMe, getString(R.string.file_clicked) + o, Toast.LENGTH_SHORT).show();
Intent intent = new Intent();
intent.putExtra("Select", o);
mMe.setResult(Activity.RESULT_OK, intent);
mMe.finish();
}
@Override
public void onAttach(Activity activity) {
public void onAttach(Activity activity)
{
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
try
{
mCallback = (OnGameListZeroListener) activity;
mMe = (GameListActivity) activity;
} catch (ClassCastException e) {
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString()
+ " must implement OnGameListZeroListener");
}

View File

@ -0,0 +1,136 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.gamelist;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import org.dolphinemu.dolphinemu.NativeLibrary;
/**
* Represents an item in the game list.
*/
public final class GameListItem implements Comparable<GameListItem>
{
private String name;
private final String data;
private final String path;
private final boolean isValid;
private Bitmap image;
/**
* Constructor.
*
* @param ctx The current {@link Context}
* @param name The name of this GameListItem.
* @param data The subtitle for this GameListItem
* @param path The file path for the game represented by this GameListItem.
* @param isValid Whether or not the emulator can handle this file.
*/
public GameListItem(Context ctx, String name, String data, String path, boolean isValid)
{
this.name = name;
this.data = data;
this.path = path;
this.isValid = isValid;
File file = new File(path);
if (!file.isDirectory() && !path.equals(""))
{
int[] Banner = NativeLibrary.GetBanner(path);
if (Banner[0] == 0)
{
try
{
// Open the no banner icon.
InputStream noBannerPath = ctx.getAssets().open("NoBanner.png");
// Decode the bitmap.
image = BitmapFactory.decodeStream(noBannerPath);
// Scale the bitmap to match other banners.
image = Bitmap.createScaledBitmap(image, 96, 32, false);
}
catch (IOException e)
{
Log.e("Exception-GameListItem", e.toString());
}
}
else
{
image = Bitmap.createBitmap(Banner, 96, 32, Bitmap.Config.ARGB_8888);
}
this.name = NativeLibrary.GetTitle(path);
}
}
/**
* Gets the name of this GameListItem.
*
* @return the name of this GameListItem.
*/
public String getName()
{
return name;
}
/**
* Gets the subtitle of this GameListItem.
*
* @return the subtitle of this GameListItem.
*/
public String getData()
{
return data;
}
/**
* Gets the file path of the game represented by this GameListItem.
*
* @return the file path of the game represented by this GameListItem.
*/
public String getPath()
{
return path;
}
/**
* Gets the image data for this game as a {@link Bitmap}.
*
* @return the image data for this game as a {@link Bitmap}.
*/
public Bitmap getImage()
{
return image;
}
/**
* Gets whether or not the emulator can handle this GameListItem.
*
* @return true, if this GameListItem can be handled by the emulator; false, otherwise.
*/
public boolean isValid()
{
return isValid;
}
public int compareTo(GameListItem o)
{
if (this.name != null)
return this.name.toLowerCase().compareTo(o.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -0,0 +1,70 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.inputconfig;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
import org.dolphinemu.dolphinemu.R;
/**
* The adapter backing the input mapping configuration.
* <p>
* Responsible for handling the list items.
*/
public final class InputConfigAdapter extends ArrayAdapter<InputConfigItem>
{
private final Context c;
private final int id;
private final List<InputConfigItem> items;
public InputConfigAdapter(Context context, int textViewResourceId, List<InputConfigItem> objects)
{
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
@Override
public InputConfigItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, parent, false);
}
final InputConfigItem item = items.get(position);
if (item != null)
{
TextView title = (TextView) v.findViewById(R.id.FolderTitle);
TextView subtitle = (TextView) v.findViewById(R.id.FolderSubTitle);
if (title != null)
title.setText(item.getName());
if (subtitle != null)
subtitle.setText(item.getBind());
}
return v;
}
}

View File

@ -1,4 +1,10 @@
package org.dolphinemu.dolphinemu;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.inputconfig;
import android.app.Activity;
import android.app.Fragment;
@ -13,63 +19,75 @@ import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
import org.dolphinemu.dolphinemu.R;
import org.dolphinemu.dolphinemu.gamelist.GameListActivity;
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
* The {@link Fragment} responsible for implementing the functionality
* within the input control mapping config.
*/
public class InputConfigFragment extends Fragment
implements GameListActivity.OnGameConfigListener{
public final class InputConfigFragment extends Fragment
implements GameListActivity.OnGameConfigListener
{
private Activity m_activity;
private ListView mDrawerList;
private InputConfigAdapter adapter;
private int configPosition = 0;
boolean Configuring = false;
boolean firstEvent = true;
private boolean Configuring = false;
private boolean firstEvent = true;
static public String getInputDesc(InputDevice input)
/**
* Gets the descriptor for the given {@link InputDevice}.
*
* @param input The {@link InputDevice} to get the descriptor of.
*
* @return the descriptor for the given {@link InputDevice}.
*/
public static String getInputDesc(InputDevice input)
{
if (input == null)
return "null"; // Happens when the inputdevice is from an unknown source
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
{
return input.getDescriptor();
}
else
{
List<InputDevice.MotionRange> motions = input.getMotionRanges();
String fakeid = "";
for (InputDevice.MotionRange range : motions)
fakeid += range.getAxis();
return fakeid;
}
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
List<InputConfigItem> Input = new ArrayList<InputConfigItem>();
int a = 0;
Input.add(a++, new InputConfigItem("Draw on-screen controls", "Android-ScreenControls", "True"));
Input.add(a++, new InputConfigItem("Button A", "Android-InputA"));
Input.add(a++, new InputConfigItem("Button B", "Android-InputB"));
Input.add(a++, new InputConfigItem("Button Start", "Android-InputStart"));
Input.add(a++, new InputConfigItem("Button X", "Android-InputX"));
Input.add(a++, new InputConfigItem("Button Y", "Android-InputY"));
Input.add(a++, new InputConfigItem("Button Z", "Android-InputZ"));
Input.add(a++, new InputConfigItem("D-Pad Up", "Android-DPadUp"));
Input.add(a++, new InputConfigItem("D-Pad Down", "Android-DPadDown"));
Input.add(a++, new InputConfigItem("D-Pad Left", "Android-DPadLeft"));
Input.add(a++, new InputConfigItem("D-Pad Right", "Android-DPadRight"));
Input.add(a++, new InputConfigItem("Main Stick Up", "Android-MainUp"));
Input.add(a++, new InputConfigItem("Main Stick Down", "Android-MainDown"));
Input.add(a++, new InputConfigItem("Main Stick Left", "Android-MainLeft"));
Input.add(a++, new InputConfigItem("Main Stick Right", "Android-MainRight"));
Input.add(a++, new InputConfigItem("C Stick Up", "Android-CStickUp"));
Input.add(a++, new InputConfigItem("C Stick Down", "Android-CStickDown"));
Input.add(a++, new InputConfigItem("C Stick Left", "Android-CStickLeft"));
Input.add(a++, new InputConfigItem("C Stick Right", "Android-CStickRight"));
Input.add(a++, new InputConfigItem("Trigger L", "Android-InputL"));
Input.add(a++, new InputConfigItem("Trigger R", "Android-InputR"));
Input.add(new InputConfigItem(getString(R.string.button_a), "Android-InputA"));
Input.add(new InputConfigItem(getString(R.string.button_b), "Android-InputB"));
Input.add(new InputConfigItem(getString(R.string.button_start), "Android-InputStart"));
Input.add(new InputConfigItem(getString(R.string.button_x), "Android-InputX"));
Input.add(new InputConfigItem(getString(R.string.button_y), "Android-InputY"));
Input.add(new InputConfigItem(getString(R.string.button_z), "Android-InputZ"));
Input.add(new InputConfigItem(getString(R.string.dpad_up), "Android-DPadUp"));
Input.add(new InputConfigItem(getString(R.string.dpad_down), "Android-DPadDown"));
Input.add(new InputConfigItem(getString(R.string.dpad_left), "Android-DPadLeft"));
Input.add(new InputConfigItem(getString(R.string.dpad_right), "Android-DPadRight"));
Input.add(new InputConfigItem(getString(R.string.main_stick_up), "Android-MainUp"));
Input.add(new InputConfigItem(getString(R.string.main_stick_down), "Android-MainDown"));
Input.add(new InputConfigItem(getString(R.string.main_stick_left), "Android-MainLeft"));
Input.add(new InputConfigItem(getString(R.string.main_stick_right), "Android-MainRight"));
Input.add(new InputConfigItem(getString(R.string.c_stick_up), "Android-CStickUp"));
Input.add(new InputConfigItem(getString(R.string.c_stick_down), "Android-CStickDown"));
Input.add(new InputConfigItem(getString(R.string.c_stick_left), "Android-CStickLeft"));
Input.add(new InputConfigItem(getString(R.string.c_stick_right), "Android-CStickRight"));
Input.add(new InputConfigItem(getString(R.string.trigger_left), "Android-InputL"));
Input.add(new InputConfigItem(getString(R.string.trigger_right), "Android-InputR"));
adapter = new InputConfigAdapter(m_activity, R.layout.folderbrowser, Input);
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
@ -79,56 +97,44 @@ public class InputConfigFragment extends Fragment
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
return mDrawerList;
}
private AdapterView.OnItemClickListener mMenuItemClickListener = new AdapterView.OnItemClickListener()
{
public void onItemClick(AdapterView<?> parent, View view, int position, long id)
{
InputConfigItem o = adapter.getItem(position);
switch(position)
{
case 0: // On screen controls
String newBind;
if (o.getBind().equals("True"))
{
Toast.makeText(m_activity, "Not Drawing on screen controls", Toast.LENGTH_SHORT).show();
newBind = "False";
}
else
{
Toast.makeText(m_activity, "Drawing on screen controls", Toast.LENGTH_SHORT).show();
newBind = "True";
}
adapter.remove(o);
o.setBind(newBind);
adapter.insert(o, position);
break;
default: // gamepad controls
Toast.makeText(m_activity, "Press button to configure " + o.getName(), Toast.LENGTH_SHORT).show();
configPosition = position;
Configuring = true;
firstEvent = true;
break;
}
Toast.makeText(m_activity, getString(R.string.press_button_to_config, o.getName()), Toast.LENGTH_SHORT).show();
configPosition = position;
Configuring = true;
firstEvent = true;
}
};
static ArrayList<Float> m_values = new ArrayList<Float>();
private static ArrayList<Float> m_values = new ArrayList<Float>();
void AssignBind(String bind)
private void AssignBind(String bind)
{
InputConfigItem o = adapter.getItem(configPosition);
adapter.remove(o);
o.setBind(bind);
adapter.insert(o, configPosition);
}
/**
* Gets the current {@link InputConfigAdapter}
*
* @return the current {@link InputConfigAdapter}.
*/
public InputConfigAdapter getAdapter()
{
return adapter;
}
// Called from GameListActivity
public boolean onMotionEvent(MotionEvent event)
{
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0))
if ((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0)
return false;
InputDevice input = event.getDevice();
@ -138,17 +144,20 @@ public class InputConfigFragment extends Fragment
if (firstEvent)
{
m_values.clear();
for (InputDevice.MotionRange range : motions) {
for (InputDevice.MotionRange range : motions)
{
m_values.add(event.getAxisValue(range.getAxis()));
}
firstEvent = false;
}
else
{
for (int a = 0; a < motions.size(); ++a)
{
InputDevice.MotionRange range;
range = motions.get(a);
InputDevice.MotionRange range = motions.get(a);
if (m_values.get(a) > (event.getAxisValue(range.getAxis()) + 0.5f))
{
AssignBind("Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "-");
@ -164,10 +173,13 @@ public class InputConfigFragment extends Fragment
}
return true;
}
// Called from GameListActivity
public boolean onKeyEvent(KeyEvent event)
{
Log.w("Dolphinemu", "Got Event " + event.getAction());
switch (event.getAction()) {
Log.w("InputConfigFragment", "Got Event " + event.getAction());
switch (event.getAction())
{
case KeyEvent.ACTION_DOWN:
case KeyEvent.ACTION_UP:
if (Configuring)
@ -177,6 +189,7 @@ public class InputConfigFragment extends Fragment
Configuring = false;
return true;
}
default:
break;
}
@ -185,14 +198,18 @@ public class InputConfigFragment extends Fragment
}
@Override
public void onAttach(Activity activity) {
public void onAttach(Activity activity)
{
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try {
try
{
m_activity = activity;
} catch (ClassCastException e) {
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString()
+ " must implement OnGameListZeroListener");
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.inputconfig;
import org.dolphinemu.dolphinemu.NativeLibrary;
/**
* Represents a controller input item (button, stick, etc).
*/
public final class InputConfigItem implements Comparable<InputConfigItem>
{
private String m_name;
private String m_Config;
private String m_bind;
private void Init(String name, String config, String defaultBind)
{
m_name = name;
m_Config = config;
String ConfigValues[] = m_Config.split("-");
String Key = ConfigValues[0];
String Value = ConfigValues[1];
m_bind = NativeLibrary.GetConfig("Dolphin.ini", Key, Value, defaultBind);
}
/**
* Constructor
*
* @param name Name of the input config item.
* @param config Name of the key in the configuration file that this control modifies.
* @param defaultBind Default binding to fall back upon if binding fails.
*/
public InputConfigItem(String name, String config, String defaultBind)
{
Init(name, config, defaultBind);
}
/**
* Constructor that creates an InputConfigItem
* that has a default binding of "None".
*
* @param name Name of the input config item.
* @param config Name of the key in the configuration file that this control modifies.
*/
public InputConfigItem(String name, String config)
{
Init(name, config, "None");
}
/**
* Gets the name of this InputConfigItem.
*
* @return the name of this InputConfigItem
*/
public String getName()
{
return m_name;
}
/**
* Gets the config key this InputConfigItem modifies.
*
* @return the config key this InputConfigItem modifies.
*/
public String getConfig()
{
return m_Config;
}
/**
* Gets the currently set binding of this InputConfigItem.
*
* @return the currently set binding of this InputConfigItem
*/
public String getBind()
{
return m_bind;
}
/**
* Sets a new binding for this InputConfigItem.
*
* @param bind The new binding.
*/
public void setBind(String bind)
{
m_bind = bind;
}
public int compareTo(InputConfigItem o)
{
if (this.m_name != null)
return this.m_name.toLowerCase().compareTo(o.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -0,0 +1,80 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.settings;
import org.dolphinemu.dolphinemu.R;
import android.app.Activity;
import android.os.Build;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceFragment;
/**
* Responsible for the loading of the CPU preferences.
*/
public final class CPUSettingsFragment extends PreferenceFragment
{
private Activity m_activity;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.cpu_prefs);
final ListPreference cpuCores = (ListPreference) findPreference("cpuCorePref");
//
// Set valid emulation cores depending on the CPU architecture
// that the Android device is running on.
//
if (Build.CPU_ABI.contains("x86"))
{
cpuCores.setEntries(R.array.emuCoreEntriesX86);
cpuCores.setEntryValues(R.array.emuCoreValuesX86);
}
else if (Build.CPU_ABI.contains("arm"))
{
cpuCores.setEntries(R.array.emuCoreEntriesARM);
cpuCores.setEntryValues(R.array.emuCoreValuesARM);
}
else
{
cpuCores.setEntries(R.array.emuCoreEntriesOther);
cpuCores.setEntryValues(R.array.emuCoreValuesOther);
}
}
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try
{
m_activity = activity;
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString());
}
}
@Override
public void onDestroy()
{
super.onDestroy();
// When this fragment is destroyed, force the settings to be saved to the ini file.
UserPreferences.SaveConfigToDolphinIni(m_activity);
}
}

View File

@ -0,0 +1,144 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.settings;
import org.dolphinemu.dolphinemu.R;
import android.app.ActionBar;
import android.app.ActionBar.Tab;
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentManager;
import android.app.FragmentTransaction;
import android.os.Bundle;
import android.support.v13.app.FragmentPagerAdapter;
import android.support.v4.view.ViewPager;
/**
* Main activity that manages all of the preference fragments used to display
* the settings to the user.
*/
public final class PrefsActivity extends Activity implements ActionBar.TabListener
{
/**
* The {@link android.support.v4.view.PagerAdapter} that will provide org.dolphinemu.dolphinemu.settings for each of the
* sections. We use a {@link android.support.v4.app.FragmentPagerAdapter} derivative, which will
* keep every loaded fragment in memory. If this becomes too memory intensive, it may be best to
* switch to a {@link android.support.v4.app.FragmentStatePagerAdapter}.
*/
private SectionsPagerAdapter mSectionsPagerAdapter;
/**
* The {@link ViewPager} that will host the section contents.
*/
private ViewPager mViewPager;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.prefs_viewpager);
// Set up the action bar.
final ActionBar actionBar = getActionBar();
actionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
// Create the adapter that will return a fragment for each of the three
// primary sections of the app.
mSectionsPagerAdapter = new SectionsPagerAdapter(getFragmentManager());
// Set up the ViewPager with the sections adapter.
mViewPager = (ViewPager) findViewById(R.id.pager);
mViewPager.setAdapter(mSectionsPagerAdapter);
// When swiping between different sections, select the corresponding
// tab. We can also use ActionBar.Tab#select() to do this if we have
// a reference to the Tab.
mViewPager.setOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener()
{
@Override
public void onPageSelected(int position)
{
actionBar.setSelectedNavigationItem(position);
}
} );
// Create a tab with text corresponding to the page title defined by
// the adapter. Also specify this Activity object, which implements
// the TabListener interface, as the callback (listener) for when
// this tab is selected.
actionBar.addTab(actionBar.newTab().setText(R.string.cpu_settings).setTabListener(this));
actionBar.addTab(actionBar.newTab().setText(R.string.video_settings).setTabListener(this));
}
public void onTabReselected(Tab arg0, FragmentTransaction arg1)
{
// Do nothing.
}
public void onTabSelected(Tab tab, FragmentTransaction ft)
{
// When the given tab is selected, switch to the corresponding page in the ViewPager.
mViewPager.setCurrentItem(tab.getPosition());
}
public void onTabUnselected(Tab tab, FragmentTransaction ft)
{
// Do nothing.
}
/**
* A {@link FragmentPagerAdapter} that returns a fragment
* corresponding to one of the sections/tabs/pages.
*/
public final class SectionsPagerAdapter extends FragmentPagerAdapter
{
public SectionsPagerAdapter(FragmentManager fm)
{
super(fm);
}
@Override
public Fragment getItem(int position)
{
switch(position)
{
case 0:
return new CPUSettingsFragment();
case 1:
return new VideoSettingsFragment();
default: // Should never happen.
return null;
}
}
@Override
public int getCount()
{
// Show total pages.
return 2;
}
@Override
public CharSequence getPageTitle(int position)
{
switch(position)
{
case 0:
return getString(R.string.cpu_settings).toUpperCase();
case 1:
return getString(R.string.video_settings).toUpperCase();
default: // Should never happen.
return null;
}
}
}
}

View File

@ -0,0 +1,235 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.settings;
import org.dolphinemu.dolphinemu.NativeLibrary;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;
/**
* A class that retrieves all of the set user preferences in Android, in a safe way.
* <p>
* If any preferences are added to this emulator, an accessor for that preference
* should be added here. This way lengthy calls to getters from SharedPreferences
* aren't made necessary.
*/
public final class UserPreferences
{
/**
* Loads the set config items from the Dolphin config files to the shared preferences of this front-end
*
* @param ctx The context used to retrieve the SharedPreferences instance.
*/
public static void LoadDolphinConfigToPrefs(Context ctx)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
// Get an editor.
SharedPreferences.Editor editor = prefs.edit();
// Add the settings.
editor.putString("cpuCorePref", getConfig("Dolphin.ini", "Core", "CPUCore", "3"));
editor.putBoolean("dualCorePref", getConfig("Dolphin.ini", "Core", "CPUThread", "False").equals("True"));
editor.putString("gpuPref", getConfig("Dolphin.ini", "Core", "GFXBackend ", "Software Renderer"));
editor.putBoolean("drawOnscreenControls", getConfig("Dolphin.ini", "Android", "ScreenControls", "True").equals("True"));
editor.putString("internalResolution", getConfig("gfx_opengl.ini", "Settings", "EFBScale", "2") );
editor.putString("anisotropicFiltering", getConfig("gfx_opengl.ini", "Enhancements", "MaxAnisotropy", "0"));
editor.putBoolean("scaledEFBCopy", getConfig("gfx_opengl.ini", "Hacks", "EFBScaleCopy", "True").equals("True"));
editor.putBoolean("perPixelLighting", getConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", "False").equals("True"));
editor.putBoolean("forceTextureFiltering", getConfig("gfx_opengl.ini", "Enhancements", "ForceFiltering", "False").equals("True"));
editor.putBoolean("disableFog", getConfig("gfx_opengl.ini", "Settings", "DisableFog", "False").equals("True"));
editor.putBoolean("skipEFBAccess", getConfig("gfx_opengl.ini", "Hacks", "EFBAccessEnable", "False").equals("True"));
editor.putBoolean("ignoreFormatChanges", getConfig("gfx_opengl.ini", "Hacks", "EFBEmulateFormatChanges", "False").equals("False"));
String efbCopyOn = getConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "False");
String efbToTexture = getConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "False");
String efbCopyCache = getConfig("gfx_opengl.ini", "Hacks", "EFBCopyCacheEnable", "False");
if (efbCopyOn.equals("False"))
{
editor.putString("efbCopyMethod", "Off");
}
else if (efbCopyOn.equals("True") && efbToTexture.equals("True"))
{
editor.putString("efbCopyMethod", "Texture");
}
else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("False"))
{
editor.putString("efbCopyMethod", "RAM (uncached)");
}
else if(efbCopyOn.equals("True") && efbToTexture.equals("False") && efbCopyCache.equals("True"))
{
editor.putString("efbCopyMethod", "RAM (cached)");
}
editor.putString("textureCacheAccuracy", getConfig("gfx_opengl.ini", "Settings", "SafeTextureCacheColorSamples", "128"));
String usingXFB = getConfig("gfx_opengl.ini", "Settings", "UseXFB", "False");
String usingRealXFB = getConfig("gfx_opengl.ini", "Settings", "UseRealXFB", "False");
if (usingXFB.equals("False"))
{
editor.putString("externalFrameBuffer", "Disabled");
}
else if (usingXFB.equals("True") && usingRealXFB.equals("False"))
{
editor.putString("externalFrameBuffer", "Virtual");
}
else if (usingXFB.equals("True") && usingRealXFB.equals("True"))
{
editor.putString("externalFrameBuffer", "Real");
}
editor.putBoolean("cacheDisplayLists", getConfig("gfx_opengl.ini", "Hacks", "DlistCachingEnable", "False").equals("True"));
editor.putBoolean("disableDestinationAlpha", getConfig("gfx_opengl.ini", "Settings", "DstAlphaPass", "False").equals("True"));
editor.putBoolean("fastDepthCalculation", getConfig("gfx_opengl.ini", "Settings", "FastDepthCalc", "True").equals("True"));
// Apply the changes.
editor.commit();
}
// Small utility method that shortens calls to NativeLibrary.GetConfig.
private static String getConfig(String ini, String section, String key, String defaultValue)
{
return NativeLibrary.GetConfig(ini, section, key, defaultValue);
}
/**
* Writes the config to the Dolphin ini file.
*
* @param ctx The context used to retrieve the user settings.
* */
public static void SaveConfigToDolphinIni(Context ctx)
{
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
// Whether or not the user is using dual core.
boolean isUsingDualCore = prefs.getBoolean("dualCorePref", true);
// Current CPU core being used. Falls back to interpreter upon error.
String currentEmuCore = prefs.getString("cpuCorePref", "0");
// Current video backend being used. Falls back to software rendering upon error.
String currentVideoBackend = prefs.getString("gpuPref", "Software Rendering");
// Whether or not to draw on-screen controls.
boolean drawingOnscreenControls = prefs.getBoolean("drawOnscreenControls", true);
// Whether or not to ignore all EFB access requests from the CPU.
boolean skipEFBAccess = prefs.getBoolean("skipEFBAccess", false);
// Whether or not to ignore changes to the EFB format.
boolean ignoreFormatChanges = prefs.getBoolean("ignoreFormatChanges", false);
// EFB copy method to use.
String efbCopyMethod = prefs.getString("efbCopyMethod", "Off");
// Texture cache accuracy. Falls back to "Fast" up error.
String textureCacheAccuracy = prefs.getString("textureCacheAccuracy", "128");
// External frame buffer emulation. Falls back to disabled upon error.
String externalFrameBuffer = prefs.getString("externalFrameBuffer", "Disabled");
// Whether or not display list caching is enabled.
boolean dlistCachingEnabled = prefs.getBoolean("cacheDisplayLists", false);
// Whether or not to disable destination alpha.
boolean disableDstAlphaPass = prefs.getBoolean("disableDestinationAlpha", false);
// Whether or not to use fast depth calculation.
boolean useFastDepthCalc = prefs.getBoolean("fastDepthCalculation", true);
// Internal resolution. Falls back to 1x Native upon error.
String internalResolution = prefs.getString("internalResolution", "2");
// Anisotropic Filtering Level. Falls back to 1x upon error.
String anisotropicFiltLevel = prefs.getString("anisotropicFiltering", "0");
// Whether or not Scaled EFB copies are used.
boolean usingScaledEFBCopy = prefs.getBoolean("scaledEFBCopy", true);
// Whether or not per-pixel lighting is used.
boolean usingPerPixelLighting = prefs.getBoolean("perPixelLighting", false);
// Whether or not texture filtering is being forced.
boolean isForcingTextureFiltering = prefs.getBoolean("forceTextureFiltering", false);
// Whether or not fog is disabled.
boolean fogIsDisabled = prefs.getBoolean("disableFog", false);
// CPU related Settings
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUCore", currentEmuCore);
NativeLibrary.SetConfig("Dolphin.ini", "Core", "CPUThread", isUsingDualCore ? "True" : "False");
// General Video Settings
NativeLibrary.SetConfig("Dolphin.ini", "Core", "GFXBackend", currentVideoBackend);
NativeLibrary.SetConfig("Dolphin.ini", "Android", "ScreenControls", drawingOnscreenControls ? "True" : "False");
// Video Hack Settings
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBAccessEnable", skipEFBAccess ? "False" : "True");
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBEmulateFormatChanges", ignoreFormatChanges ? "True" : "False");
// Set EFB Copy Method
if (efbCopyMethod.equals("Off"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "False");
}
else if (efbCopyMethod.equals("Texture"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "True");
}
else if (efbCopyMethod.equals("RAM (uncached)"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyCacheEnable", "False");
}
else if (efbCopyMethod.equals("RAM (cached)"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyEnable", "True");
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBToTextureEnable", "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBCopyCacheEnable", "True");
}
// Set texture cache accuracy
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "SafeTextureCacheColorSamples", textureCacheAccuracy);
// Set external frame buffer.
if (externalFrameBuffer.equals("Disabled"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseXFB", "False");
}
else if (externalFrameBuffer.equals("Virtual"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseXFB", "True");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseRealXFB", "False");
}
else if (externalFrameBuffer.equals("Real"))
{
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseXFB", "True");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "UseRealXFB", "True");
}
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "DlistCachingEnable", dlistCachingEnabled ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "DstAlphaPass", disableDstAlphaPass ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "FastDepthCalc", useFastDepthCalc ? "True" : "False");
//-- Enhancement Settings --//
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EFBScale", internalResolution);
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "MaxAnisotropy", anisotropicFiltLevel);
NativeLibrary.SetConfig("gfx_opengl.ini", "Hacks", "EFBScaledCopy", usingScaledEFBCopy ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "EnablePixelLighting", usingPerPixelLighting ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Enhancements", "ForceFiltering", isForcingTextureFiltering ? "True" : "False");
NativeLibrary.SetConfig("gfx_opengl.ini", "Settings", "DisableFog", fogIsDisabled ? "True" : "False");
}
}

View File

@ -0,0 +1,225 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.settings;
import javax.microedition.khronos.egl.EGL10;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.egl.EGLContext;
import javax.microedition.khronos.egl.EGLDisplay;
import javax.microedition.khronos.egl.EGLSurface;
import javax.microedition.khronos.opengles.GL10;
import org.dolphinemu.dolphinemu.R;
import android.app.Activity;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.PreferenceFragment;
/**
* Responsible for handling the loading of the video preferences.
*/
public final class VideoSettingsFragment extends PreferenceFragment
{
private Activity m_activity;
/**
* Class which provides a means to check various
* info about the OpenGL ES support for a device.
*/
public static final class VersionCheck
{
private EGL10 mEGL;
private EGLDisplay mEGLDisplay;
private EGLConfig[] mEGLConfigs;
private EGLConfig mEGLConfig;
private EGLContext mEGLContext;
private EGLSurface mEGLSurface;
private GL10 mGL;
String mThreadOwner;
public VersionCheck()
{
int[] version = new int[2];
int[] attribList = new int[] {
EGL10.EGL_WIDTH, 1,
EGL10.EGL_HEIGHT, 1,
EGL10.EGL_RENDERABLE_TYPE, 4,
EGL10.EGL_NONE
};
int EGL_CONTEXT_CLIENT_VERSION = 0x3098;
int[] ctx_attribs = new int[] {
EGL_CONTEXT_CLIENT_VERSION, 2,
EGL10.EGL_NONE
};
// No error checking performed, minimum required code to elucidate logic
mEGL = (EGL10) EGLContext.getEGL();
mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY);
mEGL.eglInitialize(mEGLDisplay, version);
mEGLConfig = chooseConfig(); // Choosing a config is a little more complicated
mEGLContext = mEGL.eglCreateContext(mEGLDisplay, mEGLConfig, EGL10.EGL_NO_CONTEXT, ctx_attribs);
mEGLSurface = mEGL.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig, attribList);
mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext);
mGL = (GL10) mEGLContext.getGL();
// Record thread owner of OpenGL context
mThreadOwner = Thread.currentThread().getName();
}
/**
* Gets the OpenGL ES version string.
*
* @return the OpenGL ES version string.
*/
public String getVersion()
{
return mGL.glGetString(GL10.GL_VERSION);
}
/**
* Gets the OpenGL ES vendor string.
*
* @return the OpenGL ES vendor string.
*/
public String getVendor()
{
return mGL.glGetString(GL10.GL_VENDOR);
}
/**
* Gets the name of the OpenGL ES renderer.
*
* @return the name of the OpenGL ES renderer.
*/
public String getRenderer()
{
return mGL.glGetString(GL10.GL_RENDERER);
}
private EGLConfig chooseConfig()
{
int[] attribList = new int[] {
EGL10.EGL_DEPTH_SIZE, 0,
EGL10.EGL_STENCIL_SIZE, 0,
EGL10.EGL_RED_SIZE, 8,
EGL10.EGL_GREEN_SIZE, 8,
EGL10.EGL_BLUE_SIZE, 8,
EGL10.EGL_ALPHA_SIZE, 8,
EGL10.EGL_NONE
};
// No error checking performed, minimum required code to elucidate logic
// Expand on this logic to be more selective in choosing a configuration
int[] numConfig = new int[1];
mEGL.eglChooseConfig(mEGLDisplay, attribList, null, 0, numConfig);
int configSize = numConfig[0];
mEGLConfigs = new EGLConfig[configSize];
mEGL.eglChooseConfig(mEGLDisplay, attribList, mEGLConfigs, configSize, numConfig);
return mEGLConfigs[0]; // Best match is probably the first configuration
}
}
/**
* Checks if this device supports OpenGL ES 3.
*
* @return true if this device supports OpenGL ES 3; false otherwise.
*/
public static boolean SupportsGLES3()
{
VersionCheck mbuffer = new VersionCheck();
String m_GLVersion = mbuffer.getVersion();
String m_GLVendor = mbuffer.getVendor();
String m_GLRenderer = mbuffer.getRenderer();
boolean mSupportsGLES3 = false;
// Check for OpenGL ES 3 support (General case).
if (m_GLVersion != null && (m_GLVersion.contains("OpenGL ES 3.0") || m_GLVersion.equals("OpenGL ES 3.0")))
mSupportsGLES3 = true;
// Checking for OpenGL ES 3 support for certain Qualcomm devices.
if (!mSupportsGLES3 && m_GLVendor != null && m_GLVendor.equals("Qualcomm"))
{
if (m_GLRenderer.contains("Adreno (TM) 3"))
{
int mVStart = m_GLVersion.indexOf("V@") + 2;
int mVEnd = 0;
float mVersion;
for (int a = mVStart; a < m_GLVersion.length(); ++a)
{
if (m_GLVersion.charAt(a) == ' ')
{
mVEnd = a;
break;
}
}
mVersion = Float.parseFloat(m_GLVersion.substring(mVStart, mVEnd));
if (mVersion >= 14.0f)
mSupportsGLES3 = true;
}
}
return mSupportsGLES3;
}
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.video_prefs);
//
// Setting valid video backends.
//
final ListPreference videoBackends = (ListPreference) findPreference("gpuPref");
final boolean deviceSupportsGLES3 = SupportsGLES3();
if (deviceSupportsGLES3)
{
videoBackends.setEntries(R.array.videoBackendEntriesGLES3);
videoBackends.setEntryValues(R.array.videoBackendValuesGLES3);
}
else
{
videoBackends.setEntries(R.array.videoBackendEntriesNoGLES3);
videoBackends.setEntryValues(R.array.videoBackendValuesNoGLES3);
}
}
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
// This makes sure that the container activity has implemented
// the callback interface. If not, it throws an exception
try
{
m_activity = activity;
}
catch (ClassCastException e)
{
throw new ClassCastException(activity.toString());
}
}
@Override
public void onDestroy()
{
super.onDestroy();
// When the fragment is done being used, save the settings to the Dolphin ini file.
UserPreferences.SaveConfigToDolphinIni(m_activity);
}
}

View File

@ -0,0 +1,67 @@
/**
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.sidemenu;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
import java.util.List;
import org.dolphinemu.dolphinemu.R;
/**
* Adapter that backs the sidebar menu.
* <p>
* Responsible for handling the elements of each sidebar item.
*/
public final class SideMenuAdapter extends ArrayAdapter<SideMenuItem>
{
private final Context c;
private final int id;
private final List<SideMenuItem>items;
public SideMenuAdapter(Context context, int textViewResourceId, List<SideMenuItem> objects)
{
super(context, textViewResourceId, objects);
c = context;
id = textViewResourceId;
items = objects;
}
@Override
public SideMenuItem getItem(int i)
{
return items.get(i);
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View v = convertView;
if (v == null)
{
LayoutInflater vi = (LayoutInflater)c.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
v = vi.inflate(id, null);
}
final SideMenuItem item = items.get(position);
if (item != null)
{
TextView title = (TextView) v.findViewById(R.id.SideMenuTitle);
if (title != null)
title.setText(item.getName());
}
return v;
}
}

View File

@ -0,0 +1,58 @@
/*
* Copyright 2013 Dolphin Emulator Project
* Licensed under GPLv2
* Refer to the license.txt file included.
*/
package org.dolphinemu.dolphinemu.sidemenu;
/**
* Represents an item that goes in the sidemenu of the app.
*/
public final class SideMenuItem implements Comparable<SideMenuItem>
{
private final String name;
private final int id;
/**
* Constructor
*
* @param name The name of the SideMenuItem.
* @param id ID number of this specific SideMenuItem.
*/
public SideMenuItem(String name, int id)
{
this.name = name;
this.id = id;
}
/**
* Gets the name of this SideMenuItem.
*
* @return the name of this SideMenuItem.
*/
public String getName()
{
return name;
}
/**
* Gets the ID of this SideMenuItem.
*
* @return the ID of this SideMenuItem.
*/
public int getID()
{
return id;
}
public int compareTo(SideMenuItem o)
{
if (name != null)
return this.name.toLowerCase().compareTo(o.getName().toLowerCase());
else
throw new IllegalArgumentException();
}
}

View File

@ -21,7 +21,6 @@ set(SRCS Src/BreakPoints.cpp
Src/Thread.cpp
Src/Timer.cpp
Src/Version.cpp
Src/VideoBackendBase.cpp
Src/x64ABI.cpp
Src/x64Analyzer.cpp
Src/x64Emitter.cpp

View File

@ -212,7 +212,6 @@
<ClCompile Include="Src\Thread.cpp" />
<ClCompile Include="Src\Timer.cpp" />
<ClCompile Include="Src\Version.cpp" />
<ClCompile Include="Src\VideoBackendBase.cpp" />
<ClCompile Include="Src\x64ABI.cpp" />
<ClCompile Include="Src\x64Analyzer.cpp" />
<ClCompile Include="Src\x64CPUDetect.cpp" />
@ -266,7 +265,6 @@
<ClInclude Include="Src\Thread.h" />
<ClInclude Include="Src\Thunk.h" />
<ClInclude Include="Src\Timer.h" />
<ClInclude Include="Src\VideoBackendBase.h" />
<ClInclude Include="Src\x64ABI.h" />
<ClInclude Include="Src\x64Analyzer.h" />
<ClInclude Include="Src\x64Emitter.h" />
@ -277,4 +275,4 @@
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
</Project>

View File

@ -23,7 +23,6 @@
<ClCompile Include="Src\Thread.cpp" />
<ClCompile Include="Src\Timer.cpp" />
<ClCompile Include="Src\Version.cpp" />
<ClCompile Include="Src\VideoBackendBase.cpp" />
<ClCompile Include="Src\x64Analyzer.cpp" />
<ClCompile Include="Src\x64Emitter.cpp" />
<ClCompile Include="Src\LogManager.cpp">
@ -87,7 +86,6 @@
<ClInclude Include="Src\Thread.h" />
<ClInclude Include="Src\Thunk.h" />
<ClInclude Include="Src\Timer.h" />
<ClInclude Include="Src\VideoBackendBase.h" />
<ClInclude Include="Src\x64Analyzer.h" />
<ClInclude Include="Src\x64Emitter.h" />
<ClInclude Include="Src\Log.h">
@ -124,4 +122,4 @@
<UniqueIdentifier>{f078f36e-a0ff-4cd0-95f8-476100d68e68}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View File

@ -17,9 +17,10 @@
#include "Common.h"
#include "CPUDetect.h"
#include "StringUtil.h"
#include "FileUtil.h"
// Only Linux platforms have /proc/cpuinfo
#if !defined(BLACKBERRY) && !defined(IOS) && !defined(__SYMBIAN32__)
const char procfile[] = "/proc/cpuinfo";
char *GetCPUString()
@ -33,7 +34,7 @@ char *GetCPUString()
auto const fp = file.GetHandle();
if (!fp)
return 0;
while (fgets(buf, sizeof(buf), fp))
{
if (strncmp(buf, marker, sizeof(marker) - 1))
@ -42,6 +43,7 @@ char *GetCPUString()
cpu_string = strndup(cpu_string, strlen(cpu_string) - 1); // Strip the newline
break;
}
return cpu_string;
}
@ -66,6 +68,9 @@ unsigned char GetCPUImplementer()
sscanf(implementer_string, "0x%02hhx", &implementer);
break;
}
free(implementer_string);
return implementer;
}
@ -90,15 +95,17 @@ unsigned short GetCPUPart()
sscanf(part_string, "0x%03hx", &part);
break;
}
return part;
free(part_string);
return part;
}
bool CheckCPUFeature(const char *feature)
{
const char marker[] = "Features\t: ";
char buf[1024];
File::IOFile file(procfile, "r");
auto const fp = file.GetHandle();
if (!fp)
@ -117,10 +124,18 @@ bool CheckCPUFeature(const char *feature)
token = strtok(NULL, " ");
}
}
return false;
}
#endif
int GetCoreCount()
{
#ifdef __SYMBIAN32__
return 1;
#elif defined(BLACKBERRY) || defined(IOS)
return 2;
#else
const char marker[] = "processor\t: ";
int cores = 0;
char buf[1024];
@ -129,14 +144,16 @@ int GetCoreCount()
auto const fp = file.GetHandle();
if (!fp)
return 0;
while (fgets(buf, sizeof(buf), fp))
{
if (strncmp(buf, marker, sizeof(marker) - 1))
continue;
++cores;
}
return cores;
#endif
}
CPUInfo cpu_info;
@ -153,12 +170,58 @@ void CPUInfo::Detect()
HTT = false;
OS64bit = false;
CPU64bit = false;
Mode64bit = false;
Mode64bit = false;
vendor = VENDOR_ARM;
// Get the information about the CPU
strncpy(cpu_string, GetCPUString(), sizeof(cpu_string));
num_cores = GetCoreCount();
#if defined(__SYMBIAN32__) || defined(BLACKBERRY) || defined(IOS)
bool isVFP3 = false;
bool isVFP4 = false;
#ifdef IOS
isVFP3 = true;
// Check for swift arch (VFP4`)
#ifdef __ARM_ARCH_7S__
isVFP4 = true;
#endif // #ifdef __ARM_ARCH_7S__
#elif defined(BLACKBERRY)
isVFP3 = true;
const char cpuInfoPath[] = "/pps/services/hw_info/inventory";
const char marker[] = "Processor_Name::";
const char qcCPU[] = "MSM";
char buf[1024];
FILE* fp;
if (fp = fopen(cpuInfoPath, "r"))
{
while (fgets(buf, sizeof(buf), fp))
{
if (strncmp(buf, marker, sizeof(marker) - 1))
continue;
if (strncmp(buf + sizeof(marker) - 1, qcCPU, sizeof(qcCPU) - 1) == 0)
isVFP4 = true;
break;
}
fclose(fp);
}
#endif
// Hardcode this for now
bSwp = true;
bHalf = true;
bThumb = false;
bFastMult = true;
bVFP = true;
bEDSP = true;
bThumbEE = isVFP3;
bNEON = isVFP3;
bVFPv3 = isVFP3;
bTLS = true;
bVFPv4 = isVFP4;
bIDIVa = isVFP4;
bIDIVt = isVFP4;
bFP = false;
bASIMD = false;
#else
strncpy(cpu_string, GetCPUString(), sizeof(cpu_string));
bSwp = CheckCPUFeature("swp");
bHalf = CheckCPUFeature("half");
bThumb = CheckCPUFeature("thumb");
@ -172,16 +235,15 @@ void CPUInfo::Detect()
bVFPv4 = CheckCPUFeature("vfpv4");
bIDIVa = CheckCPUFeature("idiva");
bIDIVt = CheckCPUFeature("idivt");
// Qualcomm Krait supports IDIVA but it doesn't report it. Check for krait.
if (GetCPUImplementer() == 0x51 && GetCPUPart() == 0x6F) // Krait(300) is 0x6F, Scorpion is 0x4D
bIDIVa = bIDIVt = true;
// These two are ARMv8 specific.
bIDIVa = bIDIVt = true;
// These two require ARMv8 or higher
bFP = CheckCPUFeature("fp");
bASIMD = CheckCPUFeature("asimd");
#endif
// On android, we build a separate library for ARMv7 so this is fine.
// TODO: Check for ARMv7 on other platforms.
#if defined(__ARM_ARCH_7A__)
bArmV7 = true;
#else
@ -193,11 +255,14 @@ void CPUInfo::Detect()
std::string CPUInfo::Summarize()
{
std::string sum;
#if defined(BLACKBERRY) || defined(IOS) || defined(__SYMBIAN32__)
sum = StringFromFormat("%i cores", num_cores);
#else
if (num_cores == 1)
sum = StringFromFormat("%s, %i core", cpu_string, num_cores);
else
sum = StringFromFormat("%s, %i cores", cpu_string, num_cores);
#endif
if (bSwp) sum += ", SWP";
if (bHalf) sum += ", Half";
if (bThumb) sum += ", Thumb";

View File

@ -86,7 +86,7 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated)
Operand2 AssumeMakeOperand2(u32 imm) {
Operand2 op2;
bool result = TryMakeOperand2(imm, op2);
_assert_msg_(DYNA_REC, result, "Could not make assumed Operand2.");
_dbg_assert_msg_(DYNA_REC, result, "Could not make assumed Operand2.");
return op2;
}
@ -117,14 +117,33 @@ bool ARMXEmitter::TrySetValue_TwoOp(ARMReg reg, u32 val)
return true;
}
void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg)
void ARMXEmitter::MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate)
{
union {float f; u32 u;} conv;
conv.f = val;
conv.f = negate ? -val : val;
// Try moving directly first if mantisse is empty
if (cpu_info.bVFPv3 && ((conv.u & 0x7FFFF) == 0))
{
// VFP Encoding for Imms: <7> Not(<6>) Repeat(<6>,5) <5:0> Zeros(19)
bool bit6 = (conv.u & 0x40000000) == 0x40000000;
bool canEncode = true;
for (u32 mask = 0x20000000; mask >= 0x2000000; mask >>= 1)
{
if (((conv.u & mask) == mask) == bit6)
canEncode = false;
}
if (canEncode)
{
u32 imm8 = (conv.u & 0x80000000) >> 24; // sign bit
imm8 |= (!bit6 << 6);
imm8 |= (conv.u & 0x1F80000) >> 19;
VMOV(dest, IMM(imm8));
return;
}
}
MOVI2R(tempReg, conv.u);
VMOV(dest, tempReg);
// TODO: VMOV an IMM directly if possible
// Otherwise, use a literal pool and VLDR directly (+- 1020)
// Otherwise, possible to use a literal pool and VLDR directly (+- 1020)
}
void ARMXEmitter::ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch)
@ -246,8 +265,12 @@ void ARMXEmitter::MOVI2R(ARMReg reg, u32 val, bool optimize)
}
void ARMXEmitter::QuickCallFunction(ARMReg reg, void *func) {
MOVI2R(reg, (u32)(func));
BL(reg);
if (BLInRange(func)) {
BL(func);
} else {
MOVI2R(reg, (u32)(func));
BL(reg);
}
}
void ARMXEmitter::SetCodePtr(u8 *ptr)
@ -369,7 +392,7 @@ FixupBranch ARMXEmitter::B_CC(CCFlags Cond)
void ARMXEmitter::B_CC(CCFlags Cond, const void *fnptr)
{
s32 distance = (s32)fnptr - (s32(code) + 8);
_assert_msg_(DYNA_REC, distance > -33554432
_dbg_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"B_CC out of range (%p calls %p)", code, fnptr);
@ -388,7 +411,7 @@ FixupBranch ARMXEmitter::BL_CC(CCFlags Cond)
void ARMXEmitter::SetJumpTarget(FixupBranch const &branch)
{
s32 distance = (s32(code) - 8) - (s32)branch.ptr;
_assert_msg_(DYNA_REC, distance > -33554432
_dbg_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"SetJumpTarget out of range (%p calls %p)", code,
branch.ptr);
@ -402,7 +425,7 @@ void ARMXEmitter::SetJumpTarget(FixupBranch const &branch)
void ARMXEmitter::B (const void *fnptr)
{
s32 distance = (s32)fnptr - (s32(code) + 8);
_assert_msg_(DYNA_REC, distance > -33554432
_dbg_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"B out of range (%p calls %p)", code, fnptr);
@ -414,10 +437,18 @@ void ARMXEmitter::B(ARMReg src)
Write32(condition | 0x12FFF10 | src);
}
bool ARMXEmitter::BLInRange(const void *fnptr) {
s32 distance = (s32)fnptr - (s32(code) + 8);
if (distance <= -33554432 || distance > 33554432)
return false;
else
return true;
}
void ARMXEmitter::BL(const void *fnptr)
{
s32 distance = (s32)fnptr - (s32(code) + 8);
_assert_msg_(DYNA_REC, distance > -33554432
_dbg_assert_msg_(DYNA_REC, distance > -33554432
&& distance <= 33554432,
"BL out of range (%p calls %p)", code, fnptr);
Write32(condition | 0x0B000000 | ((distance >> 2) & 0x00FFFFFF));
@ -555,7 +586,7 @@ void ARMXEmitter::WriteInstruction (u32 Op, ARMReg Rd, ARMReg Rn, Operand2 Rm, b
}
}
if (op == -1)
_assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType());
_dbg_assert_msg_(DYNA_REC, false, "%s not yet support %d", InstNames[Op], Rm.GetType());
Write32(condition | (op << 21) | (SetFlags ? (1 << 20) : 0) | Rn << 16 | Rd << 12 | Data);
}
@ -581,6 +612,8 @@ void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedData
void ARMXEmitter::LSL (ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, false, dest, src, op2);}
void ARMXEmitter::LSLS(ARMReg dest, ARMReg src, ARMReg op2) { WriteShiftedDataOp(1, true, dest, src, op2);}
void ARMXEmitter::LSR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(3, false, dest, src, op2);}
void ARMXEmitter::ASR (ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, false, dest, src, op2);}
void ARMXEmitter::ASRS(ARMReg dest, ARMReg src, Operand2 op2) { WriteShiftedDataOp(4, true, dest, src, op2);}
void ARMXEmitter::MUL (ARMReg dest, ARMReg src, ARMReg op2)
{
Write32(condition | (dest << 16) | (src << 8) | (9 << 4) | op2);
@ -599,6 +632,11 @@ void ARMXEmitter::UMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn)
Write4OpMultiply(0x8, destLo, destHi, rn, rm);
}
void ARMXEmitter::UMULLS(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn)
{
Write4OpMultiply(0x9, destLo, destHi, rn, rm);
}
void ARMXEmitter::SMULL(ARMReg destLo, ARMReg destHi, ARMReg rm, ARMReg rn)
{
Write4OpMultiply(0xC, destLo, destHi, rn, rm);
@ -652,11 +690,11 @@ void ARMXEmitter::RBIT(ARMReg dest, ARMReg src)
}
void ARMXEmitter::REV (ARMReg dest, ARMReg src)
{
Write32(condition | (0x6B << 20) | (0xF << 16) | (dest << 12) | (0xF3 << 4) | src);
Write32(condition | (0x6BF << 16) | (dest << 12) | (0xF3 << 4) | src);
}
void ARMXEmitter::REV16(ARMReg dest, ARMReg src)
{
Write32(condition | (0x3DF << 16) | (dest << 12) | (0xFD << 4) | src);
Write32(condition | (0x6BF << 16) | (dest << 12) | (0xFB << 4) | src);
}
void ARMXEmitter::_MSR (bool write_nzcvq, bool write_g, Operand2 op2)
@ -677,7 +715,7 @@ void ARMXEmitter::LDREX(ARMReg dest, ARMReg base)
}
void ARMXEmitter::STREX(ARMReg result, ARMReg base, ARMReg op)
{
_assert_msg_(DYNA_REC, (result != base && result != op), "STREX dest can't be other two registers");
_dbg_assert_msg_(DYNA_REC, (result != base && result != op), "STREX dest can't be other two registers");
Write32(condition | (24 << 20) | (base << 16) | (result << 12) | (0xF9 << 4) | op);
}
void ARMXEmitter::DMB ()
@ -730,7 +768,7 @@ void ARMXEmitter::WriteStoreOp(u32 Op, ARMReg Rt, ARMReg Rn, Operand2 Rm, bool R
bool SignedLoad = false;
if (op == -1)
_assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType());
_dbg_assert_msg_(DYNA_REC, false, "%s does not support %d", LoadStoreNames[Op], Rm.GetType());
switch (Op)
{
@ -854,10 +892,25 @@ ARMReg ARMXEmitter::SubBase(ARMReg Reg)
}
// NEON Specific
void ARMXEmitter::VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VABD(float)");
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VABD(float) when CPU doesn't support it");
bool register_quad = Vd >= Q0;
// Gets encoded as a double register
Vd = SubBase(Vd);
Vn = SubBase(Vn);
Vm = SubBase(Vm);
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0xD << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \
| ((Vm & 0x10) << 2) | (Vm & 0xF));
}
void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)");
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it");
_dbg_assert_msg_(DYNA_REC, Vd >= D0, "Pass invalid register to VADD(integer)");
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VADD(integer) when CPU doesn't support it");
bool register_quad = Vd >= Q0;
@ -868,13 +921,13 @@ void ARMXEmitter::VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
Write32((0xF2 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (register_quad << 6) \
| ((Vm & 0x10) << 1) | (Vm & 0xF));
| ((Vm & 0x10) << 1) | (Vm & 0xF));
}
void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)");
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it");
_dbg_assert_msg_(DYNA_REC, Vd >= Q0, "Pass invalid register to VSUB(integer)");
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Can't use VSUB(integer) when CPU doesn't support it");
// Gets encoded as a double register
Vd = SubBase(Vd);
@ -883,36 +936,37 @@ void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
Write32((0xF3 << 24) | ((Vd & 0x10) << 18) | (Size << 20) | ((Vn & 0xF) << 16) \
| ((Vd & 0xF) << 12) | (0x8 << 8) | ((Vn & 0x10) << 3) | (1 << 6) \
| ((Vm & 0x10) << 2) | (Vm & 0xF));
| ((Vm & 0x10) << 2) | (Vm & 0xF));
}
// VFP Specific
struct VFPEnc
{
s16 opc1;
s16 opc2;
};
// Double/single, Neon
const VFPEnc VFPOps[][2] = {
extern const VFPEnc VFPOps[16][2] = {
{{0xE0, 0xA0}, {0x20, 0xD1}}, // 0: VMLA
{{0xE0, 0xA4}, {0x22, 0xD1}}, // 1: VMLS
{{0xE3, 0xA0}, {0x20, 0xD0}}, // 2: VADD
{{0xE3, 0xA4}, {0x22, 0xD0}}, // 3: VSUB
{{0xE2, 0xA0}, {0x30, 0xD1}}, // 4: VMUL
{{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 5: VABS(Vn(0x0) used for encoding)
{{0xE8, 0xA0}, { -1, -1}}, // 6: VDIV
{{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 7: VNEG(Vn(0x1) used for encoding)
{{0xEB, 0xAC}, { -1, -1}}, // 8: VSQRT (Vn(0x1) used for encoding)
{{0xEB, 0xA4}, { -1, -1}}, // 9: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding)
{{0xEB, 0xAC}, { -1, -1}}, // 10: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding)
{{ -1, -1}, {0x3B, 0x30}}, // 11: VABSi
{{0xE1, 0xA4}, { -1, -1}}, // 1: VNMLA
{{0xE0, 0xA4}, {0x22, 0xD1}}, // 2: VMLS
{{0xE1, 0xA0}, { -1, -1}}, // 3: VNMLS
{{0xE3, 0xA0}, {0x20, 0xD0}}, // 4: VADD
{{0xE3, 0xA4}, {0x22, 0xD0}}, // 5: VSUB
{{0xE2, 0xA0}, {0x30, 0xD1}}, // 6: VMUL
{{0xE2, 0xA4}, { -1, -1}}, // 7: VNMUL
{{0xEB, 0xAC}, { -1 /* 0x3B */, -1 /* 0x70 */}}, // 8: VABS(Vn(0x0) used for encoding)
{{0xE8, 0xA0}, { -1, -1}}, // 9: VDIV
{{0xEB, 0xA4}, { -1 /* 0x3B */, -1 /* 0x78 */}}, // 10: VNEG(Vn(0x1) used for encoding)
{{0xEB, 0xAC}, { -1, -1}}, // 11: VSQRT (Vn(0x1) used for encoding)
{{0xEB, 0xA4}, { -1, -1}}, // 12: VCMP (Vn(0x4 | #0 ? 1 : 0) used for encoding)
{{0xEB, 0xAC}, { -1, -1}}, // 13: VCMPE (Vn(0x4 | #0 ? 1 : 0) used for encoding)
{{ -1, -1}, {0x3B, 0x30}}, // 14: VABSi
};
const char *VFPOpNames[] = {
extern const char *VFPOpNames[16] = {
"VMLA",
"VNMLA",
"VMLS",
"VNMLS",
"VADD",
"VSUB",
"VMUL",
"VNMUL",
"VABS",
"VDIV",
"VNEG",
@ -966,6 +1020,7 @@ u32 ARMXEmitter::EncodeVm(ARMReg Vm)
else
return ((Reg & 0x1) << 5) | (Reg >> 1);
}
void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm)
{
bool quad_reg = Vd >= Q0;
@ -973,39 +1028,42 @@ void ARMXEmitter::WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm)
VFPEnc enc = VFPOps[Op][quad_reg];
if (enc.opc1 == -1 && enc.opc2 == -1)
_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP");
_dbg_assert_msg_(DYNA_REC, false, "%s does not support %s", VFPOpNames[Op], quad_reg ? "NEON" : "VFP");
u32 VdEnc = EncodeVd(Vd);
u32 VnEnc = EncodeVn(Vn);
u32 VmEnc = EncodeVm(Vm);
u32 cond = quad_reg ? (0xF << 28) : condition;
Write32(cond | (enc.opc1 << 20) | VnEnc | VdEnc | (enc.opc2 << 4) | (quad_reg << 6) | (double_reg << 8) | VmEnc);
}
void ARMXEmitter::VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(0, Vd, Vn, Vm); }
void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); }
void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); }
void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); }
void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); }
void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(5, Vd, D0, Vm); }
void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); }
void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(7, Vd, D1, Vm); }
void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D1, Vm); }
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(9, Vd, D4, Vm); }
void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D4, Vm); }
void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(9, Vd, D5, D0); }
void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(10, Vd, D5, D0); }
void ARMXEmitter::VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(1, Vd, Vn, Vm); }
void ARMXEmitter::VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(2, Vd, Vn, Vm); }
void ARMXEmitter::VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(3, Vd, Vn, Vm); }
void ARMXEmitter::VADD(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(4, Vd, Vn, Vm); }
void ARMXEmitter::VSUB(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(5, Vd, Vn, Vm); }
void ARMXEmitter::VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(6, Vd, Vn, Vm); }
void ARMXEmitter::VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(7, Vd, Vn, Vm); }
void ARMXEmitter::VABS(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(8, Vd, D0, Vm); }
void ARMXEmitter::VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm){ WriteVFPDataOp(9, Vd, Vn, Vm); }
void ARMXEmitter::VNEG(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(10, Vd, D1, Vm); }
void ARMXEmitter::VSQRT(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(11, Vd, D1, Vm); }
void ARMXEmitter::VCMP(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(12, Vd, D4, Vm); }
void ARMXEmitter::VCMPE(ARMReg Vd, ARMReg Vm){ WriteVFPDataOp(13, Vd, D4, Vm); }
void ARMXEmitter::VCMP(ARMReg Vd){ WriteVFPDataOp(12, Vd, D5, D0); }
void ARMXEmitter::VCMPE(ARMReg Vd){ WriteVFPDataOp(13, Vd, D5, D0); }
void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
{
_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR");
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR");
_dbg_assert_msg_(DYNA_REC, Dest >= S0 && Dest <= D31, "Passed Invalid dest register to VLDR");
_dbg_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid Base register to VLDR");
bool Add = offset >= 0 ? true : false;
u32 imm = abs(offset);
_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough");
_dbg_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VLDR: Offset needs to be word aligned and small enough");
if (imm & 0xC03)
if (imm & 0xC03)
ERROR_LOG(DYNA_REC, "VLDR: Bad offset %08x", imm);
bool single_reg = Dest < D0;
@ -1015,25 +1073,25 @@ void ARMXEmitter::VLDR(ARMReg Dest, ARMReg Base, s16 offset)
if (single_reg)
{
Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x1) << 22) | (1 << 20) | (Base << 16) \
| ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2));
| ((Dest & 0x1E) << 11) | (10 << 8) | (imm >> 2));
}
else
{
Write32(condition | (0xD << 24) | (Add << 23) | ((Dest & 0x10) << 18) | (1 << 20) | (Base << 16) \
| ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2));
| ((Dest & 0xF) << 12) | (11 << 8) | (imm >> 2));
}
}
void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset)
{
_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR");
_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR");
_dbg_assert_msg_(DYNA_REC, Src >= S0 && Src <= D31, "Passed invalid src register to VSTR");
_dbg_assert_msg_(DYNA_REC, Base <= R15, "Passed invalid base register to VSTR");
bool Add = offset >= 0 ? true : false;
u32 imm = abs(offset);
_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough");
_dbg_assert_msg_(DYNA_REC, (imm & 0xC03) == 0, "VSTR: Offset needs to be word aligned and small enough");
if (imm & 0xC03)
if (imm & 0xC03)
ERROR_LOG(DYNA_REC, "VSTR: Bad offset %08x", imm);
bool single_reg = Src < D0;
@ -1043,12 +1101,12 @@ void ARMXEmitter::VSTR(ARMReg Src, ARMReg Base, s16 offset)
if (single_reg)
{
Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x1) << 22) | (Base << 16) \
| ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2));
| ((Src & 0x1E) << 11) | (10 << 8) | (imm >> 2));
}
else
{
Write32(condition | (0xD << 24) | (Add << 23) | ((Src & 0x10) << 18) | (Base << 16) \
| ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2));
| ((Src & 0xF) << 12) | (11 << 8) | (imm >> 2));
}
}
@ -1063,15 +1121,20 @@ void ARMXEmitter::VMSR(ARMReg Rt) {
}
// VFP and ASIMD
void ARMXEmitter::VMOV(ARMReg Dest, Operand2 op2)
{
_dbg_assert_msg_(DYNA_REC, cpu_info.bVFPv3, "VMOV #imm requires VFPv3");
Write32(condition | (0xEB << 20) | EncodeVd(Dest) | (0xA << 8) | op2.Imm8VFP());
}
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src, bool high)
{
_assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg");
_assert_msg_(DYNA_REC, Dest >= D0, "This VMOV doesn't support DEST other than VFP");
_dbg_assert_msg_(DYNA_REC, Src < S0, "This VMOV doesn't support SRC other than ARM Reg");
_dbg_assert_msg_(DYNA_REC, Dest >= D0, "This VMOV doesn't support DEST other than VFP");
Dest = SubBase(Dest);
Write32(condition | (0xE << 24) | (high << 21) | ((Dest & 0xF) << 16) | (Src << 12) \
| (11 << 8) | ((Dest & 0x10) << 3) | (1 << 4));
| (0xB << 8) | ((Dest & 0x10) << 3) | (1 << 4));
}
void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
@ -1091,7 +1154,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
else
{
// Move 64bit from Arm reg
_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON");
_dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM to NEON");
return;
}
}
@ -1111,14 +1174,14 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
else
{
// Move 64bit To Arm reg
_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON");
_dbg_assert_msg_(DYNA_REC, false, "This VMOV doesn't support moving 64bit ARM From NEON");
return;
}
}
else
{
// Move Arm reg to Arm reg
_assert_msg_(DYNA_REC, false, "VMOV doesn't support moving ARM registers");
_dbg_assert_msg_(DYNA_REC, false, "VMOV doesn't support moving ARM registers");
}
}
// Moving NEON registers
@ -1127,7 +1190,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
bool Single = DestSize == 1;
bool Quad = DestSize == 4;
_assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes");
_dbg_assert_msg_(DYNA_REC, SrcSize == DestSize, "VMOV doesn't support moving different register sizes");
Dest = SubBase(Dest);
Src = SubBase(Src);
@ -1142,7 +1205,7 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
// Double and quad
if (Quad)
{
_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD.");
_dbg_assert_msg_(DYNA_REC, cpu_info.bNEON, "Trying to use quad registers when you don't support ASIMD.");
// Gets encoded as a Double register
Write32((0xF2 << 24) | ((Dest & 0x10) << 18) | (2 << 20) | ((Src & 0xF) << 16) \
| ((Dest & 0xF) << 12) | (1 << 8) | ((Src & 0x10) << 3) | (1 << 6) \
@ -1160,13 +1223,39 @@ void ARMXEmitter::VMOV(ARMReg Dest, ARMReg Src)
void ARMXEmitter::VCVT(ARMReg Dest, ARMReg Source, int flags)
{
bool single_reg = (Dest < D0) && (Source < D0);
bool single_double = !single_reg && (Source < D0 || Dest < D0);
bool single_to_double = Source < D0;
int op = ((flags & TO_INT) ? (flags & ROUND_TO_ZERO) : (flags & IS_SIGNED)) ? 1 : 0;
int op2 = ((flags & TO_INT) ? (flags & IS_SIGNED) : 0) ? 1 : 0;
Dest = SubBase(Dest);
Source = SubBase(Source);
if (single_reg)
if (single_double)
{
// S32<->F64
if ((flags & TO_INT) || (flags & TO_FLOAT))
{
if (single_to_double)
{
Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x7 << 19) \
| ((Dest & 0xF) << 12) | (op << 7) | (0x2D << 6) | ((Source & 0x1) << 5) | (Source >> 1));
} else {
Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \
| ((Dest & 0x1E) << 11) | (op << 7) | (0x2D << 6) | ((Source & 0x10) << 1) | (Source & 0xF));
}
}
// F32<->F64
else {
if (single_to_double)
{
Write32(condition | (0x1D << 23) | ((Dest & 0x10) << 18) | (0x3 << 20) | (0x7 << 16) \
| ((Dest & 0xF) << 12) | (0x2B << 6) | ((Source & 0x1) << 5) | (Source >> 1));
} else {
Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x3 << 20) | (0x7 << 16) \
| ((Dest & 0x1E) << 11) | (0x2F << 6) | ((Source & 0x10) << 1) | (Source & 0xF));
}
}
} else if (single_reg) {
Write32(condition | (0x1D << 23) | ((Dest & 0x1) << 22) | (0x7 << 19) | ((flags & TO_INT) << 18) | (op2 << 16) \
| ((Dest & 0x1E) << 11) | (op << 7) | (0x29 << 6) | ((Source & 0x1) << 5) | (Source >> 1));
} else {

View File

@ -365,7 +365,7 @@ private:
u32 EncodeVn(ARMReg Vn);
u32 EncodeVm(ARMReg Vm);
void WriteVFPDataOp(u32 Op, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void Write4OpMultiply(u32 op, ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
// New Ops
@ -431,6 +431,7 @@ public:
void B (ARMReg src);
void BL(const void *fnptr);
void BL(ARMReg src);
bool BLInRange(const void *fnptr);
void PUSH(const int num, ...);
void POP(const int num, ...);
@ -453,6 +454,8 @@ public:
void LSLS(ARMReg dest, ARMReg src, Operand2 op2);
void LSLS(ARMReg dest, ARMReg src, ARMReg op2);
void LSR (ARMReg dest, ARMReg src, Operand2 op2);
void ASR (ARMReg dest, ARMReg src, Operand2 op2);
void ASRS(ARMReg dest, ARMReg src, Operand2 op2);
void SBC (ARMReg dest, ARMReg src, Operand2 op2);
void SBCS(ARMReg dest, ARMReg src, Operand2 op2);
void RBIT(ARMReg dest, ARMReg src);
@ -484,6 +487,7 @@ public:
void MULS(ARMReg dest, ARMReg src, ARMReg op2);
void UMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void UMULLS(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void SMULL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
void UMLAL(ARMReg destLo, ARMReg destHi, ARMReg rn, ARMReg rm);
@ -530,6 +534,7 @@ public:
// Subtracts the base from the register to give us the real one
ARMReg SubBase(ARMReg Reg);
// NEON Only
void VABD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VADD(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm);
@ -541,6 +546,10 @@ public:
// Compares against zero
void VCMP(ARMReg Vd);
void VCMPE(ARMReg Vd);
void VNMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VNMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VNMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VDIV(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VSQRT(ARMReg Vd, ARMReg Vm);
@ -552,6 +561,7 @@ public:
void VMUL(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VMLA(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VMLS(ARMReg Vd, ARMReg Vn, ARMReg Vm);
void VMOV(ARMReg Dest, Operand2 op2);
void VMOV(ARMReg Dest, ARMReg Src, bool high);
void VMOV(ARMReg Dest, ARMReg Src);
void VCVT(ARMReg Dest, ARMReg Src, int flags);
@ -564,7 +574,7 @@ public:
// Wrapper around MOVT/MOVW with fallbacks.
void MOVI2R(ARMReg reg, u32 val, bool optimize = true);
void MOVI2F(ARMReg dest, float val, ARMReg tempReg);
void MOVI2F(ARMReg dest, float val, ARMReg tempReg, bool negate = false);
void ADDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
void ANDI2R(ARMReg rd, ARMReg rs, u32 val, ARMReg scratch);
@ -624,7 +634,11 @@ public:
// Start over if you need to change the code (call FreeCodeSpace(), AllocCodeSpace()).
void WriteProtect()
{
WriteProtectMemory(region, region_size, true);
WriteProtectMemory(region, region_size, true);
}
void UnWriteProtect()
{
UnWriteProtectMemory(region, region_size, false);
}
void ResetCodePtr()
@ -636,8 +650,24 @@ public:
{
return region_size - (GetCodePtr() - region);
}
u8 *GetBasePtr() {
return region;
}
size_t GetOffset(u8 *ptr) {
return ptr - region;
}
};
// VFP Specific
struct VFPEnc {
s16 opc1;
s16 opc2;
};
extern const VFPEnc VFPOps[16][2];
extern const char *VFPOpNames[16];
} // namespace
#endif // _DOLPHIN_INTEL_CODEGEN_

View File

@ -136,7 +136,6 @@ static BOOL GetModuleNameFromAddress( UINT address, LPTSTR lpszModule )
static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, LPTSTR lpszSymbol )
{
BOOL ret = FALSE;
DWORD dwDisp = 0;
DWORD dwSymSize = 10000;
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
@ -153,9 +152,11 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
// Get symbol info for IP
#ifndef _M_X64
DWORD dwDisp = 0;
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
#else
//makes it compile but hell im not sure if this works...
DWORD64 dwDisp = 0;
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
#endif
{

View File

@ -20,45 +20,30 @@
namespace {
static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut, std::string* commentOut)
static void ParseLine(const std::string& line, std::string* keyOut, std::string* valueOut)
{
if (line[0] == '#')
return;
int FirstEquals = (int)line.find("=", 0);
int FirstCommentChar = -1;
// Comments
if (FirstCommentChar < 0)
FirstCommentChar =
(int)line.find("#", FirstEquals > 0 ? FirstEquals : 0);
if (FirstCommentChar < 0 && line[0] == ';')
FirstCommentChar = 0;
// Allow preservation of spacing before comment
if (FirstCommentChar > 0)
{
while (line[FirstCommentChar - 1] == ' ' || line[FirstCommentChar - 1] == 9) // 9 == tab
{
FirstCommentChar--;
}
}
if ((FirstEquals >= 0) && ((FirstCommentChar < 0) || (FirstEquals < FirstCommentChar)))
if (FirstEquals >= 0)
{
// Yes, a valid line!
*keyOut = StripSpaces(line.substr(0, FirstEquals));
if (commentOut) *commentOut = FirstCommentChar > 0 ? line.substr(FirstCommentChar) : std::string("");
if (valueOut) *valueOut = StripQuotes(StripSpaces(line.substr(FirstEquals + 1, FirstCommentChar - FirstEquals - 1)));
if (valueOut) *valueOut = StripQuotes(StripSpaces(line.substr(FirstEquals + 1, std::string::npos)));
}
}
}
std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, std::string* commentOut)
std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut)
{
for (std::vector<std::string>::iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string& line = *iter;
std::string lineKey;
ParseLine(line, &lineKey, valueOut, commentOut);
ParseLine(line, &lineKey, valueOut);
if (!strcasecmp(lineKey.c_str(), key))
return &line;
}
@ -67,12 +52,12 @@ std::string* IniFile::Section::GetLine(const char* key, std::string* valueOut, s
void IniFile::Section::Set(const char* key, const char* newValue)
{
std::string value, commented;
std::string* line = GetLine(key, &value, &commented);
std::string value;
std::string* line = GetLine(key, &value);
if (line)
{
// Change the value - keep the key and comment
*line = StripSpaces(key) + " = " + newValue + commented;
*line = StripSpaces(key) + " = " + newValue;
}
else
{
@ -91,7 +76,7 @@ void IniFile::Section::Set(const char* key, const std::string& newValue, const s
bool IniFile::Section::Get(const char* key, std::string* value, const char* defaultValue)
{
std::string* line = GetLine(key, value, 0);
std::string* line = GetLine(key, value);
if (!line)
{
if (defaultValue)
@ -224,7 +209,7 @@ bool IniFile::Section::Exists(const char *key) const
for (std::vector<std::string>::const_iterator iter = lines.begin(); iter != lines.end(); ++iter)
{
std::string lineKey;
ParseLine(*iter, &lineKey, NULL, NULL);
ParseLine(*iter, &lineKey, NULL);
if (!strcasecmp(lineKey.c_str(), key))
return true;
}
@ -233,7 +218,7 @@ bool IniFile::Section::Exists(const char *key) const
bool IniFile::Section::Delete(const char *key)
{
std::string* line = GetLine(key, 0, 0);
std::string* line = GetLine(key, 0);
for (std::vector<std::string>::iterator liter = lines.begin(); liter != lines.end(); ++liter)
{
if (line == &*liter)
@ -313,7 +298,7 @@ bool IniFile::DeleteKey(const char* sectionName, const char* key)
Section* section = GetSection(sectionName);
if (!section)
return false;
std::string* line = section->GetLine(key, 0, 0);
std::string* line = section->GetLine(key, 0);
for (std::vector<std::string>::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
if (line == &(*liter))
@ -335,7 +320,7 @@ bool IniFile::GetKeys(const char* sectionName, std::vector<std::string>& keys) c
for (std::vector<std::string>::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter)
{
std::string key;
ParseLine(*liter, &key, 0, 0);
ParseLine(*liter, &key, 0);
keys.push_back(key);
}
return true;
@ -421,11 +406,6 @@ bool IniFile::Load(const char* filename)
// New section!
std::string sub = line.substr(1, endpos - 1);
sections.push_back(Section(sub));
if (endpos + 1 < line.size())
{
sections[sections.size() - 1].comment = line.substr(endpos + 1);
}
}
}
else
@ -459,7 +439,7 @@ bool IniFile::Save(const char* filename)
if (section.name != "")
{
out << "[" << section.name << "]" << section.comment << std::endl;
out << "[" << section.name << "]" << std::endl;
}
for (std::vector<std::string>::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter)

View File

@ -25,7 +25,7 @@ public:
bool Exists(const char *key) const;
bool Delete(const char *key);
std::string* GetLine(const char* key, std::string* valueOut, std::string* commentOut);
std::string* GetLine(const char* key, std::string* valueOut);
void Set(const char* key, const char* newValue);
void Set(const char* key, const std::string& newValue, const std::string& defaultValue);
@ -70,7 +70,6 @@ public:
protected:
std::vector<std::string> lines;
std::string name;
std::string comment;
};
bool Load(const char* filename);

View File

@ -20,6 +20,7 @@
#include <linux/ashmem.h>
#endif
#endif
#include <set>
#if defined(__APPLE__)
static const char* ram_temp_file = "/tmp/gc_mem.tmp";
@ -151,7 +152,11 @@ u8* MemArena::Find4GBBase()
PanicAlert("Failed to map 1 GB of memory space: %s", strerror(errno));
return 0;
}
munmap(base, 0x31000000);
#ifndef ANDROID
// Android 4.3 changes how munmap works which causes crashes.
// Keep the memory space after allocating it...
munmap(base, MemSize);
#endif
return static_cast<u8*>(base);
#endif
#endif
@ -214,27 +219,7 @@ static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32
bail:
// Argh! ERROR! Free what we grabbed so far so we can try again.
for (int j = 0; j <= i; j++)
{
SKIP(flags, views[i].flags);
if (views[j].out_ptr_low && *views[j].out_ptr_low)
{
arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
*views[j].out_ptr_low = NULL;
}
if (*views[j].out_ptr)
{
#ifdef _M_X64
arena->ReleaseView(*views[j].out_ptr, views[j].size);
#else
if (!(views[j].flags & MV_MIRROR_PREVIOUS))
{
arena->ReleaseView(*views[j].out_ptr, views[j].size);
}
#endif
*views[j].out_ptr = NULL;
}
}
MemoryMap_Shutdown(views, i+1, flags, arena);
return false;
}
@ -300,15 +285,20 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemArena *arena)
{
std::set<void*> freeset;
for (int i = 0; i < num_views; i++)
{
SKIP(flags, views[i].flags);
if (views[i].out_ptr_low && *views[i].out_ptr_low)
arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
arena->ReleaseView(*views[i].out_ptr, views[i].size);
*views[i].out_ptr = NULL;
if (views[i].out_ptr_low)
*views[i].out_ptr_low = NULL;
const MemoryView* view = &views[i];
u8** outptrs[2] = {view->out_ptr_low, view->out_ptr};
for (int j = 0; j < 2; j++)
{
u8** outptr = outptrs[j];
if (outptr && *outptr && !freeset.count(*outptr))
{
arena->ReleaseView(*outptr, view->size);
freeset.insert(*outptr);
*outptr = NULL;
}
}
}
}

View File

@ -34,7 +34,39 @@ bool AsciiToHex(const char* _szValue, u32& result)
bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list args)
{
int writtenCount = vsnprintf(out, outsize, format, args);
int writtenCount;
#ifdef _WIN32
// You would think *printf are simple, right? Iterate on each character,
// if it's a format specifier handle it properly, etc.
//
// Nooooo. Not according to the C standard.
//
// According to the C99 standard (7.19.6.1 "The fprintf function")
// The format shall be a multibyte character sequence
//
// Because some character encodings might have '%' signs in the middle of
// a multibyte sequence (SJIS for example only specifies that the first
// byte of a 2 byte sequence is "high", the second byte can be anything),
// printf functions have to decode the multibyte sequences and try their
// best to not screw up.
//
// Unfortunately, on Windows, the locale for most languages is not UTF-8
// as we would need. Notably, for zh_TW, Windows chooses EUC-CN as the
// locale, and completely fails when trying to decode UTF-8 as EUC-CN.
//
// On the other hand, the fix is simple: because we use UTF-8, no such
// multibyte handling is required as we can simply assume that no '%' char
// will be present in the middle of a multibyte sequence.
//
// This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
static locale_t c_locale = NULL;
if (!c_locale)
c_locale = _create_locale(LC_ALL, ".1252");
writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
#else
writtenCount = vsnprintf(out, outsize, format, args);
#endif
if (writtenCount > 0 && writtenCount < outsize)
{
@ -58,10 +90,9 @@ std::string StringFromFormat(const char* format, ...)
va_start(args, format);
required = _vscprintf(format, args);
buf = new char[required + 1];
vsnprintf(buf, required, format, args);
CharArrayFromFormatV(buf, required + 1, format, args);
va_end(args);
buf[required] = '\0';
std::string temp = buf;
delete[] buf;
#else

View File

@ -72,6 +72,14 @@ static void __cpuid(int info[4], int x)
#endif
}
#define _XCR_XFEATURE_ENABLED_MASK 0
static unsigned long long _xgetbv(unsigned int index)
{
unsigned int eax, edx;
__asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
return ((unsigned long long)edx << 32) | eax;
}
#endif
#include "Common.h"
@ -149,8 +157,17 @@ void CPUInfo::Detect()
if ((cpu_id[2] >> 9) & 1) bSSSE3 = true;
if ((cpu_id[2] >> 19) & 1) bSSE4_1 = true;
if ((cpu_id[2] >> 20) & 1) bSSE4_2 = true;
if ((cpu_id[2] >> 28) & 1) bAVX = true;
if ((cpu_id[2] >> 25) & 1) bAES = true;
// AVX support requires 3 separate checks:
// - Is the AVX bit set in CPUID?
// - Is the XSAVE bit set in CPUID?
// - XGETBV result has the XCR bit set.
if (((cpu_id[2] >> 28) & 1) && ((cpu_id[2] >> 27) & 1))
{
if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6)
bAVX = true;
}
}
if (max_ex_fn >= 0x80000004) {
// Extract brand string

View File

@ -58,8 +58,8 @@ var describe = GetFirstStdOutLine(gitexe + cmd_describe);
var branch = GetFirstStdOutLine(gitexe + cmd_branch);
var isMaster = +("master" == branch);
// remove hash from description
describe = describe.replace(/-[^-]+(-dirty)?$/, '$1');
// remove hash (and trailing "-0" if needed) from description
describe = describe.replace(/(-0)?-[^-]+(-dirty)?$/, '$2');
var out_contents =
"#define SCM_REV_STR \"" + revision + "\"\n" +

View File

@ -11,7 +11,6 @@ set(SRCS Src/ActionReplay.cpp
Src/GeckoCodeConfig.cpp
Src/GeckoCode.cpp
Src/Movie.cpp
Src/NetPlay.cpp
Src/NetPlayClient.cpp
Src/NetPlayServer.cpp
Src/PatchEngine.cpp
@ -215,6 +214,7 @@ if(_M_ARM)
Src/PowerPC/JitArm32/JitArm_Integer.cpp
Src/PowerPC/JitArm32/JitArm_LoadStore.cpp
Src/PowerPC/JitArm32/JitArm_FloatingPoint.cpp
Src/PowerPC/JitArm32/JitArm_Paired.cpp
Src/PowerPC/JitArm32/JitArm_SystemRegisters.cpp
Src/PowerPC/JitArm32/JitArm_LoadStoreFloating.cpp)
endif()

View File

@ -338,7 +338,6 @@
<ClCompile Include="Src\IPC_HLE\WII_Socket.cpp" />
<ClCompile Include="Src\x64MemTools.cpp" />
<ClCompile Include="Src\Movie.cpp" />
<ClCompile Include="Src\NetPlay.cpp" />
<ClCompile Include="Src\NetPlayClient.cpp" />
<ClCompile Include="Src\NetPlayServer.cpp" />
<ClCompile Include="Src\PatchEngine.cpp" />
@ -550,7 +549,9 @@
<ClInclude Include="Src\IPC_HLE\WII_Socket.h" />
<ClInclude Include="Src\MemTools.h" />
<ClInclude Include="Src\Movie.h" />
<ClInclude Include="Src\NetPlay.h" />
<ClInclude Include="Src\NetPlayClient.h" />
<ClInclude Include="Src\NetPlayProto.h" />
<ClInclude Include="Src\NetPlayServer.h" />
<ClInclude Include="Src\ec_wii.h" />
<ClInclude Include="Src\PatchEngine.h" />
<ClInclude Include="Src\DSPEmulator.h" />

View File

@ -529,15 +529,6 @@
<ClCompile Include="Src\HW\Wiimote.cpp">
<Filter>HW %28Flipper/Hollywood%29\Wiimote</Filter>
</ClCompile>
<ClCompile Include="Src\NetPlay.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
<ClCompile Include="Src\NetPlayServer.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
<ClCompile Include="Src\NetPlayClient.cpp">
<Filter>NetPlay</Filter>
</ClCompile>
<ClCompile Include="Src\BootManager.cpp" />
<ClCompile Include="Src\FifoPlayer\FifoDataFile.cpp">
<Filter>FifoPlayer</Filter>
@ -567,6 +558,8 @@
<ClCompile Include="Src\PowerPC\JitInterface.cpp">
<Filter>PowerPC</Filter>
</ClCompile>
<ClCompile Include="Src\NetPlayClient.cpp" />
<ClCompile Include="Src\NetPlayServer.cpp" />
<ClCompile Include="Src\IPC_HLE\ICMPWin.cpp">
<Filter>IPC HLE %28IOS/Starlet%29\Net</Filter>
</ClCompile>
@ -1027,9 +1020,6 @@
<ClInclude Include="Src\PowerPC\CPUCoreBase.h">
<Filter>PowerPC</Filter>
</ClInclude>
<ClInclude Include="Src\NetPlay.h">
<Filter>NetPlay</Filter>
</ClInclude>
<ClInclude Include="Src\BootManager.h" />
<ClInclude Include="Src\FifoPlayer\FifoDataFile.h">
<Filter>FifoPlayer</Filter>
@ -1059,6 +1049,9 @@
<ClInclude Include="Src\PowerPC\JitInterface.h">
<Filter>PowerPC</Filter>
</ClInclude>
<ClInclude Include="Src\NetPlayClient.h" />
<ClInclude Include="Src\NetPlayProto.h" />
<ClInclude Include="Src\NetPlayServer.h" />
<ClInclude Include="Src\IPC_HLE\WII_IPC_HLE_Device_net_ssl.h">
<Filter>IPC HLE %28IOS/Starlet%29\Net</Filter>
</ClInclude>
@ -1206,9 +1199,6 @@
<Filter Include="HW %28Flipper/Hollywood%29\Wiimote\Real">
<UniqueIdentifier>{1c21a3e1-b791-4a23-b0d5-ed2b2c34007f}</UniqueIdentifier>
</Filter>
<Filter Include="NetPlay">
<UniqueIdentifier>{231ceb02-1122-402a-87a8-094a9ed768c2}</UniqueIdentifier>
</Filter>
<Filter Include="FifoPlayer">
<UniqueIdentifier>{ca7d56f7-4e84-4d15-9aea-7ae6fa7d6586}</UniqueIdentifier>
</Filter>

View File

@ -34,7 +34,7 @@
#include "Host.h"
#include "VideoBackendBase.h"
#include "Movie.h"
#include "NetPlay.h"
#include "NetPlayClient.h"
namespace BootManager
{
@ -43,7 +43,7 @@ namespace BootManager
// Apply fire liberally
struct ConfigCache
{
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF, m_EnableJIT,
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF, m_EnableJIT, bDSPThread,
bVBeamSpeedHack, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
int iTLBHack, iCPUCore;
std::string strBackend;
@ -93,6 +93,7 @@ bool BootCore(const std::string& _rFilename)
config_cache.strBackend = StartUp.m_strVideoBackend;
config_cache.bHLE_BS2 = StartUp.bHLE_BS2;
config_cache.m_EnableJIT = SConfig::GetInstance().m_EnableJIT;
config_cache.bDSPThread = StartUp.bDSPThread;
// General settings
game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread);
@ -106,6 +107,7 @@ bool BootCore(const std::string& _rFilename)
game_ini.Get("Core", "FastDiscSpeed", &StartUp.bFastDiscSpeed, StartUp.bFastDiscSpeed);
game_ini.Get("Core", "BlockMerging", &StartUp.bMergeBlocks, StartUp.bMergeBlocks);
game_ini.Get("Core", "DSPHLE", &StartUp.bDSPHLE, StartUp.bDSPHLE);
game_ini.Get("Core", "DSPThread", &StartUp.bDSPThread, StartUp.bDSPThread);
game_ini.Get("Core", "GFXBackend", &StartUp.m_strVideoBackend, StartUp.m_strVideoBackend.c_str());
game_ini.Get("Core", "CPUCore", &StartUp.iCPUCore, StartUp.iCPUCore);
game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2);
@ -136,8 +138,9 @@ bool BootCore(const std::string& _rFilename)
}
}
if (NetPlay::GetNetPlayPtr())
if (NetPlay::IsNetPlayRunning())
{
StartUp.bCPUThread = g_NetPlaySettings.m_CPUthread;
StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE;
StartUp.bEnableMemcardSaving = g_NetPlaySettings.m_WriteToMemcard;
SConfig::GetInstance().m_EnableJIT = g_NetPlaySettings.m_DSPEnableJIT;
@ -176,6 +179,7 @@ void Stop()
StartUp.bFastDiscSpeed = config_cache.bFastDiscSpeed;
StartUp.bMergeBlocks = config_cache.bMergeBlocks;
StartUp.bDSPHLE = config_cache.bDSPHLE;
StartUp.bDSPThread = config_cache.bDSPThread;
StartUp.m_strVideoBackend = config_cache.strBackend;
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
StartUp.bHLE_BS2 = config_cache.bHLE_BS2;

View File

@ -67,7 +67,12 @@ static const struct {
{ "Wiimote4Connect", 347 /* WXK_F8 */, 1 /* wxMOD_ALT */ },
{ "BalanceBoardConnect",348 /* WXK_F9 */, 1 /* wxMOD_ALT */ },
#endif
{ "ToggleIR", 0, 0 /* wxMOD_NONE */ },
{ "ToggleAspectRatio", 0, 0 /* wxMOD_NONE */ },
{ "ToggleEFBCopies", 0, 0 /* wxMOD_NONE */ },
{ "ToggleFog", 0, 0 /* wxMOD_NONE */ },
{ "IncreaseFrameLimit", 0, 0 /* wxMOD_NONE */ },
{ "DecreaseFrameLimit", 0, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot1", 340 /* WXK_F1 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot2", 341 /* WXK_F2 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot3", 342 /* WXK_F3 */, 0 /* wxMOD_NONE */ },
@ -76,6 +81,8 @@ static const struct {
{ "LoadStateSlot6", 345 /* WXK_F6 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot7", 346 /* WXK_F7 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot8", 347 /* WXK_F8 */, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot9", 0, 0 /* wxMOD_NONE */ },
{ "LoadStateSlot10",0, 0 /* wxMOD_NONE */ },
{ "SaveStateSlot1", 340 /* WXK_F1 */, 4 /* wxMOD_SHIFT */ },
{ "SaveStateSlot2", 341 /* WXK_F2 */, 4 /* wxMOD_SHIFT */ },
@ -85,6 +92,8 @@ static const struct {
{ "SaveStateSlot6", 345 /* WXK_F6 */, 4 /* wxMOD_SHIFT */ },
{ "SaveStateSlot7", 346 /* WXK_F7 */, 4 /* wxMOD_SHIFT */ },
{ "SaveStateSlot8", 347 /* WXK_F8 */, 4 /* wxMOD_SHIFT */ },
{ "SaveStateSlot9", 0, 0 /* wxMOD_NONE */ },
{ "SaveStateSlot10",0, 0 /* wxMOD_NONE */ },
{ "LoadLastState1", 0, 0 /* wxMOD_NONE */ },
{ "LoadLastState2", 0, 0 /* wxMOD_NONE */ },
@ -270,6 +279,9 @@ void SConfig::SaveSettings()
ini.Set("DSP", "Backend", sBackend);
ini.Set("DSP", "Volume", m_Volume);
// Fifo Player
ini.Set("FifoPlayer", "LoopReplay", m_LocalCoreStartupParameter.bLoopFifoReplay);
ini.Save(File::GetUserPath(F_DOLPHINCONFIG_IDX));
m_SYSCONF->Save();
}
@ -445,6 +457,8 @@ void SConfig::LoadSettings()
ini.Get("DSP", "Backend", &sBackend, BACKEND_NULLSOUND);
#endif
ini.Get("DSP", "Volume", &m_Volume, 100);
ini.Get("FifoPlayer", "LoopReplay", &m_LocalCoreStartupParameter.bLoopFifoReplay, true);
}
m_SYSCONF = new SysConf();

View File

@ -79,8 +79,6 @@ void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _
// Function declarations
void EmuThread();
void Stop();
bool g_bStopping = false;
bool g_bHwInit = false;
bool g_bStarted = false;
@ -520,9 +518,6 @@ void SetState(EState _State)
{
switch (_State)
{
case CORE_UNINITIALIZED:
Stop();
break;
case CORE_PAUSE:
CCPU::EnableStepping(true); // Break
Wiimote::Pause();

View File

@ -20,6 +20,7 @@
SCoreStartupParameter::SCoreStartupParameter()
: hInstance(0),
bEnableDebugging(false), bAutomaticStart(false), bBootToPause(false),
bJITNoBlockCache(false), bJITBlockLinking(true),
bJITOff(false),
bJITLoadStoreOff(false), bJITLoadStorelXzOff(false),
@ -46,7 +47,8 @@ SCoreStartupParameter::SCoreStartupParameter()
bRenderWindowAutoSize(false), bKeepWindowOnTop(false),
bFullscreen(false), bRenderToMain(false),
bProgressive(false), bDisableScreenSaver(false),
iPosX(100), iPosY(100), iWidth(800), iHeight(600)
iPosX(100), iPosY(100), iWidth(800), iHeight(600),
bLoopFifoReplay(true)
{
LoadDefaults();
}
@ -54,9 +56,13 @@ SCoreStartupParameter::SCoreStartupParameter()
void SCoreStartupParameter::LoadDefaults()
{
bEnableDebugging = false;
bAutomaticStart = false;
bBootToPause = false;
#ifdef USE_GDBSTUB
iGDBPort = -1;
#endif
iCPUCore = 1;
bCPUThread = false;
bSkipIdle = false;
@ -84,6 +90,8 @@ void SCoreStartupParameter::LoadDefaults()
iWidth = 800;
iHeight = 600;
bLoopFifoReplay = true;
bJITOff = false; // debugger only settings
bJITLoadStoreOff = false;
bJITLoadStoreFloatingOff = false;
@ -314,7 +322,10 @@ bool SCoreStartupParameter::AutoSetup(EBootBS2 _BootBS2)
m_strSRAM = File::GetUserPath(F_GCSRAM_IDX);
if (!bWii)
{
m_strBootROM = File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + Region + DIR_SEP GC_IPL;
m_strBootROM = File::GetUserPath(D_GCUSER_IDX) + DIR_SEP + Region + DIR_SEP GC_IPL;
if (!File::Exists(m_strBootROM))
m_strBootROM = File::GetSysDirectory() + GC_SYS_DIR + DIR_SEP + Region + DIR_SEP GC_IPL;
if (!bHLE_BS2)
{
if (!File::Exists(m_strBootROM))

View File

@ -34,6 +34,14 @@ enum Hotkey
HK_WIIMOTE4_CONNECT,
HK_BALANCEBOARD_CONNECT,
HK_TOGGLE_IR,
HK_TOGGLE_AR,
HK_TOGGLE_EFBCOPIES,
HK_TOGGLE_FOG,
HK_INCREASE_FRAME_LIMIT,
HK_DECREASE_FRAME_LIMIT,
HK_LOAD_STATE_SLOT_1,
HK_LOAD_STATE_SLOT_2,
HK_LOAD_STATE_SLOT_3,
@ -42,6 +50,8 @@ enum Hotkey
HK_LOAD_STATE_SLOT_6,
HK_LOAD_STATE_SLOT_7,
HK_LOAD_STATE_SLOT_8,
HK_LOAD_STATE_SLOT_9,
HK_LOAD_STATE_SLOT_10,
HK_SAVE_STATE_SLOT_1,
HK_SAVE_STATE_SLOT_2,
@ -51,6 +61,8 @@ enum Hotkey
HK_SAVE_STATE_SLOT_6,
HK_SAVE_STATE_SLOT_7,
HK_SAVE_STATE_SLOT_8,
HK_SAVE_STATE_SLOT_9,
HK_SAVE_STATE_SLOT_10,
HK_LOAD_LAST_STATE_1,
HK_LOAD_LAST_STATE_2,
@ -85,6 +97,7 @@ struct SCoreStartupParameter
// 0 = Interpreter
// 1 = Jit
// 2 = JitIL
// 3 = JIT ARM
int iCPUCore;
// JIT (shared between JIT and JITIL)
@ -152,6 +165,9 @@ struct SCoreStartupParameter
int iPosX, iPosY, iWidth, iHeight;
// Fifo Player related settings
bool bLoopFifoReplay;
enum EBootBS2
{
BOOT_DEFAULT,

View File

@ -6,7 +6,10 @@
#include "FifoPlayer.h"
#include "Common.h"
#include "ConfigManager.h"
#include "Core.h"
#include "CoreTiming.h"
#include "Host.h"
#include "HW/GPFifo.h"
#include "HW/Memmap.h"
@ -68,10 +71,18 @@ bool FifoPlayer::Play()
{
if (m_CurrentFrame >= m_FrameRangeEnd)
{
m_CurrentFrame = m_FrameRangeStart;
if (m_Loop)
{
m_CurrentFrame = m_FrameRangeStart;
CoreTiming::downcount = 0;
CoreTiming::Advance();
CoreTiming::downcount = 0;
CoreTiming::Advance();
}
else
{
PowerPC::Stop();
Host_Message(WM_USER_STOP);
}
}
else
{
@ -150,6 +161,7 @@ FifoPlayer::FifoPlayer() :
m_FrameWrittenCb(NULL),
m_File(NULL)
{
m_Loop = SConfig::GetInstance().m_LocalCoreStartupParameter.bLoopFifoReplay;
}
void FifoPlayer::WriteFrame(const FifoFrameInfo &frame, const AnalyzedFrameInfo &info)

View File

@ -86,6 +86,8 @@ private:
bool ShouldLoadBP(u8 address);
bool m_Loop;
u32 m_CurrentFrame;
u32 m_FrameRangeStart;
u32 m_FrameRangeEnd;

View File

@ -193,7 +193,7 @@ bool CEXIETHERNET::Activate()
}
if (mHAdapter == INVALID_HANDLE_VALUE)
{
ERROR_LOG(SP1, "Failed to open any TAP");
PanicAlert("Failed to open any TAP");
return false;
}

View File

@ -7,7 +7,7 @@
#include "../ConfigManager.h"
#include "../CoreTiming.h"
#include "../Movie.h"
#include "../NetPlay.h"
#include "../NetPlayClient.h"
#include "SystemTimers.h"
#include "ProcessorInterface.h"
@ -262,7 +262,7 @@ void Init()
if (Movie::IsRecordingInput() || Movie::IsPlayingInput())
AddDevice(Movie::IsUsingPad(i) ? (Movie::IsUsingBongo(i) ? SIDEVICE_GC_TARUKONGA : SIDEVICE_GC_CONTROLLER) : SIDEVICE_NONE, i);
else if (NetPlay::GetNetPlayPtr())
else if (NetPlay::IsNetPlayRunning())
AddDevice((SIDevices) g_NetPlaySettings.m_Controllers[i], i);
else
AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
@ -644,10 +644,12 @@ void RunSIBuffer()
int GetTicksToNextSIPoll()
{
// Poll for input at regular intervals (once per frame) when playing or recording a movie
if (Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::GetNetPlayPtr())
if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
{
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
}
if (NetPlay::IsNetPlayRunning())
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate / 2;
if (!g_Poll.Y && g_Poll.X)
return VideoInterface::GetTicksPerLine() * g_Poll.X;

View File

@ -32,7 +32,7 @@ void Shutdown()
delete *i;
g_plugin.controllers.clear();
WiimoteReal::Shutdown();
WiimoteReal::Stop();
g_controller_interface.Shutdown();
}

View File

@ -54,6 +54,7 @@ namespace WiimoteReal
{
void Initialize(bool wait = false);
void Stop();
void Shutdown();
void Resume();
void Pause();

View File

@ -13,15 +13,17 @@ static const u8 nothing_id[] = { 0x00, 0x00, 0x00, 0x00, 0x2e, 0x2e };
// The id for a partially inserted extension
static const u8 partially_id[] = { 0x00, 0x00, 0x00, 0x00, 0xff, 0xff };
Attachment::Attachment( const char* const _name ) : name( _name )
Attachment::Attachment( const char* const _name, WiimoteEmu::ExtensionReg& _reg )
: name( _name ), reg( _reg )
{
reg.resize( WIIMOTE_REG_EXT_SIZE, 0);
memset(id, 0, sizeof(id));
memset(calibration, 0, sizeof(calibration));
}
None::None() : Attachment( "None" )
None::None( WiimoteEmu::ExtensionReg& _reg ) : Attachment( "None", _reg )
{
// set up register
memcpy( &reg[0xfa], nothing_id, sizeof(nothing_id) );
memcpy(&id, nothing_id, sizeof(nothing_id));
}
std::string Attachment::GetName() const
@ -29,6 +31,14 @@ std::string Attachment::GetName() const
return name;
}
void Attachment::Reset()
{
// set up register
memset( &reg, 0, WIIMOTE_REG_EXT_SIZE );
memcpy( &reg.constant_id, id, sizeof(id) );
memcpy( &reg.calibration, calibration, sizeof(calibration) );
}
}
void ControllerEmu::Extension::GetState( u8* const data, const bool focus )

View File

@ -14,19 +14,23 @@ namespace WiimoteEmu
class Attachment : public ControllerEmu
{
public:
Attachment( const char* const _name );
Attachment( const char* const _name, WiimoteEmu::ExtensionReg& _reg );
virtual void GetState( u8* const data, const bool focus = true ) {}
void Reset();
std::string GetName() const;
const char* const name;
std::vector<u8> reg;
const char* const name;
WiimoteEmu::ExtensionReg& reg;
u8 id[6];
u8 calibration[0x10];
};
class None : public Attachment
{
public:
None();
None( WiimoteEmu::ExtensionReg& _reg );
};
}

View File

@ -53,7 +53,7 @@ static const u16 classic_dpad_bitmasks[] =
Classic::PAD_UP, Classic::PAD_DOWN, Classic::PAD_LEFT, Classic::PAD_RIGHT
};
Classic::Classic() : Attachment(_trans("Classic"))
Classic::Classic(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Classic"), _reg)
{
// buttons
groups.push_back(m_buttons = new Buttons("Buttons"));
@ -76,9 +76,9 @@ Classic::Classic() : Attachment(_trans("Classic"))
// set up register
// calibration
memcpy(&reg[0x20], classic_calibration, sizeof(classic_calibration));
memcpy(&calibration, classic_calibration, sizeof(classic_calibration));
// id
memcpy(&reg[0xfa], classic_id, sizeof(classic_id));
memcpy(&id, classic_id, sizeof(classic_id));
}
void Classic::GetState(u8* const data, const bool focus)

View File

@ -10,7 +10,7 @@ namespace WiimoteEmu
class Classic : public Attachment
{
public:
Classic();
Classic(WiimoteEmu::ExtensionReg& _reg);
void GetState( u8* const data, const bool focus );
enum

View File

@ -32,7 +32,7 @@ static const u16 drum_button_bitmasks[] =
Drums::BUTTON_PLUS,
};
Drums::Drums() : Attachment(_trans("Drums"))
Drums::Drums(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Drums"), _reg)
{
// pads
groups.push_back(m_pads = new Buttons(_trans("Pads")));
@ -49,7 +49,7 @@ Drums::Drums() : Attachment(_trans("Drums"))
// set up register
// id
memcpy(&reg[0xfa], drums_id, sizeof(drums_id));
memcpy(&id, drums_id, sizeof(drums_id));
}
void Drums::GetState(u8* const data, const bool focus)

View File

@ -10,7 +10,7 @@ namespace WiimoteEmu
class Drums : public Attachment
{
public:
Drums();
Drums(WiimoteEmu::ExtensionReg& _reg);
void GetState( u8* const data, const bool focus );
enum

View File

@ -36,7 +36,7 @@ static const u16 guitar_strum_bitmasks[] =
Guitar::BAR_DOWN,
};
Guitar::Guitar() : Attachment(_trans("Guitar"))
Guitar::Guitar(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Guitar"), _reg)
{
// frets
groups.push_back(m_frets = new Buttons(_trans("Frets")));
@ -62,7 +62,7 @@ Guitar::Guitar() : Attachment(_trans("Guitar"))
// set up register
// id
memcpy(&reg[0xfa], guitar_id, sizeof(guitar_id));
memcpy(&id, guitar_id, sizeof(guitar_id));
}
void Guitar::GetState(u8* const data, const bool focus)

View File

@ -10,7 +10,7 @@ namespace WiimoteEmu
class Guitar : public Attachment
{
public:
Guitar();
Guitar(WiimoteEmu::ExtensionReg& _reg);
void GetState( u8* const data, const bool focus );
enum

View File

@ -31,7 +31,8 @@ static const u8 nunchuk_button_bitmasks[] =
Nunchuk::BUTTON_Z,
};
Nunchuk::Nunchuk(UDPWrapper *wrp) : Attachment(_trans("Nunchuk")) , m_udpWrap(wrp)
Nunchuk::Nunchuk(UDPWrapper *wrp, WiimoteEmu::ExtensionReg& _reg)
: Attachment(_trans("Nunchuk"), _reg) , m_udpWrap(wrp)
{
// buttons
groups.push_back(m_buttons = new Buttons("Buttons"));
@ -55,9 +56,9 @@ Nunchuk::Nunchuk(UDPWrapper *wrp) : Attachment(_trans("Nunchuk")) , m_udpWrap(wr
// set up register
// calibration
memcpy(&reg[0x20], nunchuck_calibration, sizeof(nunchuck_calibration));
memcpy(&calibration, nunchuck_calibration, sizeof(nunchuck_calibration));
// id
memcpy(&reg[0xfa], nunchuck_id, sizeof(nunchuck_id));
memcpy(&id, nunchuck_id, sizeof(nunchuck_id));
// this should get set to 0 on disconnect, but it isn't, o well
memset(m_shake_step, 0, sizeof(m_shake_step));
@ -68,11 +69,45 @@ void Nunchuk::GetState(u8* const data, const bool focus)
wm_extension* const ncdata = (wm_extension*)data;
ncdata->bt = 0;
// stick / not using calibration data for stick, o well
m_stick->GetState(&ncdata->jx, &ncdata->jy, 0x80, focus ? 127 : 0);
// stick
ControlState state[2];
m_stick->GetState(&state[0], &state[1], 0, 1);
nu_cal &cal = *(nu_cal*)&reg.calibration;
nu_js cal_js[2];
cal_js[0] = *&cal.jx;
cal_js[1] = *&cal.jy;
for (int i = 0; i < 2; i++) {
ControlState &s = *&state[i];
nu_js c = *&cal_js[i];
if (s < 0)
s = s * abs(c.min - c.center) + c.center;
else if (s > 0)
s = s * abs(c.max - c.center) + c.center;
else
s = c.center;
}
ncdata->jx = u8(trim(state[0]));
ncdata->jy = u8(trim(state[1]));
if (ncdata->jx != cal.jx.center || ncdata->jy != cal.jy.center)
{
if (ncdata->jy == cal.jy.center)
ncdata->jy = cal.jy.center + 1;
if (ncdata->jx == cal.jx.center)
ncdata->jx = cal.jx.center + 1;
}
if (!focus)
{
ncdata->jx = cal.jx.center;
ncdata->jy = cal.jy.center;
}
AccelData accel;
accel_cal* calib = (accel_cal*)&reg[0x20];
accel_cal* calib = (accel_cal*)&reg.calibration[0];
// tilt
EmulateTilt(&accel, m_tilt, focus);

View File

@ -15,7 +15,7 @@ namespace WiimoteEmu
class Nunchuk : public Attachment
{
public:
Nunchuk(UDPWrapper * wrp);
Nunchuk(UDPWrapper * wrp, WiimoteEmu::ExtensionReg& _reg);
virtual void GetState( u8* const data, const bool focus );

View File

@ -30,7 +30,7 @@ static const char* const turntable_button_names[] =
"-", "+", _trans("Euphoria"),
};
Turntable::Turntable() : Attachment(_trans("Turntable"))
Turntable::Turntable(WiimoteEmu::ExtensionReg& _reg) : Attachment(_trans("Turntable"), _reg)
{
// buttons
groups.push_back(m_buttons = new Buttons("Buttons"));
@ -53,7 +53,7 @@ Turntable::Turntable() : Attachment(_trans("Turntable"))
// set up register
// id
memcpy(&reg[0xfa], turntable_id, sizeof(turntable_id));
memcpy(&id, turntable_id, sizeof(turntable_id));
}
void Turntable::GetState(u8* const data, const bool focus)

View File

@ -10,7 +10,7 @@ namespace WiimoteEmu
class Turntable : public Attachment
{
public:
Turntable();
Turntable(WiimoteEmu::ExtensionReg& _reg);
void GetState(u8* const data, const bool focus);
enum

View File

@ -851,11 +851,8 @@ void Wiimote::HandleExtensionSwap()
// set the wanted extension
m_extension->active_extension = m_extension->switch_extension;
// set register, I hate this
const std::vector<u8> &reg = ((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension])->reg;
memset(&m_reg_ext, 0, WIIMOTE_REG_EXT_SIZE);
memcpy(&m_reg_ext, &reg[0], reg.size());
// reset register
((WiimoteEmu::Attachment*)m_extension->attachments[m_extension->active_extension])->Reset();
}
}

View File

@ -286,12 +286,12 @@ Wiimote::Wiimote( const unsigned int index )
// extension
groups.push_back(m_extension = new Extension(_trans("Extension")));
m_extension->attachments.push_back(new WiimoteEmu::None());
m_extension->attachments.push_back(new WiimoteEmu::Nunchuk(m_udp));
m_extension->attachments.push_back(new WiimoteEmu::Classic());
m_extension->attachments.push_back(new WiimoteEmu::Guitar());
m_extension->attachments.push_back(new WiimoteEmu::Drums());
m_extension->attachments.push_back(new WiimoteEmu::Turntable());
m_extension->attachments.push_back(new WiimoteEmu::None(m_reg_ext));
m_extension->attachments.push_back(new WiimoteEmu::Nunchuk(m_udp, m_reg_ext));
m_extension->attachments.push_back(new WiimoteEmu::Classic(m_reg_ext));
m_extension->attachments.push_back(new WiimoteEmu::Guitar(m_reg_ext));
m_extension->attachments.push_back(new WiimoteEmu::Drums(m_reg_ext));
m_extension->attachments.push_back(new WiimoteEmu::Turntable(m_reg_ext));
m_extension->settings.push_back(new ControlGroup::Setting(_trans("Motion Plus"), 0, 0, 1));

View File

@ -17,7 +17,7 @@
#include <vector>
#include <queue>
// Registry sizes
// Registry sizes
#define WIIMOTE_EEPROM_SIZE (16*1024)
#define WIIMOTE_EEPROM_FREE_SIZE 0x1700
#define WIIMOTE_REG_SPEAKER_SIZE 10
@ -47,6 +47,30 @@ struct ADPCMState
s32 predictor, step;
};
struct ExtensionReg
{
u8 unknown1[0x08];
// address 0x08
u8 controller_data[0x06];
u8 unknown2[0x12];
// address 0x20
u8 calibration[0x10];
u8 unknown3[0x10];
// address 0x40
u8 encryption_key[0x10];
u8 unknown4[0xA0];
// address 0xF0
u8 encryption;
u8 unknown5[0x9];
// address 0xFA
u8 constant_id[6];
};
extern const ReportFeatures reporting_mode_features[];
void EmulateShake(AccelData* const accel_data
@ -143,7 +167,7 @@ private:
ControlGroup* m_rumble;
Extension* m_extension;
ControlGroup* m_options;
// WiiMote accel data
AccelData m_accel;
@ -151,7 +175,7 @@ private:
const u8 m_index;
double ir_sin, ir_cos; //for the low pass filter
UDPWrapper* m_udp;
bool m_rumble_on;
@ -201,30 +225,7 @@ private:
} m_reg_ir;
struct ExtensionReg
{
u8 unknown1[0x08];
// address 0x08
u8 controller_data[0x06];
u8 unknown2[0x12];
// address 0x20
u8 calibration[0x10];
u8 unknown3[0x10];
// address 0x40
u8 encryption_key[0x10];
u8 unknown4[0xA0];
// address 0xF0
u8 encryption;
u8 unknown5[0x9];
// address 0xFA
u8 constant_id[6];
} m_reg_ext;
ExtensionReg m_reg_ext;
struct SpeakerReg
{

View File

@ -54,7 +54,7 @@ struct wm_ir_basic
};
// Three bytes for one object
struct wm_ir_extended
struct wm_ir_extended
{
u8 x;
u8 y;
@ -150,9 +150,9 @@ struct wm_turntable_extension
struct wm_motionplus_data
{
u8 yaw1;
u8 roll1;
u8 pitch1;
u8 yaw2 : 6;
@ -230,7 +230,7 @@ struct wm_status_report
};
#define WM_WRITE_DATA 0x16
struct wm_write_data
struct wm_write_data
{
u8 rumble : 1;
u8 space : 2; //see WM_SPACE_*
@ -241,7 +241,7 @@ struct wm_write_data
};
#define WM_ACK_DATA 0x22
struct wm_acknowledge
struct wm_acknowledge
{
wm_core buttons;
u8 reportID;
@ -276,7 +276,7 @@ struct wm_read_data_reply
#define WM_RDERR_WOREG 7
#define WM_RDERR_NOMEM 8
// Data reports
#define WM_REPORT_CORE 0x30
@ -304,20 +304,20 @@ struct wm_report_core_accel_ir12
#define WM_REPORT_CORE_EXT19 0x34
#define WM_REPORT_CORE_ACCEL_EXT16 0x35
struct wm_report_core_accel_ext16
struct wm_report_core_accel_ext16
{
wm_core c;
wm_accel a;
wm_extension ext;
//wm_ir_basic ir[2];
u8 pad[10];
};
#define WM_REPORT_CORE_IR10_EXT9 0x36
#define WM_REPORT_CORE_ACCEL_IR10_EXT6 0x37
struct wm_report_core_accel_ir10_ext6
struct wm_report_core_accel_ir10_ext6
{
wm_core c;
wm_accel a;
@ -336,7 +336,7 @@ struct wm_report_ext21
#define WM_REPORT_INTERLEAVE2 0x3f
#define WM_SPEAKER_ENABLE 0x14
#define WM_SPEAKER_MUTE 0x19
#define WM_SPEAKER_MUTE 0x19
#define WM_WRITE_SPEAKER_DATA 0x18
struct wm_speaker_data
{
@ -383,9 +383,12 @@ struct cc_trigger
struct nu_cal
{
wm_accel cal_zero; // zero calibration
u8 pad1;
wm_accel cal_g; // g size
u8 pad2;
nu_js jx; //
nu_js jy; //
u8 sum[2];
};
struct cc_cal

View File

@ -570,15 +570,17 @@ void Initialize(bool wait)
g_real_wiimotes_initialized = true;
}
void Shutdown(void)
// called on emulation shutdown
void Stop(void)
{
for (unsigned int i = 0; i < MAX_BBMOTES; ++i)
if (g_wiimotes[i] && g_wiimotes[i]->IsConnected())
g_wiimotes[i]->EmuStop();
}
// WiimoteReal is shutdown on app exit
return;
// called when the dolphin app exits
void Shutdown(void)
{
g_wiimote_scanner.StopScanning();
std::lock_guard<std::recursive_mutex> lk(g_refresh_lock);

View File

@ -1256,8 +1256,6 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICom
void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandInquiry(u8* _Input)
{
// Inquiry should not be called normally
PanicAlertT("HCI_CMD_INQUIRY is called, please report!");
hci_inquiry_cp* pInquiry = (hci_inquiry_cp*)_Input;
INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_INQUIRY:");
@ -1863,8 +1861,6 @@ CWII_IPC_HLE_WiiMote* CWII_IPC_HLE_Device_usb_oh1_57e_305::AccessWiiMote(const b
}
ERROR_LOG(WII_IPC_WIIMOTE,"Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x",
_rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]);
PanicAlertT("Can't find WiiMote by bd: %02x:%02x:%02x:%02x:%02x:%02x",
_rAddr.b[0], _rAddr.b[1], _rAddr.b[2], _rAddr.b[3], _rAddr.b[4], _rAddr.b[5]);
return NULL;
}

View File

@ -156,6 +156,7 @@ void Init()
{
ReadHeader();
std::thread md5thread(CheckMD5);
md5thread.detach();
if ((strncmp((char *)tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str(), 6)))
{
PanicAlert("The recorded game (%s) is not the same as the selected game (%s)", tmpHeader.gameID, Core::g_CoreStartupParameter.GetUniqueID().c_str());
@ -167,6 +168,7 @@ void Init()
{
GetSettings();
std::thread md5thread(GetMD5);
md5thread.detach();
}
g_frameSkipCounter = g_framesToSkip;

View File

@ -1,401 +0,0 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "NetPlay.h"
// for wiimote
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "IPC_HLE/WII_IPC_HLE_WiiMote.h"
// for gcpad
#include "HW/SI_DeviceGCController.h"
#include "HW/SI_DeviceGCSteeringWheel.h"
#include "HW/SI_DeviceDanceMat.h"
// for gctime
#include "HW/EXI_DeviceIPL.h"
// for wiimote/ OSD messages
#include "Core.h"
#include "ConfigManager.h"
std::mutex crit_netplay_ptr;
static NetPlay* netplay_ptr = NULL;
NetSettings g_NetPlaySettings;
#define RPT_SIZE_HACK (1 << 16)
// called from ---GUI--- thread
NetPlay::NetPlay(NetPlayUI* dialog)
: m_dialog(dialog), m_is_running(false), m_do_loop(true)
{
m_target_buffer_size = 20;
ClearBuffers();
}
void NetPlay_Enable(NetPlay* const np)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
netplay_ptr = np;
}
void NetPlay_Disable()
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
netplay_ptr = NULL;
}
// called from ---GUI--- thread
NetPlay::~NetPlay()
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
netplay_ptr = NULL;
// not perfect
if (m_is_running)
StopGame();
}
NetPlay::Player::Player()
{
memset(pad_map, -1, sizeof(pad_map));
}
// called from ---GUI--- thread
std::string NetPlay::Player::ToString() const
{
std::ostringstream ss;
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
for (unsigned int i=0; i<4; ++i)
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
ss << '|';
return ss.str();
}
NetPad::NetPad()
{
nHi = 0x00808080;
nLo = 0x80800000;
}
NetPad::NetPad(const SPADStatus* const pad_status)
{
nHi = (u32)((u8)pad_status->stickY);
nHi |= (u32)((u8)pad_status->stickX << 8);
nHi |= (u32)((u16)pad_status->button << 16);
nHi |= 0x00800000;
nLo = (u8)pad_status->triggerRight;
nLo |= (u32)((u8)pad_status->triggerLeft << 8);
nLo |= (u32)((u8)pad_status->substickY << 16);
nLo |= (u32)((u8)pad_status->substickX << 24);
}
// called from ---NETPLAY--- thread
void NetPlay::ClearBuffers()
{
// clear pad buffers, Clear method isn't thread safe
for (unsigned int i=0; i<4; ++i)
{
while (m_pad_buffer[i].Size())
m_pad_buffer[i].Pop();
while (m_wiimote_buffer[i].Size())
m_wiimote_buffer[i].Pop();
m_wiimote_input[i].clear();
}
}
// called from ---CPU--- thread
bool NetPlay::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local pad
unsigned int in_game_num = m_local_player->pad_map[pad_nb];
// does this local pad map in game?
if (in_game_num < 4)
{
NetPad np(pad_status);
// adjust the buffer either up or down
// inserting multiple padstates or dropping states
while (m_pad_buffer[in_game_num].Size() <= m_target_buffer_size)
{
// add to buffer
m_pad_buffer[in_game_num].Push(np);
// send
SendPadState(pad_nb, np);
}
}
} // unlock players
//Common::Timer bufftimer;
//bufftimer.Start();
// get padstate from buffer and send to game
while (!m_pad_buffer[pad_nb].Pop(*netvalues))
{
// wait for receiving thread to push some data
Common::SleepCurrentThread(1);
if (false == m_is_running)
return false;
// TODO: check the time of bufftimer here,
// if it gets pretty high, ask the user if they want to disconnect
}
//u64 hangtime = bufftimer.GetTimeElapsed();
//if (hangtime > 10)
//{
// std::ostringstream ss;
// ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)";
// Core::DisplayMessage(ss.str(), 1000);
//}
return true;
}
// called from ---CPU--- thread
void NetPlay::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1);
m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size);
m_wiimote_input[_number].back().channel = _channelID;
}
}
// called from ---CPU--- thread
void NetPlay::WiimoteUpdate(int _number)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]);
// TODO: send it
m_wiimote_input[_number].clear();
}
} // unlock players
if (0 == m_wiimote_buffer[_number].Size())
{
//PanicAlert("PANIC");
return;
}
NetWiimote nw;
m_wiimote_buffer[_number].Pop(nw);
NetWiimote::const_iterator
i = nw.begin(), e = nw.end();
for ( ; i!=e; ++i)
Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK);
}
// called from ---GUI--- thread
bool NetPlay::StartGame(const std::string &path)
{
if (m_is_running)
{
PanicAlertT("Game is already running!");
return false;
}
m_dialog->AppendChat(" -- STARTING GAME -- ");
m_is_running = true;
NetPlay_Enable(this);
ClearBuffers();
// boot game
m_dialog->BootGame(path);
// temporary
NetWiimote nw;
for (unsigned int i = 0; i<4; ++i)
for (unsigned int f = 0; f<2; ++f)
m_wiimote_buffer[i].Push(nw);
return true;
}
// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
bool NetPlay::StopGame()
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
if (false == m_is_running)
{
PanicAlertT("Game isn't running!");
return false;
}
m_dialog->AppendChat(" -- STOPPING GAME -- ");
m_is_running = false;
NetPlay_Disable();
// stop game
m_dialog->StopGame();
return true;
}
void NetPlay::SetMemcardWriteEnabled(bool enabled)
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
g_NetPlaySettings.m_WriteToMemcard = enabled;
}
// called from ---CPU--- thread
u8 NetPlay::GetPadNum(u8 numPAD)
{
// TODO: i don't like that this loop is running everytime there is rumble
unsigned int i = 0;
for (; i<4; ++i)
if (numPAD == m_local_player->pad_map[i])
break;
return i;
}
void NetPlay::GetNetSettings()
{
SConfig &instance = SConfig::GetInstance();
g_NetPlaySettings.m_DSPHLE = instance.m_LocalCoreStartupParameter.bDSPHLE;
g_NetPlaySettings.m_DSPEnableJIT = instance.m_EnableJIT;
for (unsigned int i = 0; i < 4; ++i)
g_NetPlaySettings.m_Controllers[i] = SConfig::GetInstance().m_SIDevice[i];
}
// stuff hacked into dolphin
// called from ---CPU--- thread
// Actual Core function which is called on every frame
bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
return netplay_ptr->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus);
else
return false;
}
bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
// called from ---CPU--- thread
// so all players' games get the same time
u32 CEXIIPL::NetPlay_GetGCTime()
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
return 1272737767; // watev
else
return 0;
}
// called from ---CPU--- thread
// return the local pad num that should rumble given a ingame pad num
u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
return netplay_ptr->GetPadNum(numPAD);
else
return numPAD;
}
u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
// called from ---CPU--- thread
// wiimote update / used for frame counting
//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int)
{
//CritLocker crit(crit_netplay_ptr);
//if (netplay_ptr)
// netplay_ptr->WiimoteUpdate(_number);
}
// called from ---CPU--- thread
//
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
{
//CritLocker crit(crit_netplay_ptr);
//if (netplay_ptr)
// return netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now
//else
return _number;
}
// called from ---CPU--- thread
// intercept wiimote input callback
//bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size)
bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&)
{
std::lock_guard<std::mutex> lk(crit_netplay_ptr);
if (netplay_ptr)
//{
// if (_Size >= RPT_SIZE_HACK)
// {
// _Size -= RPT_SIZE_HACK;
// return false;
// }
// else
// {
// netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size);
// // don't use this packet
return true;
// }
//}
else
return false;
}
NetPlay* NetPlay::GetNetPlayPtr()
{
return netplay_ptr;
}

View File

@ -1,275 +0,0 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _NETPLAY_H
#define _NETPLAY_H
#include "Common.h"
#include "CommonTypes.h"
#include "Thread.h"
#include "Timer.h"
#include <SFML/Network.hpp>
#include "GCPadStatus.h"
#include <functional>
#include <map>
#include <queue>
#include <sstream>
#include "FifoQueue.h"
class NetPad
{
public:
NetPad();
NetPad(const SPADStatus* const);
u32 nHi;
u32 nLo;
};
struct NetSettings
{
bool m_DSPHLE;
bool m_DSPEnableJIT;
bool m_WriteToMemcard;
u8 m_Controllers[4];
};
extern NetSettings g_NetPlaySettings;
struct Rpt : public std::vector<u8>
{
u16 channel;
};
typedef std::vector<Rpt> NetWiimote;
#define NETPLAY_VERSION "Dolphin NetPlay 2013-07-22"
// messages
enum
{
NP_MSG_PLAYER_JOIN = 0x10,
NP_MSG_PLAYER_LEAVE = 0x11,
NP_MSG_CHAT_MESSAGE = 0x30,
NP_MSG_PAD_DATA = 0x60,
NP_MSG_PAD_MAPPING = 0x61,
NP_MSG_PAD_BUFFER = 0x62,
NP_MSG_WIIMOTE_DATA = 0x70,
NP_MSG_WIIMOTE_MAPPING = 0x71, // just using pad mapping for now
NP_MSG_START_GAME = 0xA0,
NP_MSG_CHANGE_GAME = 0xA1,
NP_MSG_STOP_GAME = 0xA2,
NP_MSG_DISABLE_GAME = 0xA3,
NP_MSG_READY = 0xD0,
NP_MSG_NOT_READY = 0xD1,
NP_MSG_PING = 0xE0,
NP_MSG_PONG = 0xE1,
};
typedef u8 MessageId;
typedef u8 PlayerId;
typedef s8 PadMapping;
typedef u32 FrameNum;
enum
{
CON_ERR_SERVER_FULL = 1,
CON_ERR_GAME_RUNNING,
CON_ERR_VERSION_MISMATCH
};
class NetPlayUI
{
public:
virtual ~NetPlayUI() {};
virtual void BootGame(const std::string& filename) = 0;
virtual void StopGame() = 0;
virtual void Update() = 0;
virtual void AppendChat(const std::string& msg) = 0;
virtual void OnMsgChangeGame(const std::string& filename) = 0;
virtual void OnMsgStartGame() = 0;
virtual void OnMsgStopGame() = 0;
};
class NetPlay
{
public:
NetPlay(NetPlayUI* _dialog);
virtual ~NetPlay();
//virtual void ThreadFunc() = 0;
bool is_connected;
// Send and receive pads values
void WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size);
void WiimoteUpdate(int _number);
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
virtual bool ChangeGame(const std::string& game) = 0;
virtual void GetPlayerList(std::string& list, std::vector<int>& pid_list) = 0;
virtual void SendChatMessage(const std::string& msg) = 0;
virtual bool StartGame(const std::string &path);
virtual bool StopGame();
virtual void SetMemcardWriteEnabled(bool enabled);
//void PushPadStates(unsigned int count);
u8 GetPadNum(u8 numPAD);
static NetPlay* GetNetPlayPtr();
protected:
//void GetBufferedPad(const u8 pad_nb, NetPad* const netvalues);
void ClearBuffers();
void GetNetSettings();
virtual void SendPadState(const PadMapping local_nb, const NetPad& np) = 0;
struct
{
std::recursive_mutex game;
// lock order
std::recursive_mutex players, send;
} m_crit;
class Player
{
public:
Player();
std::string ToString() const;
PlayerId pid;
std::string name;
PadMapping pad_map[4];
std::string revision;
};
Common::FifoQueue<NetPad> m_pad_buffer[4];
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];
NetWiimote m_wiimote_input[4];
NetPlayUI* m_dialog;
sf::SocketTCP m_socket;
std::thread m_thread;
sf::Selector<sf::SocketTCP> m_selector;
std::string m_selected_game;
volatile bool m_is_running;
volatile bool m_do_loop;
unsigned int m_target_buffer_size;
Player* m_local_player;
u32 m_current_game;
};
void NetPlay_Enable(NetPlay* const np);
void NetPlay_Disable();
class NetPlayServer : public NetPlay
{
public:
void ThreadFunc();
NetPlayServer(const u16 port, const std::string& name, NetPlayUI* dialog);
~NetPlayServer();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
// Send and receive pads values
//bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
bool StartGame(const std::string &path);
bool StopGame();
bool GetPadMapping(const int pid, int map[]);
bool SetPadMapping(const int pid, const int map[]);
u64 CalculateMinimumBufferTime();
void AdjustPadBufferSize(unsigned int size);
#ifdef USE_UPNP
void TryPortmapping(u16 port);
#endif
private:
class Client : public Player
{
public:
Client() : ping(0), current_game(0) {}
sf::SocketTCP socket;
u64 ping;
u32 current_game;
};
void SendPadState(const PadMapping local_nb, const NetPad& np);
void SendToClients(sf::Packet& packet, const PlayerId skip_pid = 0);
unsigned int OnConnect(sf::SocketTCP& socket);
unsigned int OnDisconnect(sf::SocketTCP& socket);
unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket);
void UpdatePadMapping();
std::map<sf::SocketTCP, Client> m_players;
Common::Timer m_ping_timer;
u32 m_ping_key;
bool m_update_pings;
#ifdef USE_UPNP
static void mapPortThread(const u16 port);
static void unmapPortThread();
static bool initUPnP();
static bool UPnPMapPort(const std::string& addr, const u16 port);
static bool UPnPUnmapPort(const u16 port);
static struct UPNPUrls m_upnp_urls;
static struct IGDdatas m_upnp_data;
static u16 m_upnp_mapped;
static bool m_upnp_inited;
static bool m_upnp_error;
static std::thread m_upnp_thread;
#endif
};
class NetPlayClient : public NetPlay
{
public:
void ThreadFunc();
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name);
~NetPlayClient();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
// Send and receive pads values
//bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
bool StartGame(const std::string &path);
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
private:
void SendPadState(const PadMapping local_nb, const NetPad& np);
unsigned int OnData(sf::Packet& packet);
PlayerId m_pid;
std::map<PlayerId, Player> m_players;
};
#endif

View File

@ -2,21 +2,81 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "NetPlay.h"
#include "NetPlayClient.h"
// for wiimote
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
#include "IPC_HLE/WII_IPC_HLE_WiiMote.h"
// for gcpad
#include "HW/SI_DeviceGCController.h"
#include "HW/SI_DeviceGCSteeringWheel.h"
#include "HW/SI_DeviceDanceMat.h"
// for gctime
#include "HW/EXI_DeviceIPL.h"
// for wiimote/ OSD messages
#include "Core.h"
#include "ConfigManager.h"
std::mutex crit_netplay_client;
static NetPlayClient * netplay_client = NULL;
NetSettings g_NetPlaySettings;
#define RPT_SIZE_HACK (1 << 16)
NetPlayClient::Player::Player()
{
memset(pad_map, -1, sizeof(pad_map));
}
// called from ---GUI--- thread
std::string NetPlayClient::Player::ToString() const
{
std::ostringstream ss;
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
for (unsigned int i=0; i<4; ++i)
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
ss << " | " << ping << "ms";
return ss.str();
}
NetPad::NetPad()
{
nHi = 0x00808080;
nLo = 0x80800000;
}
NetPad::NetPad(const SPADStatus* const pad_status)
{
nHi = (u32)((u8)pad_status->stickY);
nHi |= (u32)((u8)pad_status->stickX << 8);
nHi |= (u32)((u16)pad_status->button << 16);
nHi |= 0x00800000;
nLo = (u8)pad_status->triggerRight;
nLo |= (u32)((u8)pad_status->triggerLeft << 8);
nLo |= (u32)((u8)pad_status->substickY << 16);
nLo |= (u32)((u8)pad_status->substickX << 24);
}
// called from ---GUI--- thread
NetPlayClient::~NetPlayClient()
{
// not perfect
if (m_is_running)
StopGame();
if (is_connected)
{
m_do_loop = false;
m_thread.join();
}
}
}
// called from ---GUI--- thread
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name) : NetPlay(dialog)
NetPlayClient::NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name) : m_dialog(dialog), m_is_running(false), m_do_loop(true)
{
m_target_buffer_size = 20;
ClearBuffers();
is_connected = false;
// why is false successful? documentation says true is
@ -193,6 +253,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
packet >> m_current_game;
packet >> g_NetPlaySettings.m_CPUthread;
packet >> g_NetPlaySettings.m_DSPEnableJIT;
packet >> g_NetPlaySettings.m_DSPHLE;
packet >> g_NetPlaySettings.m_WriteToMemcard;
@ -233,6 +294,21 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
}
break;
case NP_MSG_PLAYER_PING_DATA:
{
PlayerId pid;
packet >> pid;
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
Player& player = m_players[pid];
packet >> player.ping;
}
m_dialog->Update();
}
break;
default :
PanicAlertT("Unknown message received with id : %d", mid);
break;
@ -328,12 +404,31 @@ bool NetPlayClient::StartGame(const std::string &path)
spac << m_current_game;
spac << (char *)&g_NetPlaySettings;
if (false == NetPlay::StartGame(path))
return false;
std::lock_guard<std::recursive_mutex> lks(m_crit.send);
m_socket.Send(spac);
if (m_is_running)
{
PanicAlertT("Game is already running!");
return false;
}
m_dialog->AppendChat(" -- STARTING GAME -- ");
m_is_running = true;
NetPlay_Enable(this);
ClearBuffers();
// boot game
m_dialog->BootGame(path);
// temporary
NetWiimote nw;
for (unsigned int i = 0; i<4; ++i)
for (unsigned int f = 0; f<2; ++f)
m_wiimote_buffer[i].Push(nw);
return true;
}
@ -342,3 +437,283 @@ bool NetPlayClient::ChangeGame(const std::string&)
{
return true;
}
// called from ---NETPLAY--- thread
void NetPlayClient::ClearBuffers()
{
// clear pad buffers, Clear method isn't thread safe
for (unsigned int i=0; i<4; ++i)
{
while (m_pad_buffer[i].Size())
m_pad_buffer[i].Pop();
while (m_wiimote_buffer[i].Size())
m_wiimote_buffer[i].Pop();
m_wiimote_input[i].clear();
}
}
// called from ---CPU--- thread
bool NetPlayClient::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local pad
unsigned int in_game_num = m_local_player->pad_map[pad_nb];
// does this local pad map in game?
if (in_game_num < 4)
{
NetPad np(pad_status);
// adjust the buffer either up or down
// inserting multiple padstates or dropping states
while (m_pad_buffer[in_game_num].Size() <= m_target_buffer_size)
{
// add to buffer
m_pad_buffer[in_game_num].Push(np);
// send
SendPadState(pad_nb, np);
}
}
} // unlock players
//Common::Timer bufftimer;
//bufftimer.Start();
// get padstate from buffer and send to game
while (!m_pad_buffer[pad_nb].Pop(*netvalues))
{
// wait for receiving thread to push some data
Common::SleepCurrentThread(1);
if (false == m_is_running)
return false;
// TODO: check the time of bufftimer here,
// if it gets pretty high, ask the user if they want to disconnect
}
//u64 hangtime = bufftimer.GetTimeElapsed();
//if (hangtime > 10)
//{
// std::ostringstream ss;
// ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)";
// Core::DisplayMessage(ss.str(), 1000);
//}
return true;
}
// called from ---CPU--- thread
void NetPlayClient::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1);
m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size);
m_wiimote_input[_number].back().channel = _channelID;
}
}
// called from ---CPU--- thread
void NetPlayClient::WiimoteUpdate(int _number)
{
{
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
// in game mapping for this local wiimote
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
// does this local pad map in game?
if (in_game_num < 4)
{
m_wiimote_buffer[in_game_num].Push(m_wiimote_input[_number]);
// TODO: send it
m_wiimote_input[_number].clear();
}
} // unlock players
if (0 == m_wiimote_buffer[_number].Size())
{
//PanicAlert("PANIC");
return;
}
NetWiimote nw;
m_wiimote_buffer[_number].Pop(nw);
NetWiimote::const_iterator
i = nw.begin(), e = nw.end();
for ( ; i!=e; ++i)
Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK);
}
// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
bool NetPlayClient::StopGame()
{
std::lock_guard<std::recursive_mutex> lkg(m_crit.game);
if (false == m_is_running)
{
PanicAlertT("Game isn't running!");
return false;
}
m_dialog->AppendChat(" -- STOPPING GAME -- ");
m_is_running = false;
NetPlay_Disable();
// stop game
m_dialog->StopGame();
return true;
}
// called from ---CPU--- thread
u8 NetPlayClient::GetPadNum(u8 numPAD)
{
// TODO: i don't like that this loop is running everytime there is rumble
unsigned int i = 0;
for (; i<4; ++i)
if (numPAD == m_local_player->pad_map[i])
break;
return i;
}
// stuff hacked into dolphin
// called from ---CPU--- thread
// Actual Core function which is called on every frame
bool CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
return netplay_client->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus);
else
return false;
}
bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
{
return CSIDevice_GCController::NetPlay_GetInput(numPAD, PadStatus, PADStatus);
}
// called from ---CPU--- thread
// so all players' games get the same time
u32 CEXIIPL::NetPlay_GetGCTime()
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
return 1272737767; // watev
else
return 0;
}
// called from ---CPU--- thread
// return the local pad num that should rumble given a ingame pad num
u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
return netplay_client->GetPadNum(numPAD);
else
return numPAD;
}
u8 CSIDevice_GCSteeringWheel::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
u8 CSIDevice_DanceMat::NetPlay_GetPadNum(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_GetPadNum(numPAD);
}
// called from ---CPU--- thread
// wiimote update / used for frame counting
//void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int)
{
//CritLocker crit(crit_netplay_client);
//if (netplay_client)
// netplay_client->WiimoteUpdate(_number);
}
// called from ---CPU--- thread
//
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
{
//CritLocker crit(crit_netplay_client);
//if (netplay_client)
// return netplay_client->GetPadNum(_number); // just using gcpad mapping for now
//else
return _number;
}
// called from ---CPU--- thread
// intercept wiimote input callback
//bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size)
bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int, u16, const void*, u32&)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
if (netplay_client)
//{
// if (_Size >= RPT_SIZE_HACK)
// {
// _Size -= RPT_SIZE_HACK;
// return false;
// }
// else
// {
// netplay_client->WiimoteInput(_number, _channelID, _pData, _Size);
// // don't use this packet
return true;
// }
//}
else
return false;
}
bool NetPlay::IsNetPlayRunning()
{
return netplay_client != NULL;
}
void NetPlay_Enable(NetPlayClient* const np)
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
netplay_client = np;
}
void NetPlay_Disable()
{
std::lock_guard<std::mutex> lk(crit_netplay_client);
netplay_client = NULL;
}

View File

@ -0,0 +1,135 @@
// Copyright 2013 Dolphin Emulator Project
// Licensed under GPLv2
// Refer to the license.txt file included.
#ifndef _NETPLAY_H
#define _NETPLAY_H
#include "Common.h"
#include "CommonTypes.h"
#include "Thread.h"
#include "Timer.h"
#include <SFML/Network.hpp>
#include "NetPlayProto.h"
#include "GCPadStatus.h"
#include <functional>
#include <map>
#include <queue>
#include <sstream>
#include "FifoQueue.h"
class NetPad
{
public:
NetPad();
NetPad(const SPADStatus* const);
u32 nHi;
u32 nLo;
};
class NetPlayUI
{
public:
virtual ~NetPlayUI() {};
virtual void BootGame(const std::string& filename) = 0;
virtual void StopGame() = 0;
virtual void Update() = 0;
virtual void AppendChat(const std::string& msg) = 0;
virtual void OnMsgChangeGame(const std::string& filename) = 0;
virtual void OnMsgStartGame() = 0;
virtual void OnMsgStopGame() = 0;
};
extern NetSettings g_NetPlaySettings;
class NetPlayClient
{
public:
void ThreadFunc();
NetPlayClient(const std::string& address, const u16 port, NetPlayUI* dialog, const std::string& name);
~NetPlayClient();
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
bool is_connected;
bool StartGame(const std::string &path);
bool StopGame();
bool ChangeGame(const std::string& game);
void SendChatMessage(const std::string& msg);
// Send and receive pads values
void WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size);
void WiimoteUpdate(int _number);
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
u8 GetPadNum(u8 numPAD);
protected:
void ClearBuffers();
struct
{
std::recursive_mutex game;
// lock order
std::recursive_mutex players, send;
} m_crit;
class Player
{
public:
Player();
std::string ToString() const;
PlayerId pid;
std::string name;
PadMapping pad_map[4];
std::string revision;
u32 ping;
};
Common::FifoQueue<NetPad> m_pad_buffer[4];
Common::FifoQueue<NetWiimote> m_wiimote_buffer[4];
NetWiimote m_wiimote_input[4];
NetPlayUI* m_dialog;
sf::SocketTCP m_socket;
std::thread m_thread;
sf::Selector<sf::SocketTCP> m_selector;
std::string m_selected_game;
volatile bool m_is_running;
volatile bool m_do_loop;
unsigned int m_target_buffer_size;
Player* m_local_player;
u32 m_current_game;
private:
void SendPadState(const PadMapping local_nb, const NetPad& np);
unsigned int OnData(sf::Packet& packet);
PlayerId m_pid;
std::map<PlayerId, Player> m_players;
};
namespace NetPlay {
bool IsNetPlayRunning();
};
void NetPlay_Enable(NetPlayClient* const np);
void NetPlay_Disable();
#endif

Some files were not shown because too many files have changed in this diff Show More