mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-09-24 02:08:43 +00:00
Merge branch 'master' into wii-network
Conflicts: CMakeLists.txt Source/Core/Core/Core.vcxproj Source/Core/DolphinWX/Dolphin.vcxproj Source/Core/DolphinWX/Dolphin.vcxproj.filters Source/Dolphin_2010.sln Source/VSProps/Dolphin.Win32.props Source/VSProps/Dolphin.x64.props
This commit is contained in:
commit
9de7611ff9
613 changed files with 28216 additions and 20036 deletions
|
@ -1,8 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="org.dolphinemu.dolphinemu"
|
||||
android:versionCode="2"
|
||||
android:versionName="0.2" >
|
||||
android:versionCode="10"
|
||||
android:versionName="0.10" >
|
||||
|
||||
<uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14"/>
|
||||
|
||||
|
@ -25,18 +25,25 @@
|
|||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.GameListView"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme"
|
||||
android:configChanges="orientation|locale|keyboard|keyboardHidden|navigation|fontScale|uiMode" >
|
||||
</activity>
|
||||
<activity
|
||||
<activity
|
||||
android:name="org.dolphinemu.dolphinemu.FolderBrowser"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@android:style/Theme"
|
||||
android:configChanges="orientation|locale|keyboard|keyboardHidden|navigation|fontScale|uiMode" >
|
||||
</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" >
|
||||
</activity>
|
||||
</application>
|
||||
|
||||
</manifest>
|
||||
|
|
186
Source/Android/assets/Dolphin.ini
Normal file
186
Source/Android/assets/Dolphin.ini
Normal file
|
@ -0,0 +1,186 @@
|
|||
[General]
|
||||
GCMPathes = 0
|
||||
LastFilename =
|
||||
ShowLag = False
|
||||
RecursiveGCMPaths = False
|
||||
NANDRoot = //sdcard/dolphin-emu/Wii
|
||||
WirelessMac =
|
||||
[Core]
|
||||
CPUCore = 3
|
||||
CPUThread = False
|
||||
GFXBackend = Software Renderer
|
||||
HLE_BS2 = False
|
||||
Fastmem = True
|
||||
DSPThread = False
|
||||
DSPHLE = True
|
||||
SkipIdle = True
|
||||
DefaultGCM =
|
||||
DVDRoot =
|
||||
Apploader =
|
||||
EnableCheats = False
|
||||
SelectedLanguage = 0
|
||||
DPL2Decoder = False
|
||||
Latency = 14
|
||||
MemcardA =
|
||||
MemcardB =
|
||||
SlotA = 1
|
||||
SlotB = 255
|
||||
SerialPort1 = 255
|
||||
BBA_MAC =
|
||||
SIDevice0 = 6
|
||||
SIDevice1 = 0
|
||||
SIDevice2 = 0
|
||||
SIDevice3 = 0
|
||||
WiiSDCard = False
|
||||
WiiKeyboard = False
|
||||
WiimoteReconnectOnLoad = True
|
||||
WiimoteContinuousScanning = False
|
||||
WiimoteEnableSpeaker = True
|
||||
RunCompareServer = False
|
||||
RunCompareClient = False
|
||||
FrameLimit = 0x00000001
|
||||
UseFPS = False
|
||||
[Interface]
|
||||
ConfirmStop = False
|
||||
UsePanicHandlers = True
|
||||
OnScreenDisplayMessages = True
|
||||
HideCursor = False
|
||||
AutoHideCursor = False
|
||||
MainWindowPosX = 100
|
||||
MainWindowPosY = 100
|
||||
MainWindowWidth = 800
|
||||
MainWindowHeight = 600
|
||||
Language = 0
|
||||
ShowToolbar = True
|
||||
ShowStatusbar = True
|
||||
ShowLogWindow = False
|
||||
ShowLogConfigWindow = False
|
||||
ShowConsole = False
|
||||
ThemeName = Boomy
|
||||
[Hotkeys]
|
||||
Open = 79
|
||||
OpenModifier = 2
|
||||
ChangeDisc = 0
|
||||
ChangeDiscModifier = 0
|
||||
RefreshList = 0
|
||||
RefreshListModifier = 0
|
||||
PlayPause = 349
|
||||
PlayPauseModifier = 0
|
||||
Stop = 27
|
||||
StopModifier = 0
|
||||
Reset = 0
|
||||
ResetModifier = 0
|
||||
FrameAdvance = 0
|
||||
FrameAdvanceModifier = 0
|
||||
StartRecording = 0
|
||||
StartRecordingModifier = 0
|
||||
PlayRecording = 0
|
||||
PlayRecordingModifier = 0
|
||||
ExportRecording = 0
|
||||
ExportRecordingModifier = 0
|
||||
Readonlymode = 0
|
||||
ReadonlymodeModifier = 0
|
||||
ToggleFullscreen = 13
|
||||
ToggleFullscreenModifier = 1
|
||||
Screenshot = 348
|
||||
ScreenshotModifier = 0
|
||||
Exit = 0
|
||||
ExitModifier = 0
|
||||
Wiimote1Connect = 344
|
||||
Wiimote1ConnectModifier = 1
|
||||
Wiimote2Connect = 345
|
||||
Wiimote2ConnectModifier = 1
|
||||
Wiimote3Connect = 346
|
||||
Wiimote3ConnectModifier = 1
|
||||
Wiimote4Connect = 347
|
||||
Wiimote4ConnectModifier = 1
|
||||
LoadStateSlot1 = 340
|
||||
LoadStateSlot1Modifier = 0
|
||||
LoadStateSlot2 = 341
|
||||
LoadStateSlot2Modifier = 0
|
||||
LoadStateSlot3 = 342
|
||||
LoadStateSlot3Modifier = 0
|
||||
LoadStateSlot4 = 343
|
||||
LoadStateSlot4Modifier = 0
|
||||
LoadStateSlot5 = 344
|
||||
LoadStateSlot5Modifier = 0
|
||||
LoadStateSlot6 = 345
|
||||
LoadStateSlot6Modifier = 0
|
||||
LoadStateSlot7 = 346
|
||||
LoadStateSlot7Modifier = 0
|
||||
LoadStateSlot8 = 347
|
||||
LoadStateSlot8Modifier = 0
|
||||
SaveStateSlot1 = 340
|
||||
SaveStateSlot1Modifier = 4
|
||||
SaveStateSlot2 = 341
|
||||
SaveStateSlot2Modifier = 4
|
||||
SaveStateSlot3 = 342
|
||||
SaveStateSlot3Modifier = 4
|
||||
SaveStateSlot4 = 343
|
||||
SaveStateSlot4Modifier = 4
|
||||
SaveStateSlot5 = 344
|
||||
SaveStateSlot5Modifier = 4
|
||||
SaveStateSlot6 = 345
|
||||
SaveStateSlot6Modifier = 4
|
||||
SaveStateSlot7 = 346
|
||||
SaveStateSlot7Modifier = 4
|
||||
SaveStateSlot8 = 347
|
||||
SaveStateSlot8Modifier = 4
|
||||
LoadLastState1 = 0
|
||||
LoadLastState1Modifier = 0
|
||||
LoadLastState2 = 0
|
||||
LoadLastState2Modifier = 0
|
||||
LoadLastState3 = 0
|
||||
LoadLastState3Modifier = 0
|
||||
LoadLastState4 = 0
|
||||
LoadLastState4Modifier = 0
|
||||
LoadLastState5 = 0
|
||||
LoadLastState5Modifier = 0
|
||||
LoadLastState6 = 0
|
||||
LoadLastState6Modifier = 0
|
||||
LoadLastState7 = 0
|
||||
LoadLastState7Modifier = 0
|
||||
LoadLastState8 = 0
|
||||
LoadLastState8Modifier = 0
|
||||
SaveFirstState = 0
|
||||
SaveFirstStateModifier = 0
|
||||
UndoLoadState = 351
|
||||
UndoLoadStateModifier = 0
|
||||
UndoSaveState = 351
|
||||
UndoSaveStateModifier = 4
|
||||
[Display]
|
||||
FullscreenResolution = Auto
|
||||
Fullscreen = False
|
||||
RenderToMain = False
|
||||
RenderWindowXPos = -1
|
||||
RenderWindowYPos = -1
|
||||
RenderWindowWidth = 640
|
||||
RenderWindowHeight = 480
|
||||
RenderWindowAutoSize = False
|
||||
KeepWindowOnTop = False
|
||||
ProgressiveScan = False
|
||||
DisableScreenSaver = True
|
||||
ForceNTSCJ = False
|
||||
[GameList]
|
||||
ListDrives = False
|
||||
ListWad = True
|
||||
ListWii = True
|
||||
ListGC = True
|
||||
ListJap = True
|
||||
ListPal = True
|
||||
ListUsa = True
|
||||
ListFrance = True
|
||||
ListItaly = True
|
||||
ListKorea = True
|
||||
ListTaiwan = True
|
||||
ListUnknown = True
|
||||
ListSort = 3
|
||||
ListSortSecondary = 0
|
||||
[Movie]
|
||||
PauseMovie = False
|
||||
Author =
|
||||
[DSP]
|
||||
EnableJIT = True
|
||||
DumpAudio = False
|
||||
Backend = OpenSLES
|
||||
Volume = 100
|
|
@ -1,29 +1,29 @@
|
|||
[GCPad1]
|
||||
Device = Android/0/Touchscreen
|
||||
Buttons/A = Button 0
|
||||
Buttons/B = Button 1
|
||||
Buttons/X = C
|
||||
Buttons/Y = S
|
||||
Buttons/Z = D
|
||||
Buttons/Start = Button 2
|
||||
Main Stick/Up = Up
|
||||
Main Stick/Down = Down
|
||||
Main Stick/Left = Left
|
||||
Main Stick/Right = Right
|
||||
Buttons/A = `Button 0`
|
||||
Buttons/B = `Button 1`
|
||||
Buttons/X = `Button 3`
|
||||
Buttons/Y = `Button 4`
|
||||
Buttons/Z = `Button 5`
|
||||
Buttons/Start = `Button 2`
|
||||
Main Stick/Up = `Axis 10`
|
||||
Main Stick/Down = `Axis 11`
|
||||
Main Stick/Left = `Axis 12`
|
||||
Main Stick/Right = `Axis 13`
|
||||
Main Stick/Modifier = Shift_L
|
||||
Main Stick/Modifier/Range = 50.000000
|
||||
C-Stick/Up = I
|
||||
C-Stick/Down = K
|
||||
C-Stick/Left = J
|
||||
C-Stick/Right = L
|
||||
C-Stick/Up = `Axis 14`
|
||||
C-Stick/Down = `Axis 15`
|
||||
C-Stick/Left = `Axis 16`
|
||||
C-Stick/Right = `Axis 17`
|
||||
C-Stick/Modifier = Control_L
|
||||
C-Stick/Modifier/Range = 50.000000
|
||||
Triggers/L = Q
|
||||
Triggers/R = W
|
||||
D-Pad/Up = T
|
||||
D-Pad/Down = G
|
||||
D-Pad/Left = F
|
||||
D-Pad/Right = H
|
||||
Triggers/L = `Axis 18`
|
||||
Triggers/R = `Axis 19`
|
||||
D-Pad/Up = `Button 6`
|
||||
D-Pad/Down = `Button 7`
|
||||
D-Pad/Left = `Button 8`
|
||||
D-Pad/Right = `Button 9`
|
||||
[GCPad2]
|
||||
[GCPad3]
|
||||
[GCPad4]
|
||||
|
|
BIN
Source/Android/libs/android-support-v13.jar
Normal file
BIN
Source/Android/libs/android-support-v13.jar
Normal file
Binary file not shown.
|
@ -12,4 +12,3 @@
|
|||
|
||||
# Project target.
|
||||
target=android-17
|
||||
android.library.reference.1=../../Externals/android-menudrawer/library
|
||||
|
|
BIN
Source/Android/res/drawable/ic_drawer.png
Normal file
BIN
Source/Android/res/drawable/ic_drawer.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 178 B |
|
@ -3,42 +3,27 @@
|
|||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
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" >
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" >
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView01"
|
||||
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="@+id/TextView01"
|
||||
android:text="Title"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView02"
|
||||
android:id="@+id/FolderSubTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dip"
|
||||
android:text="@+id/TextView02" />
|
||||
android:text="Subtitle" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
|
|
|
@ -1,7 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical" >
|
||||
|
||||
</LinearLayout>
|
20
Source/Android/res/layout/gamelist_activity.xml
Normal file
20
Source/Android/res/layout/gamelist_activity.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<android.support.v4.widget.DrawerLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/drawer_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<FrameLayout
|
||||
android:id="@+id/content_frame"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
<ListView
|
||||
android:id="@+id/left_drawer"
|
||||
android:layout_width="240dp"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="start"
|
||||
android:choiceMode="singleChoice"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp"
|
||||
android:background="#333"/>
|
||||
</android.support.v4.widget.DrawerLayout>
|
|
@ -9,7 +9,7 @@
|
|||
android:layout_height="wrap_content" >
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/imageView1"
|
||||
android:id="@+id/GameItemIcon"
|
||||
android:layout_width="96dp"
|
||||
android:layout_height="match_parent" />
|
||||
|
||||
|
@ -19,7 +19,7 @@
|
|||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView01"
|
||||
android:id="@+id/GameItemTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dip"
|
||||
|
@ -29,7 +29,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView02"
|
||||
android:id="@+id/GameItemSubText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="10dip"
|
||||
|
@ -40,3 +40,4 @@
|
|||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
7
Source/Android/res/layout/gamelist_listview.xml
Normal file
7
Source/Android/res/layout/gamelist_listview.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<ListView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/gamelist"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:choiceMode="singleChoice"
|
||||
android:divider="@android:color/transparent"
|
||||
android:dividerHeight="0dp"/>
|
24
Source/Android/res/layout/prefs.xml
Normal file
24
Source/Android/res/layout/prefs.xml
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?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>
|
|
@ -15,7 +15,7 @@
|
|||
android:orientation="vertical" >
|
||||
|
||||
<TextView
|
||||
android:id="@+id/TextView01"
|
||||
android:id="@+id/SideMenuTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginLeft="5dip"
|
||||
|
|
12
Source/Android/res/values/prefvalues.xml
Normal file
12
Source/Android/res/values/prefvalues.xml
Normal file
|
@ -0,0 +1,12 @@
|
|||
<?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>
|
|
@ -2,5 +2,7 @@
|
|||
<resources>
|
||||
|
||||
<string name="app_name">Dolphin Emulator</string>
|
||||
<string name="drawer_open">Open navigation drawer</string>
|
||||
<string name="drawer_close">Close navigation drawer</string>
|
||||
|
||||
</resources>
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ListView;
|
||||
|
||||
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 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) {
|
||||
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
mMainList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
|
||||
List<GameListItem> Input = new ArrayList<GameListItem>();
|
||||
int a = 0;
|
||||
|
||||
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);
|
||||
mMainList.setAdapter(adapter);
|
||||
|
||||
return mMainList;
|
||||
}
|
||||
@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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +1,22 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
import net.simonvt.menudrawer.MenuDrawer;
|
||||
|
||||
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;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.List;
|
||||
|
||||
public class DolphinEmulator<MainActivity> extends Activity
|
||||
{
|
||||
static private NativeGLSurfaceView GLview = null;
|
||||
|
@ -25,20 +24,7 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
|
||||
private float screenWidth;
|
||||
private float screenHeight;
|
||||
|
||||
public static native void onTouchEvent(int Action, float X, float Y);
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("dolphin-emu-nogui");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.w("me", ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void CopyAsset(String asset, String output) {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
|
@ -55,6 +41,7 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
Log.e("tag", "Failed to copy asset file: " + asset, e);
|
||||
}
|
||||
}
|
||||
|
||||
private void copyFile(InputStream in, OutputStream out) throws IOException {
|
||||
byte[] buffer = new byte[1024];
|
||||
int read;
|
||||
|
@ -68,21 +55,21 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
{
|
||||
super.onStop();
|
||||
if (Running)
|
||||
NativeGLSurfaceView.StopEmulation();
|
||||
NativeLibrary.StopEmulation();
|
||||
}
|
||||
@Override
|
||||
public void onPause()
|
||||
{
|
||||
super.onPause();
|
||||
if (Running)
|
||||
NativeGLSurfaceView.PauseEmulation();
|
||||
NativeLibrary.PauseEmulation();
|
||||
}
|
||||
@Override
|
||||
public void onResume()
|
||||
{
|
||||
super.onResume();
|
||||
if (Running)
|
||||
NativeGLSurfaceView.UnPauseEmulation();
|
||||
NativeLibrary.UnPauseEmulation();
|
||||
}
|
||||
|
||||
/** Called when the activity is first created. */
|
||||
|
@ -92,21 +79,26 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
if (savedInstanceState == null)
|
||||
{
|
||||
|
||||
Intent ListIntent = new Intent(this, GameListView.class);
|
||||
Intent ListIntent = new Intent(this, GameListActivity.class);
|
||||
startActivityForResult(ListIntent, 1);
|
||||
|
||||
// Make the assets directory
|
||||
String strDir = Environment.getExternalStorageDirectory()+File.separator+"dolphin-emu";
|
||||
File directory = new File(strDir);
|
||||
String BaseDir = Environment.getExternalStorageDirectory()+File.separator+"dolphin-emu";
|
||||
File directory = new File(BaseDir);
|
||||
directory.mkdirs();
|
||||
|
||||
strDir += File.separator+"Config";
|
||||
directory = new File(strDir);
|
||||
String ConfigDir = BaseDir + File.separator + "Config";
|
||||
directory = new File(ConfigDir);
|
||||
directory.mkdirs();
|
||||
|
||||
|
||||
String GCDir = BaseDir + File.separator + "GC";
|
||||
directory = new File(GCDir);
|
||||
directory.mkdirs();
|
||||
|
||||
// Copy assets if needed
|
||||
java.io.File file = new java.io.File(
|
||||
Environment.getExternalStorageDirectory()+File.separator+"dolphin-emu" + File.separator + "NoBanner.png");
|
||||
Environment.getExternalStorageDirectory()+File.separator+
|
||||
"dolphin-emu" + File.separator + "GC" + File.separator + "dsp_coef.bin");
|
||||
if(!file.exists())
|
||||
{
|
||||
CopyAsset("ButtonA.png",
|
||||
|
@ -123,7 +115,29 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
"dolphin-emu" + File.separator + "NoBanner.png");
|
||||
CopyAsset("GCPadNew.ini",
|
||||
Environment.getExternalStorageDirectory()+File.separator+
|
||||
"dolphin-emu" + File.separator +"Config"+ File.separator +"GCPadNew.ini");
|
||||
"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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -143,8 +157,12 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
|
||||
String FileName = data.getStringExtra("Select");
|
||||
GLview = new NativeGLSurfaceView(this);
|
||||
//this.getWindow().setUiOptions(View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN, View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN);
|
||||
GLview.SetDimensions(screenWidth, screenHeight);
|
||||
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);
|
||||
setContentView(GLview);
|
||||
Running = true;
|
||||
|
@ -164,14 +182,68 @@ public class DolphinEmulator<MainActivity> extends Activity
|
|||
float ScreenX = ((X / screenWidth) * 2.0f) - 1.0f;
|
||||
float ScreenY = ((Y / screenHeight) * -2.0f) + 1.0f;
|
||||
|
||||
onTouchEvent(Action, ScreenX, ScreenY);
|
||||
NativeLibrary.onTouchEvent(Action, ScreenX, ScreenY);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean overrideKeys()
|
||||
{
|
||||
|
||||
// Gets button presses
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
int action = 0;
|
||||
|
||||
// Special catch for the back key
|
||||
// Currently disabled because stopping and starting emulation is broken.
|
||||
/*
|
||||
if ( event.getSource() == InputDevice.SOURCE_KEYBOARD
|
||||
&& event.getKeyCode() == KeyEvent.KEYCODE_BACK
|
||||
&& event.getAction() == KeyEvent.ACTION_UP
|
||||
)
|
||||
{
|
||||
if (Running)
|
||||
NativeLibrary.StopEmulation();
|
||||
Running = false;
|
||||
Intent ListIntent = new Intent(this, GameListActivity.class);
|
||||
startActivityForResult(ListIntent, 1);
|
||||
return true;
|
||||
}
|
||||
*/
|
||||
|
||||
if (Running)
|
||||
{
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
action = 0;
|
||||
break;
|
||||
case KeyEvent.ACTION_UP:
|
||||
action = 1;
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
InputDevice input = event.getDevice();
|
||||
NativeLibrary.onGamePadEvent(InputConfigFragment.getInputDesc(input), event.getKeyCode(), action);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
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)
|
||||
{
|
||||
InputDevice.MotionRange range;
|
||||
range = motions.get(a);
|
||||
NativeLibrary.onGamePadMoveEvent(InputConfigFragment.getInputDesc(input), range.getAxis(), event.getAxisValue(range.getAxis()));
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,98 +1,134 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.simonvt.menudrawer.MenuDrawer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Intent;
|
||||
import android.app.Fragment;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemLongClickListener;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class FolderBrowser extends ListActivity {
|
||||
private GameListAdapter adapter;
|
||||
import java.io.File;
|
||||
import java.util.*;
|
||||
|
||||
public class FolderBrowser extends Fragment {
|
||||
private Activity m_activity;
|
||||
private FolderBrowserAdapter adapter;
|
||||
private ListView mDrawerList;
|
||||
private View rootView;
|
||||
private static File currentDir = null;
|
||||
private void Fill(File f)
|
||||
|
||||
// Populates the FolderView with the given currDir's contents.
|
||||
private void Fill(File currDir)
|
||||
{
|
||||
File[]dirs = f.listFiles();
|
||||
this.setTitle("Current Dir: " + f.getName());
|
||||
m_activity.setTitle("Current Dir: " + currDir.getName());
|
||||
File[] dirs = currDir.listFiles();
|
||||
List<GameListItem>dir = new ArrayList<GameListItem>();
|
||||
List<GameListItem>fls = new ArrayList<GameListItem>();
|
||||
|
||||
|
||||
// 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"));
|
||||
|
||||
// Search for any directories or supported files within the current dir.
|
||||
try
|
||||
{
|
||||
for(File ff: dirs)
|
||||
for(File entry : dirs)
|
||||
{
|
||||
if (ff.getName().charAt(0) != '.')
|
||||
if(ff.isDirectory())
|
||||
dir.add(new GameListItem(getApplicationContext(), ff.getName(),"Folder",ff.getAbsolutePath()));
|
||||
String entryName = entry.getName();
|
||||
|
||||
if (entryName.charAt(0) != '.')
|
||||
{
|
||||
if(entry.isDirectory())
|
||||
{
|
||||
dir.add(new GameListItem(m_activity, entryName,"Folder",entry.getAbsolutePath(), true));
|
||||
}
|
||||
else
|
||||
if (ff.getName().toLowerCase().contains(".gcm") ||
|
||||
ff.getName().toLowerCase().contains(".iso") ||
|
||||
ff.getName().toLowerCase().contains(".wbfs") ||
|
||||
ff.getName().toLowerCase().contains(".gcz") ||
|
||||
ff.getName().toLowerCase().contains(".dol") ||
|
||||
ff.getName().toLowerCase().contains(".elf"))
|
||||
fls.add(new GameListItem(getApplicationContext(), ff.getName(),"File Size: "+ff.length(),ff.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
Collections.sort(dir);
|
||||
Collections.sort(fls);
|
||||
dir.addAll(fls);
|
||||
if (!f.getName().equalsIgnoreCase("sdcard"))
|
||||
dir.add(0, new GameListItem(getApplicationContext(), "..", "Parent Directory", f.getParent()));
|
||||
|
||||
adapter = new GameListAdapter(this,R.layout.folderbrowser,dir);
|
||||
this.setListAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
// TODO Auto-generated method stub
|
||||
super.onListItemClick(l, v, position, id);
|
||||
GameListItem o = adapter.getItem(position);
|
||||
if(o.getData().equalsIgnoreCase("folder")||o.getData().equalsIgnoreCase("parent directory")){
|
||||
currentDir = new File(o.getPath());
|
||||
Fill(currentDir);
|
||||
{
|
||||
if (validExts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
{
|
||||
fls.add(new GameListItem(m_activity, entryName,"File Size: "+entry.length(),entry.getAbsolutePath(), true));
|
||||
}
|
||||
else if (archiveExts.contains(entryName.toLowerCase().substring(entryName.lastIndexOf('.'))))
|
||||
{
|
||||
fls.add(new GameListItem(m_activity, entryName,"File Size: "+entry.length(),entry.getAbsolutePath(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
catch(Exception ignored)
|
||||
{
|
||||
}
|
||||
|
||||
Collections.sort(dir);
|
||||
Collections.sort(fls);
|
||||
dir.addAll(fls);
|
||||
|
||||
// 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));
|
||||
|
||||
adapter = new FolderBrowserAdapter(m_activity, R.layout.folderbrowser, dir);
|
||||
mDrawerList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
mDrawerList.setAdapter(adapter);
|
||||
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
|
||||
}
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container,
|
||||
Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
if(currentDir == null)
|
||||
currentDir = new File(Environment.getExternalStorageDirectory().getPath());
|
||||
|
||||
rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
|
||||
Fill(currentDir);
|
||||
return mDrawerList;
|
||||
}
|
||||
|
||||
private AdapterView.OnItemClickListener mMenuItemClickListener = new AdapterView.OnItemClickListener()
|
||||
{
|
||||
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"))
|
||||
{
|
||||
currentDir = new File(o.getPath());
|
||||
Fill(currentDir);
|
||||
}
|
||||
else
|
||||
if (o.isValid())
|
||||
FolderSelected();
|
||||
else
|
||||
Toast.makeText(m_activity, "Can not use compressed file types.", Toast.LENGTH_LONG).show();
|
||||
}
|
||||
};
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
private void FolderSelected()
|
||||
{
|
||||
String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPathes", "0");
|
||||
int intDirectories = Integer.parseInt(Directories);
|
||||
Directories = Integer.toString(intDirectories + 1);
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "GCMPathes", Directories);
|
||||
NativeLibrary.SetConfig("Dolphin.ini", "General", "GCMPath" + Integer.toString(intDirectories), currentDir.getPath());
|
||||
|
||||
((GameListActivity)m_activity).SwitchPage(0);
|
||||
}
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("Select", currentDir.getPath());
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
|
||||
this.finish();
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,289 @@
|
|||
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{
|
||||
|
||||
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;
|
||||
|
||||
private static GameListActivity mMe;
|
||||
|
||||
// Called from the game list fragment
|
||||
public void onZeroFiles()
|
||||
{
|
||||
mDrawerLayout.openDrawer(mDrawerList);
|
||||
}
|
||||
|
||||
@Override
|
||||
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));
|
||||
|
||||
mDrawerAdapter = new SideMenuAdapter(this, R.layout.sidemenu, dir);
|
||||
mDrawerList.setAdapter(mDrawerAdapter);
|
||||
mDrawerList.setOnItemClickListener(mMenuItemClickListener);
|
||||
|
||||
// enable ActionBar app icon to behave as action to toggle nav drawer
|
||||
getActionBar().setDisplayHomeAsUpEnabled(true);
|
||||
getActionBar().setHomeButtonEnabled(true);
|
||||
|
||||
// ActionBarDrawerToggle ties together the the proper interactions
|
||||
// between the sliding drawer and the action bar app icon
|
||||
mDrawerToggle = new ActionBarDrawerToggle(
|
||||
this, /* host Activity */
|
||||
mDrawerLayout, /* DrawerLayout object */
|
||||
R.drawable.ic_drawer, /* nav drawer image to replace 'Up' caret */
|
||||
R.string.drawer_open, /* "open drawer" description for accessibility */
|
||||
R.string.drawer_close /* "close drawer" description for accessibility */
|
||||
) {
|
||||
public void onDrawerClosed(View view) {
|
||||
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
|
||||
}
|
||||
|
||||
public void onDrawerOpened(View drawerView) {
|
||||
invalidateOptionsMenu(); // creates call to onPrepareOptionsMenu()
|
||||
}
|
||||
};
|
||||
mDrawerLayout.setDrawerListener(mDrawerToggle);
|
||||
|
||||
recreateFragment();
|
||||
}
|
||||
|
||||
private void recreateFragment()
|
||||
{
|
||||
mCurFragment = new GameListFragment();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
fragmentManager.beginTransaction().replace(R.id.content_frame, mCurFragment).commit();
|
||||
}
|
||||
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",
|
||||
};
|
||||
|
||||
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();
|
||||
for (int a = 0; a < adapter.getCount(); ++a)
|
||||
{
|
||||
InputConfigItem o = adapter.getItem(a);
|
||||
String config = o.getConfig();
|
||||
String bind = o.getBind();
|
||||
String ConfigValues[] = config.split("-");
|
||||
String Key = ConfigValues[0];
|
||||
String Value = ConfigValues[1];
|
||||
NativeLibrary.SetConfig("Dolphin.ini", Key, Value, bind);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0: // Game List
|
||||
case 4: // About
|
||||
/* Do Nothing */
|
||||
break;
|
||||
}
|
||||
switch(toPage)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
mCurFragmentNum = 0;
|
||||
mCurFragment = new GameListFragment();
|
||||
FragmentManager fragmentManager = getFragmentManager();
|
||||
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();
|
||||
}
|
||||
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)
|
||||
{
|
||||
SideMenuItem o = mDrawerAdapter.getItem(position);
|
||||
mDrawerLayout.closeDrawer(mDrawerList);
|
||||
SwitchPage(o.getID());
|
||||
}
|
||||
};
|
||||
/**
|
||||
* When using the ActionBarDrawerToggle, you must call it during
|
||||
* onPostCreate() and onConfigurationChanged()...
|
||||
*/
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
super.onPostCreate(savedInstanceState);
|
||||
// Sync the toggle state after onRestoreInstanceState has occurred.
|
||||
mDrawerToggle.syncState();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
// Pass any configuration change to the drawer toggls
|
||||
mDrawerToggle.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
/* Called whenever we call invalidateOptionsMenu() */
|
||||
@Override
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return super.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
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)) {
|
||||
return true;
|
||||
}
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
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) {
|
||||
if (mCurFragmentNum == 3)
|
||||
if (((OnGameConfigListener)mCurFragment).onMotionEvent(event))
|
||||
return true;
|
||||
return super.dispatchGenericMotionEvent(event);
|
||||
}
|
||||
// Gets button presses
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (mCurFragmentNum == 3)
|
||||
if (((OnGameConfigListener)mCurFragment).onKeyEvent(event))
|
||||
return true;
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -10,48 +8,48 @@ 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.TextView01);
|
||||
TextView t2 = (TextView) v.findViewById(R.id.TextView02);
|
||||
ImageView v1 = (ImageView) v.findViewById(R.id.imageView1);
|
||||
|
||||
if(t1!=null)
|
||||
t1.setText(o.getName());
|
||||
if(t2!=null)
|
||||
t2.setText(o.getData());
|
||||
if(v1!=null)
|
||||
v1.setImageBitmap(o.getImage());
|
||||
|
||||
}
|
||||
return v;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,128 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ListView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Copyright 2013 Dolphin Emulator Project
|
||||
* Licensed under GPLv2
|
||||
* Refer to the license.txt file included.
|
||||
*/
|
||||
public class GameListFragment extends Fragment
|
||||
{
|
||||
private ListView mMainList;
|
||||
private GameListAdapter mGameAdapter;
|
||||
private static GameListActivity mMe;
|
||||
OnGameListZeroListener mCallback;
|
||||
|
||||
public interface OnGameListZeroListener {
|
||||
public void onZeroFiles();
|
||||
}
|
||||
|
||||
public GameListFragment() {
|
||||
// Empty constructor required for fragment subclasses
|
||||
}
|
||||
private void Fill()
|
||||
{
|
||||
List<GameListItem> fls = new ArrayList<GameListItem>();
|
||||
String Directories = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPathes", "0");
|
||||
int intDirectories = Integer.parseInt(Directories);
|
||||
|
||||
// Extensions to filter by.
|
||||
Set<String> exts = new HashSet<String>(Arrays.asList(".gcm", ".iso", ".wbfs", ".gcz", ".dol", ".elf", ".dff"));
|
||||
|
||||
for (int a = 0; a < intDirectories; ++a)
|
||||
{
|
||||
String BrowseDir = NativeLibrary.GetConfig("Dolphin.ini", "General", "GCMPath" + Integer.toString(a), "");
|
||||
File currentDir = new File(BrowseDir);
|
||||
File[]dirs = currentDir.listFiles();
|
||||
try
|
||||
{
|
||||
for(File entry : dirs)
|
||||
{
|
||||
String entryName = entry.getName();
|
||||
|
||||
if (entryName.charAt(0) != '.')
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(Exception ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
Collections.sort(fls);
|
||||
|
||||
mGameAdapter = new GameListAdapter(mMe, R.layout.gamelist_layout, fls);
|
||||
mMainList.setAdapter(mGameAdapter);
|
||||
if (fls.size() == 0)
|
||||
mCallback.onZeroFiles();
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
|
||||
Fill();
|
||||
|
||||
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")))
|
||||
{
|
||||
onFileClick(o.getPath());
|
||||
}
|
||||
}
|
||||
};
|
||||
private void onFileClick(String o)
|
||||
{
|
||||
Toast.makeText(mMe, "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) {
|
||||
super.onAttach(activity);
|
||||
|
||||
// This makes sure that the container activity has implemented
|
||||
// the callback interface. If not, it throws an exception
|
||||
try {
|
||||
mCallback = (OnGameListZeroListener) activity;
|
||||
mMe = (GameListActivity) activity;
|
||||
} catch (ClassCastException e) {
|
||||
throw new ClassCastException(activity.toString()
|
||||
+ " must implement OnGameListZeroListener");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,42 +1,30 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
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;
|
||||
|
||||
public class GameListItem implements Comparable<GameListItem>{
|
||||
private String name;
|
||||
private String data;
|
||||
private String path;
|
||||
private Bitmap image;
|
||||
public static native int[] GetBanner(String filename);
|
||||
public static native String GetTitle(String filename);
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("dolphin-emu-nogui");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.w("me", ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public GameListItem(Context ctx, String n,String d,String p)
|
||||
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())
|
||||
if (!file.isDirectory() && !path.equals(""))
|
||||
{
|
||||
int[] Banner = GetBanner(path);
|
||||
int[] Banner = NativeLibrary.GetBanner(path);
|
||||
if (Banner[0] == 0)
|
||||
{
|
||||
try {
|
||||
|
@ -50,7 +38,7 @@ public class GameListItem implements Comparable<GameListItem>{
|
|||
}
|
||||
else
|
||||
image = Bitmap.createBitmap(Banner, 96, 32, Bitmap.Config.ARGB_8888);
|
||||
name = GetTitle(path);
|
||||
name = NativeLibrary.GetTitle(path);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -72,6 +60,10 @@ public class GameListItem implements Comparable<GameListItem>{
|
|||
{
|
||||
return image;
|
||||
}
|
||||
public boolean isValid()
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
public int compareTo(GameListItem o)
|
||||
{
|
||||
|
|
|
@ -1,181 +0,0 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import net.simonvt.menudrawer.MenuDrawer;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ListActivity;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MenuItem;
|
||||
import android.view.Surface;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
public class GameListView extends ListActivity {
|
||||
private GameListAdapter adapter;
|
||||
private static File currentDir = null;
|
||||
private MenuDrawer mDrawer;
|
||||
|
||||
private SideMenuAdapter mAdapter;
|
||||
private ListView mList;
|
||||
private static GameListView me;
|
||||
public static native String GetConfig(String Key, String Value, String Default);
|
||||
public static native void SetConfig(String Key, String Value, String Default);
|
||||
|
||||
private void Fill(File f)
|
||||
{
|
||||
File[]dirs = f.listFiles();
|
||||
this.setTitle("Game List");
|
||||
List<GameListItem>dir = new ArrayList<GameListItem>();
|
||||
List<GameListItem>fls = new ArrayList<GameListItem>();
|
||||
|
||||
try
|
||||
{
|
||||
for(File ff: dirs)
|
||||
{
|
||||
if (ff.getName().charAt(0) != '.')
|
||||
if(!ff.isDirectory())
|
||||
if (ff.getName().toLowerCase().contains(".gcm") ||
|
||||
ff.getName().toLowerCase().contains(".iso") ||
|
||||
ff.getName().toLowerCase().contains(".wbfs") ||
|
||||
ff.getName().toLowerCase().contains(".gcz") ||
|
||||
ff.getName().toLowerCase().contains(".dol") ||
|
||||
ff.getName().toLowerCase().contains(".elf"))
|
||||
fls.add(new GameListItem(getApplicationContext(), ff.getName(),"File Size: "+ff.length(),ff.getAbsolutePath()));
|
||||
}
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
Collections.sort(dir);
|
||||
Collections.sort(fls);
|
||||
dir.addAll(fls);
|
||||
|
||||
adapter = new GameListAdapter(this,R.layout.main,dir);
|
||||
this.setListAdapter(adapter);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onListItemClick(ListView l, View v, int position, long id) {
|
||||
// TODO Auto-generated method stub
|
||||
super.onListItemClick(l, v, position, id);
|
||||
GameListItem o = adapter.getItem(position);
|
||||
if(o.getData().equalsIgnoreCase("folder")||o.getData().equalsIgnoreCase("parent directory")){
|
||||
}
|
||||
else
|
||||
{
|
||||
onFileClick(o.getPath());
|
||||
}
|
||||
}
|
||||
|
||||
private void onFileClick(String o)
|
||||
{
|
||||
Toast.makeText(this, "File Clicked: " + o, Toast.LENGTH_SHORT).show();
|
||||
|
||||
Intent intent = new Intent();
|
||||
intent.putExtra("Select", o);
|
||||
setResult(Activity.RESULT_OK, intent);
|
||||
|
||||
this.finish();
|
||||
}
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data)
|
||||
{
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
|
||||
if (resultCode == Activity.RESULT_OK)
|
||||
{
|
||||
String FileName = data.getStringExtra("Select");
|
||||
Toast.makeText(this, "Folder Selected: " + FileName, Toast.LENGTH_SHORT).show();
|
||||
SetConfig("General", "GCMPathes", "1");
|
||||
SetConfig("General", "GCMPaths0", FileName);
|
||||
|
||||
currentDir = new File(FileName);
|
||||
Fill(currentDir);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState)
|
||||
{
|
||||
super.onCreate(savedInstanceState);
|
||||
me = this;
|
||||
|
||||
mDrawer = MenuDrawer.attach(this, MenuDrawer.MENU_DRAG_CONTENT);
|
||||
|
||||
String BrowseDir = GetConfig("General", "GCMPaths0", "");
|
||||
if(currentDir == null)
|
||||
currentDir = new File(BrowseDir);
|
||||
Fill(currentDir);
|
||||
|
||||
List<SideMenuItem>dir = new ArrayList<SideMenuItem>();
|
||||
dir.add(new SideMenuItem("Browse Folder", 0));
|
||||
|
||||
mList = new ListView(this);
|
||||
mAdapter = new SideMenuAdapter(this,R.layout.sidemenu,dir);
|
||||
mList.setAdapter(mAdapter);
|
||||
mList.setOnItemClickListener(mItemClickListener);
|
||||
|
||||
mDrawer.setMenuView(mList);
|
||||
}
|
||||
private AdapterView.OnItemClickListener mItemClickListener = new AdapterView.OnItemClickListener() {
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
SideMenuItem o = mAdapter.getItem(position);
|
||||
|
||||
switch(o.getID())
|
||||
{
|
||||
case 0:
|
||||
Toast.makeText(me, "Loading up the browser", Toast.LENGTH_SHORT).show();
|
||||
Intent ListIntent = new Intent(me, FolderBrowser.class);
|
||||
startActivityForResult(ListIntent, 1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mDrawer.closeMenu();
|
||||
}
|
||||
};
|
||||
@Override
|
||||
public void setContentView(int layoutResID) {
|
||||
// This override is only needed when using MENU_DRAG_CONTENT.
|
||||
mDrawer.setContentView(layoutResID);
|
||||
onContentChanged();
|
||||
}
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
switch (item.getItemId()) {
|
||||
case android.R.id.home:
|
||||
mDrawer.toggleMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
final int drawerState = mDrawer.getDrawerState();
|
||||
if (drawerState == MenuDrawer.STATE_OPEN || drawerState == MenuDrawer.STATE_OPENING) {
|
||||
mDrawer.closeMenu();
|
||||
return;
|
||||
}
|
||||
|
||||
super.onBackPressed();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Fragment;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
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 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;
|
||||
|
||||
static public 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)
|
||||
{
|
||||
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"));
|
||||
|
||||
adapter = new InputConfigAdapter(m_activity, R.layout.folderbrowser, Input);
|
||||
View rootView = inflater.inflate(R.layout.gamelist_listview, container, false);
|
||||
mDrawerList = (ListView) rootView.findViewById(R.id.gamelist);
|
||||
|
||||
mDrawerList.setAdapter(adapter);
|
||||
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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static ArrayList<Float> m_values = new ArrayList<Float>();
|
||||
|
||||
void AssignBind(String bind)
|
||||
{
|
||||
InputConfigItem o = adapter.getItem(configPosition);
|
||||
adapter.remove(o);
|
||||
o.setBind(bind);
|
||||
adapter.insert(o, configPosition);
|
||||
}
|
||||
public InputConfigAdapter getAdapter()
|
||||
{
|
||||
return adapter;
|
||||
}
|
||||
// Called from GameListActivity
|
||||
public boolean onMotionEvent(MotionEvent event)
|
||||
{
|
||||
if (((event.getSource() & InputDevice.SOURCE_CLASS_JOYSTICK) == 0))
|
||||
return false;
|
||||
|
||||
InputDevice input = event.getDevice();
|
||||
List<InputDevice.MotionRange> motions = input.getMotionRanges();
|
||||
if (Configuring)
|
||||
{
|
||||
if (firstEvent)
|
||||
{
|
||||
m_values.clear();
|
||||
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);
|
||||
if (m_values.get(a) > (event.getAxisValue(range.getAxis()) + 0.5f))
|
||||
{
|
||||
AssignBind("Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "-");
|
||||
Configuring = false;
|
||||
}
|
||||
else if (m_values.get(a) < (event.getAxisValue(range.getAxis()) - 0.5f))
|
||||
{
|
||||
AssignBind("Device '" + InputConfigFragment.getInputDesc(input) + "'-Axis " + range.getAxis() + "+");
|
||||
Configuring = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public boolean onKeyEvent(KeyEvent event)
|
||||
{
|
||||
Log.w("Dolphinemu", "Got Event " + event.getAction());
|
||||
switch (event.getAction()) {
|
||||
case KeyEvent.ACTION_DOWN:
|
||||
case KeyEvent.ACTION_UP:
|
||||
if (Configuring)
|
||||
{
|
||||
InputDevice input = event.getDevice();
|
||||
AssignBind("Device '" + InputConfigFragment.getInputDesc(input) + "'-Button " + event.getKeyCode());
|
||||
Configuring = false;
|
||||
return true;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
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();
|
||||
}
|
||||
}
|
|
@ -1,9 +1,6 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceHolder;
|
||||
import android.view.SurfaceView;
|
||||
|
||||
|
@ -14,23 +11,6 @@ public class NativeGLSurfaceView extends SurfaceView {
|
|||
static private boolean Created = false;
|
||||
static private float width;
|
||||
static private float height;
|
||||
|
||||
public static native void main(String File, Surface surf, int width, int height);
|
||||
public static native void UnPauseEmulation();
|
||||
public static native void PauseEmulation();
|
||||
public static native void StopEmulation();
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("dolphin-emu-nogui");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.w("me", ex.toString());
|
||||
}
|
||||
}
|
||||
|
||||
public NativeGLSurfaceView(Context context) {
|
||||
super(context);
|
||||
|
@ -40,7 +20,7 @@ public class NativeGLSurfaceView extends SurfaceView {
|
|||
{
|
||||
@Override
|
||||
public void run() {
|
||||
main(FileName, getHolder().getSurface(), (int)width, (int)height);
|
||||
NativeLibrary.Run(FileName, getHolder().getSurface(), (int)width, (int)height);
|
||||
}
|
||||
};
|
||||
getHolder().addCallback(new SurfaceHolder.Callback() {
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
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.
|
||||
*/
|
||||
public 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 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 UnPauseEmulation();
|
||||
public static native void PauseEmulation();
|
||||
public static native void StopEmulation();
|
||||
|
||||
static
|
||||
{
|
||||
try
|
||||
{
|
||||
System.loadLibrary("dolphin-emu-nogui");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.w("me", ex.toString());
|
||||
}
|
||||
}
|
||||
}
|
211
Source/Android/src/org/dolphinemu/dolphinemu/PrefsFragment.java
Normal file
211
Source/Android/src/org/dolphinemu/dolphinemu/PrefsFragment.java
Normal file
|
@ -0,0 +1,211 @@
|
|||
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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,7 +1,5 @@
|
|||
package org.dolphinemu.dolphinemu;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -9,6 +7,8 @@ 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;
|
||||
|
@ -35,7 +35,7 @@ public class SideMenuAdapter extends ArrayAdapter<SideMenuItem>{
|
|||
}
|
||||
final SideMenuItem o = items.get(position);
|
||||
if (o != null) {
|
||||
TextView t1 = (TextView) v.findViewById(R.id.TextView01);
|
||||
TextView t1 = (TextView) v.findViewById(R.id.SideMenuTitle);
|
||||
|
||||
if(t1!=null)
|
||||
t1.setText(o.getName());
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
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;
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _ALSA_SOUND_STREAM_H
|
||||
#define _ALSA_SOUND_STREAM_H
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <CoreServices/CoreServices.h>
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _COREAUDIO_SOUND_STREAM_H
|
||||
#define _COREAUDIO_SOUND_STREAM_H
|
||||
|
|
|
@ -28,7 +28,7 @@ bool DSound::CreateBuffer()
|
|||
|
||||
// Fill out DSound buffer description.
|
||||
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
|
||||
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_STICKYFOCUS | DSBCAPS_CTRLVOLUME;
|
||||
dsbdesc.dwFlags = DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_GLOBALFOCUS;
|
||||
dsbdesc.dwBufferBytes = bufferSize = BUFSIZE;
|
||||
dsbdesc.lpwfxFormat = (WAVEFORMATEX *)&pcmwf;
|
||||
dsbdesc.guid3DAlgorithm = DS3DALG_DEFAULT;
|
||||
|
|
|
@ -32,7 +32,7 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
|||
return numSamples;
|
||||
}
|
||||
|
||||
unsigned int numLeft = Common::AtomicLoad(m_numSamples);
|
||||
unsigned int numLeft = GetNumSamples();
|
||||
if (m_AIplaying) {
|
||||
if (numLeft < numSamples)//cannot do much about this
|
||||
m_AIplaying = false;
|
||||
|
@ -43,6 +43,16 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
|||
m_AIplaying = true;
|
||||
}
|
||||
|
||||
// Cache access in non-volatile variable
|
||||
// This is the only function changing the read value, so it's safe to
|
||||
// cache it locally although it's written here.
|
||||
// The writing pointer will be modified outside, but it will only increase,
|
||||
// so we will just ignore new written data while interpolating.
|
||||
// Without this cache, the compiler wouldn't be allowed to optimize the
|
||||
// interpolation loop.
|
||||
u32 indexR = Common::AtomicLoad(m_indexR);
|
||||
u32 indexW = Common::AtomicLoad(m_indexW);
|
||||
|
||||
if (m_AIplaying) {
|
||||
numLeft = (numLeft > numSamples) ? numSamples : numLeft;
|
||||
|
||||
|
@ -57,7 +67,7 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
|||
|
||||
for (unsigned int i = 0; i < numLeft * 2; i += 8)
|
||||
{
|
||||
_mm_storeu_si128((__m128i *)&samples[i], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&m_buffer[(m_indexR + i) & INDEX_MASK]), sr_mask));
|
||||
_mm_storeu_si128((__m128i *)&samples[i], _mm_shuffle_epi8(_mm_loadu_si128((__m128i *)&m_buffer[(indexR + i) & INDEX_MASK]), sr_mask));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
@ -65,38 +75,38 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
|||
{
|
||||
for (unsigned int i = 0; i < numLeft * 2; i+=2)
|
||||
{
|
||||
samples[i] = Common::swap16(m_buffer[(m_indexR + i + 1) & INDEX_MASK]);
|
||||
samples[i+1] = Common::swap16(m_buffer[(m_indexR + i) & INDEX_MASK]);
|
||||
samples[i] = Common::swap16(m_buffer[(indexR + i + 1) & INDEX_MASK]);
|
||||
samples[i+1] = Common::swap16(m_buffer[(indexR + i) & INDEX_MASK]);
|
||||
}
|
||||
}
|
||||
m_indexR += numLeft * 2;
|
||||
indexR += numLeft * 2;
|
||||
}
|
||||
else //linear interpolation
|
||||
{
|
||||
//render numleft sample pairs to samples[]
|
||||
//advance m_indexR with sample position
|
||||
//advance indexR with sample position
|
||||
//remember fractional offset
|
||||
|
||||
static u32 frac = 0;
|
||||
const u32 ratio = (u32)( 65536.0f * (float)AudioInterface::GetAIDSampleRate() / (float)m_sampleRate );
|
||||
|
||||
for (u32 i = 0; i < numLeft * 2; i+=2) {
|
||||
u32 m_indexR2 = m_indexR + 2; //next sample
|
||||
if ((m_indexR2 & INDEX_MASK) == (m_indexW & INDEX_MASK)) //..if it exists
|
||||
m_indexR2 = m_indexR;
|
||||
u32 indexR2 = indexR + 2; //next sample
|
||||
if ((indexR2 & INDEX_MASK) == (indexW & INDEX_MASK)) //..if it exists
|
||||
indexR2 = indexR;
|
||||
|
||||
s16 l1 = Common::swap16(m_buffer[m_indexR & INDEX_MASK]); //current
|
||||
s16 l2 = Common::swap16(m_buffer[m_indexR2 & INDEX_MASK]); //next
|
||||
s16 l1 = Common::swap16(m_buffer[indexR & INDEX_MASK]); //current
|
||||
s16 l2 = Common::swap16(m_buffer[indexR2 & INDEX_MASK]); //next
|
||||
int sampleL = ((l1 << 16) + (l2 - l1) * (u16)frac) >> 16;
|
||||
samples[i+1] = sampleL;
|
||||
|
||||
s16 r1 = Common::swap16(m_buffer[(m_indexR + 1) & INDEX_MASK]); //current
|
||||
s16 r2 = Common::swap16(m_buffer[(m_indexR2 + 1) & INDEX_MASK]); //next
|
||||
s16 r1 = Common::swap16(m_buffer[(indexR + 1) & INDEX_MASK]); //current
|
||||
s16 r2 = Common::swap16(m_buffer[(indexR2 + 1) & INDEX_MASK]); //next
|
||||
int sampleR = ((r1 << 16) + (r2 - r1) * (u16)frac) >> 16;
|
||||
samples[i] = sampleR;
|
||||
|
||||
frac += ratio;
|
||||
m_indexR += 2 * (u16)(frac >> 16);
|
||||
indexR += 2 * (u16)(frac >> 16);
|
||||
frac &= 0xffff;
|
||||
}
|
||||
}
|
||||
|
@ -109,12 +119,15 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
|||
if (numSamples > numLeft)
|
||||
{
|
||||
unsigned short s[2];
|
||||
s[0] = Common::swap16(m_buffer[(m_indexR - 1) & INDEX_MASK]);
|
||||
s[1] = Common::swap16(m_buffer[(m_indexR - 2) & INDEX_MASK]);
|
||||
s[0] = Common::swap16(m_buffer[(indexR - 1) & INDEX_MASK]);
|
||||
s[1] = Common::swap16(m_buffer[(indexR - 2) & INDEX_MASK]);
|
||||
for (unsigned int i = numLeft*2; i < numSamples*2; i+=2)
|
||||
*(u32*)(samples+i) = *(u32*)(s);
|
||||
// memset(&samples[numLeft * 2], 0, (numSamples - numLeft) * 4);
|
||||
}
|
||||
|
||||
// Flush cached variable
|
||||
Common::AtomicStore(m_indexR, indexR);
|
||||
|
||||
//when logging, also throttle HLE audio
|
||||
if (m_logAudio) {
|
||||
|
@ -135,19 +148,21 @@ unsigned int CMixer::Mix(short* samples, unsigned int numSamples)
|
|||
AudioInterface::Callback_GetStreaming(samples, numSamples, m_sampleRate);
|
||||
}
|
||||
|
||||
|
||||
Common::AtomicAdd(m_numSamples, -(s32)numLeft);
|
||||
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
|
||||
void CMixer::PushSamples(const short *samples, unsigned int num_samples)
|
||||
{
|
||||
// Cache access in non-volatile variable
|
||||
// indexR isn't allowed to cache in the audio throttling loop as it
|
||||
// needs to get updates to not deadlock.
|
||||
u32 indexW = Common::AtomicLoad(m_indexW);
|
||||
|
||||
if (m_throttle)
|
||||
{
|
||||
// The auto throttle function. This loop will put a ceiling on the CPU MHz.
|
||||
while (num_samples + Common::AtomicLoad(m_numSamples) > MAX_SAMPLES)
|
||||
while (num_samples * 2 + ((indexW - Common::AtomicLoad(m_indexR)) & INDEX_MASK) >= MAX_SAMPLES * 2)
|
||||
{
|
||||
if (*PowerPC::GetStatePtr() != PowerPC::CPU_RUNNING || soundStream->IsMuted())
|
||||
break;
|
||||
|
@ -160,37 +175,47 @@ void CMixer::PushSamples(const short *samples, unsigned int num_samples)
|
|||
}
|
||||
|
||||
// Check if we have enough free space
|
||||
if (num_samples + Common::AtomicLoad(m_numSamples) > MAX_SAMPLES)
|
||||
// indexW == m_indexR results in empty buffer, so indexR must always be smaller than indexW
|
||||
if (num_samples * 2 + ((indexW - Common::AtomicLoad(m_indexR)) & INDEX_MASK) >= MAX_SAMPLES * 2)
|
||||
return;
|
||||
|
||||
// AyuanX: Actual re-sampling work has been moved to sound thread
|
||||
// to alleviate the workload on main thread
|
||||
// and we simply store raw data here to make fast mem copy
|
||||
int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (m_indexW & INDEX_MASK)) * sizeof(short);
|
||||
int over_bytes = num_samples * 4 - (MAX_SAMPLES * 2 - (indexW & INDEX_MASK)) * sizeof(short);
|
||||
if (over_bytes > 0)
|
||||
{
|
||||
memcpy(&m_buffer[m_indexW & INDEX_MASK], samples, num_samples * 4 - over_bytes);
|
||||
memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4 - over_bytes);
|
||||
memcpy(&m_buffer[0], samples + (num_samples * 4 - over_bytes) / sizeof(short), over_bytes);
|
||||
}
|
||||
else
|
||||
{
|
||||
memcpy(&m_buffer[m_indexW & INDEX_MASK], samples, num_samples * 4);
|
||||
memcpy(&m_buffer[indexW & INDEX_MASK], samples, num_samples * 4);
|
||||
}
|
||||
|
||||
m_indexW += num_samples * 2;
|
||||
|
||||
if (AudioInterface::GetAIDSampleRate() == m_sampleRate)
|
||||
Common::AtomicAdd(m_numSamples, num_samples);
|
||||
else if ((AudioInterface::GetAIDSampleRate() == 32000) && (m_sampleRate == 48000))
|
||||
Common::AtomicAdd(m_numSamples, num_samples * 3 / 2);
|
||||
else
|
||||
Common::AtomicAdd(m_numSamples, num_samples * 2 / 3);
|
||||
|
||||
|
||||
Common::AtomicAdd(m_indexW, num_samples * 2);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unsigned int CMixer::GetNumSamples()
|
||||
{
|
||||
return Common::AtomicLoad(m_numSamples);
|
||||
// Guess how many samples would be available after interpolation.
|
||||
// As interpolation needs at least on sample from the future to
|
||||
// linear interpolate between them, one sample less is available.
|
||||
// We also can't say the current interpolation state (specially
|
||||
// the frac), so to be sure, subtract one again to be sure not
|
||||
// to underflow the fifo.
|
||||
|
||||
u32 numSamples = ((Common::AtomicLoad(m_indexW) - Common::AtomicLoad(m_indexR)) & INDEX_MASK) / 2;
|
||||
|
||||
if (AudioInterface::GetAIDSampleRate() == m_sampleRate)
|
||||
numSamples = numSamples; // 1:1
|
||||
else if (m_sampleRate == 48000 && AudioInterface::GetAIDSampleRate() == 32000)
|
||||
numSamples = numSamples * 3 / 2 - 2; // most common case
|
||||
else
|
||||
numSamples = numSamples * m_sampleRate / AudioInterface::GetAIDSampleRate() - 2;
|
||||
|
||||
return numSamples;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,6 @@ public:
|
|||
, m_channels(2)
|
||||
, m_HLEready(false)
|
||||
, m_logAudio(0)
|
||||
, m_numSamples(0)
|
||||
, m_indexW(0)
|
||||
, m_indexR(0)
|
||||
, m_AIplaying(true)
|
||||
|
@ -97,9 +96,8 @@ protected:
|
|||
bool m_throttle;
|
||||
|
||||
short m_buffer[MAX_SAMPLES * 2];
|
||||
volatile u32 m_numSamples;
|
||||
u32 m_indexW;
|
||||
u32 m_indexR;
|
||||
volatile u32 m_indexW;
|
||||
volatile u32 m_indexR;
|
||||
|
||||
bool m_AIplaying;
|
||||
std::mutex m_csMixing;
|
||||
|
|
|
@ -97,7 +97,7 @@ void OpenALStream::SetVolume(int volume)
|
|||
fVolume = (float)volume / 100.0f;
|
||||
|
||||
if (uiSource)
|
||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
||||
}
|
||||
|
||||
void OpenALStream::Update()
|
||||
|
@ -124,6 +124,17 @@ void OpenALStream::SoundLoop()
|
|||
{
|
||||
Common::SetCurrentThreadName("Audio thread - openal");
|
||||
|
||||
bool surround_capable = Core::g_CoreStartupParameter.bDPL2Decoder;
|
||||
#if defined(__APPLE__)
|
||||
bool float32_capable = false;
|
||||
const ALenum AL_FORMAT_STEREO_FLOAT32 = 0;
|
||||
// OSX does not have the alext AL_FORMAT_51CHN32 yet.
|
||||
surround_capable = false;
|
||||
const ALenum AL_FORMAT_51CHN32 = 0;
|
||||
#else
|
||||
bool float32_capable = true;
|
||||
#endif
|
||||
|
||||
u32 ulFrequency = m_mixer->GetSampleRate();
|
||||
numBuffers = Core::g_CoreStartupParameter.iLatency + 2; // OpenAL requires a minimum of two buffers
|
||||
|
||||
|
@ -136,22 +147,20 @@ void OpenALStream::SoundLoop()
|
|||
alGenSources(1, &uiSource);
|
||||
|
||||
// Short Silence
|
||||
memset(sampleBuffer, 0, OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * numBuffers);
|
||||
memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * 4);
|
||||
memset(sampleBuffer, 0, OAL_MAX_SAMPLES * numBuffers * FRAME_SURROUND_FLOAT);
|
||||
memset(realtimeBuffer, 0, OAL_MAX_SAMPLES * FRAME_STEREO_SHORT);
|
||||
for (int i = 0; i < numBuffers; i++)
|
||||
{
|
||||
#if !defined(__APPLE__)
|
||||
if (Core::g_CoreStartupParameter.bDPL2Decoder)
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_51CHN32, sampleBuffer, 4 * SIZE_FLOAT * SURROUND_CHANNELS, ulFrequency);
|
||||
if (surround_capable)
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_51CHN32, sampleBuffer, 4 * FRAME_SURROUND_FLOAT, ulFrequency);
|
||||
else
|
||||
#endif
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, 4 * 2 * 2, ulFrequency);
|
||||
alBufferData(uiBuffers[i], AL_FORMAT_STEREO16, realtimeBuffer, 4 * FRAME_STEREO_SHORT, ulFrequency);
|
||||
}
|
||||
alSourceQueueBuffers(uiSource, numBuffers, uiBuffers);
|
||||
alSourcePlay(uiSource);
|
||||
|
||||
|
||||
// Set the default sound volume as saved in the config file.
|
||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
||||
alSourcef(uiSource, AL_GAIN, fVolume);
|
||||
|
||||
// TODO: Error handling
|
||||
//ALenum err = alGetError();
|
||||
|
@ -170,14 +179,7 @@ void OpenALStream::SoundLoop()
|
|||
soundTouch.setSetting(SETTING_SEEKWINDOW_MS, 28);
|
||||
soundTouch.setSetting(SETTING_OVERLAP_MS, 12);
|
||||
|
||||
bool surround_capable = Core::g_CoreStartupParameter.bDPL2Decoder;
|
||||
#if defined(__APPLE__)
|
||||
bool float32_capable = false;
|
||||
#else
|
||||
bool float32_capable = true;
|
||||
#endif
|
||||
|
||||
while (!threadData)
|
||||
while (!threadData)
|
||||
{
|
||||
// num_samples_to_render in this update - depends on SystemTimers::AUDIO_DMA_PERIOD.
|
||||
const u32 stereo_16_bit_size = 4;
|
||||
|
@ -193,12 +195,9 @@ void OpenALStream::SoundLoop()
|
|||
numSamples = m_mixer->Mix(realtimeBuffer, numSamples);
|
||||
|
||||
// Convert the samples from short to float
|
||||
float dest[OAL_MAX_SAMPLES * 2 * 2 * OAL_MAX_BUFFERS];
|
||||
for (u32 i = 0; i < numSamples; ++i)
|
||||
{
|
||||
dest[i * 2 + 0] = (float)realtimeBuffer[i * 2 + 0] / (1 << 16);
|
||||
dest[i * 2 + 1] = (float)realtimeBuffer[i * 2 + 1] / (1 << 16);
|
||||
}
|
||||
float dest[OAL_MAX_SAMPLES * STEREO_CHANNELS];
|
||||
for (u32 i = 0; i < numSamples * STEREO_CHANNELS; ++i)
|
||||
dest[i] = (float)realtimeBuffer[i] / (1 << 16);
|
||||
|
||||
soundTouch.putSamples(dest, numSamples);
|
||||
|
||||
|
@ -230,101 +229,94 @@ void OpenALStream::SoundLoop()
|
|||
}
|
||||
}
|
||||
|
||||
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * SIZE_FLOAT * OAL_MAX_BUFFERS);
|
||||
unsigned int nSamples = soundTouch.receiveSamples(sampleBuffer, OAL_MAX_SAMPLES * numBuffers);
|
||||
|
||||
if (nSamples > minSamples)
|
||||
if (nSamples <= minSamples)
|
||||
continue;
|
||||
|
||||
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
|
||||
if (iBuffersFilled == 0)
|
||||
{
|
||||
// Remove the Buffer from the Queue. (uiBuffer contains the Buffer ID for the unqueued Buffer)
|
||||
if (iBuffersFilled == 0)
|
||||
{
|
||||
alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error unqueuing buffers: %08x", err);
|
||||
}
|
||||
}
|
||||
#if defined(__APPLE__)
|
||||
// OSX does not have the alext AL_FORMAT_51CHN32 yet.
|
||||
surround_capable = false;
|
||||
#else
|
||||
if (surround_capable)
|
||||
{
|
||||
float dpl2[OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS];
|
||||
dpl2decode(sampleBuffer, nSamples, dpl2);
|
||||
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN32, dpl2, nSamples * SIZE_FLOAT * SURROUND_CHANNELS, ulFrequency);
|
||||
ALenum err = alGetError();
|
||||
if (err == AL_INVALID_ENUM)
|
||||
{
|
||||
// 5.1 is not supported by the host, fallback to stereo
|
||||
WARN_LOG(AUDIO, "Unable to set 5.1 surround mode. Updating OpenAL Soft might fix this issue.");
|
||||
surround_capable = false;
|
||||
}
|
||||
else if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering data: %08x", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!surround_capable)
|
||||
{
|
||||
#if !defined(__APPLE__)
|
||||
if (float32_capable)
|
||||
{
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO_FLOAT32, sampleBuffer, nSamples * 4 * 2, ulFrequency);
|
||||
ALenum err = alGetError();
|
||||
if (err == AL_INVALID_ENUM)
|
||||
{
|
||||
float32_capable = false;
|
||||
}
|
||||
else if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering float32 data: %08x", err);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (!float32_capable)
|
||||
{
|
||||
// Convert the samples from float to short
|
||||
short stereo[OAL_MAX_SAMPLES * 2 * 2 * OAL_MAX_BUFFERS];
|
||||
for (u32 i = 0; i < nSamples; ++i)
|
||||
{
|
||||
stereo[i * 2 + 0] = (short)((float)sampleBuffer[i * 2 + 0] * (1 << 16));
|
||||
stereo[i * 2 + 1] = (short)((float)sampleBuffer[i * 2 + 1] * (1 << 16));
|
||||
}
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, stereo, nSamples * 2 * 2, ulFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]);
|
||||
alSourceUnqueueBuffers(uiSource, iBuffersProcessed, uiBufferTemp);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error queuing buffers: %08x", err);
|
||||
ERROR_LOG(AUDIO, "Error unqueuing buffers: %08x", err);
|
||||
}
|
||||
iBuffersFilled++;
|
||||
}
|
||||
|
||||
if (iBuffersFilled == numBuffers)
|
||||
if (surround_capable)
|
||||
{
|
||||
float dpl2[OAL_MAX_SAMPLES * OAL_MAX_BUFFERS * SURROUND_CHANNELS];
|
||||
dpl2decode(sampleBuffer, nSamples, dpl2);
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_51CHN32, dpl2, nSamples * FRAME_SURROUND_FLOAT, ulFrequency);
|
||||
ALenum err = alGetError();
|
||||
if (err == AL_INVALID_ENUM)
|
||||
{
|
||||
alSourcePlay(uiSource);
|
||||
err = alGetError();
|
||||
if (err != 0)
|
||||
// 5.1 is not supported by the host, fallback to stereo
|
||||
WARN_LOG(AUDIO, "Unable to set 5.1 surround mode. Updating OpenAL Soft might fix this issue.");
|
||||
surround_capable = false;
|
||||
}
|
||||
else if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering data: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
if (float32_capable)
|
||||
{
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO_FLOAT32, sampleBuffer, nSamples * FRAME_STEREO_FLOAT, ulFrequency);
|
||||
ALenum err = alGetError();
|
||||
if (err == AL_INVALID_ENUM)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err);
|
||||
float32_capable = false;
|
||||
}
|
||||
else if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred while buffering float32 data: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
alGetSourcei(uiSource, AL_SOURCE_STATE, &iState);
|
||||
if (iState != AL_PLAYING)
|
||||
else
|
||||
{
|
||||
// Buffer underrun occurred, resume playback
|
||||
alSourcePlay(uiSource);
|
||||
err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err);
|
||||
}
|
||||
// Convert the samples from float to short
|
||||
short stereo[OAL_MAX_SAMPLES * STEREO_CHANNELS * OAL_MAX_BUFFERS];
|
||||
for (u32 i = 0; i < nSamples * STEREO_CHANNELS; ++i)
|
||||
stereo[i] = (short)((float)sampleBuffer[i] * (1 << 16));
|
||||
|
||||
alBufferData(uiBufferTemp[iBuffersFilled], AL_FORMAT_STEREO16, stereo, nSamples * FRAME_STEREO_SHORT, ulFrequency);
|
||||
}
|
||||
}
|
||||
|
||||
alSourceQueueBuffers(uiSource, 1, &uiBufferTemp[iBuffersFilled]);
|
||||
ALenum err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error queuing buffers: %08x", err);
|
||||
}
|
||||
iBuffersFilled++;
|
||||
|
||||
if (iBuffersFilled == numBuffers)
|
||||
{
|
||||
alSourcePlay(uiSource);
|
||||
err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred during playback: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
alGetSourcei(uiSource, AL_SOURCE_STATE, &iState);
|
||||
if (iState != AL_PLAYING)
|
||||
{
|
||||
// Buffer underrun occurred, resume playback
|
||||
alSourcePlay(uiSource);
|
||||
err = alGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
ERROR_LOG(AUDIO, "Error occurred resuming playback: %08x", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,11 +30,16 @@
|
|||
#include <soundtouch/STTypes.h>
|
||||
|
||||
// 16 bit Stereo
|
||||
#define SFX_MAX_SOURCE 1
|
||||
#define OAL_MAX_BUFFERS 32
|
||||
#define OAL_MAX_SAMPLES 256
|
||||
#define SURROUND_CHANNELS 6 // number of channels in surround mode
|
||||
#define SIZE_FLOAT 4 // size of a float in bytes
|
||||
#define SFX_MAX_SOURCE 1
|
||||
#define OAL_MAX_BUFFERS 32
|
||||
#define OAL_MAX_SAMPLES 256
|
||||
#define STEREO_CHANNELS 2
|
||||
#define SURROUND_CHANNELS 6 // number of channels in surround mode
|
||||
#define SIZE_SHORT 2
|
||||
#define SIZE_FLOAT 4 // size of a float in bytes
|
||||
#define FRAME_STEREO_SHORT STEREO_CHANNELS * SIZE_SHORT
|
||||
#define FRAME_STEREO_FLOAT STEREO_CHANNELS * SIZE_FLOAT
|
||||
#define FRAME_SURROUND_FLOAT SURROUND_CHANNELS * SIZE_FLOAT
|
||||
#endif
|
||||
|
||||
class OpenALStream: public SoundStream
|
||||
|
@ -61,8 +66,8 @@ private:
|
|||
std::thread thread;
|
||||
Common::Event soundSyncEvent;
|
||||
|
||||
short realtimeBuffer[OAL_MAX_SAMPLES * 2];
|
||||
soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * SIZE_FLOAT * SURROUND_CHANNELS * OAL_MAX_BUFFERS];
|
||||
short realtimeBuffer[OAL_MAX_SAMPLES * STEREO_CHANNELS];
|
||||
soundtouch::SAMPLETYPE sampleBuffer[OAL_MAX_SAMPLES * SURROUND_CHANNELS * OAL_MAX_BUFFERS];
|
||||
ALuint uiBuffers[OAL_MAX_BUFFERS];
|
||||
ALuint uiSource;
|
||||
ALfloat fVolume;
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef ANDROID
|
||||
#include "Common.h"
|
||||
|
@ -54,7 +41,8 @@ static void bqPlayerCallback(SLAndroidSimpleBufferQueueItf bq, void *context) {
|
|||
// Comment from sample code:
|
||||
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
||||
// which for this code example would indicate a programming error
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
_assert_msg_(AUDIO, SL_RESULT_SUCCESS == result, "Couldn't enqueue audio stream.");
|
||||
|
||||
|
||||
curBuffer ^= 1; // Switch buffer
|
||||
// Render to the fresh buffer
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _OPENSLSTREAM_H_
|
||||
#define _OPENSLSTREAM_H_
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <functional>
|
||||
|
||||
|
|
|
@ -1,19 +1,6 @@
|
|||
// Copyright (C) 2003 Dolphin Project.
|
||||
|
||||
// This program is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, version 2.0.
|
||||
|
||||
// This program is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License 2.0 for more details.
|
||||
|
||||
// A copy of the GPL 2.0 should have been included with the program.
|
||||
// If not, see http://www.gnu.org/licenses/
|
||||
|
||||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _PULSE_AUDIO_STREAM_H
|
||||
#define _PULSE_AUDIO_STREAM_H
|
||||
|
|
|
@ -8,10 +8,11 @@
|
|||
|
||||
enum {BUF_SIZE = 32*1024};
|
||||
|
||||
WaveFileWriter::WaveFileWriter()
|
||||
WaveFileWriter::WaveFileWriter():
|
||||
skip_silence(false),
|
||||
audio_size(0),
|
||||
conv_buffer(NULL)
|
||||
{
|
||||
conv_buffer = 0;
|
||||
skip_silence = false;
|
||||
}
|
||||
|
||||
WaveFileWriter::~WaveFileWriter()
|
||||
|
@ -39,6 +40,8 @@ bool WaveFileWriter::Start(const char *filename, unsigned int HLESampleRate)
|
|||
return false;
|
||||
}
|
||||
|
||||
audio_size = 0;
|
||||
|
||||
// -----------------
|
||||
// Write file header
|
||||
// -----------------
|
||||
|
|
|
@ -44,6 +44,56 @@ char *GetCPUString()
|
|||
}
|
||||
return cpu_string;
|
||||
}
|
||||
|
||||
unsigned char GetCPUImplementer()
|
||||
{
|
||||
const char marker[] = "CPU implementer\t: ";
|
||||
char *implementer_string = 0;
|
||||
unsigned char implementer = 0;
|
||||
char buf[1024];
|
||||
|
||||
File::IOFile file(procfile, "r");
|
||||
auto const fp = file.GetHandle();
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
{
|
||||
if (strncmp(buf, marker, sizeof(marker) - 1))
|
||||
continue;
|
||||
implementer_string = buf + sizeof(marker) - 1;
|
||||
implementer_string = strndup(implementer_string, strlen(implementer_string) - 1); // Strip the newline
|
||||
sscanf(implementer_string, "0x%02hhx", &implementer);
|
||||
break;
|
||||
}
|
||||
return implementer;
|
||||
}
|
||||
|
||||
unsigned short GetCPUPart()
|
||||
{
|
||||
const char marker[] = "CPU part\t: ";
|
||||
char *part_string = 0;
|
||||
unsigned short part = 0;
|
||||
char buf[1024];
|
||||
|
||||
File::IOFile file(procfile, "r");
|
||||
auto const fp = file.GetHandle();
|
||||
if (!fp)
|
||||
return 0;
|
||||
|
||||
while (fgets(buf, sizeof(buf), fp))
|
||||
{
|
||||
if (strncmp(buf, marker, sizeof(marker) - 1))
|
||||
continue;
|
||||
part_string = buf + sizeof(marker) - 1;
|
||||
part_string = strndup(part_string, strlen(part_string) - 1); // Strip the newline
|
||||
sscanf(part_string, "0x%03hx", &part);
|
||||
break;
|
||||
}
|
||||
return part;
|
||||
|
||||
}
|
||||
|
||||
bool CheckCPUFeature(const char *feature)
|
||||
{
|
||||
const char marker[] = "Features\t: ";
|
||||
|
@ -123,10 +173,9 @@ void CPUInfo::Detect()
|
|||
bIDIVa = CheckCPUFeature("idiva");
|
||||
bIDIVt = CheckCPUFeature("idivt");
|
||||
|
||||
// On some buggy kernels(Qualcomm) they show that they support VFPv4 but not IDIVa
|
||||
// All VFPv4 CPUs will support IDIVa
|
||||
if (bVFPv4)
|
||||
bIDIVa = bIDIVt = true;
|
||||
// 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.
|
||||
bFP = CheckCPUFeature("fp");
|
||||
|
|
|
@ -86,7 +86,7 @@ bool TryMakeOperand2_AllowNegation(s32 imm, Operand2 &op2, bool *negated)
|
|||
Operand2 AssumeMakeOperand2(u32 imm) {
|
||||
Operand2 op2;
|
||||
bool result = TryMakeOperand2(imm, op2);
|
||||
_dbg_assert_msg_(JIT, result, "Could not make assumed Operand2.");
|
||||
_assert_msg_(DYNA_REC, result, "Could not make assumed Operand2.");
|
||||
return op2;
|
||||
}
|
||||
|
||||
|
@ -868,7 +868,7 @@ 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) << 2) | (Vm & 0xF));
|
||||
| ((Vm & 0x10) << 1) | (Vm & 0xF));
|
||||
|
||||
}
|
||||
void ARMXEmitter::VSUB(IntegerSize Size, ARMReg Vd, ARMReg Vn, ARMReg Vm)
|
||||
|
|
|
@ -143,7 +143,6 @@ enum HOST_COMM
|
|||
WM_USER_STOP = 10,
|
||||
WM_USER_CREATE,
|
||||
WM_USER_SETCURSOR,
|
||||
WM_USER_KEYDOWN,
|
||||
};
|
||||
|
||||
// Used for notification on emulation state
|
||||
|
|
|
@ -86,6 +86,45 @@ inline u64 _rotr64(u64 x, unsigned int shift){
|
|||
#define unlink _unlink
|
||||
#define snprintf _snprintf
|
||||
#define vscprintf _vscprintf
|
||||
|
||||
// Locale Cross-Compatibility
|
||||
#define locale_t _locale_t
|
||||
#define freelocale _free_locale
|
||||
#define newlocale(mask, locale, base) _create_locale(mask, locale)
|
||||
|
||||
#define LC_GLOBAL_LOCALE ((locale_t)-1)
|
||||
#define LC_ALL_MASK LC_ALL
|
||||
#define LC_COLLATE_MASK LC_COLLATE
|
||||
#define LC_CTYPE_MASK LC_CTYPE
|
||||
#define LC_MONETARY_MASK LC_MONETARY
|
||||
#define LC_NUMERIC_MASK LC_NUMERIC
|
||||
#define LC_TIME_MASK LC_TIME
|
||||
|
||||
inline locale_t uselocale(locale_t new_locale)
|
||||
{
|
||||
// Retrieve the current per thread locale setting
|
||||
bool bIsPerThread = (_configthreadlocale(0) == _ENABLE_PER_THREAD_LOCALE);
|
||||
|
||||
// Retrieve the current thread-specific locale
|
||||
locale_t old_locale = bIsPerThread ? _get_current_locale() : LC_GLOBAL_LOCALE;
|
||||
|
||||
if(new_locale == LC_GLOBAL_LOCALE)
|
||||
{
|
||||
// Restore the global locale
|
||||
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
|
||||
}
|
||||
else if(new_locale != NULL)
|
||||
{
|
||||
// Configure the thread to set the locale only for this thread
|
||||
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
|
||||
|
||||
// Set all locale categories
|
||||
for(int i = LC_MIN; i <= LC_MAX; i++)
|
||||
setlocale(i, new_locale->locinfo->lc_category[i].locale);
|
||||
}
|
||||
|
||||
return old_locale;
|
||||
}
|
||||
|
||||
// 64 bit offsets for windows
|
||||
#define fseeko _fseeki64
|
||||
|
@ -123,17 +162,19 @@ const char* GetLastErrorMsg();
|
|||
namespace Common
|
||||
{
|
||||
inline u8 swap8(u8 _data) {return _data;}
|
||||
inline u32 swap24(const u8* _data) {return (_data[0] << 16) | (_data[1] << 8) | _data[2];}
|
||||
|
||||
#ifdef ANDROID
|
||||
#undef swap16
|
||||
#undef swap32
|
||||
#undef swap64
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
|
||||
inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
|
||||
inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
|
||||
#elif _M_ARM
|
||||
#ifdef ANDROID
|
||||
#undef swap16
|
||||
#undef swap32
|
||||
#undef swap64
|
||||
#endif
|
||||
inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
|
||||
inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
|
||||
inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);}
|
||||
|
|
|
@ -27,8 +27,12 @@ const char *scm_rev_str = "Dolphin "
|
|||
#ifdef _M_X64
|
||||
#define NP_ARCH "x64"
|
||||
#else
|
||||
#ifdef _M_ARM
|
||||
#define NP_ARCH "ARM"
|
||||
#else
|
||||
#define NP_ARCH "x86"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
const char *netplay_dolphin_ver = SCM_DESC_STR " W" NP_ARCH;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
#include "../../../Plugins/Plugin_VideoDX9/Src/VideoBackend.h"
|
||||
#include "../../../Plugins/Plugin_VideoDX11/Src/VideoBackend.h"
|
||||
#endif
|
||||
#ifndef USE_GLES
|
||||
#if !defined(USE_GLES) || USE_GLES3
|
||||
#include "../../../Plugins/Plugin_VideoOGL/Src/VideoBackend.h"
|
||||
#endif
|
||||
#include "../../../Plugins/Plugin_VideoSoftware/Src/VideoBackend.h"
|
||||
|
@ -45,7 +45,7 @@ void VideoBackend::PopulateList()
|
|||
if (IsGteVista())
|
||||
g_available_video_backends.push_back(backends[0] = new DX11::VideoBackend);
|
||||
#endif
|
||||
#ifndef USE_GLES
|
||||
#if !defined(USE_GLES) || USE_GLES3
|
||||
g_available_video_backends.push_back(backends[1] = new OGL::VideoBackend);
|
||||
#endif
|
||||
g_available_video_backends.push_back(backends[3] = new SW::VideoSoftware);
|
||||
|
|
|
@ -112,6 +112,7 @@ set(SRCS Src/ActionReplay.cpp
|
|||
Src/HW/SI.cpp
|
||||
Src/HW/SI_DeviceAMBaseboard.cpp
|
||||
Src/HW/SI_Device.cpp
|
||||
Src/HW/SI_DeviceDanceMat.cpp
|
||||
Src/HW/SI_DeviceGBA.cpp
|
||||
Src/HW/SI_DeviceGCController.cpp
|
||||
Src/HW/SI_DeviceGCSteeringWheel.cpp
|
||||
|
@ -219,7 +220,7 @@ endif()
|
|||
|
||||
set(LIBS bdisasm inputcommon videosoftware sfml-network)
|
||||
|
||||
if(NOT USE_GLES)
|
||||
if(NOT USE_GLES OR USE_GLES3)
|
||||
set(LIBS ${LIBS} videoogl)
|
||||
endif()
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" />
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\miniupnpc\src;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -123,12 +123,11 @@
|
|||
<Lib>
|
||||
<AdditionalLibraryDirectories>
|
||||
</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\miniupnpc\src;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -136,12 +135,11 @@
|
|||
<Lib>
|
||||
<AdditionalLibraryDirectories>
|
||||
</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\miniupnpc\src;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -155,7 +153,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\miniupnpc\src;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -165,12 +163,11 @@
|
|||
<Lib>
|
||||
<AdditionalLibraryDirectories>
|
||||
</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\miniupnpc\src;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -184,7 +181,7 @@
|
|||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
|
||||
<ClCompile>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
<AdditionalIncludeDirectories>.\Src;..\Common\Src;..\VideoCommon\Src;..\AudioCommon\Src;..\DiscIO\Src;..\InputCommon\Src;..\wiiuse\Src;..\..\..\Externals\Bochs_disasm;..\..\..\Externals\SFML\include;..\..\..\Externals\LZO;..\..\..\Externals\portaudio\include;..\..\..\Externals\zlib;..\..\..\Externals\miniupnpc\src;..\..\..\Externals\polarssl\include;..\..\..\Externals\libusb\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
|
@ -194,7 +191,6 @@
|
|||
<Lib>
|
||||
<AdditionalLibraryDirectories>
|
||||
</AdditionalLibraryDirectories>
|
||||
<LinkTimeCodeGeneration>true</LinkTimeCodeGeneration>
|
||||
</Lib>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
|
@ -302,6 +298,7 @@
|
|||
<ClCompile Include="Src\HW\SI.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_Device.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceAMBaseboard.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceDanceMat.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceGBA.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceGCController.cpp" />
|
||||
<ClCompile Include="Src\HW\SI_DeviceGCSteeringWheel.cpp" />
|
||||
|
@ -506,6 +503,7 @@
|
|||
<ClInclude Include="Src\HW\SI.h" />
|
||||
<ClInclude Include="Src\HW\SI_Device.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceAMBaseboard.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceDanceMat.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceGBA.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceGCController.h" />
|
||||
<ClInclude Include="Src\HW\SI_DeviceGCSteeringWheel.h" />
|
||||
|
|
|
@ -289,6 +289,9 @@
|
|||
<ClCompile Include="Src\HW\SI_DeviceGCSteeringWheel.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\SI_DeviceDanceMat.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Src\HW\VideoInterface.cpp">
|
||||
<Filter>HW %28Flipper/Hollywood%29\VI - Video Interface</Filter>
|
||||
</ClCompile>
|
||||
|
@ -820,6 +823,9 @@
|
|||
<ClInclude Include="Src\HW\SI_DeviceGCSteeringWheel.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\SI_DeviceDanceMat.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Src\HW\SI.h">
|
||||
<Filter>HW %28Flipper/Hollywood%29\SI - Serial Interface</Filter>
|
||||
</ClInclude>
|
||||
|
|
|
@ -34,6 +34,7 @@
|
|||
#include "Host.h"
|
||||
#include "VideoBackendBase.h"
|
||||
#include "Movie.h"
|
||||
#include "NetPlay.h"
|
||||
|
||||
namespace BootManager
|
||||
{
|
||||
|
@ -42,7 +43,7 @@ namespace BootManager
|
|||
// Apply fire liberally
|
||||
struct ConfigCache
|
||||
{
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF,
|
||||
bool valid, bCPUThread, bSkipIdle, bEnableFPRF, bMMU, bDCBZOFF, m_EnableJIT,
|
||||
bVBeamSpeedHack, bSyncGPU, bFastDiscSpeed, bMergeBlocks, bDSPHLE, bHLE_BS2;
|
||||
int iTLBHack, iCPUCore;
|
||||
std::string strBackend;
|
||||
|
@ -60,6 +61,7 @@ bool BootCore(const std::string& _rFilename)
|
|||
StartUp.m_BootType = SCoreStartupParameter::BOOT_ISO;
|
||||
StartUp.m_strFilename = _rFilename;
|
||||
SConfig::GetInstance().m_LastFilename = _rFilename;
|
||||
SConfig::GetInstance().SaveSettings();
|
||||
StartUp.bRunCompareClient = false;
|
||||
StartUp.bRunCompareServer = false;
|
||||
|
||||
|
@ -90,6 +92,7 @@ bool BootCore(const std::string& _rFilename)
|
|||
config_cache.bDSPHLE = StartUp.bDSPHLE;
|
||||
config_cache.strBackend = StartUp.m_strVideoBackend;
|
||||
config_cache.bHLE_BS2 = StartUp.bHLE_BS2;
|
||||
config_cache.m_EnableJIT = SConfig::GetInstance().m_EnableJIT;
|
||||
|
||||
// General settings
|
||||
game_ini.Get("Core", "CPUThread", &StartUp.bCPUThread, StartUp.bCPUThread);
|
||||
|
@ -108,20 +111,6 @@ bool BootCore(const std::string& _rFilename)
|
|||
game_ini.Get("Core", "HLE_BS2", &StartUp.bHLE_BS2, StartUp.bHLE_BS2);
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
{
|
||||
StartUp.bCPUThread = Movie::IsDualCore();
|
||||
StartUp.bSkipIdle = Movie::IsSkipIdle();
|
||||
StartUp.bDSPHLE = Movie::IsDSPHLE();
|
||||
StartUp.bProgressive = Movie::IsProgressive();
|
||||
StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed();
|
||||
StartUp.iCPUCore = Movie::GetCPUMode();
|
||||
if (Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave() && !StartUp.bWii)
|
||||
{
|
||||
if (File::Exists("Movie.raw"))
|
||||
File::Delete("Movie.raw");
|
||||
}
|
||||
}
|
||||
// Wii settings
|
||||
if (StartUp.bWii)
|
||||
{
|
||||
|
@ -130,6 +119,30 @@ bool BootCore(const std::string& _rFilename)
|
|||
}
|
||||
}
|
||||
|
||||
// movie settings
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved())
|
||||
{
|
||||
StartUp.bCPUThread = Movie::IsDualCore();
|
||||
StartUp.bSkipIdle = Movie::IsSkipIdle();
|
||||
StartUp.bDSPHLE = Movie::IsDSPHLE();
|
||||
StartUp.bProgressive = Movie::IsProgressive();
|
||||
StartUp.bFastDiscSpeed = Movie::IsFastDiscSpeed();
|
||||
StartUp.iCPUCore = Movie::GetCPUMode();
|
||||
StartUp.bSyncGPU = Movie::IsSyncGPU();
|
||||
if (Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave() && !StartUp.bWii)
|
||||
{
|
||||
if (File::Exists(File::GetUserPath(D_GCUSER_IDX) + "Movie.raw"))
|
||||
File::Delete(File::GetUserPath(D_GCUSER_IDX) + "Movie.raw");
|
||||
}
|
||||
}
|
||||
|
||||
if (NetPlay::GetNetPlayPtr())
|
||||
{
|
||||
StartUp.bDSPHLE = g_NetPlaySettings.m_DSPHLE;
|
||||
StartUp.bEnableMemcardSaving = g_NetPlaySettings.m_WriteToMemcard;
|
||||
SConfig::GetInstance().m_EnableJIT = g_NetPlaySettings.m_DSPEnableJIT;
|
||||
}
|
||||
|
||||
// Run the game
|
||||
// Init the core
|
||||
if (!Core::Init())
|
||||
|
@ -166,6 +179,7 @@ void Stop()
|
|||
StartUp.m_strVideoBackend = config_cache.strBackend;
|
||||
VideoBackend::ActivateBackend(StartUp.m_strVideoBackend);
|
||||
StartUp.bHLE_BS2 = config_cache.bHLE_BS2;
|
||||
SConfig::GetInstance().m_EnableJIT = config_cache.m_EnableJIT;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,11 +35,13 @@ static const struct {
|
|||
|
||||
{ "ToggleFullscreen", 70 /* 'F' */, 2 /* wxMOD_CMD */ },
|
||||
{ "Screenshot", 83 /* 'S' */, 2 /* wxMOD_CMD */ },
|
||||
{ "Exit", 0, 0 /* wxMOD_NONE */ },
|
||||
|
||||
{ "Wiimote1Connect", 49 /* '1' */, 2 /* wxMOD_CMD */ },
|
||||
{ "Wiimote2Connect", 50 /* '2' */, 2 /* wxMOD_CMD */ },
|
||||
{ "Wiimote3Connect", 51 /* '3' */, 2 /* wxMOD_CMD */ },
|
||||
{ "Wiimote4Connect", 52 /* '4' */, 2 /* wxMOD_CMD */ },
|
||||
{ "BalanceBoardConnect",53 /* '4' */, 2 /* wxMOD_CMD */ },
|
||||
#else
|
||||
{ "Open", 79 /* 'O' */, 2 /* wxMOD_CONTROL */},
|
||||
{ "ChangeDisc", 0, 0 /* wxMOD_NONE */ },
|
||||
|
@ -57,11 +59,13 @@ static const struct {
|
|||
|
||||
{ "ToggleFullscreen", 13 /* WXK_RETURN */, 1 /* wxMOD_ALT */ },
|
||||
{ "Screenshot", 348 /* WXK_F9 */, 0 /* wxMOD_NONE */ },
|
||||
{ "Exit", 0, 0 /* wxMOD_NONE */ },
|
||||
|
||||
{ "Wiimote1Connect", 344 /* WXK_F5 */, 1 /* wxMOD_ALT */ },
|
||||
{ "Wiimote2Connect", 345 /* WXK_F6 */, 1 /* wxMOD_ALT */ },
|
||||
{ "Wiimote3Connect", 346 /* WXK_F7 */, 1 /* wxMOD_ALT */ },
|
||||
{ "Wiimote4Connect", 347 /* WXK_F8 */, 1 /* wxMOD_ALT */ },
|
||||
{ "BalanceBoardConnect",348 /* WXK_F9 */, 1 /* wxMOD_ALT */ },
|
||||
#endif
|
||||
|
||||
{ "LoadStateSlot1", 340 /* WXK_F1 */, 0 /* wxMOD_NONE */ },
|
||||
|
@ -81,6 +85,21 @@ static const struct {
|
|||
{ "SaveStateSlot6", 345 /* WXK_F6 */, 4 /* wxMOD_SHIFT */ },
|
||||
{ "SaveStateSlot7", 346 /* WXK_F7 */, 4 /* wxMOD_SHIFT */ },
|
||||
{ "SaveStateSlot8", 347 /* WXK_F8 */, 4 /* wxMOD_SHIFT */ },
|
||||
|
||||
{ "LoadLastState1", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState2", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState3", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState4", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState5", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState6", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState7", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadLastState8", 0, 0 /* wxMOD_NONE */ },
|
||||
|
||||
{ "SaveFirstState", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "UndoLoadState", 351 /* WXK_F12 */, 0 /* wxMOD_NONE */ },
|
||||
{ "UndoSaveState", 351 /* WXK_F12 */, 4 /* wxMOD_SHIFT */ },
|
||||
{ "SaveStateFile", 0, 0 /* wxMOD_NONE */ },
|
||||
{ "LoadStateFile", 0, 0 /* wxMOD_NONE */ },
|
||||
};
|
||||
|
||||
SConfig::SConfig()
|
||||
|
@ -231,7 +250,6 @@ void SConfig::SaveSettings()
|
|||
|
||||
ini.Set("Core", "WiiSDCard", m_WiiSDCard);
|
||||
ini.Set("Core", "WiiKeyboard", m_WiiKeyboard);
|
||||
ini.Set("Core", "WiimoteReconnectOnLoad", m_WiimoteReconnectOnLoad);
|
||||
ini.Set("Core", "WiimoteContinuousScanning", m_WiimoteContinuousScanning);
|
||||
ini.Set("Core", "WiimoteEnableSpeaker", m_WiimoteEnableSpeaker);
|
||||
ini.Set("Core", "RunCompareServer", m_LocalCoreStartupParameter.bRunCompareServer);
|
||||
|
@ -297,7 +315,7 @@ void SConfig::LoadSettings()
|
|||
|
||||
{
|
||||
// Interface
|
||||
ini.Get("Interface", "ConfirmStop", &m_LocalCoreStartupParameter.bConfirmStop, false);
|
||||
ini.Get("Interface", "ConfirmStop", &m_LocalCoreStartupParameter.bConfirmStop, true);
|
||||
ini.Get("Interface", "UsePanicHandlers", &m_LocalCoreStartupParameter.bUsePanicHandlers, true);
|
||||
ini.Get("Interface", "OnScreenDisplayMessages", &m_LocalCoreStartupParameter.bOnScreenDisplayMessages, true);
|
||||
ini.Get("Interface", "HideCursor", &m_LocalCoreStartupParameter.bHideCursor, false);
|
||||
|
@ -325,7 +343,7 @@ void SConfig::LoadSettings()
|
|||
|
||||
// Display
|
||||
ini.Get("Display", "Fullscreen", &m_LocalCoreStartupParameter.bFullscreen, false);
|
||||
ini.Get("Display", "FullscreenResolution", &m_LocalCoreStartupParameter.strFullscreenResolution, "640x480");
|
||||
ini.Get("Display", "FullscreenResolution", &m_LocalCoreStartupParameter.strFullscreenResolution, "Auto");
|
||||
ini.Get("Display", "RenderToMain", &m_LocalCoreStartupParameter.bRenderToMain, false);
|
||||
ini.Get("Display", "RenderWindowXPos", &m_LocalCoreStartupParameter.iRenderWindowXPos, -1);
|
||||
ini.Get("Display", "RenderWindowYPos", &m_LocalCoreStartupParameter.iRenderWindowYPos, -1);
|
||||
|
@ -391,13 +409,13 @@ void SConfig::LoadSettings()
|
|||
|
||||
ini.Get("Core", "WiiSDCard", &m_WiiSDCard, false);
|
||||
ini.Get("Core", "WiiKeyboard", &m_WiiKeyboard, false);
|
||||
ini.Get("Core", "WiimoteReconnectOnLoad", &m_WiimoteReconnectOnLoad, true);
|
||||
ini.Get("Core", "WiimoteContinuousScanning", &m_WiimoteContinuousScanning, false);
|
||||
ini.Get("Core", "WiimoteEnableSpeaker", &m_WiimoteEnableSpeaker, true);
|
||||
ini.Get("Core", "RunCompareServer", &m_LocalCoreStartupParameter.bRunCompareServer, false);
|
||||
ini.Get("Core", "RunCompareClient", &m_LocalCoreStartupParameter.bRunCompareClient, false);
|
||||
ini.Get("Core", "MMU", &m_LocalCoreStartupParameter.bMMU, false);
|
||||
ini.Get("Core", "TLBHack", &m_LocalCoreStartupParameter.iTLBHack, 0);
|
||||
ini.Get("Core", "BBDumpPort", &m_LocalCoreStartupParameter.iBBDumpPort, -1);
|
||||
ini.Get("Core", "VBeam", &m_LocalCoreStartupParameter.bVBeamSpeedHack, false);
|
||||
ini.Get("Core", "SyncGPU", &m_LocalCoreStartupParameter.bSyncGPU, false);
|
||||
ini.Get("Core", "FastDiscSpeed", &m_LocalCoreStartupParameter.bFastDiscSpeed, false);
|
||||
|
|
|
@ -28,7 +28,6 @@ struct SConfig : NonCopyable
|
|||
// Wii Devices
|
||||
bool m_WiiSDCard;
|
||||
bool m_WiiKeyboard;
|
||||
bool m_WiimoteReconnectOnLoad;
|
||||
bool m_WiimoteContinuousScanning;
|
||||
bool m_WiimoteEnableSpeaker;
|
||||
|
||||
|
|
|
@ -59,6 +59,7 @@
|
|||
|
||||
#include "State.h"
|
||||
#include "Movie.h"
|
||||
#include "PatchEngine.h"
|
||||
|
||||
// TODO: ugly, remove
|
||||
bool g_aspect_wide;
|
||||
|
@ -83,7 +84,6 @@ void Stop();
|
|||
bool g_bStopping = false;
|
||||
bool g_bHwInit = false;
|
||||
bool g_bStarted = false;
|
||||
bool g_bRealWiimote = false;
|
||||
void *g_pWindowHandle = NULL;
|
||||
std::string g_stateFileName;
|
||||
std::thread g_EmuThread;
|
||||
|
@ -282,6 +282,8 @@ void Stop() // - Hammertime!
|
|||
|
||||
INFO_LOG(CONSOLE, "Stop [Main Thread]\t\t---- Shutdown complete ----");
|
||||
Movie::Shutdown();
|
||||
PatchEngine::Shutdown();
|
||||
|
||||
g_bStopping = false;
|
||||
}
|
||||
|
||||
|
@ -404,13 +406,13 @@ void EmuThread()
|
|||
// Load and Init Wiimotes - only if we are booting in wii mode
|
||||
if (g_CoreStartupParameter.bWii)
|
||||
{
|
||||
Wiimote::Initialize(g_pWindowHandle);
|
||||
Wiimote::Initialize(g_pWindowHandle, !g_stateFileName.empty());
|
||||
|
||||
// Activate wiimotes which don't have source set to "None"
|
||||
for (unsigned int i = 0; i != MAX_WIIMOTES; ++i)
|
||||
for (unsigned int i = 0; i != MAX_BBMOTES; ++i)
|
||||
if (g_wiimote_sources[i])
|
||||
GetUsbPointer()->AccessWiiMote(i | 0x100)->
|
||||
Activate(true);
|
||||
GetUsbPointer()->AccessWiiMote(i | 0x100)->Activate(true);
|
||||
|
||||
}
|
||||
|
||||
// The hardware is initialized.
|
||||
|
@ -523,9 +525,11 @@ void SetState(EState _State)
|
|||
break;
|
||||
case CORE_PAUSE:
|
||||
CCPU::EnableStepping(true); // Break
|
||||
Wiimote::Pause();
|
||||
break;
|
||||
case CORE_RUN:
|
||||
CCPU::EnableStepping(false);
|
||||
Wiimote::Resume();
|
||||
break;
|
||||
default:
|
||||
PanicAlertT("Invalid state");
|
||||
|
@ -699,7 +703,8 @@ void UpdateTitle()
|
|||
u32 Speed = DrawnVideo * (100 * 1000) / (VideoInterface::TargetRefreshRate * ElapseTime);
|
||||
|
||||
// Settings are shown the same for both extended and summary info
|
||||
std::string SSettings = StringFromFormat("%s %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC");
|
||||
std::string SSettings = StringFromFormat("%s %s | %s | %s", cpu_core_base->GetName(), _CoreParameter.bCPUThread ? "DC" : "SC",
|
||||
g_video_backend->GetName().c_str(), _CoreParameter.bDSPHLE ? "HLE" : "LLE");
|
||||
|
||||
// Use extended or summary information. The summary information does not print the ticks data,
|
||||
// that's more of a debugging interest, it can always be optional of course if someone is interested.
|
||||
|
@ -716,7 +721,7 @@ void UpdateTitle()
|
|||
|
||||
float TicksPercentage = (float)diff / (float)(SystemTimers::GetTicksPerSecond() / 1000000) * 100;
|
||||
|
||||
std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
|
||||
std::string SFPS = StringFromFormat("FPS: %u - VPS: %u - %u%%", FPS, VPS, Speed);
|
||||
SFPS += StringFromFormat(" | CPU: %s%i MHz [Real: %i + IdleSkip: %i] / %i MHz (%s%3.0f%%)",
|
||||
_CoreParameter.bSkipIdle ? "~" : "",
|
||||
(int)(diff),
|
||||
|
@ -729,11 +734,11 @@ void UpdateTitle()
|
|||
#else // Summary information
|
||||
std::string SFPS;
|
||||
if (Movie::IsPlayingInput())
|
||||
SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
|
||||
SFPS = StringFromFormat("VI: %u/%u - Frame: %u/%u - FPS: %u - VPS: %u - %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_totalFrames, (u32)Movie::g_currentInputCount, (u32)Movie::g_totalInputCount, FPS, VPS, Speed);
|
||||
else if (Movie::IsRecordingInput())
|
||||
SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - SPEED: %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
|
||||
SFPS = StringFromFormat("VI: %u - Frame: %u - FPS: %u - VPS: %u - %u%%", (u32)Movie::g_currentFrame, (u32)Movie::g_currentInputCount, FPS, VPS, Speed);
|
||||
else
|
||||
SFPS = StringFromFormat("FPS: %u - VPS: %u - SPEED: %u%%", FPS, VPS, Speed);
|
||||
SFPS = StringFromFormat("FPS: %u - VPS: %u - %u%%", FPS, VPS, Speed);
|
||||
#endif
|
||||
|
||||
// This is our final "frame counter" string
|
||||
|
|
|
@ -36,7 +36,7 @@ SCoreStartupParameter::SCoreStartupParameter()
|
|||
bMergeBlocks(false), bEnableMemcardSaving(true),
|
||||
bDPL2Decoder(false), iLatency(14),
|
||||
bRunCompareServer(false), bRunCompareClient(false),
|
||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), bVBeamSpeedHack(false),
|
||||
bMMU(false), bDCBZOFF(false), iTLBHack(0), iBBDumpPort(0), bVBeamSpeedHack(false),
|
||||
bSyncGPU(false), bFastDiscSpeed(false),
|
||||
SelectedLanguage(0), bWii(false),
|
||||
bConfirmStop(false), bHideCursor(false),
|
||||
|
@ -68,6 +68,7 @@ void SCoreStartupParameter::LoadDefaults()
|
|||
bMMU = false;
|
||||
bDCBZOFF = false;
|
||||
iTLBHack = 0;
|
||||
iBBDumpPort = -1;
|
||||
bVBeamSpeedHack = false;
|
||||
bSyncGPU = false;
|
||||
bFastDiscSpeed = false;
|
||||
|
|
|
@ -26,11 +26,13 @@ enum Hotkey
|
|||
|
||||
HK_FULLSCREEN,
|
||||
HK_SCREENSHOT,
|
||||
HK_EXIT,
|
||||
|
||||
HK_WIIMOTE1_CONNECT,
|
||||
HK_WIIMOTE2_CONNECT,
|
||||
HK_WIIMOTE3_CONNECT,
|
||||
HK_WIIMOTE4_CONNECT,
|
||||
HK_BALANCEBOARD_CONNECT,
|
||||
|
||||
HK_LOAD_STATE_SLOT_1,
|
||||
HK_LOAD_STATE_SLOT_2,
|
||||
|
@ -50,6 +52,21 @@ enum Hotkey
|
|||
HK_SAVE_STATE_SLOT_7,
|
||||
HK_SAVE_STATE_SLOT_8,
|
||||
|
||||
HK_LOAD_LAST_STATE_1,
|
||||
HK_LOAD_LAST_STATE_2,
|
||||
HK_LOAD_LAST_STATE_3,
|
||||
HK_LOAD_LAST_STATE_4,
|
||||
HK_LOAD_LAST_STATE_5,
|
||||
HK_LOAD_LAST_STATE_6,
|
||||
HK_LOAD_LAST_STATE_7,
|
||||
HK_LOAD_LAST_STATE_8,
|
||||
|
||||
HK_SAVE_FIRST_STATE,
|
||||
HK_UNDO_LOAD_STATE,
|
||||
HK_UNDO_SAVE_STATE,
|
||||
HK_SAVE_STATE_FILE,
|
||||
HK_LOAD_STATE_FILE,
|
||||
|
||||
NUM_HOTKEYS,
|
||||
};
|
||||
|
||||
|
@ -108,6 +125,7 @@ struct SCoreStartupParameter
|
|||
bool bMMU;
|
||||
bool bDCBZOFF;
|
||||
int iTLBHack;
|
||||
int iBBDumpPort;
|
||||
bool bVBeamSpeedHack;
|
||||
bool bSyncGPU;
|
||||
bool bFastDiscSpeed;
|
||||
|
|
|
@ -170,7 +170,10 @@ void EventDoState(PointerWrap &p, BaseEvent* ev)
|
|||
|
||||
// we can't savestate ev->type directly because events might not get registered in the same order (or at all) every time.
|
||||
// so, we savestate the event's type's name, and derive ev->type from that when loading.
|
||||
std::string name = event_types[ev->type].name;
|
||||
std::string name;
|
||||
if (p.GetMode() != PointerWrap::MODE_READ)
|
||||
name = event_types[ev->type].name;
|
||||
|
||||
p.Do(name);
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
{
|
||||
|
|
|
@ -137,6 +137,7 @@ bool DSPCore_Init(const char *irom_filename, const char *coef_filename,
|
|||
{
|
||||
g_dsp.step_counter = 0;
|
||||
cyclesLeft = 0;
|
||||
init_hax = false;
|
||||
dspjit = NULL;
|
||||
|
||||
g_dsp.irom = (u16*)AllocateMemoryPages(DSP_IROM_BYTE_SIZE);
|
||||
|
|
|
@ -246,14 +246,9 @@ static void gdsp_idma_in(u16 dsp_addr, u32 addr, u32 size)
|
|||
}
|
||||
WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
||||
|
||||
g_dsp.iram_crc = DSPHost_CodeLoaded(g_dsp.cpu_ram + (addr & 0x0fffffff), size);
|
||||
|
||||
NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc);
|
||||
DSPHost_CodeLoaded((const u8*)g_dsp.iram + dsp_addr, size);
|
||||
|
||||
if (dspjit)
|
||||
dspjit->ClearIRAM();
|
||||
|
||||
DSPAnalyzer::Analyze();
|
||||
NOTICE_LOG(DSPLLE, "*** Copy new UCode from 0x%08x to 0x%04x (crc: %8x)", addr, dsp_addr, g_dsp.iram_crc);
|
||||
}
|
||||
|
||||
static void gdsp_idma_out(u16 dsp_addr, u32 addr, u32 size)
|
||||
|
|
|
@ -15,7 +15,7 @@ void DSPHost_WriteHostMemory(u8 value, u32 addr);
|
|||
bool DSPHost_OnThread();
|
||||
bool DSPHost_Wii();
|
||||
void DSPHost_InterruptRequest();
|
||||
u32 DSPHost_CodeLoaded(const u8 *ptr, int size);
|
||||
void DSPHost_CodeLoaded(const u8 *ptr, int size);
|
||||
void DSPHost_UpdateDebugger();
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1563,6 +1563,7 @@ void DSPEmitter::lsrn(const UDSPInstruction opc)
|
|||
FixupBranch noShift = J_CC(CC_Z);
|
||||
//CL gets automatically masked with 0x3f on IA32/AMD64
|
||||
//MOVZX(64, 16, RCX, R(RAX));
|
||||
MOV(64, R(RCX), R(RAX));
|
||||
//AND(16, R(RCX), Imm16(0x3f));
|
||||
TEST(16, R(RAX), Imm16(0x40));
|
||||
FixupBranch shiftLeft = J_CC(CC_Z);
|
||||
|
|
|
@ -63,6 +63,38 @@ u32 GeckoCode::Code::GetAddress() const
|
|||
return gcaddress + (use_po ? pointer_address : (base_address & 0xFE000000));
|
||||
}
|
||||
|
||||
// return true if a code exists
|
||||
bool GeckoCode::Exist(u32 address, u32 data)
|
||||
{
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
codes_iter = codes.begin(),
|
||||
codes_end = codes.end();
|
||||
for (; codes_iter != codes_end; ++codes_iter)
|
||||
{
|
||||
if (codes_iter->address == address && codes_iter->data == data)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true if the code is identical
|
||||
bool GeckoCode::Compare(GeckoCode compare) const
|
||||
{
|
||||
if (codes.size() != compare.codes.size())
|
||||
return false;
|
||||
|
||||
unsigned int exist = 0;
|
||||
std::vector<GeckoCode::Code>::const_iterator
|
||||
codes_iter = codes.begin(),
|
||||
codes_end = codes.end();
|
||||
for (; codes_iter != codes_end; ++codes_iter)
|
||||
{
|
||||
if (compare.Exist(codes_iter->address, codes_iter->data))
|
||||
exist++;
|
||||
}
|
||||
return exist == codes.size();
|
||||
}
|
||||
|
||||
static std::mutex active_codes_lock;
|
||||
|
||||
// currently running code
|
||||
|
|
|
@ -66,6 +66,9 @@ namespace Gecko
|
|||
std::vector<std::string> notes;
|
||||
|
||||
bool enabled;
|
||||
|
||||
bool Compare(GeckoCode compare) const;
|
||||
bool Exist(u32 address, u32 data);
|
||||
};
|
||||
|
||||
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "PowerPC/SignatureDB.h"
|
||||
#include "PowerPC/PPCSymbolDB.h"
|
||||
#include "CommonPaths.h"
|
||||
#include "TextureCacheBase.h"
|
||||
|
||||
namespace HLE_Misc
|
||||
{
|
||||
|
@ -310,6 +311,7 @@ void ExecuteDOL(u8* dolFile, u32 fileSize)
|
|||
}
|
||||
|
||||
PowerPC::ppcState.iCache.Reset();
|
||||
TextureCache::RequestInvalidateTextureCache();
|
||||
|
||||
CWII_IPC_HLE_Device_usb_oh1_57e_305* s_Usb = GetUsbPointer();
|
||||
size_t size = s_Usb->m_WiiMotes.size();
|
||||
|
|
|
@ -687,12 +687,29 @@ void UpdateAudioDMA()
|
|||
|
||||
void Do_ARAM_DMA()
|
||||
{
|
||||
g_dspState.DSPControl.DMAState = 1;
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
|
||||
|
||||
// Force an early exception check on large transfers. Fixes RE2 audio.
|
||||
if (g_arDMA.Cnt.count > 2048 && g_arDMA.Cnt.count <= 6144)
|
||||
if (g_arDMA.Cnt.count == 32)
|
||||
{
|
||||
// Beyond Good and Evil (GGEE41) sends count 32
|
||||
// Lost Kingdoms 2 needs the exception check here in DSP HLE mode
|
||||
GenerateDSPInterrupt(INT_ARAM);
|
||||
CoreTiming::ForceExceptionCheck(100);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_dspState.DSPControl.DMAState = 1;
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, et_GenerateDSPInterrupt, INT_ARAM | (1<<16));
|
||||
|
||||
// Force an early exception check on large transfers. Fixes RE2 audio.
|
||||
// NFS:HP2 (<= 6144)
|
||||
// Viewtiful Joe (<= 6144)
|
||||
// Sonic Mega Collection (> 2048)
|
||||
// Paper Mario battles (> 32)
|
||||
// Mario Super Baseball (> 32)
|
||||
// Knockout Kings 2003 loading (> 32)
|
||||
// WWE DOR (> 32)
|
||||
if (g_arDMA.Cnt.count > 2048 && g_arDMA.Cnt.count <= 6144)
|
||||
CoreTiming::ForceExceptionCheck(100);
|
||||
}
|
||||
|
||||
// Real hardware DMAs in 32byte chunks, but we can get by with 8byte chunks
|
||||
if (g_arDMA.Cnt.dir)
|
||||
|
|
|
@ -66,9 +66,8 @@ void CUCode_AX::LoadResamplingCoefficients()
|
|||
|
||||
WARN_LOG(DSPHLE, "Loading polyphase resampling coeffs from %s", filename.c_str());
|
||||
|
||||
FILE* fp = fopen(filename.c_str(), "rb");
|
||||
fread(m_coeffs, 1, 0x1000, fp);
|
||||
fclose(fp);
|
||||
File::IOFile fp(filename, "rb");
|
||||
fp.ReadBytes(m_coeffs, 0x1000);
|
||||
|
||||
for (u32 i = 0; i < 0x800; ++i)
|
||||
m_coeffs[i] = Common::swap16(m_coeffs[i]);
|
||||
|
@ -240,7 +239,11 @@ void CUCode_AX::HandleCommandList()
|
|||
MixAUXBLR(HILO_TO_32(addr), HILO_TO_32(addr2));
|
||||
break;
|
||||
|
||||
case CMD_UNK_11: curr_idx += 2; break;
|
||||
case CMD_SET_OPPOSITE_LR:
|
||||
addr_hi = m_cmdlist[curr_idx++];
|
||||
addr_lo = m_cmdlist[curr_idx++];
|
||||
SetOppositeLR(HILO_TO_32(addr));
|
||||
break;
|
||||
|
||||
case CMD_UNK_12:
|
||||
{
|
||||
|
@ -590,6 +593,18 @@ void CUCode_AX::MixAUXBLR(u32 ul_addr, u32 dl_addr)
|
|||
}
|
||||
}
|
||||
|
||||
void CUCode_AX::SetOppositeLR(u32 src_addr)
|
||||
{
|
||||
int* ptr = (int*)HLEMemory_Get_Pointer(src_addr);
|
||||
for (u32 i = 0; i < 5 * 32; ++i)
|
||||
{
|
||||
int inp = Common::swap32(*ptr++);
|
||||
m_samples_left[i] = -inp;
|
||||
m_samples_right[i] = inp;
|
||||
m_samples_surround[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void CUCode_AX::SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl,
|
||||
u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl)
|
||||
{
|
||||
|
|
|
@ -147,6 +147,7 @@ protected:
|
|||
void SetMainLR(u32 src_addr);
|
||||
void OutputSamples(u32 out_addr, u32 surround_addr);
|
||||
void MixAUXBLR(u32 ul_addr, u32 dl_addr);
|
||||
void SetOppositeLR(u32 src_addr);
|
||||
void SendAUXAndMix(u32 main_auxa_up, u32 auxb_s_up, u32 main_l_dl,
|
||||
u32 main_r_dl, u32 auxb_l_dl, u32 auxb_r_dl);
|
||||
|
||||
|
@ -173,7 +174,7 @@ private:
|
|||
CMD_OUTPUT = 0x0E,
|
||||
CMD_END = 0x0F,
|
||||
CMD_MIX_AUXB_LR = 0x10,
|
||||
CMD_UNK_11 = 0x11,
|
||||
CMD_SET_OPPOSITE_LR = 0x11,
|
||||
CMD_UNK_12 = 0x12,
|
||||
CMD_SEND_AUX_AND_MIX = 0x13,
|
||||
};
|
||||
|
|
|
@ -457,8 +457,12 @@ void ProcessVoice(PB_TYPE& pb, const AXBuffers& buffers, u16 count, AXMixControl
|
|||
}
|
||||
|
||||
// Optionally, execute a low pass filter
|
||||
if (pb.lpf.enabled)
|
||||
// TODO: LPF code is currently broken, causing Super Monkey Ball sound
|
||||
// corruption. Disabled until someone figures out what is wrong with it.
|
||||
if (0 && pb.lpf.enabled)
|
||||
{
|
||||
pb.lpf.yn1 = LowPassFilter(samples, count, pb.lpf.yn1, pb.lpf.a0, pb.lpf.b0);
|
||||
}
|
||||
|
||||
// Mix LRS, AUXA and AUXB depending on mixer_control
|
||||
// TODO: Handle DPL2 on AUXB.
|
||||
|
|
|
@ -214,7 +214,6 @@ clear_buffer:
|
|||
template <typename T>
|
||||
void PrintObject(const T &Obj)
|
||||
{
|
||||
char byte[2] = {0};
|
||||
std::stringstream ss;
|
||||
u8 *o = (u8 *)&Obj;
|
||||
|
||||
|
@ -223,16 +222,17 @@ void PrintObject(const T &Obj)
|
|||
CompileTimeAssert<sizeof(ZeldaVoicePB) == 0x180> ensure_zpb_size_correct;
|
||||
(void)ensure_zpb_size_correct;
|
||||
|
||||
ss << std::hex;
|
||||
for (size_t i = 0; i < sizeof(T); i++)
|
||||
{
|
||||
if((i > 0) && ((i & 1) == 0))
|
||||
ss << " ";
|
||||
|
||||
sprintf(byte, "%02X", Common::swap16(o[i]));
|
||||
ss << byte;
|
||||
if((i & 1) == 0)
|
||||
ss << ' ';
|
||||
ss.width(2);
|
||||
ss.fill('0');
|
||||
ss << Common::swap16(o[i]);
|
||||
}
|
||||
|
||||
DEBUG_LOG(DSPHLE, "AFC PB: %s", ss.str().c_str());
|
||||
DEBUG_LOG(DSPHLE, "AFC PB:%s", ss.str().c_str());
|
||||
}
|
||||
|
||||
void CUCode_Zelda::RenderVoice_AFC(ZeldaVoicePB &PB, s16 *_Buffer, int _Size)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#include "Common.h"
|
||||
#include "Hash.h"
|
||||
#include "DSP/DSPAnalyzer.h"
|
||||
#include "DSP/DSPCore.h"
|
||||
#include "DSP/DSPHost.h"
|
||||
#include "DSPSymbols.h"
|
||||
#include "DSPLLETools.h"
|
||||
|
@ -45,23 +47,23 @@ void DSPHost_InterruptRequest()
|
|||
DSP::GenerateDSPInterruptFromDSPEmu(DSP::INT_DSP);
|
||||
}
|
||||
|
||||
u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
|
||||
void DSPHost_CodeLoaded(const u8 *ptr, int size)
|
||||
{
|
||||
u32 ector_crc = HashEctor(ptr, size);
|
||||
g_dsp.iram_crc = HashEctor(ptr, size);
|
||||
|
||||
#if defined(_DEBUG) || defined(DEBUGFAST)
|
||||
DumpDSPCode(ptr, size, ector_crc);
|
||||
DumpDSPCode(ptr, size, g_dsp.iram_crc);
|
||||
#endif
|
||||
|
||||
DSPSymbols::Clear();
|
||||
|
||||
// Auto load text file - if none just disassemble.
|
||||
|
||||
NOTICE_LOG(DSPLLE, "ector_crc: %08x", ector_crc);
|
||||
NOTICE_LOG(DSPLLE, "g_dsp.iram_crc: %08x", g_dsp.iram_crc);
|
||||
|
||||
DSPSymbols::Clear();
|
||||
bool success = false;
|
||||
switch (ector_crc)
|
||||
switch (g_dsp.iram_crc)
|
||||
{
|
||||
case 0x86840740: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Zelda.txt"); break;
|
||||
case 0x42f64ac4: success = DSPSymbols::ReadAnnotatedAssembly("../../docs/DSP/DSP_UC_Luigi.txt"); break;
|
||||
|
@ -86,7 +88,10 @@ u32 DSPHost_CodeLoaded(const u8 *ptr, int size)
|
|||
|
||||
DSPHost_UpdateDebugger();
|
||||
|
||||
return ector_crc;
|
||||
if (dspjit)
|
||||
dspjit->ClearIRAM();
|
||||
|
||||
DSPAnalyzer::Analyze();
|
||||
}
|
||||
|
||||
void DSPHost_UpdateDebugger()
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "Core.h"
|
||||
|
||||
#include "DSPLLEGlobals.h" // Local
|
||||
#include "DSP/DSPHost.h"
|
||||
#include "DSP/DSPInterpreter.h"
|
||||
#include "DSP/DSPHWInterface.h"
|
||||
#include "DSP/disassemble.h"
|
||||
|
@ -67,7 +68,6 @@ void DSPLLE::DoState(PointerWrap &p)
|
|||
p.Do(g_dsp.reg_stack[i]);
|
||||
}
|
||||
|
||||
p.Do(g_dsp.iram_crc);
|
||||
p.Do(g_dsp.step_counter);
|
||||
p.Do(g_dsp.ifx_regs);
|
||||
p.Do(g_dsp.mbox[0]);
|
||||
|
@ -75,8 +75,11 @@ void DSPLLE::DoState(PointerWrap &p)
|
|||
UnWriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
||||
p.DoArray(g_dsp.iram, DSP_IRAM_SIZE);
|
||||
WriteProtectMemory(g_dsp.iram, DSP_IRAM_BYTE_SIZE, false);
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
DSPHost_CodeLoaded((const u8*)g_dsp.iram, DSP_IRAM_BYTE_SIZE);
|
||||
p.DoArray(g_dsp.dram, DSP_DRAM_SIZE);
|
||||
p.Do(cyclesLeft);
|
||||
p.Do(init_hax);
|
||||
p.Do(m_cycle_count);
|
||||
|
||||
bool prevInitMixer = m_InitMixer;
|
||||
|
|
|
@ -530,6 +530,9 @@ void UpdateInterrupts()
|
|||
{
|
||||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_DI, false);
|
||||
}
|
||||
|
||||
// Required for Summoner: A Goddess Reborn
|
||||
CoreTiming::ForceExceptionCheck(50);
|
||||
}
|
||||
|
||||
void GenerateDIInterrupt(DI_InterruptType _DVDInterrupt)
|
||||
|
|
|
@ -48,7 +48,7 @@ CEXIMemoryCard::CEXIMemoryCard(const int index)
|
|||
{
|
||||
m_strFilename = (card_index == 0) ? SConfig::GetInstance().m_strMemoryCardA : SConfig::GetInstance().m_strMemoryCardB;
|
||||
if (Movie::IsPlayingInput() && Movie::IsConfigSaved() && Movie::IsUsingMemcard() && Movie::IsStartingFromClearSave())
|
||||
m_strFilename = "Movie.raw";
|
||||
m_strFilename = File::GetUserPath(D_GCUSER_IDX) + "Movie.raw";
|
||||
|
||||
// we're potentially leaking events here, since there's no UnregisterEvent until emu shutdown, but I guess it's inconsequential
|
||||
et_this_card = CoreTiming::RegisterEvent((card_index == 0) ? "memcardFlushA" : "memcardFlushB", FlushCallback);
|
||||
|
|
|
@ -215,7 +215,12 @@ GCMemcard::GCMemcard(const char *filename, bool forceCreation, bool sjis)
|
|||
}
|
||||
|
||||
mcdFile.Close();
|
||||
|
||||
initDirBatPointers();
|
||||
}
|
||||
|
||||
void GCMemcard::initDirBatPointers()
|
||||
{
|
||||
if (BE16(dir.UpdateCounter) > (BE16(dir_backup.UpdateCounter)))
|
||||
{
|
||||
CurrentDir = &dir;
|
||||
|
@ -1273,7 +1278,8 @@ bool GCMemcard::Format(bool sjis, u16 SizeMb)
|
|||
GCMBlock b;
|
||||
mc_data_blocks.push_back(b);
|
||||
}
|
||||
|
||||
|
||||
initDirBatPointers();
|
||||
m_valid = true;
|
||||
|
||||
return Save();
|
||||
|
|
|
@ -171,6 +171,7 @@ private:
|
|||
|
||||
u32 ImportGciInternal(FILE* gcih, const char *inputFile, const std::string &outputFile);
|
||||
static void FormatInternal(GCMC_Header &GCP);
|
||||
void initDirBatPointers() ;
|
||||
public:
|
||||
|
||||
GCMemcard(const char* fileName, bool forceCreation=false, bool sjis=false);
|
||||
|
|
|
@ -113,18 +113,18 @@ void HW_Default_Write(const T _Data, const u32 _Address){ ERROR_LOG(MASTER_LOG,
|
|||
template <class T>
|
||||
void HW_Default_Read(T _Data, const u32 _Address){ ERROR_LOG(MASTER_LOG, "Illegal HW Read%lu %08x", (unsigned long)sizeof(T)*8, _Address); _dbg_assert_(MEMMAP, 0);}
|
||||
|
||||
#define PAGE_SHIFT 10
|
||||
#define PAGE_SIZE (1 << PAGE_SHIFT)
|
||||
#define PAGE_MASK (PAGE_SHIFT - 1)
|
||||
#define HW_PAGE_SHIFT 10
|
||||
#define HW_PAGE_SIZE (1 << HW_PAGE_SHIFT)
|
||||
#define HW_PAGE_MASK (HW_PAGE_SHIFT - 1)
|
||||
|
||||
template <class T, u8 *P> void HW_Read_Memory(T &_Data, const u32 _Address)
|
||||
{
|
||||
_Data = *(T *)&P[_Address & PAGE_MASK];
|
||||
_Data = *(T *)&P[_Address & HW_PAGE_MASK];
|
||||
}
|
||||
|
||||
template <class T, u8 *P> void HW_Write_Memory(T _Data, const u32 _Address)
|
||||
{
|
||||
*(T *)&P[_Address & PAGE_MASK] = _Data;
|
||||
*(T *)&P[_Address & HW_PAGE_MASK] = _Data;
|
||||
}
|
||||
|
||||
// Create shortcuts to the hardware devices' read and write functions.
|
||||
|
|
|
@ -136,6 +136,11 @@ u16 Read_U16(const u32 _Address);
|
|||
u32 Read_U32(const u32 _Address);
|
||||
u64 Read_U64(const u32 _Address);
|
||||
|
||||
// Useful helper functions, used by ARM JIT
|
||||
float Read_F32(const u32 _Address);
|
||||
double Read_F64(const u32 _Address);
|
||||
|
||||
|
||||
// used by JIT. Return zero-extended 32bit values
|
||||
u32 Read_U8_ZX(const u32 _Address);
|
||||
u32 Read_U16_ZX(const u32 _Address);
|
||||
|
|
|
@ -407,6 +407,30 @@ u64 Read_U64(const u32 _Address)
|
|||
return _var;
|
||||
}
|
||||
|
||||
double Read_F64(const u32 _Address)
|
||||
{
|
||||
union
|
||||
{
|
||||
u64 i;
|
||||
double d;
|
||||
} cvt;
|
||||
|
||||
cvt.i = Read_U64(_Address);
|
||||
return cvt.d;
|
||||
}
|
||||
|
||||
float Read_F32(const u32 _Address)
|
||||
{
|
||||
union
|
||||
{
|
||||
u32 i;
|
||||
float d;
|
||||
} cvt;
|
||||
|
||||
cvt.i = Read_U32(_Address);
|
||||
return cvt.d;
|
||||
}
|
||||
|
||||
u32 Read_U8_ZX(const u32 _Address)
|
||||
{
|
||||
return (u32)Read_U8(_Address);
|
||||
|
@ -602,9 +626,6 @@ union UPTE2
|
|||
u32 Hex;
|
||||
};
|
||||
|
||||
u32 pagetable_base = 0;
|
||||
u32 pagetable_hashmask = 0;
|
||||
|
||||
void GenerateDSIException(u32 _EffectiveAddress, bool _bWrite)
|
||||
{
|
||||
if (_bWrite)
|
||||
|
@ -648,8 +669,8 @@ void SDRUpdated()
|
|||
{
|
||||
return;
|
||||
}
|
||||
pagetable_base = htaborg<<16;
|
||||
pagetable_hashmask = ((xx<<10)|0x3ff);
|
||||
PowerPC::ppcState.pagetable_base = htaborg<<16;
|
||||
PowerPC::ppcState.pagetable_hashmask = ((xx<<10)|0x3ff);
|
||||
}
|
||||
|
||||
|
||||
|
@ -660,10 +681,10 @@ void SDRUpdated()
|
|||
#define TLB_WAYS 2
|
||||
#define NUM_TLBS 2
|
||||
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_INDEX_SHIFT 12
|
||||
#define PAGE_INDEX_MASK 0x3f
|
||||
#define PAGE_TAG_SHIFT 18
|
||||
#define HW_PAGE_SIZE 4096
|
||||
#define HW_PAGE_INDEX_SHIFT 12
|
||||
#define HW_PAGE_INDEX_MASK 0x3f
|
||||
#define HW_PAGE_TAG_SHIFT 18
|
||||
|
||||
#define TLB_FLAG_MOST_RECENT 0x01
|
||||
#define TLB_FLAG_INVALID 0x02
|
||||
|
@ -683,7 +704,7 @@ static tlb_entry tlb[NUM_TLBS][TLB_SIZE/TLB_WAYS][TLB_WAYS];
|
|||
u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *paddr)
|
||||
{
|
||||
#ifdef FAST_TLB_CACHE
|
||||
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
|
||||
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK];
|
||||
if(tlbe[0].tag == (vpa & ~0xfff) && !(tlbe[0].flags & TLB_FLAG_INVALID))
|
||||
{
|
||||
tlbe[0].flags |= TLB_FLAG_MOST_RECENT;
|
||||
|
@ -732,19 +753,19 @@ u32 LookupTLBPageAddress(const XCheckTLBFlag _Flag, const u32 vpa, u32 *paddr)
|
|||
void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
|
||||
{
|
||||
#ifdef FAST_TLB_CACHE
|
||||
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
|
||||
tlb_entry *tlbe = tlb[_Flag == FLAG_OPCODE][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK];
|
||||
if((tlbe[0].flags & TLB_FLAG_MOST_RECENT) == 0)
|
||||
{
|
||||
tlbe[0].flags = TLB_FLAG_MOST_RECENT;
|
||||
tlbe[1].flags &= ~TLB_FLAG_MOST_RECENT;
|
||||
tlbe[0].paddr = PTE2.RPN << PAGE_INDEX_SHIFT;
|
||||
tlbe[0].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
|
||||
tlbe[0].tag = vpa & ~0xfff;
|
||||
}
|
||||
else
|
||||
{
|
||||
tlbe[1].flags = TLB_FLAG_MOST_RECENT;
|
||||
tlbe[0].flags &= ~TLB_FLAG_MOST_RECENT;
|
||||
tlbe[1].paddr = PTE2.RPN << PAGE_INDEX_SHIFT;
|
||||
tlbe[1].paddr = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
|
||||
tlbe[1].tag = vpa & ~0xfff;
|
||||
}
|
||||
#else
|
||||
|
@ -753,7 +774,7 @@ void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
|
|||
// ITLB cache
|
||||
PowerPC::ppcState.itlb_last++;
|
||||
PowerPC::ppcState.itlb_last &= 127;
|
||||
PowerPC::ppcState.itlb_pa[PowerPC::ppcState.itlb_last] = PTE2.RPN << PAGE_INDEX_SHIFT;
|
||||
PowerPC::ppcState.itlb_pa[PowerPC::ppcState.itlb_last] = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
|
||||
PowerPC::ppcState.itlb_va[PowerPC::ppcState.itlb_last] = vpa & ~0xfff;
|
||||
}
|
||||
else
|
||||
|
@ -761,7 +782,7 @@ void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
|
|||
// DTLB cache
|
||||
PowerPC::ppcState.dtlb_last++;
|
||||
PowerPC::ppcState.dtlb_last &= 127;
|
||||
PowerPC::ppcState.dtlb_pa[PowerPC::ppcState.dtlb_last] = PTE2.RPN << PAGE_INDEX_SHIFT;
|
||||
PowerPC::ppcState.dtlb_pa[PowerPC::ppcState.dtlb_last] = PTE2.RPN << HW_PAGE_INDEX_SHIFT;
|
||||
PowerPC::ppcState.dtlb_va[PowerPC::ppcState.dtlb_last] = vpa & ~0xfff;
|
||||
}
|
||||
#endif
|
||||
|
@ -770,7 +791,7 @@ void UpdateTLBEntry(const XCheckTLBFlag _Flag, UPTE2 PTE2, const u32 vpa)
|
|||
void InvalidateTLBEntry(u32 vpa)
|
||||
{
|
||||
#ifdef FAST_TLB_CACHE
|
||||
tlb_entry *tlbe = tlb[0][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
|
||||
tlb_entry *tlbe = tlb[0][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK];
|
||||
if(tlbe[0].tag == (vpa & ~0xfff))
|
||||
{
|
||||
tlbe[0].flags |= TLB_FLAG_INVALID;
|
||||
|
@ -779,7 +800,7 @@ void InvalidateTLBEntry(u32 vpa)
|
|||
{
|
||||
tlbe[1].flags |= TLB_FLAG_INVALID;
|
||||
}
|
||||
tlb_entry *tlbe_i = tlb[1][(vpa>>PAGE_INDEX_SHIFT)&PAGE_INDEX_MASK];
|
||||
tlb_entry *tlbe_i = tlb[1][(vpa>>HW_PAGE_INDEX_SHIFT)&HW_PAGE_INDEX_MASK];
|
||||
if(tlbe_i[0].tag == (vpa & ~0xfff))
|
||||
{
|
||||
tlbe_i[0].flags |= TLB_FLAG_INVALID;
|
||||
|
@ -825,7 +846,7 @@ u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
|
|||
|
||||
// hash function no 1 "xor" .360
|
||||
u32 hash1 = (VSID ^ page_index);
|
||||
u32 pteg_addr = ((hash1 & pagetable_hashmask) << 6) | pagetable_base;
|
||||
u32 pteg_addr = ((hash1 & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base;
|
||||
|
||||
// hash1
|
||||
for (int i = 0; i < 8; i++)
|
||||
|
@ -860,7 +881,7 @@ u32 TranslatePageAddress(const u32 _Address, const XCheckTLBFlag _Flag)
|
|||
|
||||
// hash function no 2 "not" .360
|
||||
hash1 = ~hash1;
|
||||
pteg_addr = ((hash1 & pagetable_hashmask) << 6) | pagetable_base;
|
||||
pteg_addr = ((hash1 & PowerPC::ppcState.pagetable_hashmask) << 6) | PowerPC::ppcState.pagetable_base;
|
||||
for (int i = 0; i < 8; i++)
|
||||
{
|
||||
u32 pte = bswap(*(u32*)&pRAM[pteg_addr]);
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include "../ConfigManager.h"
|
||||
#include "../CoreTiming.h"
|
||||
#include "../Movie.h"
|
||||
#include "../NetPlay.h"
|
||||
|
||||
#include "SystemTimers.h"
|
||||
#include "ProcessorInterface.h"
|
||||
|
@ -261,6 +262,8 @@ 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())
|
||||
AddDevice((SIDevices) g_NetPlaySettings.m_Controllers[i], i);
|
||||
else
|
||||
AddDevice(SConfig::GetInstance().m_SIDevice[i], i);
|
||||
}
|
||||
|
@ -641,7 +644,7 @@ void RunSIBuffer()
|
|||
int GetTicksToNextSIPoll()
|
||||
{
|
||||
// Poll for input at regular intervals (once per frame) when playing or recording a movie
|
||||
if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
|
||||
if (Movie::IsPlayingInput() || Movie::IsRecordingInput() || NetPlay::GetNetPlayPtr())
|
||||
{
|
||||
return SystemTimers::GetTicksPerSecond() / VideoInterface::TargetRefreshRate;
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "SI_Device.h"
|
||||
#include "SI_DeviceGCController.h"
|
||||
#include "SI_DeviceGCSteeringWheel.h"
|
||||
#include "SI_DeviceDanceMat.h"
|
||||
#include "SI_DeviceGBA.h"
|
||||
#include "SI_DeviceAMBaseboard.h"
|
||||
|
||||
|
@ -64,6 +65,10 @@ ISIDevice* SIDevice_Create(const SIDevices device, const int port_number)
|
|||
return new CSIDevice_GCController(device, port_number);
|
||||
break;
|
||||
|
||||
case SIDEVICE_DANCEMAT:
|
||||
return new CSIDevice_DanceMat(device, port_number);
|
||||
break;
|
||||
|
||||
case SIDEVICE_GC_STEERING:
|
||||
return new CSIDevice_GCSteeringWheel(device, port_number);
|
||||
break;
|
||||
|
|
|
@ -34,6 +34,7 @@ enum TSIDevices
|
|||
SI_GC_CONTROLLER = (SI_TYPE_GC | SI_GC_STANDARD),
|
||||
SI_GC_KEYBOARD = (SI_TYPE_GC | 0x00200000),
|
||||
SI_GC_STEERING = SI_TYPE_GC, // (shuffle2)I think the "chainsaw" is the same (Or else it's just standard)
|
||||
SI_DANCEMAT = (SI_TYPE_GC | SI_GC_STANDARD | 0x00000300),
|
||||
SI_AM_BASEBOARD = 0x10110800 // gets ORd with dipswitch state
|
||||
};
|
||||
|
||||
|
@ -49,6 +50,7 @@ enum SIDevices
|
|||
SIDEVICE_GC_CONTROLLER,
|
||||
SIDEVICE_GC_KEYBOARD,
|
||||
SIDEVICE_GC_STEERING,
|
||||
SIDEVICE_DANCEMAT,
|
||||
SIDEVICE_GC_TARUKONGA,
|
||||
SIDEVICE_AM_BASEBOARD
|
||||
};
|
||||
|
|
264
Source/Core/Core/Src/HW/SI_DeviceDanceMat.cpp
Normal file
264
Source/Core/Core/Src/HW/SI_DeviceDanceMat.cpp
Normal file
|
@ -0,0 +1,264 @@
|
|||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "SI.h"
|
||||
#include "SI_Device.h"
|
||||
#include "SI_DeviceDanceMat.h"
|
||||
|
||||
#include "EXI_Device.h"
|
||||
#include "EXI_DeviceMic.h"
|
||||
|
||||
#include "GCPad.h"
|
||||
|
||||
#include "../Movie.h"
|
||||
|
||||
#include "../CoreTiming.h"
|
||||
#include "SystemTimers.h"
|
||||
#include "ProcessorInterface.h"
|
||||
#include "../Core.h"
|
||||
|
||||
// --- Dance mat gamecube controller ---
|
||||
CSIDevice_DanceMat::CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber)
|
||||
: ISIDevice(device, _iDeviceNumber)
|
||||
, m_TButtonComboStart(0)
|
||||
, m_TButtonCombo(0)
|
||||
, m_LastButtonCombo(COMBO_NONE)
|
||||
{
|
||||
memset(&m_Origin, 0, sizeof(SOrigin));
|
||||
m_Origin.uCommand = CMD_ORIGIN;
|
||||
m_Origin.uOriginStickX = 0x80; // center
|
||||
m_Origin.uOriginStickY = 0x80;
|
||||
m_Origin.uSubStickStickX = 0x80;
|
||||
m_Origin.uSubStickStickY = 0x80;
|
||||
m_Origin.uTrigger_L = 0x00;
|
||||
m_Origin.uTrigger_R = 0x00;
|
||||
|
||||
// Dunno if we need to do this, game/lib should set it?
|
||||
m_Mode = 0x03;
|
||||
}
|
||||
|
||||
int CSIDevice_DanceMat::RunBuffer(u8* _pBuffer, int _iLength)
|
||||
{
|
||||
// For debug logging only
|
||||
ISIDevice::RunBuffer(_pBuffer, _iLength);
|
||||
|
||||
// Read the command
|
||||
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[3]);
|
||||
|
||||
// Handle it
|
||||
switch (command)
|
||||
{
|
||||
case CMD_RESET:
|
||||
*(u32*)&_pBuffer[0] = SI_DANCEMAT;
|
||||
break;
|
||||
|
||||
case CMD_DIRECT:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength);
|
||||
u32 high, low;
|
||||
GetData(high, low);
|
||||
for (int i = 0; i < (_iLength - 1) / 2; i++)
|
||||
{
|
||||
_pBuffer[0 + i] = (high >> (i * 8)) & 0xff;
|
||||
_pBuffer[4 + i] = (low >> (i * 8)) & 0xff;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case CMD_ORIGIN:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
|
||||
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
|
||||
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
||||
{
|
||||
_pBuffer[i ^ 3] = *pCalibration++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Recalibrate (FiRES: i am not 100 percent sure about this)
|
||||
case CMD_RECALIBRATE:
|
||||
{
|
||||
INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
|
||||
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
|
||||
for (int i = 0; i < (int)sizeof(SOrigin); i++)
|
||||
{
|
||||
_pBuffer[i ^ 3] = *pCalibration++;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// DEFAULT
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
|
||||
PanicAlert("SI: Unknown command (0x%x)", command);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return _iLength;
|
||||
}
|
||||
|
||||
|
||||
// GetData
|
||||
|
||||
// Return true on new data (max 7 Bytes and 6 bits ;)
|
||||
// [00?SYXBA] [1LRZUDRL] [x] [y] [cx] [cy] [l] [r]
|
||||
// |\_ ERR_LATCH (error latched - check SISR)
|
||||
// |_ ERR_STATUS (error on last GetData or SendCmd?)
|
||||
bool CSIDevice_DanceMat::GetData(u32& _Hi, u32& _Low)
|
||||
{
|
||||
SPADStatus PadStatus;
|
||||
memset(&PadStatus, 0, sizeof(PadStatus));
|
||||
|
||||
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
|
||||
Movie::CallInputManip(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
|
||||
u32 netValues[2];
|
||||
if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, PadStatus, netValues))
|
||||
{
|
||||
_Hi = netValues[0]; // first 4 bytes
|
||||
_Low = netValues[1]; // last 4 bytes
|
||||
return true;
|
||||
}
|
||||
|
||||
Movie::SetPolledDevice();
|
||||
|
||||
if(Movie::IsPlayingInput())
|
||||
{
|
||||
Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
Movie::InputUpdate();
|
||||
}
|
||||
else if(Movie::IsRecordingInput())
|
||||
{
|
||||
Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
Movie::InputUpdate();
|
||||
}
|
||||
else
|
||||
{
|
||||
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
|
||||
}
|
||||
|
||||
// Map the dpad to the blue arrows, the buttons to the orange arrows
|
||||
// Z = + button, Start = - button
|
||||
u16 map = 0;
|
||||
if (PadStatus.button & PAD_BUTTON_UP)
|
||||
map |= 0x1000;
|
||||
if (PadStatus.button & PAD_BUTTON_DOWN)
|
||||
map |= 0x2;
|
||||
if (PadStatus.button & PAD_BUTTON_LEFT)
|
||||
map |= 0x8;
|
||||
if (PadStatus.button & PAD_BUTTON_RIGHT)
|
||||
map |= 0x4;
|
||||
if (PadStatus.button & PAD_BUTTON_Y)
|
||||
map |= 0x200;
|
||||
if (PadStatus.button & PAD_BUTTON_A)
|
||||
map |= 0x10;
|
||||
if (PadStatus.button & PAD_BUTTON_B)
|
||||
map |= 0x100;
|
||||
if (PadStatus.button & PAD_BUTTON_X)
|
||||
map |= 0x800;
|
||||
if (PadStatus.button & PAD_TRIGGER_Z)
|
||||
map |= 0x400;
|
||||
if (PadStatus.button & PAD_BUTTON_START)
|
||||
map |= 0x1;
|
||||
|
||||
_Hi = (u32)(map << 16) | 0x8080;
|
||||
|
||||
// Low bits are packed differently per mode
|
||||
if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits
|
||||
}
|
||||
else if (m_Mode == 1)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits
|
||||
}
|
||||
else if (m_Mode == 2)
|
||||
{
|
||||
// Identifies the dance mat
|
||||
_Low = 0x8080ffff;
|
||||
}
|
||||
else if (m_Mode == 3)
|
||||
{
|
||||
// Analog A/B are always 0
|
||||
_Low = (u8)PadStatus.triggerRight; // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
|
||||
}
|
||||
else if (m_Mode == 4)
|
||||
{
|
||||
_Low = (u8)(PadStatus.analogB); // All 8 bits
|
||||
_Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits
|
||||
// triggerLeft/Right are always 0
|
||||
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
|
||||
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// SendCommand
|
||||
void CSIDevice_DanceMat::SendCommand(u32 _Cmd, u8 _Poll)
|
||||
{
|
||||
UCommand command(_Cmd);
|
||||
|
||||
switch (command.Command)
|
||||
{
|
||||
// Costis sent it in some demos :)
|
||||
case 0x00:
|
||||
break;
|
||||
|
||||
case CMD_WRITE:
|
||||
{
|
||||
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
|
||||
unsigned int uStrength = command.Parameter2;
|
||||
|
||||
// get the correct pad number that should rumble locally when using netplay
|
||||
const u8 numPAD = NetPlay_GetPadNum(ISIDevice::m_iDeviceNumber);
|
||||
|
||||
if (numPAD < 4)
|
||||
Pad::Rumble(numPAD, uType, uStrength);
|
||||
|
||||
if (!_Poll)
|
||||
{
|
||||
m_Mode = command.Parameter2;
|
||||
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
|
||||
PanicAlert("SI: Unknown direct command");
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Savestate support
|
||||
void CSIDevice_DanceMat::DoState(PointerWrap& p)
|
||||
{
|
||||
p.Do(m_Origin);
|
||||
p.Do(m_Mode);
|
||||
p.Do(m_TButtonComboStart);
|
||||
p.Do(m_TButtonCombo);
|
||||
p.Do(m_LastButtonCombo);
|
||||
}
|
105
Source/Core/Core/Src/HW/SI_DeviceDanceMat.h
Normal file
105
Source/Core/Core/Src/HW/SI_DeviceDanceMat.h
Normal file
|
@ -0,0 +1,105 @@
|
|||
// Copyright 2013 Dolphin Emulator Project
|
||||
// Licensed under GPLv2
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifndef _SI_DEVICEDANCEMAT_H
|
||||
#define _SI_DEVICEDANCEMAT_H
|
||||
|
||||
#include "SI_Device.h"
|
||||
#include "GCPadStatus.h"
|
||||
|
||||
|
||||
// standard gamecube controller
|
||||
class CSIDevice_DanceMat : public ISIDevice
|
||||
{
|
||||
private:
|
||||
|
||||
// Commands
|
||||
enum EBufferCommands
|
||||
{
|
||||
CMD_RESET = 0x00,
|
||||
CMD_DIRECT = 0x40,
|
||||
CMD_ORIGIN = 0x41,
|
||||
CMD_RECALIBRATE = 0x42,
|
||||
};
|
||||
|
||||
struct SOrigin
|
||||
{
|
||||
u8 uCommand;// Maybe should be button bits?
|
||||
u8 unk_1; // ..and this would be the other half
|
||||
u8 uOriginStickX;
|
||||
u8 uOriginStickY;
|
||||
u8 uSubStickStickX;
|
||||
u8 uSubStickStickY;
|
||||
u8 uTrigger_L;
|
||||
u8 uTrigger_R;
|
||||
u8 unk_4;
|
||||
u8 unk_5;
|
||||
u8 unk_6;
|
||||
u8 unk_7;
|
||||
};
|
||||
|
||||
enum EDirectCommands
|
||||
{
|
||||
CMD_WRITE = 0x40
|
||||
};
|
||||
|
||||
union UCommand
|
||||
{
|
||||
u32 Hex;
|
||||
struct
|
||||
{
|
||||
u32 Parameter1 : 8;
|
||||
u32 Parameter2 : 8;
|
||||
u32 Command : 8;
|
||||
u32 : 8;
|
||||
};
|
||||
UCommand() {Hex = 0;}
|
||||
UCommand(u32 _iValue) {Hex = _iValue;}
|
||||
};
|
||||
|
||||
enum EButtonCombo
|
||||
{
|
||||
COMBO_NONE = 0,
|
||||
COMBO_ORIGIN,
|
||||
COMBO_RESET
|
||||
};
|
||||
|
||||
// struct to compare input against
|
||||
// Set on connection and (standard pad only) on button combo
|
||||
SOrigin m_Origin;
|
||||
|
||||
// PADAnalogMode
|
||||
u8 m_Mode;
|
||||
|
||||
// Timer to track special button combos:
|
||||
// y, X, start for 3 seconds updates origin with current status
|
||||
// Technically, the above is only on standard pad, wavebird does not support it for example
|
||||
// b, x, start for 3 seconds triggers reset (PI reset button interrupt)
|
||||
u64 m_TButtonComboStart, m_TButtonCombo;
|
||||
// Type of button combo from the last/current poll
|
||||
EButtonCombo m_LastButtonCombo;
|
||||
|
||||
public:
|
||||
|
||||
// Constructor
|
||||
CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber);
|
||||
|
||||
// Run the SI Buffer
|
||||
virtual int RunBuffer(u8* _pBuffer, int _iLength);
|
||||
|
||||
// Send and Receive pad input from network
|
||||
static bool NetPlay_GetInput(u8 numPAD, SPADStatus status, u32 *PADStatus);
|
||||
static u8 NetPlay_GetPadNum(u8 numPAD);
|
||||
|
||||
// Return true on new data
|
||||
virtual bool GetData(u32& _Hi, u32& _Low);
|
||||
|
||||
// Send a command directly
|
||||
virtual void SendCommand(u32 _Cmd, u8 _Poll);
|
||||
|
||||
// Savestate support
|
||||
virtual void DoState(PointerWrap& p);
|
||||
};
|
||||
|
||||
#endif
|
|
@ -804,11 +804,9 @@ static void BeginField(FieldType field)
|
|||
u32 fbWidth = m_HorizontalStepping.FieldSteps * 16;
|
||||
u32 fbHeight = (m_HorizontalStepping.FbSteps / m_HorizontalStepping.FieldSteps) * m_VerticalTimingRegister.ACV;
|
||||
|
||||
// TODO: Are the "Bottom Field" and "Top Field" registers actually more
|
||||
// like "First Field" and "Second Field" registers? There's an important
|
||||
// difference because NTSC and PAL have opposite field orders.
|
||||
|
||||
u32 xfbAddr = (field == FIELD_LOWER) ? GetXFBAddressBottom() : GetXFBAddressTop();
|
||||
// NTSC and PAL have opposite field orders.
|
||||
FieldType order = (m_DisplayControlRegister.FMT == 0) ? FIELD_LOWER : FIELD_UPPER;
|
||||
u32 xfbAddr = (field == order) ? GetXFBAddressBottom() : GetXFBAddressTop();
|
||||
|
||||
static const char* const fieldTypeNames[] = { "Progressive", "Upper", "Lower" };
|
||||
|
||||
|
|
|
@ -211,9 +211,9 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
default:
|
||||
_dbg_assert_msg_(WII_IPC, 0, "w32 %08x @ %08x", _Value, _Address);
|
||||
break;
|
||||
}
|
||||
|
||||
//WII_IPC_HLE_Interface::Update();
|
||||
}
|
||||
|
||||
WII_IPC_HLE_Interface::Update();
|
||||
CoreTiming::ScheduleEvent_Threadsafe(0, updateInterrupts, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -32,31 +32,42 @@ void Shutdown()
|
|||
delete *i;
|
||||
g_plugin.controllers.clear();
|
||||
|
||||
// WiimoteReal is shutdown on app exit
|
||||
//WiimoteReal::Shutdown();
|
||||
WiimoteReal::Shutdown();
|
||||
|
||||
g_controller_interface.Shutdown();
|
||||
}
|
||||
|
||||
// if plugin isn't initialized, init and load config
|
||||
void Initialize(void* const hwnd)
|
||||
void Initialize(void* const hwnd, bool wait)
|
||||
{
|
||||
// add 4 wiimotes
|
||||
for (unsigned int i = 0; i<4; ++i)
|
||||
for (unsigned int i = WIIMOTE_CHAN_0; i<MAX_BBMOTES; ++i)
|
||||
g_plugin.controllers.push_back(new WiimoteEmu::Wiimote(i));
|
||||
|
||||
|
||||
|
||||
g_controller_interface.SetHwnd(hwnd);
|
||||
g_controller_interface.Initialize();
|
||||
|
||||
g_plugin.LoadConfig(false);
|
||||
|
||||
WiimoteReal::Initialize();
|
||||
WiimoteReal::Initialize(wait);
|
||||
|
||||
// reload Wiimotes with our settings
|
||||
if (Movie::IsPlayingInput() || Movie::IsRecordingInput())
|
||||
Movie::ChangeWiiPads();
|
||||
}
|
||||
|
||||
void Resume()
|
||||
{
|
||||
WiimoteReal::Resume();
|
||||
}
|
||||
|
||||
void Pause()
|
||||
{
|
||||
WiimoteReal::Pause();
|
||||
}
|
||||
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
// Function: ControlChannel
|
||||
// Purpose: An L2CAP packet is passed from the Core to the Wiimote,
|
||||
|
@ -71,11 +82,8 @@ void Initialize(void* const hwnd)
|
|||
//
|
||||
void ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
||||
{
|
||||
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
|
||||
if (WIIMOTE_SRC_HYBRID & g_wiimote_sources[_number])
|
||||
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->ControlChannel(_channelID, _pData, _Size);
|
||||
|
||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[_number])
|
||||
WiimoteReal::ControlChannel(_number, _channelID, _pData, _Size);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
|
@ -92,10 +100,8 @@ void ControlChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
|||
//
|
||||
void InterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
||||
{
|
||||
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
|
||||
if (WIIMOTE_SRC_HYBRID & g_wiimote_sources[_number])
|
||||
((WiimoteEmu::Wiimote*)g_plugin.controllers[_number])->InterruptChannel(_channelID, _pData, _Size);
|
||||
else
|
||||
WiimoteReal::InterruptChannel(_number, _channelID, _pData, _Size);
|
||||
}
|
||||
|
||||
// __________________________________________________________________________________________________
|
||||
|
@ -134,7 +140,7 @@ void Update(int _number)
|
|||
unsigned int GetAttached()
|
||||
{
|
||||
unsigned int attached = 0;
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
for (unsigned int i=0; i<MAX_BBMOTES; ++i)
|
||||
if (g_wiimote_sources[i])
|
||||
attached |= (1 << i);
|
||||
return attached;
|
||||
|
@ -151,7 +157,7 @@ void DoState(u8 **ptr, PointerWrap::Mode mode)
|
|||
// TODO:
|
||||
|
||||
PointerWrap p(ptr, mode);
|
||||
for (unsigned int i=0; i<4; ++i)
|
||||
for (unsigned int i=0; i<MAX_BBMOTES; ++i)
|
||||
((WiimoteEmu::Wiimote*)g_plugin.controllers[i])->DoState(p);
|
||||
}
|
||||
|
||||
|
|
|
@ -8,7 +8,16 @@
|
|||
#include "../../InputCommon/Src/InputConfig.h"
|
||||
#include "ChunkFile.h"
|
||||
|
||||
#define MAX_WIIMOTES 4
|
||||
enum {
|
||||
WIIMOTE_CHAN_0 = 0,
|
||||
WIIMOTE_CHAN_1,
|
||||
WIIMOTE_CHAN_2,
|
||||
WIIMOTE_CHAN_3,
|
||||
WIIMOTE_BALANCE_BOARD,
|
||||
MAX_WIIMOTES = WIIMOTE_BALANCE_BOARD,
|
||||
MAX_BBMOTES = 5,
|
||||
};
|
||||
|
||||
|
||||
#define WIIMOTE_INI_NAME "WiimoteNew"
|
||||
|
||||
|
@ -20,13 +29,15 @@ enum
|
|||
WIIMOTE_SRC_HYBRID = 3, // emu + real
|
||||
};
|
||||
|
||||
extern unsigned int g_wiimote_sources[MAX_WIIMOTES];
|
||||
extern unsigned int g_wiimote_sources[MAX_BBMOTES];
|
||||
|
||||
namespace Wiimote
|
||||
{
|
||||
|
||||
void Shutdown();
|
||||
void Initialize(void* const hwnd);
|
||||
void Initialize(void* const hwnd, bool wait = false);
|
||||
void Resume();
|
||||
void Pause();
|
||||
|
||||
unsigned int GetAttached();
|
||||
void DoState(u8 **ptr, PointerWrap::Mode mode);
|
||||
|
@ -42,8 +53,10 @@ void Update(int _number);
|
|||
namespace WiimoteReal
|
||||
{
|
||||
|
||||
void Initialize();
|
||||
void Initialize(bool wait = false);
|
||||
void Shutdown();
|
||||
void Resume();
|
||||
void Pause();
|
||||
void Refresh();
|
||||
|
||||
void LoadSettings();
|
||||
|
|
|
@ -72,6 +72,7 @@ void Nunchuk::GetState(u8* const data, const bool focus)
|
|||
m_stick->GetState(&ncdata->jx, &ncdata->jy, 0x80, focus ? 127 : 0);
|
||||
|
||||
AccelData accel;
|
||||
accel_cal* calib = (accel_cal*)®[0x20];
|
||||
|
||||
// tilt
|
||||
EmulateTilt(&accel, m_tilt, focus);
|
||||
|
@ -81,7 +82,7 @@ void Nunchuk::GetState(u8* const data, const bool focus)
|
|||
// swing
|
||||
EmulateSwing(&accel, m_swing);
|
||||
// shake
|
||||
EmulateShake(&accel, m_shake, m_shake_step);
|
||||
EmulateShake(&accel, calib, m_shake, m_shake_step);
|
||||
// buttons
|
||||
m_buttons->GetState(&ncdata->bt, nunchuk_button_bitmasks);
|
||||
}
|
||||
|
@ -119,7 +120,6 @@ void Nunchuk::GetState(u8* const data, const bool focus)
|
|||
}
|
||||
|
||||
wm_accel* dt = (wm_accel*)&ncdata->ax;
|
||||
accel_cal* calib = (accel_cal*)®[0x20];
|
||||
dt->x = u8(trim(accel.x * (calib->one_g.x - calib->zero_g.x) + calib->zero_g.x));
|
||||
dt->y = u8(trim(accel.y * (calib->one_g.y - calib->zero_g.y) + calib->zero_g.y));
|
||||
dt->z = u8(trim(accel.z * (calib->one_g.z - calib->zero_g.z) + calib->zero_g.z));
|
||||
|
|
|
@ -29,15 +29,662 @@
|
|||
|
||||
#include "Attachment/Attachment.h"
|
||||
|
||||
/* Bit shift conversions */
|
||||
static u32 swap24(const u8* src)
|
||||
{
|
||||
return (src[0] << 16) | (src[1] << 8) | src[2];
|
||||
}
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
||||
void Spy(Wiimote* wm_, const void* data_, int size_)
|
||||
{
|
||||
#if 0
|
||||
// enable log
|
||||
bool logCom = true;
|
||||
bool logData = true;
|
||||
bool logMP = false;
|
||||
bool logAudio = false;
|
||||
|
||||
std::string Name, TmpData;
|
||||
static int c;
|
||||
int size;
|
||||
u16 SampleValue;
|
||||
bool AudioData = false;
|
||||
bool DataReport = false;
|
||||
static std::queue<u32> dataRep;
|
||||
static u8 dataReply[3] = {0};
|
||||
bool emu = wm_;
|
||||
static Wiimote* wm = 0;
|
||||
|
||||
// a container for f.e. the extension encryption key
|
||||
if (!wm_ && !wm)
|
||||
wm = new Wiimote(0);
|
||||
else
|
||||
wm = wm_;
|
||||
|
||||
// ignore emulated Wiimote data
|
||||
if (emu) return;
|
||||
|
||||
const hid_packet* const hidp = (hid_packet*)data_;
|
||||
const wm_report* const sr = (wm_report*)hidp->data;
|
||||
|
||||
// use a non-pointer array because that makes read syntax shorter
|
||||
u8 data[32] = {};
|
||||
memcpy(data, data_, size_);
|
||||
|
||||
switch(data[1])
|
||||
{
|
||||
case WM_RUMBLE:
|
||||
size = 1;
|
||||
if (logCom) Name.append("WM_RUMBLE");
|
||||
break;
|
||||
|
||||
case WM_LEDS:
|
||||
size = sizeof(wm_leds);
|
||||
if (logCom) Name.append("WM_LEDS");
|
||||
break;
|
||||
|
||||
case WM_REPORT_MODE:
|
||||
size = sizeof(wm_report_mode);
|
||||
if (logCom) Name.append("WM_REPORT_MODE");
|
||||
ERROR_LOG(CONSOLE, "WM_REPORT_MODE: 0x%02x", data[3]);
|
||||
break;
|
||||
|
||||
case WM_IR_PIXEL_CLOCK:
|
||||
if (logCom) Name.append("WM_IR_PIXEL_CLOCK");
|
||||
break;
|
||||
|
||||
case WM_SPEAKER_ENABLE:
|
||||
if (logCom) Name.append("WM_SPEAKER_ENABLE");
|
||||
NOTICE_LOG(CONSOLE, "Speaker on: %d", sr->enable);
|
||||
break;
|
||||
|
||||
case WM_REQUEST_STATUS:
|
||||
size = sizeof(wm_request_status);
|
||||
if (logCom) Name.append("WM_REQUEST_STATUS");
|
||||
NOTICE_LOG(CONSOLE, "WM_REQUEST_STATUS: %s", ArrayToString(data, size+2, 0).c_str());
|
||||
break;
|
||||
|
||||
case WM_WRITE_DATA:
|
||||
{
|
||||
if (logCom) Name.append("W 0x16");
|
||||
size = sizeof(wm_write_data);
|
||||
|
||||
wm_write_data* wd = (wm_write_data*)sr->data;
|
||||
u32 address = Common::swap24(wd->address);
|
||||
address &= ~0x010000;
|
||||
|
||||
switch(data[2] >> 0x01)
|
||||
{
|
||||
case WM_SPACE_EEPROM:
|
||||
if (logCom) Name.append(" REG_EEPROM"); break;
|
||||
case WM_SPACE_REGS1:
|
||||
case WM_SPACE_REGS2: {
|
||||
|
||||
const u8 region_offset = (u8)address;
|
||||
void *region_ptr = NULL;
|
||||
int region_size = 0;
|
||||
|
||||
switch(data[3])
|
||||
{
|
||||
case 0xa2:
|
||||
if (logCom)
|
||||
{
|
||||
Name.append(" REG_SPEAKER");
|
||||
if(data[6] == 7)
|
||||
{
|
||||
//INFO_LOG(CONSOLE, "Sound configuration:");
|
||||
if(data[8] == 0x00)
|
||||
{
|
||||
//memcpy(&SampleValue, &data[9], 2);
|
||||
//NOTICE_LOG(CONSOLE, " Data format: 4-bit ADPCM (%i Hz)", 6000000 / SampleValue);
|
||||
//NOTICE_LOG(CONSOLE, " Volume: %02i%%", (data[11] / 0x40) * 100);
|
||||
}
|
||||
else if (data[8] == 0x40)
|
||||
{
|
||||
//memcpy(&SampleValue, &data[9], 2);
|
||||
//NOTICE_LOG(CONSOLE, " Data format: 8-bit PCM (%i Hz)", 12000000 / SampleValue);
|
||||
//NOTICE_LOG(CONSOLE, " Volume: %02i%%", (data[11] / 0xff) * 100);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 0xa4:
|
||||
if (logCom) Name.append(" REG_EXT");
|
||||
// Update the encryption mode
|
||||
if (data[5] == 0xf0) {
|
||||
if (!emu)
|
||||
wm->m_reg_ext.encryption = wd->data[0];
|
||||
//NOTICE_LOG(CONSOLE, "Extension encryption: %u", wm->m_reg_ext.encryption);
|
||||
}
|
||||
region_ptr = &wm->m_reg_ext;
|
||||
break;
|
||||
case 0xa6 :
|
||||
if (logCom) Name.append(" REG_M+");
|
||||
// update the encryption mode
|
||||
if (data[5] == 0xf0) {
|
||||
if (!emu)
|
||||
wm->m_reg_motion_plus.activated = wd->data[0];
|
||||
//NOTICE_LOG(CONSOLE, "Extension enryption: %u", wm->m_reg_ext.encryption);
|
||||
}
|
||||
region_ptr = &wm->m_reg_motion_plus;
|
||||
break;
|
||||
case 0xb0:
|
||||
if (logCom) Name.append(" REG_IR"); break;
|
||||
}
|
||||
|
||||
// save register
|
||||
if (!emu && region_ptr)
|
||||
memcpy((u8*)region_ptr + region_offset, wd->data, wd->size);
|
||||
// save key
|
||||
if (region_offset >= 0x40 && region_offset <= 0x4c) {
|
||||
if(!emu)
|
||||
wiimote_gen_key(&wm->m_ext_key, wm->m_reg_ext.encryption_key);
|
||||
INFO_LOG(CONSOLE, "Writing key: %s", ArrayToString((u8*)&wm->m_ext_key, sizeof(wm->m_ext_key), 0, 30).c_str());
|
||||
}
|
||||
if (data[3] == 0xa4 || data[3] == 0xa6) {
|
||||
//DEBUG_LOG(CONSOLE, "M+: %s", ArrayToString((u8*)&wm->m_reg_motion_plus, sizeof(wm->m_reg_motion_plus), 0, 30).c_str());
|
||||
//DEBUG_LOG(CONSOLE, "M+: %s", ArrayToString((u8*)&wm->m_reg_motion_plus.ext_identifier, sizeof(wm->m_reg_motion_plus.ext_identifier), 0, 30).c_str());
|
||||
NOTICE_LOG(CONSOLE, "W[0x%02x 0x%02x|%d]: %s", data[3], region_offset, wd->size, ArrayToString(wd->data, wd->size, 0).c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_READ_DATA:
|
||||
{
|
||||
if (logCom) Name.append("R");
|
||||
size = sizeof(wm_read_data);
|
||||
|
||||
wm_read_data* rd = (wm_read_data*)sr->data;
|
||||
u32 address = Common::swap24(rd->address);
|
||||
u8 addressLO = address & 0xFFFF;
|
||||
address &= 0xFEFFFF;
|
||||
u16 size = Common::swap16(rd->size);
|
||||
u8 *const block = new u8[size];
|
||||
void *region_ptr = NULL;
|
||||
|
||||
dataRep.push(((data[2]>>1)<<16) + ((data[3])<<8) + addressLO);
|
||||
|
||||
switch(data[2]>>1)
|
||||
{
|
||||
case WM_SPACE_EEPROM:
|
||||
if (logCom) Name.append(" REG_EEPROM");
|
||||
if (!emu)
|
||||
memcpy(block, wm->m_eeprom + address, size);
|
||||
break;
|
||||
case WM_SPACE_REGS1:
|
||||
case WM_SPACE_REGS2:
|
||||
// ignore second byte for extension area
|
||||
if (address>>16 == 0xA4) address &= 0xFF00FF;
|
||||
const u8 region_offset = (u8)address;
|
||||
switch(data[3])
|
||||
{
|
||||
case 0xa2:
|
||||
if (logCom) Name.append(" REG_SPEAKER");
|
||||
region_ptr = &wm->m_reg_speaker;
|
||||
break;
|
||||
case 0xa4:
|
||||
if (logCom) Name.append(" REG_EXT");
|
||||
region_ptr = &wm->m_reg_motion_plus;
|
||||
break;
|
||||
case 0xa6:
|
||||
if (logCom) Name.append(" REG_M+");
|
||||
region_ptr = &wm->m_reg_motion_plus;
|
||||
break;
|
||||
case 0xb0:
|
||||
if (logCom) Name.append(" REG_IR");
|
||||
region_ptr = &wm->m_reg_ir;
|
||||
break;
|
||||
}
|
||||
//if (!emu && region_ptr)
|
||||
//memcpy(block, (u8*)region_ptr + region_offset, size);
|
||||
//WARN_LOG(CONSOLE, "READING[0x%02x 0x%02x|%d]: %s", data[3], region_offset, size, ArrayToString(block, size, 0, 30).c_str());
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_WRITE_SPEAKER_DATA:
|
||||
if (logCom) Name.append("WM_SPEAKER_DATA");
|
||||
size = 21;
|
||||
break;
|
||||
|
||||
case WM_SPEAKER_MUTE:
|
||||
if (logCom) Name.append("WM_SPEAKER");
|
||||
size = 1;
|
||||
NOTICE_LOG(CONSOLE, "Speaker mute: %d", sr->enable);
|
||||
break;
|
||||
|
||||
case WM_IR_LOGIC:
|
||||
if (logCom) Name.append("WM_IR");
|
||||
size = 1;
|
||||
break;
|
||||
|
||||
case WM_STATUS_REPORT:
|
||||
size = sizeof(wm_status_report);
|
||||
Name = "WM_STATUS_REPORT";
|
||||
//INFO_LOG(CONSOLE, "WM_STATUS_REPORT: %s", ArrayToString(data, size+2, 0).c_str());
|
||||
{
|
||||
wm_status_report* pStatus = (wm_status_report*)(data + 2);
|
||||
ERROR_LOG(CONSOLE, ""
|
||||
"Statusreport extension: %i",
|
||||
//"Speaker enabled: %i"
|
||||
//"IR camera enabled: %i"
|
||||
//"LED 1: %i\n"
|
||||
//"LED 2: %i\n"
|
||||
//"LED 3: %i\n"
|
||||
//"LED 4: %i\n"
|
||||
//"Battery low: %i\n"
|
||||
//"Battery level: %i",
|
||||
pStatus->extension
|
||||
//pStatus->speaker,
|
||||
//pStatus->ir,
|
||||
//(pStatus->leds >> 0),
|
||||
//(pStatus->leds >> 1),
|
||||
//(pStatus->leds >> 2),
|
||||
//(pStatus->leds >> 3),
|
||||
//pStatus->battery_low,
|
||||
//pStatus->battery
|
||||
);
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_READ_DATA_REPLY:
|
||||
{
|
||||
size = sizeof(wm_read_data_reply);
|
||||
Name = "R_REPLY";
|
||||
|
||||
u8 data2[32];
|
||||
memset(data2, 0, sizeof(data2));
|
||||
memcpy(data2, data, size_);
|
||||
wm_read_data_reply* const rdr = (wm_read_data_reply*)(data2 + 2);
|
||||
|
||||
bool decrypted = false;
|
||||
if(!dataRep.empty())
|
||||
{
|
||||
dataReply[0] = (dataRep.front()>>16)&0x00FF;
|
||||
dataReply[1] = (dataRep.front()>>8)&0x00FF;
|
||||
dataReply[2] = dataRep.front()&0x00FF;
|
||||
dataRep.pop();
|
||||
}
|
||||
|
||||
switch(dataReply[0])
|
||||
{
|
||||
case WM_SPACE_EEPROM:
|
||||
if (logCom)
|
||||
Name.append(" REG_EEPROM");
|
||||
// Wiimote calibration
|
||||
if(data[4] == 0xf0 && data[5] == 0x00 && data[6] == 0x10) {
|
||||
if(data[6] == 0x10) {
|
||||
accel_cal* calib = (accel_cal*)&rdr->data[6];
|
||||
ERROR_LOG(CONSOLE, "Wiimote calibration:");
|
||||
//SERROR_LOG(CONSOLE, "%s", ArrayToString(rdr->data, rdr->size).c_str());
|
||||
ERROR_LOG(CONSOLE, "Cal_zero.x: %i", calib->zero_g.x);
|
||||
ERROR_LOG(CONSOLE, "Cal_zero.y: %i", calib->zero_g.y);
|
||||
ERROR_LOG(CONSOLE, "Cal_zero.z: %i", calib->zero_g.z);
|
||||
ERROR_LOG(CONSOLE, "Cal_g.x: %i", calib->one_g.x);
|
||||
ERROR_LOG(CONSOLE, "Cal_g.y: %i", calib->one_g.y);
|
||||
ERROR_LOG(CONSOLE, "Cal_g.z: %i", calib->one_g.z);
|
||||
// save
|
||||
if (!emu)
|
||||
memcpy(wm->m_eeprom + 0x16, rdr->data + 6, rdr->size);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case WM_SPACE_REGS1:
|
||||
case WM_SPACE_REGS2:
|
||||
switch(dataReply[1])
|
||||
{
|
||||
case 0xa2: if (logCom) Name.append(" REG_SPEAKER"); break;
|
||||
case 0xa4: if (logCom) Name.append(" REG_EXT"); break;
|
||||
case 0xa6: if (logCom) Name.append(" REG_M+"); break;
|
||||
case 0xb0: if (logCom) Name.append(" REG_IR"); break;
|
||||
}
|
||||
}
|
||||
|
||||
// save key
|
||||
if (!emu && rdr->address>>8 == 0x40)
|
||||
{
|
||||
memcpy(((u8*)&wm->m_reg_ext.encryption_key), rdr->data, rdr->size+1);
|
||||
wiimote_gen_key(&wm->m_ext_key, wm->m_reg_ext.encryption_key);
|
||||
NOTICE_LOG(CONSOLE, "Reading key: %s", ArrayToString(((u8*)&wm->m_ext_key), sizeof(wm->m_ext_key), 0, 30).c_str());
|
||||
}
|
||||
|
||||
// select decryption
|
||||
//if(((!wm->GetMotionPlusActive() && ((u8*)&wm->m_reg_ext)[0xf0] == 0xaa) || (wm->GetMotionPlusActive() && ((u8*)&wm->m_reg_motion_plus)[0xf0] == 0xaa)) && rdr->address>>8 < 0xf0) {
|
||||
|
||||
//if(((((u8*)&wm->m_reg_ext)[0xf0] == 0xaa) || ((u8*)&wm->m_reg_motion_plus)[0xf0] == 0xaa) && rdr->address>>8 < 0xf0) {
|
||||
|
||||
//if(!wm->GetMotionPlusActive() && ((u8*)&wm->m_reg_ext)[0xf0] == 0xaa && rdr->address>>8 < 0xf0) {
|
||||
|
||||
//if(!wm->GetMotionPlusActive() && ((u8*)&wm->m_reg_ext)[0xf0] == 0xaa) {
|
||||
|
||||
// SWARN_LOG(CONSOLE, "key %s", ArrayToString(((u8*)&wm->m_ext_key), sizeof(wm->m_ext_key), 0, 30).c_str());
|
||||
// SWARN_LOG(CONSOLE, "decrypt %s", ArrayToString(rdr->data, rdr->size+1, 0, 30).c_str());
|
||||
// wiimote_decrypt(&wm->m_ext_key, rdr->data, dataReply[2]&0xffff, rdr->size+1);
|
||||
// SWARN_LOG(CONSOLE, "decrypt %s", ArrayToString(rdr->data, rdr->size+1, 0, 30).c_str());
|
||||
// decrypted = true;
|
||||
//}
|
||||
|
||||
// save data
|
||||
if (!emu && !rdr->error)
|
||||
{
|
||||
//if (dataReply[1] == 0xa4 && wm->GetMotionPlusActive())
|
||||
//memcpy(&((u8*)&wm->m_reg_motion_plus)[rdr->address>>8], rdr->data, rdr->size+1);
|
||||
//if (dataReply[1] == 0xa4 && !wm->GetMotionPlusActive())
|
||||
//if (dataReply[1] == 0xa4)
|
||||
// memcpy(&((u8*)&wm->m_reg_ext)[rdr->address>>8], rdr->data, rdr->size+1);
|
||||
//if (!wm->GetMotionPlusActive() && wm->GetMotionPlusAttached())
|
||||
//if (dataReply[1] == 0xa6)
|
||||
// memcpy(&((u8*)&wm->m_reg_motion_plus)[rdr->address>>8], rdr->data, rdr->size+1);
|
||||
//INFO_LOG(CONSOLE, "Saving[0x%2x:0x%2x]: %s", dataReply[1], rdr->address>>8, ArrayToString(rdr->data, rdr->size+1).c_str());
|
||||
}
|
||||
|
||||
if (!rdr->error && rdr->address>>8 >= 0xf0 && rdr->address>>8 <= 0xff)
|
||||
{
|
||||
//INFO_LOG(CONSOLE, "Extension ID: %s", ArrayToString(rdr->data, rdr->size+1).c_str());
|
||||
}
|
||||
|
||||
// Nunchuck calibration
|
||||
if(data[4] == 0xf0 && data[5] == 0x00 && (data[6] == 0x20 || data[6] == 0x30))
|
||||
{
|
||||
// log
|
||||
//TmpData = StringFromFormat("Read[%s] (enc): %s", (Emu ? "Emu" : "Real"), ArrayToString(data, size + 2).c_str());
|
||||
|
||||
// decrypt
|
||||
//if(((u8*)&wm->m_reg_ext)[0xf0] == 0xaa) {
|
||||
// wiimote_decrypt(&wm->m_ext_key, &data[0x07], 0x00, (data[4] >> 0x04) + 1);
|
||||
|
||||
//if (wm->m_extension->name == "NUNCHUCK") {
|
||||
// INFO_LOG(CONSOLE, "\nGame got the Nunchuck calibration:\n");
|
||||
// INFO_LOG(CONSOLE, "Cal_zero.x: %i\n", data[7 + 0]);
|
||||
// INFO_LOG(CONSOLE, "Cal_zero.y: %i\n", data[7 + 1]);
|
||||
// INFO_LOG(CONSOLE, "Cal_zero.z: %i\n", data[7 + 2]);
|
||||
// INFO_LOG(CONSOLE, "Cal_g.x: %i\n", data[7 + 4]);
|
||||
// INFO_LOG(CONSOLE, "Cal_g.y: %i\n", data[7 + 5]);
|
||||
// INFO_LOG(CONSOLE, "Cal_g.z: %i\n", data[7 + 6]);
|
||||
// INFO_LOG(CONSOLE, "Js.Max.x: %i\n", data[7 + 8]);
|
||||
// INFO_LOG(CONSOLE, "Js.Min.x: %i\n", data[7 + 9]);
|
||||
// INFO_LOG(CONSOLE, "Js.Center.x: %i\n", data[7 + 10]);
|
||||
// INFO_LOG(CONSOLE, "Js.Max.y: %i\n", data[7 + 11]);
|
||||
// INFO_LOG(CONSOLE, "Js.Min.y: %i\n", data[7 + 12]);
|
||||
// INFO_LOG(CONSOLE, "JS.Center.y: %i\n\n", data[7 + 13]);
|
||||
//}
|
||||
//else // g_Config.bClassicControllerConnected {
|
||||
// INFO_LOG(CONSOLE, "\nGame got the Classic Controller calibration:\n");
|
||||
// INFO_LOG(CONSOLE, "Lx.Max: %i\n", data[7 + 0]);
|
||||
// INFO_LOG(CONSOLE, "Lx.Min: %i\n", data[7 + 1]);
|
||||
// INFO_LOG(CONSOLE, "Lx.Center: %i\n", data[7 + 2]);
|
||||
// INFO_LOG(CONSOLE, "Ly.Max: %i\n", data[7 + 3]);
|
||||
// INFO_LOG(CONSOLE, "Ly.Min: %i\n", data[7 + 4]);
|
||||
// INFO_LOG(CONSOLE, "Ly.Center: %i\n", data[7 + 5]);
|
||||
// INFO_LOG(CONSOLE, "Rx.Max.x: %i\n", data[7 + 6]);
|
||||
// INFO_LOG(CONSOLE, "Rx.Min.x: %i\n", data[7 + 7]);
|
||||
// INFO_LOG(CONSOLE, "Rx.Center.x: %i\n", data[7 + 8]);
|
||||
// INFO_LOG(CONSOLE, "Ry.Max.y: %i\n", data[7 + 9]);
|
||||
// INFO_LOG(CONSOLE, "Ry.Min: %i\n", data[7 + 10]);
|
||||
// INFO_LOG(CONSOLE, "Ry.Center: %i\n\n", data[7 + 11]);
|
||||
// INFO_LOG(CONSOLE, "Lt.Neutral: %i\n", data[7 + 12]);
|
||||
// INFO_LOG(CONSOLE, "Rt.Neutral %i\n\n", data[7 + 13]);
|
||||
//}
|
||||
|
||||
// save values
|
||||
if (!emu)
|
||||
{
|
||||
// Save to registry
|
||||
if(data[7 + 0] != 0xff)
|
||||
{
|
||||
//memcpy((u8*)&wm->m_reg_ext.calibration, &data[7], 0x10);
|
||||
//memcpy((u8*)&wm->m_reg_ext.unknown3, &data[7], 0x10);
|
||||
}
|
||||
// Save the default values that should work with Wireless Nunchucks
|
||||
else
|
||||
{
|
||||
//WiimoteEmu::SetDefaultExtensionRegistry();
|
||||
}
|
||||
//WiimoteEmu::UpdateEeprom();
|
||||
}
|
||||
// third party Nunchuck
|
||||
else if(data[7] == 0xff)
|
||||
{
|
||||
//memcpy(wm->m_reg_ext + 0x20, WiimoteEmu::wireless_nunchuck_calibration, sizeof(WiimoteEmu::wireless_nunchuck_calibration));
|
||||
//memcpy(wm->m_reg_ext + 0x30, WiimoteEmu::wireless_nunchuck_calibration, sizeof(WiimoteEmu::wireless_nunchuck_calibration));
|
||||
}
|
||||
|
||||
// print encrypted data
|
||||
//INFO_LOG(CONSOLE, "WM_READ_DATA_REPLY: Extension calibration: %s", TmpData.c_str());
|
||||
}
|
||||
|
||||
if (dataReply[1] == 0xa4 || dataReply[1] == 0xa6)
|
||||
{
|
||||
if(rdr->error == 7 || rdr->error == 8)
|
||||
{
|
||||
WARN_LOG(CONSOLE, "R%s[0x%02x 0x%02x]: e-%d", decrypted?"*":"", dataReply[1], rdr->address>>8, rdr->error);
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG(CONSOLE, "R%s[0x%02x 0x%02x|%d]: %s", decrypted?"*":"", dataReply[1], rdr->address>>8, rdr->size+1, ArrayToString(rdr->data, rdr->size+1, 0).c_str());
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_ACK_DATA:
|
||||
size = sizeof(wm_acknowledge);
|
||||
Name = "WM_ACK_DATA";
|
||||
//INFO_LOG(CONSOLE, "ACK 0x%02x", data[4]);
|
||||
break;
|
||||
|
||||
case WM_REPORT_CORE:
|
||||
size = sizeof(wm_report_core);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_ACCEL:
|
||||
size = sizeof(wm_report_core_accel);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_EXT8:
|
||||
size = sizeof(wm_report_core_accel_ir12);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_ACCEL_IR12:
|
||||
size = sizeof(wm_report_core_accel_ir12);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_EXT19:
|
||||
size = sizeof(wm_report_core_accel_ext16);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_ACCEL_EXT16:
|
||||
size = sizeof(wm_report_core_accel_ext16);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_IR10_EXT9:
|
||||
size = sizeof(wm_report_core_accel_ir10_ext6);
|
||||
DataReport = true;
|
||||
break;
|
||||
case WM_REPORT_CORE_ACCEL_IR10_EXT6:
|
||||
size = sizeof(wm_report_core_accel_ir10_ext6);
|
||||
DataReport = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
size = 15;
|
||||
NOTICE_LOG(CONSOLE, "Debugging[%s]: Unknown channel 0x%02x", (emu ? "E" : "R"), data[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
//if (DataReport && wm->GetMotionPlusActive())
|
||||
//{
|
||||
// if (data[1] == WM_REPORT_CORE_ACCEL_IR10_EXT6)
|
||||
// static bool extension = false;
|
||||
// if (extension != (bool)(data[17+4]&1))
|
||||
// ERROR_LOG(CONSOLE, "Datareport extension %d", data[17+4]&1);
|
||||
// extension = data[17+4]&1;
|
||||
//}
|
||||
|
||||
if (!DataReport && logCom && size <= 30)
|
||||
{
|
||||
ERROR_LOG_S(CONSOLE, "Com[%s] %s: %s", (emu ? "E" : "R"), Name.c_str(), ArrayToString(data, size + 2, 0).c_str());
|
||||
}
|
||||
|
||||
if (logAudio && AudioData)
|
||||
{
|
||||
//DEBUG_LOG(CONSOLE, "%s: %s\n", Name.c_str(), ArrayToString(data, std::min(10,size), 0, 30).c_str());
|
||||
}
|
||||
|
||||
if (DataReport && (logData || logMP))
|
||||
{
|
||||
// decrypt extension data
|
||||
//if (data[1] == 0x37 && !wm->GetMotionPlusActive())
|
||||
//if (data[1] == 0x37)
|
||||
// wiimote_decrypt(&wm->m_ext_key, &data[17], 0x00, 0x06);
|
||||
//if (data[1] == 0x35)
|
||||
// wiimote_decrypt(&wm->m_ext_key, &data[7], 0x00, 0x06);
|
||||
|
||||
//if (data[1] == 0x35 || data[1] == 0x37)
|
||||
//{
|
||||
// if (!g_DebugMP && mp->is_mp_data) return;
|
||||
// if (!g_DebugData && !mp->is_mp_data) return;
|
||||
//}
|
||||
|
||||
std::string SCore = "", SAcc = "", SIR = "", SExt = "", SExtID = "";
|
||||
|
||||
wm_core* core = (wm_core*)sr->data;
|
||||
accel_cal* calib = (accel_cal*)&wm->m_eeprom[0x16];
|
||||
wm_accel* accel = (wm_accel*)&data[4];
|
||||
|
||||
//SCore = StringFromFormat(
|
||||
// "%d %d %d %d ",
|
||||
// core->xL,
|
||||
// core->yL,
|
||||
// core->zL,
|
||||
// core->unknown);
|
||||
|
||||
SAcc = StringFromFormat(
|
||||
//"%3d %3d %3d"
|
||||
//" | %3d %3d %3d"
|
||||
//" | %3d %3d %3d"
|
||||
"| %5.2f %5.2f %5.2f"
|
||||
//, calib->zero_g.x, calib->zero_g.y, calib->zero_g.z
|
||||
//, (calib->zero_g.x<<2) + calib->zero_g.xL, (calib->zero_g.y<<2) + calib->zero_g.yL, (calib->zero_g.z<<2) + calib->zero_g.zL
|
||||
//, calib->one_g.x, calib->one_g.y, calib->one_g.z
|
||||
//, (calib->one_g.x<<2) + calib->one_g.xL, (calib->one_g.y<<2) + calib->one_g.yL, (calib->one_g.z<<2) + calib->one_g.zL
|
||||
//, accel->x, accel->y, accel->z
|
||||
//, (accel->x<<2) + core->xL, (accel->y<<2) + core->yL, (accel->z<<2) + core->zL
|
||||
, (accel->x - calib->zero_g.x) / float(calib->one_g.x-calib->zero_g.x), (accel->y - calib->zero_g.y) / float(calib->one_g.y-calib->zero_g.y), (accel->z - calib->zero_g.z) / float(calib->one_g.z-calib->zero_g.z));
|
||||
|
||||
NOTICE_LOG(CONSOLE, "%d", size);
|
||||
|
||||
if (data[1] == WM_REPORT_CORE_ACCEL_IR12)
|
||||
{
|
||||
wm_ir_extended *ir = (wm_ir_extended*)&data[7];
|
||||
|
||||
SIR = StringFromFormat(
|
||||
"%4u %4u | %u"
|
||||
, ir->x | ir->xhi << 8
|
||||
, ir->y | ir->yhi << 8
|
||||
, ir->size);
|
||||
}
|
||||
|
||||
if (data[1] == WM_REPORT_CORE_ACCEL_EXT16)
|
||||
{
|
||||
wm_extension *nc = (wm_extension*)&data[7];
|
||||
|
||||
SExt = StringFromFormat(
|
||||
"%02x %02x | %02x %02x %02x | %02x"
|
||||
, nc->jx, nc->jy
|
||||
, nc->ax, nc->ay, nc->az
|
||||
, nc->bt);
|
||||
}
|
||||
|
||||
if (data[1] == WM_REPORT_CORE_ACCEL_IR10_EXT6)
|
||||
{
|
||||
wm_ir_basic *ir = (wm_ir_basic*)&data[7];
|
||||
|
||||
SIR = StringFromFormat(
|
||||
"%4u %4u %4u %4u"
|
||||
, ir->x1 | ir->x1hi << 8
|
||||
, ir->y1 | ir->y1hi << 8
|
||||
, ir->x2 | ir->x2hi << 8
|
||||
, ir->y2 | ir->y1hi << 8);
|
||||
|
||||
/*
|
||||
wm_motionplus *mp = (wm_motionplus*)&data[17];
|
||||
wm_nc_mp *nc_mp = (wm_nc_mp *)&data[17];
|
||||
|
||||
if (mp->is_mp_data)
|
||||
{
|
||||
SExt = StringFromFormat(""
|
||||
//"%02x %02x %02x %02x %02x %02x"
|
||||
//"| %04x %04x %04x
|
||||
" %5.2f %5.2f %5.2f"
|
||||
" %s%s%s"
|
||||
//, mp->roll1, mp->roll2
|
||||
//, mp->pitch1, mp->pitch2
|
||||
//, mp->yaw1, mp->yaw2
|
||||
//, mp->pitch2<<8 | mp->pitch1
|
||||
//, mp->roll2<<8 | mp->roll1
|
||||
//, mp->yaw2<<8 | mp->yaw1
|
||||
//, mp->pitch2<<8 | mp->pitch1
|
||||
//, mp->roll2<<8 | mp->roll1
|
||||
//, mp->yaw2<<8 | mp->yaw1
|
||||
, float((mp->pitch2<<8 | mp->pitch1) - 0x1f7f) / float(0x1fff)
|
||||
, float((mp->roll2<<8 | mp->roll1) - 0x1f7f) / float(0x1fff)
|
||||
, float((mp->yaw2<<8 | mp->yaw1) - 0x1f7f) / float(0x1fff)
|
||||
, mp->pitch_slow?"*":" ", mp->roll_slow?"*":" ", mp->yaw_slow?"*":" ");
|
||||
}
|
||||
else
|
||||
{
|
||||
SExt = StringFromFormat(
|
||||
"%02x %02x | %02x %02x | %02x %02x %02x | %02x %02x %02x",
|
||||
nc_mp->bz, nc_mp->bc,
|
||||
nc_mp->jx, nc_mp->jy,
|
||||
nc_mp->ax+nc_mp->axL, nc_mp->ay+nc_mp->ayL, (nc_mp->az<<1)+nc_mp->azL);
|
||||
}
|
||||
|
||||
SExtID = StringFromFormat(
|
||||
"[%s|%d|%d]"
|
||||
, mp->is_mp_data ? "+" : "e"
|
||||
, mp->is_mp_data ? mp->extension_connected : nc_mp->extension_connected
|
||||
, wm->m_extension->active_extension);
|
||||
*/
|
||||
|
||||
//DEBUG_LOG_S(CONSOLE, "M+ %d Extension %d %d %s", mp->is_mp_data, mp->is_mp_data ?
|
||||
// mp->extension_connected : ((wm_nc_mp*)&data[17])->extension_connected, wm->m_extension->active_extension,
|
||||
// ArrayToString(((u8*)&wm->m_reg_motion_plus.ext_identifier), sizeof(wm->m_reg_motion_plus.ext_identifier), 0).c_str());
|
||||
}
|
||||
|
||||
// select log data
|
||||
WARN_LOG_S(CONSOLE, "Data"
|
||||
"[%s]"
|
||||
" | id %s"
|
||||
" | %s"
|
||||
" | c %s"
|
||||
" | a %s"
|
||||
" | ir %s"
|
||||
" | ext %s"
|
||||
//" | %s"
|
||||
//" | %s"
|
||||
//" | %s"
|
||||
, (emu ? "E" : "R")
|
||||
, SExtID.c_str()
|
||||
, ArrayToString(data, 2, 0).c_str()
|
||||
, SCore.c_str()
|
||||
, SAcc.c_str()
|
||||
, SIR.c_str()
|
||||
, SExt.c_str()
|
||||
//, ArrayToString(&data[4], 3, 0).c_str()
|
||||
//, (accel->x - 0x7f) / float(0xff), (accel->y - 0x7f) / float(0xff), (accel->z - 0x7f) / float(0xff)
|
||||
//, ArrayToString(&data[17], 6, 0).c_str(),
|
||||
);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void Wiimote::ReportMode(const wm_report_mode* const dr)
|
||||
{
|
||||
//INFO_LOG(WIIMOTE, "Set data report mode");
|
||||
|
@ -64,7 +711,7 @@ void Wiimote::ReportMode(const wm_report_mode* const dr)
|
|||
an Input Report back to the Wii. Input and Output is from the Wii's
|
||||
perspective, Output means data to the Wiimote (from the Wii), Input means
|
||||
data from the Wiimote.
|
||||
|
||||
|
||||
The call browser:
|
||||
|
||||
1. Wiimote_InterruptChannel > InterruptChannel > HidOutputReport
|
||||
|
@ -113,7 +760,8 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
|
|||
break;
|
||||
|
||||
case WM_REQUEST_STATUS : // 0x15
|
||||
RequestStatus((wm_request_status*)sr->data);
|
||||
if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index])
|
||||
RequestStatus((wm_request_status*)sr->data);
|
||||
return; // sends its own ack
|
||||
break;
|
||||
|
||||
|
@ -122,7 +770,8 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
|
|||
break;
|
||||
|
||||
case WM_READ_DATA : // 0x17
|
||||
ReadData((wm_read_data*)sr->data);
|
||||
if (WIIMOTE_SRC_EMU & g_wiimote_sources[m_index])
|
||||
ReadData((wm_read_data*)sr->data);
|
||||
return; // sends its own ack
|
||||
break;
|
||||
|
||||
|
@ -164,7 +813,7 @@ void Wiimote::HidOutputReport(const wm_report* const sr, const bool send_ack)
|
|||
}
|
||||
|
||||
// send ack
|
||||
if (send_ack)
|
||||
if (send_ack && WIIMOTE_SRC_EMU & g_wiimote_sources[m_index])
|
||||
SendAck(sr->wm);
|
||||
}
|
||||
|
||||
|
@ -231,7 +880,7 @@ void Wiimote::RequestStatus(const wm_request_status* const rs)
|
|||
*(wm_status_report*)(data + 2) = m_status;
|
||||
|
||||
// hybrid wiimote stuff
|
||||
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && (m_extension->switch_extension <= 0))
|
||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index] && (m_extension->switch_extension <= 0))
|
||||
{
|
||||
using namespace WiimoteReal;
|
||||
|
||||
|
@ -253,7 +902,7 @@ void Wiimote::RequestStatus(const wm_request_status* const rs)
|
|||
/* Write data to Wiimote and Extensions registers. */
|
||||
void Wiimote::WriteData(const wm_write_data* const wd)
|
||||
{
|
||||
u32 address = swap24(wd->address);
|
||||
u32 address = Common::swap24(wd->address);
|
||||
|
||||
// ignore the 0x010000 bit
|
||||
address &= ~0x010000;
|
||||
|
@ -290,7 +939,7 @@ void Wiimote::WriteData(const wm_write_data* const wd)
|
|||
}
|
||||
}
|
||||
break;
|
||||
|
||||
|
||||
case WM_SPACE_REGS1 :
|
||||
case WM_SPACE_REGS2 :
|
||||
{
|
||||
|
@ -354,7 +1003,7 @@ void Wiimote::WriteData(const wm_write_data* const wd)
|
|||
|
||||
if (&m_reg_ext == region_ptr)
|
||||
{
|
||||
// Run the key generation on all writes in the key area, it doesn't matter
|
||||
// Run the key generation on all writes in the key area, it doesn't matter
|
||||
// that we send it parts of a key, only the last full key will have an effect
|
||||
if (address >= 0xa40040 && address <= 0xa4004c)
|
||||
wiimote_gen_key(&m_ext_key, m_reg_ext.encryption_key);
|
||||
|
@ -381,9 +1030,9 @@ void Wiimote::WriteData(const wm_write_data* const wd)
|
|||
}
|
||||
|
||||
/* Read data from Wiimote and Extensions registers. */
|
||||
void Wiimote::ReadData(const wm_read_data* const rd)
|
||||
void Wiimote::ReadData(const wm_read_data* const rd)
|
||||
{
|
||||
u32 address = swap24(rd->address);
|
||||
u32 address = Common::swap24(rd->address);
|
||||
u16 size = Common::swap16(rd->size);
|
||||
|
||||
// ignore the 0x010000 bit
|
||||
|
@ -391,10 +1040,10 @@ void Wiimote::ReadData(const wm_read_data* const rd)
|
|||
|
||||
// hybrid wiimote stuff
|
||||
// relay the read data request to real-wiimote
|
||||
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index] && ((0xA4 != (address >> 16)) || (m_extension->switch_extension <= 0)))
|
||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index] && ((0xA4 != (address >> 16)) || (m_extension->switch_extension <= 0)))
|
||||
{
|
||||
WiimoteReal::InterruptChannel(m_index, m_reporting_channel, ((u8*)rd) - 2, sizeof(wm_read_data) + 2); // hacky
|
||||
|
||||
|
||||
// don't want emu-wiimote to send reply
|
||||
return;
|
||||
}
|
||||
|
@ -408,9 +1057,9 @@ void Wiimote::ReadData(const wm_read_data* const rd)
|
|||
{
|
||||
//PanicAlert("ReadData: reading from EEPROM: address: 0x%x size: 0x%x", address, size);
|
||||
// Read from EEPROM
|
||||
if (address + size >= WIIMOTE_EEPROM_FREE_SIZE)
|
||||
if (address + size >= WIIMOTE_EEPROM_FREE_SIZE)
|
||||
{
|
||||
if (address + size > WIIMOTE_EEPROM_SIZE)
|
||||
if (address + size > WIIMOTE_EEPROM_SIZE)
|
||||
{
|
||||
PanicAlert("ReadData: address + size out of bounds");
|
||||
delete [] block;
|
||||
|
@ -503,7 +1152,7 @@ void Wiimote::ReadData(const wm_read_data* const rd)
|
|||
}
|
||||
|
||||
// want the requested address, not the above modified one
|
||||
rr.address = swap24(rd->address);
|
||||
rr.address = Common::swap24(rd->address);
|
||||
rr.size = size;
|
||||
//rr.channel = _channelID;
|
||||
rr.position = 0;
|
||||
|
@ -643,6 +1292,21 @@ void Wiimote::DoState(PointerWrap& p)
|
|||
}
|
||||
}
|
||||
p.DoMarker("Wiimote");
|
||||
|
||||
if (p.GetMode() == PointerWrap::MODE_READ)
|
||||
RealState();
|
||||
}
|
||||
|
||||
// load real Wiimote state
|
||||
void Wiimote::RealState()
|
||||
{
|
||||
using namespace WiimoteReal;
|
||||
|
||||
if (g_wiimotes[m_index])
|
||||
{
|
||||
g_wiimotes[m_index]->SetChannel(m_reporting_channel);
|
||||
g_wiimotes[m_index]->EnableDataReporting(m_reporting_mode);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -86,6 +86,7 @@ const ReportFeatures reporting_mode_features[] =
|
|||
};
|
||||
|
||||
void EmulateShake(AccelData* const accel
|
||||
, accel_cal* const calib
|
||||
, ControllerEmu::Buttons* const buttons_group
|
||||
, u8* const shake_step )
|
||||
{
|
||||
|
@ -94,7 +95,7 @@ void EmulateShake(AccelData* const accel
|
|||
auto const shake_step_max = 15;
|
||||
|
||||
// peak G-force
|
||||
auto const shake_intensity = 3.f;
|
||||
double shake_intensity;
|
||||
|
||||
// shake is a bitfield of X,Y,Z shake button states
|
||||
static const unsigned int btns[] = { 0x01, 0x02, 0x04 };
|
||||
|
@ -105,6 +106,9 @@ void EmulateShake(AccelData* const accel
|
|||
{
|
||||
if (shake & (1 << i))
|
||||
{
|
||||
double zero = double((&(calib->zero_g.x))[i]);
|
||||
double one = double((&(calib->one_g.x))[i]);
|
||||
shake_intensity = max(zero / (one - zero), (255.f - zero) / (one - zero));
|
||||
(&(accel->x))[i] = std::sin(TAU * shake_step[i] / shake_step_max) * shake_intensity;
|
||||
shake_step[i] = (shake_step[i] + 1) % shake_step_max;
|
||||
}
|
||||
|
@ -406,6 +410,7 @@ void Wiimote::GetAccelData(u8* const data, u8* const buttons)
|
|||
const bool has_focus = HAS_FOCUS;
|
||||
const bool is_sideways = m_options->settings[1]->value != 0;
|
||||
const bool is_upright = m_options->settings[2]->value != 0;
|
||||
accel_cal* calib = (accel_cal*)&m_eeprom[0x16];
|
||||
|
||||
// ----TILT----
|
||||
EmulateTilt(&m_accel, m_tilt, has_focus, is_sideways, is_upright);
|
||||
|
@ -415,11 +420,10 @@ void Wiimote::GetAccelData(u8* const data, u8* const buttons)
|
|||
if (has_focus)
|
||||
{
|
||||
EmulateSwing(&m_accel, m_swing, is_sideways, is_upright);
|
||||
EmulateShake(&m_accel, m_shake, m_shake_step);
|
||||
EmulateShake(&m_accel, calib, m_shake, m_shake_step);
|
||||
UDPTLayer::GetAcceleration(m_udp, &m_accel);
|
||||
}
|
||||
wm_accel* dt = (wm_accel*)data;
|
||||
accel_cal* calib = (accel_cal*)&m_eeprom[0x16];
|
||||
double cx,cy,cz;
|
||||
cx=trim(m_accel.x*(calib->one_g.x-calib->zero_g.x)+calib->zero_g.x);
|
||||
cy=trim(m_accel.y*(calib->one_g.y-calib->zero_g.y)+calib->zero_g.y);
|
||||
|
@ -777,7 +781,10 @@ void Wiimote::Update()
|
|||
|
||||
// send data report
|
||||
if (rptf_size)
|
||||
{
|
||||
WiimoteEmu::Spy(this, data, rptf_size);
|
||||
Core::Callback_WiimoteInterruptChannel(m_index, m_reporting_channel, data, rptf_size);
|
||||
}
|
||||
}
|
||||
|
||||
void Wiimote::ControlChannel(const u16 _channelID, const void* _pData, u32 _Size)
|
||||
|
@ -849,13 +856,15 @@ void Wiimote::InterruptChannel(const u16 _channelID, const void* _pData, u32 _Si
|
|||
{
|
||||
const wm_report* const sr = (wm_report*)hidp->data;
|
||||
|
||||
if (WIIMOTE_SRC_HYBRID == g_wiimote_sources[m_index])
|
||||
if (WIIMOTE_SRC_REAL & g_wiimote_sources[m_index])
|
||||
{
|
||||
switch (sr->wm)
|
||||
{
|
||||
// these two types are handled in RequestStatus() & ReadData()
|
||||
case WM_REQUEST_STATUS :
|
||||
case WM_READ_DATA :
|
||||
if (WIIMOTE_SRC_REAL == g_wiimote_sources[m_index])
|
||||
WiimoteReal::InterruptChannel(m_index, _channelID, _pData, _Size);
|
||||
break;
|
||||
|
||||
default :
|
||||
|
|
|
@ -24,6 +24,11 @@
|
|||
#define WIIMOTE_REG_EXT_SIZE 0x100
|
||||
#define WIIMOTE_REG_IR_SIZE 0x34
|
||||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
class Wiimote;
|
||||
}
|
||||
|
||||
namespace WiimoteEmu
|
||||
{
|
||||
|
||||
|
@ -45,6 +50,7 @@ struct ADPCMState
|
|||
extern const ReportFeatures reporting_mode_features[];
|
||||
|
||||
void EmulateShake(AccelData* const accel_data
|
||||
, accel_cal* const calib
|
||||
, ControllerEmu::Buttons* const buttons_group
|
||||
, u8* const shake_step);
|
||||
|
||||
|
@ -65,6 +71,8 @@ inline double trim(double a)
|
|||
|
||||
class Wiimote : public ControllerEmu
|
||||
{
|
||||
friend class WiimoteReal::Wiimote;
|
||||
friend void Spy(Wiimote* wm_, const void* data_, int size_);
|
||||
public:
|
||||
|
||||
enum
|
||||
|
@ -91,6 +99,7 @@ public:
|
|||
void ControlChannel(const u16 _channelID, const void* _pData, u32 _Size);
|
||||
|
||||
void DoState(PointerWrap& p);
|
||||
void RealState();
|
||||
|
||||
void LoadDefaults(const ControllerInterface& ciface);
|
||||
|
||||
|
@ -234,6 +243,8 @@ private:
|
|||
} m_reg_speaker;
|
||||
};
|
||||
|
||||
void Spy(Wiimote* wm_, const void* data_, int size_);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,9 +32,10 @@ WiimoteScanner::~WiimoteScanner()
|
|||
void WiimoteScanner::Update()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimote* & found_board)
|
||||
{
|
||||
return std::vector<Wiimote*>();
|
||||
found_wiimotes.clear();
|
||||
found_board = NULL;
|
||||
}
|
||||
|
||||
bool WiimoteScanner::IsReady() const
|
||||
|
|
|
@ -63,23 +63,22 @@ WiimoteScanner::~WiimoteScanner()
|
|||
void WiimoteScanner::Update()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimote* & found_board)
|
||||
{
|
||||
std::vector<Wiimote*> found_wiimotes;
|
||||
|
||||
// supposedly 1.28 seconds
|
||||
int const wait_len = 1;
|
||||
|
||||
int const max_infos = 255;
|
||||
inquiry_info scan_infos[max_infos] = {};
|
||||
auto* scan_infos_ptr = scan_infos;
|
||||
|
||||
found_board = NULL;
|
||||
|
||||
// Scan for bluetooth devices
|
||||
int const found_devices = hci_inquiry(device_id, wait_len, max_infos, NULL, &scan_infos_ptr, IREQ_CACHE_FLUSH);
|
||||
if (found_devices < 0)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "Error searching for bluetooth devices.");
|
||||
return found_wiimotes;
|
||||
return;
|
||||
}
|
||||
|
||||
DEBUG_LOG(WIIMOTE, "Found %i bluetooth device(s).", found_devices);
|
||||
|
@ -91,7 +90,7 @@ std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
|||
|
||||
// BT names are a maximum of 248 bytes apparently
|
||||
char name[255] = {};
|
||||
if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 0) < 0)
|
||||
if (hci_read_remote_name(device_sock, &scan_infos[i].bdaddr, sizeof(name), name, 1000) < 0)
|
||||
{
|
||||
ERROR_LOG(WIIMOTE, "name request failed");
|
||||
continue;
|
||||
|
@ -119,14 +118,20 @@ std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
|||
|
||||
auto* const wm = new Wiimote;
|
||||
wm->bdaddr = scan_infos[i].bdaddr;
|
||||
found_wiimotes.push_back(wm);
|
||||
|
||||
NOTICE_LOG(WIIMOTE, "Found wiimote (%s).", bdaddr_str);
|
||||
if(IsBalanceBoardName(name))
|
||||
{
|
||||
found_board = wm;
|
||||
NOTICE_LOG(WIIMOTE, "Found balance board (%s).", bdaddr_str);
|
||||
}
|
||||
else
|
||||
{
|
||||
found_wiimotes.push_back(wm);
|
||||
NOTICE_LOG(WIIMOTE, "Found wiimote (%s).", bdaddr_str);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found_wiimotes;
|
||||
}
|
||||
|
||||
// Connect to a wiimote with a known address.
|
||||
|
|
|
@ -87,8 +87,8 @@ inline void init_lib()
|
|||
hid_lib = LoadLibrary(_T("hid.dll"));
|
||||
if (!hid_lib)
|
||||
{
|
||||
PanicAlertT("Failed to load hid.dll");
|
||||
exit(EXIT_FAILURE);
|
||||
PanicAlertT("Failed to load hid.dll! Connecting real Wiimotes won't work and Dolphin might crash unexpectedly!");
|
||||
return;
|
||||
}
|
||||
|
||||
HidD_GetHidGuid = (PHidD_GetHidGuid)GetProcAddress(hid_lib, "HidD_GetHidGuid");
|
||||
|
@ -98,15 +98,15 @@ inline void init_lib()
|
|||
if (!HidD_GetHidGuid || !HidD_GetAttributes ||
|
||||
!HidD_SetOutputReport || !HidD_GetProductString)
|
||||
{
|
||||
PanicAlertT("Failed to load hid.dll");
|
||||
exit(EXIT_FAILURE);
|
||||
PanicAlertT("Failed to load hid.dll! Connecting real Wiimotes won't work and Dolphin might crash unexpectedly!");
|
||||
return;
|
||||
}
|
||||
|
||||
bthprops_lib = LoadLibrary(_T("bthprops.cpl"));
|
||||
if (!bthprops_lib)
|
||||
{
|
||||
PanicAlertT("Failed to load bthprops.cpl");
|
||||
exit(EXIT_FAILURE);
|
||||
PanicAlertT("Failed to load bthprops.cpl! Connecting real Wiimotes won't work and Dolphin might crash unexpectedly!");
|
||||
return;
|
||||
}
|
||||
|
||||
Bth_BluetoothFindDeviceClose = (PBth_BluetoothFindDeviceClose)GetProcAddress(bthprops_lib, "BluetoothFindDeviceClose");
|
||||
|
@ -128,8 +128,8 @@ inline void init_lib()
|
|||
!Bth_BluetoothSetServiceState || !Bth_BluetoothAuthenticateDevice ||
|
||||
!Bth_BluetoothEnumerateInstalledServices)
|
||||
{
|
||||
PanicAlertT("Failed to load bthprops.cpl");
|
||||
exit(EXIT_FAILURE);
|
||||
PanicAlertT("Failed to load bthprops.cpl! Connecting real Wiimotes won't work and Dolphin might crash unexpectedly!");
|
||||
return;
|
||||
}
|
||||
|
||||
initialized = true;
|
||||
|
@ -138,6 +138,10 @@ inline void init_lib()
|
|||
|
||||
namespace WiimoteReal
|
||||
{
|
||||
|
||||
|
||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, int len);
|
||||
int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index);
|
||||
|
||||
template <typename T>
|
||||
void ProcessWiimotes(bool new_scan, T& callback);
|
||||
|
@ -183,7 +187,7 @@ void WiimoteScanner::Update()
|
|||
// Does not replace already found wiimotes even if they are disconnected.
|
||||
// wm is an array of max_wiimotes wiimotes
|
||||
// Returns the total number of found and connected wiimotes.
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimote* & found_board)
|
||||
{
|
||||
ProcessWiimotes(true, [](HANDLE hRadio, const BLUETOOTH_RADIO_INFO& rinfo, BLUETOOTH_DEVICE_INFO_STRUCT& btdi)
|
||||
{
|
||||
|
@ -198,8 +202,6 @@ std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
|||
// Get all hid devices connected
|
||||
HDEVINFO const device_info = SetupDiGetClassDevs(&device_id, NULL, NULL, (DIGCF_DEVICEINTERFACE | DIGCF_PRESENT));
|
||||
|
||||
std::vector<Wiimote*> wiimotes;
|
||||
|
||||
SP_DEVICE_INTERFACE_DATA device_data;
|
||||
device_data.cbSize = sizeof(device_data);
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA detail_data = NULL;
|
||||
|
@ -214,10 +216,24 @@ std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
|||
|
||||
// Query the data for this device
|
||||
if (SetupDiGetDeviceInterfaceDetail(device_info, &device_data, detail_data, len, NULL, NULL))
|
||||
{
|
||||
{
|
||||
auto const wm = new Wiimote;
|
||||
wm->devicepath = detail_data->DevicePath;
|
||||
wiimotes.push_back(wm);
|
||||
bool real_wiimote = false, is_bb = false;
|
||||
|
||||
CheckDeviceType(wm->devicepath, real_wiimote, is_bb);
|
||||
if (is_bb)
|
||||
{
|
||||
found_board = wm;
|
||||
}
|
||||
else if (real_wiimote)
|
||||
{
|
||||
found_wiimotes.push_back(wm);
|
||||
}
|
||||
else
|
||||
{
|
||||
delete wm;
|
||||
}
|
||||
}
|
||||
|
||||
free(detail_data);
|
||||
|
@ -229,7 +245,196 @@ std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
|||
//if (!wiimotes.empty())
|
||||
// SLEEP(2000);
|
||||
|
||||
return wiimotes;
|
||||
}
|
||||
int CheckDeviceType_Write(HANDLE &dev_handle, const u8* buf, int size, int attempts)
|
||||
{
|
||||
OVERLAPPED hid_overlap_write = OVERLAPPED();
|
||||
hid_overlap_write.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
enum win_bt_stack_t stack = MSBT_STACK_UNKNOWN;
|
||||
|
||||
DWORD written = 0;
|
||||
|
||||
for (; attempts>0; --attempts)
|
||||
{
|
||||
if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, size))
|
||||
{
|
||||
auto const wait_result = WaitForSingleObject(hid_overlap_write.hEvent, WIIMOTE_DEFAULT_TIMEOUT);
|
||||
if (WAIT_TIMEOUT == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "CheckDeviceType_Write: A timeout occurred on writing to Wiimote.");
|
||||
CancelIo(dev_handle);
|
||||
continue;
|
||||
}
|
||||
else if (WAIT_FAILED == wait_result)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "CheckDeviceType_Write: A wait error occurred on writing to Wiimote.");
|
||||
CancelIo(dev_handle);
|
||||
continue;
|
||||
}
|
||||
if (GetOverlappedResult(dev_handle, &hid_overlap_write, &written, TRUE))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CloseHandle(hid_overlap_write.hEvent);
|
||||
|
||||
return written;
|
||||
}
|
||||
|
||||
int CheckDeviceType_Read(HANDLE &dev_handle, u8* buf, int attempts)
|
||||
{
|
||||
OVERLAPPED hid_overlap_read = OVERLAPPED();
|
||||
hid_overlap_read.hEvent = CreateEvent(NULL, true, false, NULL);
|
||||
int read = 0;
|
||||
for (; attempts>0; --attempts)
|
||||
{
|
||||
read = _IORead(dev_handle, hid_overlap_read, buf, 1);
|
||||
if (read > 0)
|
||||
break;
|
||||
}
|
||||
|
||||
CloseHandle(hid_overlap_read.hEvent);
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
// A convoluted way of checking if a device is a Wii Balance Board and if it is a connectable Wiimote.
|
||||
// Because nothing on Windows should be easy.
|
||||
// (We can't seem to easily identify the bluetooth device an HID device belongs to...)
|
||||
void WiimoteScanner::CheckDeviceType(std::basic_string<TCHAR> &devicepath, bool &real_wiimote, bool &is_bb)
|
||||
{
|
||||
real_wiimote = false;
|
||||
is_bb = false;
|
||||
|
||||
#ifdef SHARE_WRITE_WIIMOTES
|
||||
std::lock_guard<std::mutex> lk(g_connected_wiimotes_lock);
|
||||
if (g_connected_wiimotes.count(devicepath) != 0)
|
||||
return;
|
||||
#endif
|
||||
|
||||
HANDLE dev_handle = CreateFile(devicepath.c_str(),
|
||||
GENERIC_READ | GENERIC_WRITE,
|
||||
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
||||
NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED,
|
||||
NULL);
|
||||
if (dev_handle == INVALID_HANDLE_VALUE)
|
||||
return;
|
||||
// enable to only check for official nintendo wiimotes/bb's
|
||||
bool check_vidpid = false;
|
||||
HIDD_ATTRIBUTES attrib;
|
||||
attrib.Size = sizeof(attrib);
|
||||
if (!check_vidpid ||
|
||||
(HidD_GetAttributes(dev_handle, &attrib) &&
|
||||
(attrib.VendorID == 0x057e) &&
|
||||
(attrib.ProductID == 0x0306)))
|
||||
{
|
||||
int rc = 0;
|
||||
// max_cycles insures we are never stuck here due to bad coding...
|
||||
int max_cycles = 20;
|
||||
u8 buf[MAX_PAYLOAD] = {0};
|
||||
|
||||
u8 const req_status_report[] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_REQUEST_STATUS, 0};
|
||||
// The new way to initialize the extension is by writing 0x55 to 0x(4)A400F0, then writing 0x00 to 0x(4)A400FB
|
||||
// 52 16 04 A4 00 F0 01 55
|
||||
// 52 16 04 A4 00 FB 01 00
|
||||
u8 const disable_enc_pt1_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xf0, 0x01, 0x55};
|
||||
u8 const disable_enc_pt2_report[MAX_PAYLOAD] = {WM_SET_REPORT | WM_BT_OUTPUT, WM_WRITE_DATA, 0x04, 0xa4, 0x00, 0xfb, 0x01, 0x00};
|
||||
|
||||
rc = CheckDeviceType_Write(dev_handle,
|
||||
disable_enc_pt1_report,
|
||||
sizeof(disable_enc_pt1_report),
|
||||
1);
|
||||
rc = CheckDeviceType_Write(dev_handle,
|
||||
disable_enc_pt2_report,
|
||||
sizeof(disable_enc_pt2_report),
|
||||
1);
|
||||
|
||||
rc = CheckDeviceType_Write(dev_handle,
|
||||
req_status_report,
|
||||
sizeof(req_status_report),
|
||||
1);
|
||||
|
||||
while (rc > 0 && --max_cycles > 0)
|
||||
{
|
||||
if ((rc = CheckDeviceType_Read(dev_handle, buf, 1)) <= 0)
|
||||
{
|
||||
// DEBUG_LOG(WIIMOTE, "CheckDeviceType: Read failed...");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (buf[1])
|
||||
{
|
||||
case WM_STATUS_REPORT:
|
||||
{
|
||||
real_wiimote = true;
|
||||
|
||||
// DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Status Report");
|
||||
wm_status_report * wsr = (wm_status_report*)&buf[2];
|
||||
if (wsr->extension)
|
||||
{
|
||||
// Wiimote with extension, we ask it what kind.
|
||||
u8 read_ext[MAX_PAYLOAD] = {0};
|
||||
read_ext[0] = WM_SET_REPORT | WM_BT_OUTPUT;
|
||||
read_ext[1] = WM_READ_DATA;
|
||||
// Extension type register.
|
||||
*(u32*)&read_ext[2] = Common::swap32(0x4a400fa);
|
||||
// Size.
|
||||
*(u16*)&read_ext[6] = Common::swap16(6);
|
||||
rc = CheckDeviceType_Write(dev_handle, read_ext, 8, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Normal Wiimote, exit while and be happy.
|
||||
rc = -1;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case WM_ACK_DATA:
|
||||
{
|
||||
real_wiimote = true;
|
||||
//wm_acknowledge * wm = (wm_acknowledge*)&buf[2];
|
||||
//DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Ack Error: %X ReportID: %X", wm->errorID, wm->reportID);
|
||||
break;
|
||||
}
|
||||
case WM_READ_DATA_REPLY:
|
||||
{
|
||||
// DEBUG_LOG(WIIMOTE, "CheckDeviceType: Got Data Reply");
|
||||
wm_read_data_reply * wrdr
|
||||
= (wm_read_data_reply*)&buf[2];
|
||||
// Check if it has returned what we asked.
|
||||
if (Common::swap16(wrdr->address) == 0x00fa)
|
||||
{
|
||||
real_wiimote = true;
|
||||
// 0x020420A40000ULL means balance board.
|
||||
u64 ext_type = (*(u64*)&wrdr->data[0]);
|
||||
// DEBUG_LOG(WIIMOTE,
|
||||
// "CheckDeviceType: GOT EXT TYPE %llX",
|
||||
// ext_type);
|
||||
is_bb = (ext_type == 0x020420A40000ULL);
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(WIIMOTE,
|
||||
"CheckDeviceType: GOT UNREQUESTED ADDRESS %X",
|
||||
Common::swap16(wrdr->address));
|
||||
}
|
||||
// force end
|
||||
rc = -1;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
// We let read try again incase there is another packet waiting.
|
||||
// DEBUG_LOG(WIIMOTE, "CheckDeviceType: GOT UNKNOWN REPLY: %X", buf[1]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
CloseHandle(dev_handle);
|
||||
}
|
||||
|
||||
bool WiimoteScanner::IsReady() const
|
||||
|
@ -355,7 +560,7 @@ bool Wiimote::IsConnected() const
|
|||
// positive = read packet
|
||||
// negative = didn't read packet
|
||||
// zero = error
|
||||
int Wiimote::IORead(u8* buf)
|
||||
int _IORead(HANDLE &dev_handle, OVERLAPPED &hid_overlap_read, u8* buf, int index)
|
||||
{
|
||||
// Add data report indicator byte (here, 0xa1)
|
||||
buf[0] = 0xa1;
|
||||
|
@ -405,79 +610,97 @@ int Wiimote::IORead(u8* buf)
|
|||
}
|
||||
}
|
||||
|
||||
WiimoteEmu::Spy(NULL, buf, bytes + 1);
|
||||
|
||||
return bytes + 1;
|
||||
}
|
||||
|
||||
// positive = read packet
|
||||
// negative = didn't read packet
|
||||
// zero = error
|
||||
int Wiimote::IORead(u8* buf)
|
||||
{
|
||||
return _IORead(dev_handle, hid_overlap_read, buf, index);
|
||||
}
|
||||
|
||||
|
||||
int _IOWrite(HANDLE &dev_handle, OVERLAPPED &hid_overlap_write, enum win_bt_stack_t &stack, const u8* buf, int len)
|
||||
{
|
||||
WiimoteEmu::Spy(NULL, buf, len);
|
||||
|
||||
switch (stack)
|
||||
{
|
||||
case MSBT_STACK_UNKNOWN:
|
||||
{
|
||||
// Try to auto-detect the stack type
|
||||
stack = MSBT_STACK_BLUESOLEIL;
|
||||
if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, len))
|
||||
return 1;
|
||||
|
||||
stack = MSBT_STACK_MS;
|
||||
if (_IOWrite(dev_handle, hid_overlap_write, stack, buf, len))
|
||||
return 1;
|
||||
|
||||
stack = MSBT_STACK_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
case MSBT_STACK_MS:
|
||||
{
|
||||
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
|
||||
//FlushFileBuffers(dev_handle);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
auto err = GetLastError();
|
||||
if (err == 121)
|
||||
{
|
||||
// Semaphore timeout
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to the Wiimote");
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
case MSBT_STACK_BLUESOLEIL:
|
||||
{
|
||||
u8 big_buf[MAX_PAYLOAD];
|
||||
if (len < MAX_PAYLOAD)
|
||||
{
|
||||
std::copy(buf, buf + len, big_buf);
|
||||
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
|
||||
buf = big_buf;
|
||||
}
|
||||
|
||||
ResetEvent(hid_overlap_write.hEvent);
|
||||
DWORD bytes = 0;
|
||||
if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write))
|
||||
{
|
||||
// WriteFile always returns true with bluesoleil.
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const err = GetLastError();
|
||||
if (ERROR_IO_PENDING == err)
|
||||
{
|
||||
CancelIo(dev_handle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Wiimote::IOWrite(const u8* buf, int len)
|
||||
{
|
||||
switch (stack)
|
||||
{
|
||||
case MSBT_STACK_UNKNOWN:
|
||||
{
|
||||
// Try to auto-detect the stack type
|
||||
stack = MSBT_STACK_BLUESOLEIL;
|
||||
if (IOWrite(buf, len))
|
||||
return 1;
|
||||
|
||||
stack = MSBT_STACK_MS;
|
||||
if (IOWrite(buf, len))
|
||||
return 1;
|
||||
|
||||
stack = MSBT_STACK_UNKNOWN;
|
||||
break;
|
||||
}
|
||||
case MSBT_STACK_MS:
|
||||
{
|
||||
auto result = HidD_SetOutputReport(dev_handle, const_cast<u8*>(buf) + 1, len - 1);
|
||||
//FlushFileBuffers(dev_handle);
|
||||
|
||||
if (!result)
|
||||
{
|
||||
auto err = GetLastError();
|
||||
if (err == 121)
|
||||
{
|
||||
// Semaphore timeout
|
||||
NOTICE_LOG(WIIMOTE, "WiimoteIOWrite[MSBT_STACK_MS]: Unable to send data to the Wiimote");
|
||||
}
|
||||
else
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "IOWrite[MSBT_STACK_MS]: ERROR: %08x", err);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
case MSBT_STACK_BLUESOLEIL:
|
||||
{
|
||||
u8 big_buf[MAX_PAYLOAD];
|
||||
if (len < MAX_PAYLOAD)
|
||||
{
|
||||
std::copy(buf, buf + len, big_buf);
|
||||
std::fill(big_buf + len, big_buf + MAX_PAYLOAD, 0);
|
||||
buf = big_buf;
|
||||
}
|
||||
|
||||
ResetEvent(hid_overlap_write.hEvent);
|
||||
DWORD bytes = 0;
|
||||
if (WriteFile(dev_handle, buf + 1, MAX_PAYLOAD - 1, &bytes, &hid_overlap_write))
|
||||
{
|
||||
// WriteFile always returns true with bluesoleil.
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
auto const err = GetLastError();
|
||||
if (ERROR_IO_PENDING == err)
|
||||
{
|
||||
CancelIo(dev_handle);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return _IOWrite(dev_handle, hid_overlap_write, stack, buf, len);
|
||||
}
|
||||
|
||||
// invokes callback for each found wiimote bluetooth device
|
||||
|
@ -498,7 +721,7 @@ void ProcessWiimotes(bool new_scan, T& callback)
|
|||
|
||||
BLUETOOTH_FIND_RADIO_PARAMS radioParam;
|
||||
radioParam.dwSize = sizeof(radioParam);
|
||||
|
||||
|
||||
HANDLE hRadio;
|
||||
|
||||
// TODO: save radio(s) in the WiimoteScanner constructor?
|
||||
|
|
|
@ -116,22 +116,21 @@ WiimoteScanner::~WiimoteScanner()
|
|||
void WiimoteScanner::Update()
|
||||
{}
|
||||
|
||||
std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
||||
void WiimoteScanner::FindWiimotes(std::vector<Wiimote*> & found_wiimotes, Wiimote* & found_board)
|
||||
{
|
||||
// TODO: find the device in the constructor and save it for later
|
||||
|
||||
std::vector<Wiimote*> wiimotes;
|
||||
IOBluetoothHostController *bth;
|
||||
IOBluetoothDeviceInquiry *bti;
|
||||
SearchBT *sbt;
|
||||
NSEnumerator *en;
|
||||
found_board = NULL;
|
||||
|
||||
bth = [[IOBluetoothHostController alloc] init];
|
||||
if ([bth addressAsString] == nil)
|
||||
{
|
||||
WARN_LOG(WIIMOTE, "No bluetooth host controller");
|
||||
[bth release];
|
||||
return wiimotes;
|
||||
return;
|
||||
}
|
||||
|
||||
sbt = [[SearchBT alloc] init];
|
||||
|
@ -162,14 +161,20 @@ std::vector<Wiimote*> WiimoteScanner::FindWiimotes()
|
|||
|
||||
Wiimote *wm = new Wiimote();
|
||||
wm->btd = dev;
|
||||
wiimotes.push_back(wm);
|
||||
|
||||
if(IsBalanceBoardName([[dev name] UTF8String]))
|
||||
{
|
||||
found_board = wm;
|
||||
}
|
||||
else
|
||||
{
|
||||
found_wiimotes.push_back(wm);
|
||||
}
|
||||
}
|
||||
|
||||
[bth release];
|
||||
[bti release];
|
||||
[sbt release];
|
||||
|
||||
return wiimotes;
|
||||
}
|
||||
|
||||
bool WiimoteScanner::IsReady() const
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue