From 946fb127523d726767a3025327b1ead4d998873d Mon Sep 17 00:00:00 2001 From: John Peterson Date: Wed, 28 Jan 2009 16:09:08 +0000 Subject: [PATCH] Wiimote: Partial work on movement recording (not working yet) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2021 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/IniFile.cpp | 377 ++++++++------- .../Plugin_Wiimote/Plugin_Wiimote.vcproj | 2 +- Source/Plugins/Plugin_Wiimote/Src/Config.cpp | 4 +- Source/Plugins/Plugin_Wiimote/Src/Config.h | 2 +- .../Plugins/Plugin_Wiimote/Src/ConfigDlg.cpp | 437 +++++++++++++++--- Source/Plugins/Plugin_Wiimote/Src/ConfigDlg.h | 62 ++- Source/Plugins/Plugin_Wiimote/Src/EmuMain.cpp | 58 ++- .../Plugins/Plugin_Wiimote/Src/FillReport.cpp | 31 +- .../Plugin_Wiimote/Src/ReadWiimote.cpp | 40 +- Source/Plugins/Plugin_Wiimote/Src/main.cpp | 102 +++- Source/Plugins/Plugin_Wiimote/Src/main.h | 37 +- .../Plugin_Wiimote/Src/wiimote_real.cpp | 75 +-- .../Plugins/Plugin_Wiimote/Src/wiimote_real.h | 1 + 13 files changed, 903 insertions(+), 325 deletions(-) diff --git a/Source/Core/Common/Src/IniFile.cpp b/Source/Core/Common/Src/IniFile.cpp index 4c5b1e2ba7..957af38925 100644 --- a/Source/Core/Common/Src/IniFile.cpp +++ b/Source/Core/Common/Src/IniFile.cpp @@ -16,6 +16,9 @@ // http://code.google.com/p/dolphin-emu/ // see IniFile.h +////////////////////////////////////////////////////////////////////////////////////// +// Include +// ------------ #include #include @@ -27,15 +30,24 @@ #include "StringUtil.h" #include "IniFile.h" +/////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////// +// Class +// ------------ IniFile::IniFile() {} IniFile::~IniFile() {} +/////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// +// Section functions used locally only +// ------------ Section::Section() : lines(), name(""), comment("") {} @@ -79,6 +91,7 @@ Section* IniFile::GetOrCreateSection(const char* sectionName) return(section); } +/////////////////////////////// bool IniFile::DeleteSection(const char* sectionName) @@ -158,7 +171,194 @@ std::string* IniFile::GetLine(Section* section, const char* key, std::string* va return 0; } +void IniFile::SetLines(const char* sectionName, const std::vector &lines) +{ + Section* section = GetOrCreateSection(sectionName); + section->lines.clear(); + for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) + { + section->lines.push_back(*iter); + } +} + + +bool IniFile::DeleteKey(const char* sectionName, const char* key) +{ + Section* section = GetSection(sectionName); + + if (!section) + { + return false; + } + + std::string* line = GetLine(section, key, 0, 0); + + for (std::vector::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) + { + if (line == &(*liter)) + { + section->lines.erase(liter); + return true; + } + } + + return false; //shouldn't happen +} + + +bool IniFile::GetKeys(const char* sectionName, std::vector& keys) const +{ + const Section* section = GetSection(sectionName); + + if (!section) + { + return false; + } + + keys.clear(); + + for (std::vector::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) + { + std::string key; + ParseLine(*liter, &key, 0, 0); + keys.push_back(key); + } + + return true; +} + + +bool IniFile::GetLines(const char* sectionName, std::vector& lines) const +{ + const Section* section = GetSection(sectionName); + if (!section) + return false; + + lines.clear(); + for (std::vector::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter) + { + std::string line = StripSpaces(*iter); + int commentPos = (int)line.find('#'); + if (commentPos == 0) + { + continue; + } + + if (commentPos != (int)std::string::npos) + { + line = StripSpaces(line.substr(0, commentPos)); + } + + lines.push_back(line); + } + + return true; +} + + +void IniFile::SortSections() +{ + std::sort(sections.begin(), sections.end()); +} + + +////////////////////////////////////////////////////////////////////////////////////// +// Load and save file +// ------------ +bool IniFile::Load(const char* filename) +{ + // Maximum number of letters in a line + static const int MAX_BYTES = 1024*10; + + sections.clear(); + sections.push_back(Section("")); + //first section consists of the comments before the first real section + + // Open file + std::ifstream in; + in.open(filename, std::ios::in); + + if (in.fail()) + { + return false; + } + + while (!in.eof()) + { + char templine[MAX_BYTES]; + in.getline(templine, MAX_BYTES); + std::string line = templine; + + if (in.eof()) + { + break; + } + + if (line.size() > 0) + { + if (line[0] == '[') + { + size_t endpos = line.find("]"); + + if (endpos != std::string::npos) + { + // New section! + std::string sub = line.substr(1, endpos - 1); + sections.push_back(Section(sub)); + + if (endpos + 1 < line.size()) + { + sections[sections.size() - 1].comment = line.substr(endpos + 1); + } + } + } + else + { + sections[sections.size() - 1].lines.push_back(line); + } + } + } + + in.close(); + return true; +} + +bool IniFile::Save(const char* filename) +{ + std::ofstream out; + out.open(filename, std::ios::out); + + if (out.fail()) + { + return false; + } + + for (std::vector
::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) + { + const Section& section = *iter; + + if (section.name != "") + { + out << "[" << section.name << "]" << section.comment << std::endl; + } + + for (std::vector::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter) + { + std::string s = *liter; + out << s << std::endl; + } + } + + out.close(); + return true; +} +////////////////////////////////////////// + + +////////////////////////////////////////////////////////////////////////////////////// +// Get and set elements +// ------------ void IniFile::Set(const char* sectionName, const char* key, const char* newValue) { Section* section = GetOrCreateSection(sectionName); @@ -195,17 +395,6 @@ void IniFile::Set(const char* sectionName, const char* key, bool newValue) Set(sectionName, key, StringFromBool(newValue).c_str()); } - -void IniFile::SetLines(const char* sectionName, const std::vector &lines) -{ - Section* section = GetOrCreateSection(sectionName); - section->lines.clear(); - - for (std::vector::const_iterator iter = lines.begin(); iter != lines.end(); ++iter) - { - section->lines.push_back(*iter); - } -} bool IniFile::Get(const char* sectionName, const char* key, std::string* value, const char* defaultValue) { Section* section = GetSection(sectionName); @@ -279,173 +468,9 @@ bool IniFile::Get(const char* sectionName, const char* key, bool* value, bool de *value = defaultValue; return false; } +//////////////////////////////////////// -bool IniFile::DeleteKey(const char* sectionName, const char* key) -{ - Section* section = GetSection(sectionName); - - if (!section) - { - return false; - } - - std::string* line = GetLine(section, key, 0, 0); - - for (std::vector::iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) - { - if (line == &(*liter)) - { - section->lines.erase(liter); - return true; - } - } - - return false; //shouldn't happen -} - - -bool IniFile::Load(const char* filename) -{ - sections.clear(); - sections.push_back(Section("")); - //first section consists of the comments before the first real section - - std::ifstream in; - in.open(filename, std::ios::in); - - if (in.fail()) - { - return false; - } - - while (!in.eof()) - { - char templine[512]; - in.getline(templine, 512); - std::string line = templine; - - if (in.eof()) - { - break; - } - - if (line.size() > 0) - { - if (line[0] == '[') - { - size_t endpos = line.find("]"); - - if (endpos != std::string::npos) - { - // New section! - std::string sub = line.substr(1, endpos - 1); - sections.push_back(Section(sub)); - - if (endpos + 1 < line.size()) - { - sections[sections.size() - 1].comment = line.substr(endpos + 1); - } - } - } - else - { - sections[sections.size() - 1].lines.push_back(line); - } - } - } - - in.close(); - return true; -} - - -bool IniFile::Save(const char* filename) -{ - std::ofstream out; - out.open(filename, std::ios::out); - - if (out.fail()) - { - return false; - } - - for (std::vector
::const_iterator iter = sections.begin(); iter != sections.end(); ++iter) - { - const Section& section = *iter; - - if (section.name != "") - { - out << "[" << section.name << "]" << section.comment << std::endl; - } - - for (std::vector::const_iterator liter = section.lines.begin(); liter != section.lines.end(); ++liter) - { - std::string s = *liter; - out << s << std::endl; - } - } - - out.close(); - return true; -} - - -bool IniFile::GetKeys(const char* sectionName, std::vector& keys) const -{ - const Section* section = GetSection(sectionName); - - if (!section) - { - return false; - } - - keys.clear(); - - for (std::vector::const_iterator liter = section->lines.begin(); liter != section->lines.end(); ++liter) - { - std::string key; - ParseLine(*liter, &key, 0, 0); - keys.push_back(key); - } - - return true; -} - - -bool IniFile::GetLines(const char* sectionName, std::vector& lines) const -{ - const Section* section = GetSection(sectionName); - if (!section) - return false; - - lines.clear(); - for (std::vector::const_iterator iter = section->lines.begin(); iter != section->lines.end(); ++iter) - { - std::string line = StripSpaces(*iter); - int commentPos = (int)line.find('#'); - if (commentPos == 0) - { - continue; - } - - if (commentPos != (int)std::string::npos) - { - line = StripSpaces(line.substr(0, commentPos)); - } - - lines.push_back(line); - } - - return true; -} - - -void IniFile::SortSections() -{ - std::sort(sections.begin(), sections.end()); -} - /* int main() diff --git a/Source/Plugins/Plugin_Wiimote/Plugin_Wiimote.vcproj b/Source/Plugins/Plugin_Wiimote/Plugin_Wiimote.vcproj index 591a460718..8993fb652e 100644 --- a/Source/Plugins/Plugin_Wiimote/Plugin_Wiimote.vcproj +++ b/Source/Plugins/Plugin_Wiimote/Plugin_Wiimote.vcproj @@ -233,7 +233,7 @@ Connect(wxID_ANY, wxEVT_KEY_DOWN, // Keyboard + wxKeyEventHandler(ConfigDialog::OnKeyDown), + (wxObject*)0, this); } ConfigDialog::~ConfigDialog() -{ - g_FrameOpen = false; - if (!g_EmulatorRunning) Shutdown(); +{ } +void ConfigDialog::OnKeyDown(wxKeyEvent& event) +{ + event.Skip(); + + // Escape a recording event + if (event.GetKeyCode() == WXK_ESCAPE) + { + m_bWaitForRecording = false; + m_bRecording = false; + UpdateGUI(); + } +} +void ConfigDialog::OnClose(wxCloseEvent& WXUNUSED (event)) +{ + SaveFile(); + g_Config.Save(); + g_FrameOpen = false; + SuccessAlert("Saved\n"); + if (!g_EmulatorRunning) Shutdown(); + EndModal(0); +} + +void ConfigDialog::CloseClick(wxCommandEvent& WXUNUSED (event)) +{ + // wxWidgets function. This will also trigger EVT_CLOSE(). + Close(); +} + +void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event)) +{ + +} + +void ConfigDialog::LoadFile() +{ + Console::Print("LoadFile\n"); + + IniFile file; + file.Load("WiimoteMovement.ini"); + + for(int i = 1; i < (RECORDING_ROWS + 1); i++) + { + // Get row name + std::string SaveName = StringFromFormat("Recording%i", i); + + // HotKey + int TmpRecordHotKey; file.Get(SaveName.c_str(), "HotKey", &TmpRecordHotKey, -1); + m_RecordHotKey[i]->SetSelection(TmpRecordHotKey); + + // Movement name + std::string TmpMovementName; file.Get(SaveName.c_str(), "MovementName", &TmpMovementName, ""); + m_RecordText[i]->SetValue(TmpMovementName.c_str()); + + // Game name + std::string TmpGameName; file.Get(SaveName.c_str(), "GameName", &TmpGameName, ""); + m_RecordGameText[i]->SetValue(TmpGameName.c_str()); + + // Recording speed + int TmpRecordSpeed; file.Get(SaveName.c_str(), "RecordingSpeed", &TmpRecordSpeed, -1); + if(TmpRecordSpeed != -1) + m_RecordSpeed[i]->SetValue(wxString::Format(wxT("%i"), TmpRecordSpeed)); + else + m_RecordSpeed[i]->SetValue(wxT("")); + + // Playback speed (currently always saved directly after a recording) + int TmpPlaybackSpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaybackSpeed, -1); + m_RecordPlayBackSpeed[i]->SetSelection(TmpPlaybackSpeed); + } +} +void ConfigDialog::SaveFile() +{ + Console::Print("SaveFile\n"); + + IniFile file; + file.Load("WiimoteMovement.ini"); + + for(int i = 1; i < (RECORDING_ROWS + 1); i++) + { + // Get row name + std::string SaveName = StringFromFormat("Recording%i", i); + + // HotKey + file.Set(SaveName.c_str(), "HotKey", m_RecordHotKey[i]->GetSelection()); + + // Movement name + file.Set(SaveName.c_str(), "MovementName", m_RecordText[i]->GetValue().c_str()); + + // Game name + file.Set(SaveName.c_str(), "GameName", m_RecordGameText[i]->GetValue().c_str()); + + // Recording speed (currently always saved directly after a recording) + /* + wxString TmpRecordSpeed = m_RecordSpeed[i]->GetValue(); + if(TmpRecordSpeed.length() > 0) + int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", TmpRecordSpeed); + else + int TmpRecordSpeed; file.Set(SaveName.c_str(), "RecordingSpeed", "-1"); + */ + + // Playback speed (currently always saved directly after a recording) + file.Set(SaveName.c_str(), "PlaybackSpeed", m_RecordPlayBackSpeed[i]->GetSelection()); + } + + file.Save("WiimoteMovement.ini"); +} +///////////////////////////// + ///////////////////////////////////////////////////////////////////////// // Create GUI @@ -142,7 +285,7 @@ void ConfigDialog::CreateGUIControls() //////////////////////////////////////////////////////////////////////////////// // Real Wiimote // ---------------- - // General + // Basic Settings wxStaticBoxSizer * sbRealBasic = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Basic Settings")); m_ConnectRealWiimote = new wxCheckBox(m_PageReal, ID_CONNECT_REAL, wxT("Connect real Wiimote")); m_UseRealWiimote = new wxCheckBox(m_PageReal, ID_USE_REAL, wxT("Use real Wiimote")); @@ -151,10 +294,25 @@ void ConfigDialog::CreateGUIControls() m_ConnectRealWiimote->SetValue(g_Config.bConnectRealWiimote); m_UseRealWiimote->SetValue(g_Config.bUseRealWiimote); - // ================================================== // Status + wxStaticBoxSizer * sbRealStatus = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Status")); + m_TextUpdateRate = new wxStaticText(m_PageReal, wxID_ANY, wxT("Update rate: 000 times/s")); + m_UpdateMeters = new wxCheckBox(m_PageReal, ID_UPDATE_REAL, wxT("Update gauges")); + + m_UpdateMeters->SetValue(g_Config.bUpdateRealWiimote); + + m_UpdateMeters->SetToolTip(wxT( + "You can turn this off when a game is running to avoid a unnecessary slowdown that comes from redrawing the\n" + "configuration screen. Remember that you also need to press '+' on your Wiimote before you can record movements." + )); + + sbRealStatus->Add(m_TextUpdateRate, 0, wxEXPAND | (wxALL), 5); + sbRealStatus->Add(m_UpdateMeters, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxUP), 5); + + // ================================================== + // Wiimote Status // ---------------- - wxBoxSizer * sbRealStatus = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer * sbRealWiimoteStatus = new wxBoxSizer(wxHORIZONTAL); wxStaticBoxSizer * sbRealBattery = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Battery")); wxStaticBoxSizer * sbRealRoll = new wxStaticBoxSizer(wxHORIZONTAL, m_PageReal, wxT("Roll and Pitch")); @@ -213,10 +371,10 @@ void ConfigDialog::CreateGUIControls() sbRealGForce->Add(sBoxGForce[0], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[1], 0, wxEXPAND | (wxALL), 5); sbRealGForce->Add(sBoxGForce[2], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[0], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[1], 0, wxEXPAND | (wxALL), 5); sbRealAccel->Add(sBoxAccel[2], 0, wxEXPAND | (wxALL), 5); - sbRealStatus->Add(sbRealBattery, 0, wxEXPAND | (wxALL), 5); - sbRealStatus->Add(sbRealRoll, 0, wxEXPAND | (wxALL), 5); - sbRealStatus->Add(sbRealGForce, 0, wxEXPAND | (wxALL), 5); - sbRealStatus->Add(sbRealAccel, 0, wxEXPAND | (wxALL), 5); + sbRealWiimoteStatus->Add(sbRealBattery, 0, wxEXPAND | (wxLEFT), 0); + sbRealWiimoteStatus->Add(sbRealRoll, 0, wxEXPAND | (wxLEFT), 5); + sbRealWiimoteStatus->Add(sbRealGForce, 0, wxEXPAND | (wxLEFT), 5); + sbRealWiimoteStatus->Add(sbRealAccel, 0, wxEXPAND | (wxLEFT), 5); m_GaugeBattery->SetToolTip(wxT("Press '+' to show the current status. Press '-' to stop recording the status.")); // ========================================== @@ -228,28 +386,35 @@ void ConfigDialog::CreateGUIControls() wxStaticBoxSizer * sbRealRecord = new wxStaticBoxSizer(wxVERTICAL, m_PageReal, wxT("Record movements")); wxArrayString StrHotKey; - for(int i = 0; i < 10; i++) - StrHotKey.Add(wxString::Format(wxT("Shift + %i"), i)); + for(int i = 0; i < 10; i++) StrHotKey.Add(wxString::Format(wxT("%i"), i)); wxArrayString StrPlayBackSpeed; - for(int i = 1; i < 8; i++) - StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*5)); + for(int i = 1; i < 15; i++) StrPlayBackSpeed.Add(wxString::Format(wxT("%i"), i*25)); - wxBoxSizer * sRealRecord[RECORDING_ROWS]; + wxBoxSizer * sRealRecord[RECORDING_ROWS + 1]; - wxStaticText * m_TextRec = new wxStaticText(m_PageReal, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(25, 15), wxALIGN_CENTRE); - wxStaticText * m_TextHotKey = new wxStaticText(m_PageReal, wxID_ANY, wxT("HotKey"), wxDefaultPosition, wxSize(62, 15), wxALIGN_CENTRE); - wxStaticText * m_TextMovement = new wxStaticText(m_PageReal, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(262, 15), wxALIGN_CENTRE); - wxStaticText * m_TextGame = new wxStaticText(m_PageReal, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(262, 15), wxALIGN_CENTRE); - wxStaticText * m_TextRecSped = new wxStaticText(m_PageReal, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(35, 15), wxALIGN_CENTRE); + wxStaticText * m_TextRec = new wxStaticText(m_PageReal, wxID_ANY, wxT("Rec."), wxDefaultPosition, wxSize(80, 15), wxALIGN_CENTRE); + wxStaticText * m_TextHotKey = new wxStaticText(m_PageReal, wxID_ANY, wxT("HotKey"), wxDefaultPosition, wxSize(40, 15), wxALIGN_CENTRE); + wxStaticText * m_TextMovement = new wxStaticText(m_PageReal, wxID_ANY, wxT("Movement name"), wxDefaultPosition, wxSize(200, 15), wxALIGN_CENTRE); + wxStaticText * m_TextGame = new wxStaticText(m_PageReal, wxID_ANY, wxT("Game name"), wxDefaultPosition, wxSize(200, 15), wxALIGN_CENTRE); + wxStaticText * m_TextRecSped = new wxStaticText(m_PageReal, wxID_ANY, wxT("R. s."), wxDefaultPosition, wxSize(30, 15), wxALIGN_CENTRE); wxStaticText * m_TextPlaySpeed = new wxStaticText(m_PageReal, wxID_ANY, wxT("Pl. s."), wxDefaultPosition, wxSize(40, 15), wxALIGN_CENTRE); - m_TextRec->SetToolTip(wxT("Press this button, then start the recording by pressing 'A' on the Wiimote and stop the recording by pressing" - " 'A' again.")); - m_TextRecSped->SetToolTip(wxT("Recording speed")); - m_TextPlaySpeed->SetToolTip(wxT("Playback speed")); + m_TextRec->SetToolTip(wxT( + "To record a movement first press this button, then start the recording by pressing 'A' on the Wiimote and stop the recording\n" + "by letting go of 'A'")); + m_TextHotKey->SetToolTip(wxT("The HotKey is Shift + [Number] for Wiimote movements and Ctrl + [Number] for Nunchuck movements")); + m_TextRecSped->SetToolTip(wxT("Recording speed in average measurements per second")); + m_TextPlaySpeed->SetToolTip(wxT( + "Playback speed: A playback speed of 100 means that the playback occurs at the same rate as it was recorded. (You can see the\n" + "current update rate in the Status window above when a game is running.) However, if your framerate is only at 50% of full speed\n" + "you may want to select a playback rate of 50, because then the game might perceive the playback as a full speed playback. (This\n" + "holds if Wiimote_Update() is tied to the framerate, I'm not sure that this is the case. It seemed to vary somewhat with different\n" + "framerates but not nearly enough to say that it was tied to the framerate.) So until this is better understood you'll have\n" + "to try different playback rates and see which one that works." + )); sRealRecord[0] = new wxBoxSizer(wxHORIZONTAL); - sRealRecord[0]->Add(m_TextRec, 0, wxEXPAND | (wxLEFT), 8); + sRealRecord[0]->Add(m_TextRec, 0, wxEXPAND | (wxLEFT), 5); sRealRecord[0]->Add(m_TextHotKey, 0, wxEXPAND | (wxLEFT), 5); sRealRecord[0]->Add(m_TextMovement, 0, wxEXPAND | (wxLEFT), 5); sRealRecord[0]->Add(m_TextGame, 0, wxEXPAND | (wxLEFT), 5); @@ -257,28 +422,28 @@ void ConfigDialog::CreateGUIControls() sRealRecord[0]->Add(m_TextPlaySpeed, 0, wxEXPAND | (wxLEFT), 5); sbRealRecord->Add(sRealRecord[0], 0, wxEXPAND | (wxALL), 0); - for(int i = 1; i < RECORDING_ROWS; i++) + for(int i = 1; i < (RECORDING_ROWS + 1); i++) { sRealRecord[i] = new wxBoxSizer(wxHORIZONTAL); - m_RecordButton[i] = new wxButton(m_PageReal, IDB_RECORD, wxEmptyString, wxDefaultPosition, wxSize(21, 14), 0, wxDefaultValidator, wxEmptyString); + m_RecordButton[i] = new wxButton(m_PageReal, IDB_RECORD + i, wxEmptyString, wxDefaultPosition, wxSize(80, 20), 0, wxDefaultValidator, wxEmptyString); m_RecordHotKey[i] = new wxChoice(m_PageReal, IDC_RECORD, wxDefaultPosition, wxDefaultSize, StrHotKey); - m_RecordText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(250, 19)); - m_RecordGameText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(250, 19)); + m_RecordText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_TEXT, wxT(""), wxDefaultPosition, wxSize(200, 19)); + m_RecordGameText[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_GAMETEXT, wxT(""), wxDefaultPosition, wxSize(200, 19)); m_RecordSpeed[i] = new wxTextCtrl(m_PageReal, IDT_RECORD_SPEED, wxT(""), wxDefaultPosition, wxSize(30, 19), wxTE_READONLY | wxTE_CENTRE); m_RecordPlayBackSpeed[i] = new wxChoice(m_PageReal, IDT_RECORD_PLAYSPEED, wxDefaultPosition, wxDefaultSize, StrPlayBackSpeed); - m_RecordText[i]->SetMaxLength(50); - m_RecordGameText[i]->SetMaxLength(50); + m_RecordText[i]->SetMaxLength(35); + m_RecordGameText[i]->SetMaxLength(35); m_RecordSpeed[i]->Enable(false); - sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxALL), 5); - sRealRecord[i]->Add(m_RecordHotKey[i], 0, wxEXPAND | (wxALL), 5); - sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxALL), 5); - sRealRecord[i]->Add(m_RecordGameText[i], 0, wxEXPAND | (wxALL), 5); - sRealRecord[i]->Add(m_RecordSpeed[i], 0, wxEXPAND | (wxALL), 5); - sRealRecord[i]->Add(m_RecordPlayBackSpeed[i], 0, wxEXPAND | (wxALL), 5); + sRealRecord[i]->Add(m_RecordButton[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordHotKey[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordText[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordGameText[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordSpeed[i], 0, wxEXPAND | (wxLEFT), 5); + sRealRecord[i]->Add(m_RecordPlayBackSpeed[i], 0, wxEXPAND | (wxLEFT), 5); - sbRealRecord->Add(sRealRecord[i], 0, wxEXPAND | (wxALL), 0); + sbRealRecord->Add(sRealRecord[i], 0, wxEXPAND | (wxTOP), 2); } // ========================================== @@ -289,10 +454,14 @@ void ConfigDialog::CreateGUIControls() sbRealBasic->Add(m_ConnectRealWiimote, 0, wxEXPAND | (wxALL), 5); sbRealBasic->Add(m_UseRealWiimote, 0, wxEXPAND | (wxALL), 5); + wxBoxSizer * sRealBasicStatus = new wxBoxSizer(wxHORIZONTAL); + sRealBasicStatus->Add(sbRealBasic, 0, wxEXPAND | (wxLEFT), 0); + sRealBasicStatus->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT), 5); + wxBoxSizer * sRealMain = new wxBoxSizer(wxVERTICAL); - sRealMain->Add(sbRealBasic, 0, wxEXPAND | (wxALL), 5); - sRealMain->Add(sbRealStatus, 0, wxEXPAND | (wxLEFT | wxLEFT | wxDOWN), 5); - sRealMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxLEFT | wxDOWN), 5); + sRealMain->Add(sRealBasicStatus, 0, wxEXPAND | (wxALL), 5); + sRealMain->Add(sbRealWiimoteStatus, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); + sRealMain->Add(sbRealRecord, 0, wxEXPAND | (wxLEFT | wxRIGHT | wxDOWN), 5); ///////////////////////////////// @@ -308,28 +477,164 @@ void ConfigDialog::CreateGUIControls() Fit(); Center(); + + ControlsCreated = true; ///////////////////////////////// } - -void ConfigDialog::OnClose(wxCloseEvent& WXUNUSED (event)) -{ - g_Config.Save(); - EndModal(0); -} - -void ConfigDialog::CloseClick(wxCommandEvent& WXUNUSED (event)) -{ - Close(); -} - -void ConfigDialog::AboutClick(wxCommandEvent& WXUNUSED (event)) -{ - -} ///////////////////////////////// -//void ConfigDialog::Update() +///////////////////////////////////////////////////////////////////////// +/* Record movement */ +// ------------ + +void ConfigDialog::ConvertToString() +{ + // Load ini file + IniFile file; + file.Load("WiimoteMovement.ini"); + std::string TmpStr = "", TmpTime = ""; + + for (int i = 0; i < m_vRecording.size(); i++) + { + // Write the movement data + TmpStr += StringFromFormat("%02x", m_vRecording.at(i).x); + TmpStr += StringFromFormat("%02x", m_vRecording.at(i).y); + TmpStr += StringFromFormat("%02x", m_vRecording.at(i).z); + if(i < (m_vRecording.size() - 1)) TmpStr += ","; + + /* Break just short of the IniFile.cpp byte limit so that we don't crash file.Load() the next time. + This limit should never be hit because of the recording limit below. I keep it here just in case. */ + if(TmpStr.length() > (1024*10 - 10)) + { + break; + PanicAlert("Your recording was to long, the entire recording was not saved."); + } + + // Write the timestamps. The upper limit is 99 seconds. + int Time = (int)((m_vRecording.at(i).Time - m_vRecording.at(0).Time) * 1000); + TmpTime += StringFromFormat("%05i", Time); + if(i < (m_vRecording.size() - 1)) TmpTime += ","; + //Console::Print("Time: %f %i\n", m_vRecording.at(i).Time, Time); + } + + // Recordings per second + double Recordings = (double)m_vRecording.size(); + double Time = m_vRecording.at(m_vRecording.size() - 1).Time - m_vRecording.at(0).Time; + int Rate = (int)(Recordings / Time); + m_RecordSpeed[m_iRecordTo]->SetValue(wxString::Format(wxT("%i"), Rate)); + + std::string SaveName = StringFromFormat("Recording%i", m_iRecordTo); + file.Set(SaveName.c_str(), "Movement", TmpStr.c_str()); + file.Set(SaveName.c_str(), "Time", TmpTime.c_str()); + file.Set(SaveName.c_str(), "RecordingSpeed", Rate); + file.Save("WiimoteMovement.ini"); +} + +// Timeout the recording +void ConfigDialog::Update(wxTimerEvent& WXUNUSED(event)) +{ + m_bWaitForRecording = false; + m_bRecording = false; + m_RecordButton[m_iRecordTo]->SetLabel(""); + UpdateGUI(); +} + +// One second timeout for another A press +void ConfigDialog::UpdateA(wxTimerEvent& WXUNUSED(event)) +{ + m_bAllowA = true; + Console::Print("A allowed again"); +} + +void ConfigDialog::RecordMovement(wxCommandEvent& event) +{ + m_iRecordTo = event.GetId() - 2000; + + if(WiiMoteReal::g_MotionSensing) + { + // Check if there already is a recording here + if(m_RecordSpeed[m_iRecordTo]->GetLineLength(0) > 0) + { + if(!AskYesNo("Do you want to replace the current recording?")) return; + } + m_RecordButton[m_iRecordTo]->SetLabel("Hold A"); + } + else + { + m_RecordButton[m_iRecordTo]->SetLabel("Press +"); + return; + } + + m_bWaitForRecording = true; + m_bAllowA = true; + m_bRecording = false; + + UpdateGUI(); + + m_TimeoutTimer->Start(5000, true); + //m_TimeoutATimer->Start(500, true); +} + +void ConfigDialog::DoRecordA(bool Pressed) +{ + // Return if we are not waiting or recording + if (! (m_bWaitForRecording || m_bRecording)) return; + + // Return if we are waiting but have not pressed A + if (m_bWaitForRecording && !Pressed) return; + + // Return if we are recording but are still pressing A + if (m_bRecording && Pressed) return; + + //m_bAllowA = false; + m_bRecording = Pressed; + + // Start recording, only run this once + if(m_bRecording && m_bWaitForRecording) + { + m_RecordButton[m_iRecordTo]->SetLabel("Recording..."); + m_vRecording.clear(); // Clear the list + m_TimeoutTimer->Stop(); + m_bWaitForRecording = false; + } + // The recording is done + else + { + m_RecordButton[m_iRecordTo]->SetLabel("Done"); + Console::Print("Done: %i %i\n", m_bWaitForRecording, m_bRecording); + //m_bAllowA = true; + ConvertToString(); + } + + UpdateGUI(); +} + +void ConfigDialog::DoRecordMovement(u8 _x, u8 _y, u8 _z) +{ + if (!m_bRecording) return; + + Console::Print("DoRecordMovement\n"); + + SRecording Tmp; + Tmp.x = _x; + Tmp.y = _y; + Tmp.z = _z; + Tmp.Time = GetDoubleTime(); + m_vRecording.push_back(Tmp); + + /* The upper limit of a recording coincides with the IniFile.cpp limit, each list element + is 7 bytes, therefore be divide by 7 */ + if (m_vRecording.size() > (10*1024 / 7 - 2) ) + { + m_bRecording = false; + m_RecordButton[m_iRecordTo]->SetLabel("Done"); + ConvertToString(); + UpdateGUI(); + } +} +///////////////////////////////// + ///////////////////////////////////////////////////////////////////////// @@ -493,10 +798,12 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event) case ID_CONNECT_REAL: DoConnectReal(); break; - case ID_USE_REAL: g_Config.bUseRealWiimote = m_UseRealWiimote->IsChecked(); break; + case ID_UPDATE_REAL: + g_Config.bUpdateRealWiimote = m_UpdateMeters->IsChecked(); + break; ///////////////// } g_Config.Save(); @@ -510,6 +817,8 @@ void ConfigDialog::GeneralSettingsChanged(wxCommandEvent& event) // ------------- void ConfigDialog::UpdateGUI() { + Console::Print("UpdateGUI: \n"); + /* I have disabled this option during a running game because it's enough to be able to switch between using and not using then. To also use the connect option during a running game would mean that the wiimote must be sent the current reporting mode and the channel ID after it @@ -517,5 +826,7 @@ void ConfigDialog::UpdateGUI() for that so that this option can be enabled during gameplay. */ m_ConnectRealWiimote->Enable(!g_EmulatorRunning); m_UseRealWiimote->Enable(g_RealWiiMotePresent && g_Config.bConnectRealWiimote); - Console::Print("Present: %i, Connect: %i\n", g_RealWiiMotePresent, g_Config.bConnectRealWiimote); + + for(int i = IDB_RECORD + 1; i < (IDB_RECORD + RECORDING_ROWS + 1); i++) + if(ControlsCreated) m_Notebook->FindItem(i)->Enable(!(m_bWaitForRecording || m_bRecording)); } diff --git a/Source/Plugins/Plugin_Wiimote/Src/ConfigDlg.h b/Source/Plugins/Plugin_Wiimote/Src/ConfigDlg.h index b180c70423..41a93453d2 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/ConfigDlg.h +++ b/Source/Plugins/Plugin_Wiimote/Src/ConfigDlg.h @@ -18,6 +18,9 @@ #ifndef __CONFIGDIALOG_h__ #define __CONFIGDIALOG_h__ +#include +#include + #include #include #include @@ -30,7 +33,6 @@ #include #include - class ConfigDialog : public wxDialog { public: @@ -40,17 +42,33 @@ class ConfigDialog : public wxDialog long style = wxDEFAULT_DIALOG_STYLE); virtual ~ConfigDialog(); + // General open, close and event functions void CloseClick(wxCommandEvent& event); void UpdateGUI(); + void OnKeyDown(wxKeyEvent& event); + void LoadFile(); void SaveFile(); + + // Status + wxStaticText * m_TextUpdateRate; + // Flash lights on connect functions wxTimer * m_ExitTimer; void DoFlashLights(); void StartTimer(); void FlashLights(wxTimerEvent& WXUNUSED(event)) { DoFlashLights(); } bool ShutDown; int TimerCounter; - //void Update(wxTimerEvent& WXUNUSED(event)); + // Wiimote status wxGauge *m_GaugeBattery, *m_GaugeRoll[2], *m_GaugeGForce[3], *m_GaugeAccel[3]; + bool m_bWaitForRecording, m_bRecording, m_bAllowA; + int m_iRecordTo; + void RecordMovement(wxCommandEvent& event); + void DoRecordMovement(u8 _x, u8 _y, u8 _z); + void DoRecordA(bool Pressed); + void ConvertToString(); + wxTimer *m_TimeoutTimer, *m_TimeoutATimer; + void Update(wxTimerEvent& WXUNUSED(event)); + void UpdateA(wxTimerEvent& WXUNUSED(event)); private: DECLARE_EVENT_TABLE(); @@ -60,25 +78,38 @@ class ConfigDialog : public wxDialog wxNotebook *m_Notebook; wxPanel *m_PageEmu, *m_PageReal; + bool ControlsCreated; + wxCheckBox *m_SidewaysDPad; // Emulated Wiimote settings wxCheckBox *m_WideScreen; wxCheckBox *m_NunchuckConnected, *m_ClassicControllerConnected; - wxCheckBox *m_ConnectRealWiimote, *m_UseRealWiimote; // Real Wiimote settings + wxCheckBox *m_ConnectRealWiimote, *m_UseRealWiimote, *m_UpdateMeters; // Real Wiimote settings - static const int RECORDING_ROWS = 11; - wxButton * m_RecordButton[RECORDING_ROWS]; - wxChoice * m_RecordHotKey[RECORDING_ROWS]; - wxTextCtrl * m_RecordText[RECORDING_ROWS]; - wxTextCtrl * m_RecordGameText[RECORDING_ROWS]; - wxTextCtrl * m_RecordSpeed[RECORDING_ROWS]; - wxChoice * m_RecordPlayBackSpeed[RECORDING_ROWS]; + //static const int RECORDING_ROWS = 15; + wxButton * m_RecordButton[RECORDING_ROWS + 1]; + wxChoice * m_RecordHotKey[RECORDING_ROWS + 1]; + wxTextCtrl * m_RecordText[RECORDING_ROWS + 1]; + wxTextCtrl * m_RecordGameText[RECORDING_ROWS + 1]; + wxTextCtrl * m_RecordSpeed[RECORDING_ROWS + 1]; + wxChoice * m_RecordPlayBackSpeed[RECORDING_ROWS + 1]; + + /* + struct m_sRecording + { + u8 x; + u8 y; + u8 z; + double Time; + }; + */ + std::vector m_vRecording; enum { ID_CLOSE = 1000, ID_ABOUTOGL, - IDTM_EXIT, IDTM_UPDATE, // Timer + IDTM_EXIT, IDTM_UPDATE, IDTM_UPDATEA, // Timer ID_NOTEBOOK, ID_PAGEEMU, @@ -89,13 +120,14 @@ class ConfigDialog : public wxDialog ID_NUNCHUCKCONNECTED, ID_CLASSICCONTROLLERCONNECTED, // Real - ID_CONNECT_REAL, ID_USE_REAL, IDT_STATUS, - IDB_RECORD, IDC_RECORD, IDT_RECORD_TEXT, IDT_RECORD_GAMETEXT, IDT_RECORD_SPEED, IDT_RECORD_PLAYSPEED + ID_CONNECT_REAL, ID_USE_REAL, ID_UPDATE_REAL, IDT_STATUS, + IDB_RECORD = 2000, + IDC_RECORD = 3000, + IDT_RECORD_TEXT, IDT_RECORD_GAMETEXT, IDT_RECORD_SPEED, IDT_RECORD_PLAYSPEED }; void OnClose(wxCloseEvent& event); void CreateGUIControls(); - void AboutClick(wxCommandEvent& event); void DoConnectReal(); // Real @@ -105,4 +137,6 @@ class ConfigDialog : public wxDialog void GeneralSettingsChanged(wxCommandEvent& event); }; +extern ConfigDialog *frame; + #endif diff --git a/Source/Plugins/Plugin_Wiimote/Src/EmuMain.cpp b/Source/Plugins/Plugin_Wiimote/Src/EmuMain.cpp index f83f656ac5..0caa15ca73 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/EmuMain.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/EmuMain.cpp @@ -26,8 +26,9 @@ #include "Common.h" // Common #include "StringUtil.h" // for ArrayToString() +#include "IniFile.h" -#include "main.h" +#include "main.h" // Local #include "wiimote_hid.h" #include "EmuSubroutines.h" #include "EmuDefinitions.h" @@ -137,6 +138,61 @@ void Initialize() g_EmulatedWiiMoteInitialized = true; + ////////////////////////////////////// + // Load pre-recorded movements + // --------------- + IniFile file; + file.Load("WiimoteMovement.ini"); + + for(int i = 0; i < RECORDING_ROWS; i++) + { + // Get row name + std::string SaveName = StringFromFormat("Recording%i", i + 1); + + // Get movement + std::string TmpMovement; file.Get(SaveName.c_str(), "Movement", &TmpMovement, ""); + + // Get time + std::string TmpTime; file.Get(SaveName.c_str(), "Time", &TmpTime, ""); + + SRecording Tmp; + for (int j = 0, k = 0; j < TmpMovement.length(); j+=7) + { + // Skip blank savings + if (TmpMovement.length() < 3) continue; + + std::string StrX = TmpMovement.substr(j, 2); + std::string StrY = TmpMovement.substr(j + 2, 2); + std::string StrZ = TmpMovement.substr(j + 4, 2); + u32 TmpX, TmpY, TmpZ; + AsciiToHex(StrX.c_str(), TmpX); + AsciiToHex(StrY.c_str(), TmpY); + AsciiToHex(StrZ.c_str(), TmpZ); + Tmp.x = (u8)TmpX; + Tmp.x = (u8)TmpY; + Tmp.x = (u8)TmpZ; + + // Go to next set of time values + int Time = atoi(TmpTime.substr(k, 5).c_str()); + Tmp.Time = (double)(Time/1000); + VRecording.at(i).Recording.push_back(Tmp); + k += 6; + } + + // HotKey + int TmpRecordHotKey; file.Get(SaveName.c_str(), "HotKey", &TmpRecordHotKey, -1); + VRecording.at(i).HotKey = TmpRecordHotKey; + + // Recording speed + int TmpPlaybackSpeed; file.Get(SaveName.c_str(), "PlaybackSpeed", &TmpPlaybackSpeed, -1); + VRecording.at(i).PlaybackSpeed = TmpPlaybackSpeed; + + Console::Print("Size:%i HotKey:%i Speed:%i\n", + VRecording.at(i).Recording.size(), VRecording.at(i).HotKey, VRecording.at(i).PlaybackSpeed + ); + } + ////////////////////////// + // I forgot what these were for? // g_RegExt[0xfd] = 0x1e; // g_RegExt[0xfc] = 0x9a; diff --git a/Source/Plugins/Plugin_Wiimote/Src/FillReport.cpp b/Source/Plugins/Plugin_Wiimote/Src/FillReport.cpp index cc18660ae6..1ea2295f0d 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/FillReport.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/FillReport.cpp @@ -46,9 +46,12 @@ namespace WiiMoteEmu //****************************************************************************** +//////////////////////////////////////////////////////////// +// Wiimote core buttons +// --------------- void FillReportInfo(wm_core& _core) { - /* This has to be filled with zeroes because when no buttons are pressed the + /* This has to be filled with zeroes (and not for example 0xff) because when no buttons are pressed the value is 00 00 */ memset(&_core, 0x00, sizeof(wm_core)); @@ -67,9 +70,7 @@ void FillReportInfo(wm_core& _core) _core.home = GetAsyncKeyState('H') ? 1 : 0; - /* Sideways controls (for example for Wario Land) was not enabled automatically - so I have to use this function. I'm not sure how it works on the actual Wii. - */ + /* Sideways controls (for example for Wario Land) if the Wiimote is intended to be held sideways */ if(g_Config.bSidewaysDPad) { _core.left = GetAsyncKeyState(VK_DOWN) ? 1 : 0; @@ -88,15 +89,18 @@ void FillReportInfo(wm_core& _core) // TODO: fill in #endif } +////////////////////////// -// ----------------------------- -/* Global declarations for FillReportAcc. The accelerometer x, y and z values range from - 0x00 to 0xff with the default netural values being [y = 0x84, x = 0x84, z = 0x9f] - according to a source. The extremes are 0x00 for (-) and 0xff for (+). It's important - that all values are not 0x80, the the mouse pointer can disappear from the screen - permanently then, until z is adjusted back. */ + +//////////////////////////////////////////////////////////// +// Wiimote accelerometer +// --------------- +/* The accelerometer x, y and z values range from 0x00 to 0xff with the default netural values + being [y = 0x84, x = 0x84, z = 0x9f] according to a source. The extremes are 0x00 for (-) + and 0xff for (+). It's important that all values are not 0x80, the mouse pointer can disappear + from the screen permanently then, until z is adjusted back. */ // ---------- -// the variables are global so they can be changed during debugging +// Global declarations for FillReportAcc: These variables are global so they can be changed during debugging //int A = 0, B = 128, C = 64; // for debugging //int a = 1, b = 1, c = 2, d = -2; // for debugging //int consoleDisplay = 0; @@ -283,6 +287,7 @@ void FillReportAcc(wm_accel& _acc) AX, AY, AZ );*/ } +///////////////////////// void FillReportIR(wm_ir_extended& _ir0, wm_ir_extended& _ir1) @@ -459,7 +464,7 @@ void FillReportIRBasic(wm_ir_basic& _ir0, wm_ir_basic& _ir1) int abc = 0; // =================================================== -/* Generate the 6 byte extension report, encrypted. The bytes are JX JY AX AY AZ BT. */ +/* Generate the 6 byte extension report for the Nunchuck, encrypted. The bytes are JX JY AX AY AZ BT. */ // ---------------- void FillReportExtension(wm_extension& _ext) { @@ -529,6 +534,7 @@ void FillReportExtension(wm_extension& _ext) // Write it back to the extension memcpy(&_ext, &g_RegExtTmpReport[0x08], sizeof(_ext)); } +// ======================= // =================================================== @@ -706,6 +712,7 @@ void FillReportClassicExtension(wm_classic_extension& _ext) // Write it back memcpy(&_ext, &g_RegExtTmpReport[0x08], sizeof(_ext)); } +// ======================= } // end of namespace diff --git a/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp b/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp index 2b32243ace..d52bd96f7e 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/ReadWiimote.cpp @@ -28,7 +28,11 @@ #include "StringUtil.h" #include "wiimote_real.h" // Local -#include "main.h" // Local +#include "main.h" +#if defined(HAVE_WX) && HAVE_WX + #include "ConfigDlg.h" +#endif +#include "Config.h" //////////////////////////////////////// namespace WiiMoteReal @@ -68,13 +72,19 @@ void handle_event(struct wiimote_t* wm) * This is useful because it saves battery power. */ if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_MINUS)) + { wiiuse_motion_sensing(wm, 0); + g_MotionSensing = false; + } /* * Pressing plus will tell the wiimote we are interested in movement. */ if (IS_JUST_PRESSED(wm, WIIMOTE_BUTTON_PLUS)) + { wiiuse_motion_sensing(wm, 1); + g_MotionSensing = true; + } /* If the accelerometer is turned on then print angles */ if (WIIUSE_USING_ACC(wm)) @@ -85,22 +95,30 @@ void handle_event(struct wiimote_t* wm) Tmp += StringFromFormat("Battery: %1.2f\n", wm->battery_level); Tmp += StringFromFormat("G-Force x, y, z: %1.2f %1.2f %1.2f\n", wm->gforce.x, wm->gforce.y, wm->gforce.z); Tmp += StringFromFormat("Accel x, y, z: %03i %03i %03i\n\n", wm->accel.x, wm->accel.y, wm->accel.z); - Console::Print("%s", Tmp.c_str()); + //Console::Print("%s", Tmp.c_str()); if(frame) { - frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5)); + if(g_Config.bUpdateRealWiimote) + { + frame->m_GaugeBattery->SetValue((int)floor((wm->battery_level * 100) + 0.5)); - frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180); - frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180); + frame->m_GaugeRoll[0]->SetValue(wm->orient.roll + 180); + frame->m_GaugeRoll[1]->SetValue(wm->orient.pitch + 180); - frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5)); - frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5)); - frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5)); + frame->m_GaugeGForce[0]->SetValue((int)floor((wm->gforce.x * 100) + 300.5)); + frame->m_GaugeGForce[1]->SetValue((int)floor((wm->gforce.y * 100) + 300.5)); + frame->m_GaugeGForce[2]->SetValue((int)floor((wm->gforce.z * 100) + 300.5)); - frame->m_GaugeAccel[0]->SetValue(wm->accel.x); - frame->m_GaugeAccel[1]->SetValue(wm->accel.y); - frame->m_GaugeAccel[2]->SetValue(wm->accel.z); + frame->m_GaugeAccel[0]->SetValue(wm->accel.x); + frame->m_GaugeAccel[1]->SetValue(wm->accel.y); + frame->m_GaugeAccel[2]->SetValue(wm->accel.z); + } + + frame->DoRecordMovement(wm->accel.x, wm->accel.y, wm->accel.z); + + if (IS_PRESSED(wm, WIIMOTE_BUTTON_A)) frame->DoRecordA(true); + else frame->DoRecordA(false); } } } diff --git a/Source/Plugins/Plugin_Wiimote/Src/main.cpp b/Source/Plugins/Plugin_Wiimote/Src/main.cpp index 1a9d23a4af..92e858aab7 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/main.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/main.cpp @@ -20,17 +20,16 @@ // Includes // ŻŻŻŻŻŻŻŻŻŻŻŻŻ #include "Common.h" // Common -#include "Config.h" #include "StringUtil.h" #include "ConsoleWindow.h" // For Start, Print, GetHwnd - -#if defined(HAVE_WX) && HAVE_WX - #include - #include "ConfigDlg.h" -#endif +#include "Timer.h" #define EXCLUDEMAIN_H // Avoid certain declarations in main.h #include "main.h" // Local +#if defined(HAVE_WX) && HAVE_WX + #include "ConfigDlg.h" +#endif +#include "Config.h" #include "pluginspecs_wiimote.h" #include "EmuMain.h" #if HAVE_WIIUSE @@ -50,6 +49,17 @@ bool g_RealWiiMotePresent = false; bool g_RealWiiMoteInitialized = false; bool g_EmulatedWiiMoteInitialized = false; +// Update speed +int g_UpdateCounter = 0; +double g_UpdateTime = 0; +int g_UpdateRate = 0; +int g_UpdateWriteScreen = 0; +std::vector g_UpdateTimeList (5, 0); + +// Movement recording +std::vector VRecording(RECORDING_ROWS); + +// DLL instance HINSTANCE g_hInstance; #if defined(HAVE_WX) && HAVE_WX @@ -134,6 +144,8 @@ void DllConfig(HWND _hParent) win.SetHWND(_hParent); #endif + Console::Open(); + g_FrameOpen = true; frame = new ConfigDialog(&win); @@ -266,6 +278,18 @@ extern "C" void Wiimote_ControlChannel(u16 _channelID, const void* _pData, u32 _ // ---------------- extern "C" void Wiimote_Update() { + // Tell us about the update rate, but only about once every second to avoid a major slowdown + if (frame) + { + GetUpdateRate(); + if (g_UpdateWriteScreen > g_UpdateRate) + { + frame->m_TextUpdateRate->SetLabel(wxString::Format("Update rate: %03i times/s", g_UpdateRate)); + g_UpdateWriteScreen = 0; + } + g_UpdateWriteScreen++; + } + if (!g_Config.bUseRealWiimote || !g_RealWiiMotePresent) WiiMoteEmu::Update(); #if HAVE_WIIUSE @@ -285,17 +309,79 @@ extern "C" unsigned int Wiimote_GetAttachedControllers() // Supporting functions //****************************************************************************** + +/* Returns a timestamp with three decimals for precise time comparisons. The return format is + of the form seconds.milleseconds for example 1234.123. The leding seconds have no particular meaning + but are just there to enable use to tell if we have entered a new second or now. */ +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +double GetDoubleTime() +{ +#if defined(HAVE_WX) && HAVE_WX + wxDateTime datetime = wxDateTime::UNow(); // Get timestamp + u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970(); // Get continous timestamp + + /* Remove a few years. We only really want enough seconds to make sure that we are + detecting actual actions, perhaps 60 seconds is enough really, but I leave a + year of seconds anyway, in case the user's clock is incorrect or something like that */ + TmpSeconds = TmpSeconds - (38 * 365 * 24 * 60 * 60); + + //if (TmpSeconds < 0) return 0; // Check the the user's clock is working somewhat + + u32 Seconds = (u32)TmpSeconds; // Make a smaller integer that fits in the double + double ms = datetime.GetMillisecond() / 1000.0; + double TmpTime = Seconds + ms; + return TmpTime; +#endif +} + +/* Calculate the current update frequency. Calculate the time between ten updates, and average + five such rates. If we assume there are 60 updates per second if the game is running at full + speed then we get this measure on average once every second. The reason to have a few updates + between each measurement is becase the milliseconds may not be perfectly accurate and may return + the same time even when a milliseconds has actually passed, for example.*/ +int GetUpdateRate() +{ +#if defined(HAVE_WX) && HAVE_WX + if(g_UpdateCounter == 10) + { + // Erase the old ones + if(g_UpdateTimeList.size() == 5) g_UpdateTimeList.erase(g_UpdateTimeList.begin() + 0); + + // Calculate the time and save it + int Time = (int)(10 / (GetDoubleTime() - g_UpdateTime)); + g_UpdateTimeList.push_back(Time); + //Console::Print("Time: %i %f\n", Time, GetDoubleTime()); + + int TotalTime = 0; + for (int i = 0; i < g_UpdateTimeList.size(); i++) + TotalTime += g_UpdateTimeList.at(i); + g_UpdateRate = TotalTime / 5; + + // Write the new update time + g_UpdateTime = GetDoubleTime(); + + g_UpdateCounter = 0; + } + + g_UpdateCounter++; + + return g_UpdateRate; +#else + return 0; +#endif +} + void DoInitialize() { // ---------------------------------------- // Debugging window // ---------- - /*Console::Open(100, 750, "Wiimote"); // give room for 20 rows + /**/Console::Open(100, 750, "Wiimote"); // give room for 20 rows Console::Print("Wiimote console opened\n"); // Move window //MoveWindow(Console::GetHwnd(), 0,400, 100*8,10*14, true); // small window - MoveWindow(Console::GetHwnd(), 400,0, 100*8,70*14, true); // big window*/ + MoveWindow(Console::GetHwnd(), 400,0, 100*8,70*14, true); // big window // --------------- // Load config settings diff --git a/Source/Plugins/Plugin_Wiimote/Src/main.h b/Source/Plugins/Plugin_Wiimote/Src/main.h index 18e54b87d0..c9bebf2f39 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/main.h +++ b/Source/Plugins/Plugin_Wiimote/Src/main.h @@ -22,9 +22,6 @@ // Includes // ŻŻŻŻŻŻŻŻŻŻ #include // System -#if defined(HAVE_WX) && HAVE_WX - #include "ConfigDlg.h" -#endif //////////////////////////////// @@ -41,6 +38,24 @@ // Declarations // ŻŻŻŻŻŻŻŻŻ void DoInitialize(); +double GetDoubleTime(); +int GetUpdateRate(); + +// Movement recording +#define RECORDING_ROWS 15 +struct SRecording +{ + u8 x; + u8 y; + u8 z; + double Time; +}; +struct SRecordingAll +{ + std::vector Recording; + int HotKey; + int PlaybackSpeed; +}; #ifndef EXCLUDEMAIN_H extern bool g_EmulatorRunning; @@ -48,10 +63,20 @@ void DoInitialize(); extern bool g_RealWiiMotePresent; extern bool g_RealWiiMoteInitialized; extern bool g_EmulatedWiiMoteInitialized; + + // Update speed + extern int g_UpdateCounter; + extern double g_UpdateTime; + extern int g_UpdateWriteScreen; + extern int g_UpdateRate; + extern std::vector g_UpdateTimeList; - #if defined(HAVE_WX) && HAVE_WX - extern ConfigDialog *frame; - #endif + // Movement recording + extern std::vector VRecording; + + //#if defined(HAVE_WX) && HAVE_WX && defined(__CONFIGDIALOG_h__) + // extern ConfigDialog *frame; + //#endif #endif //////////////////////////////// diff --git a/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.cpp b/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.cpp index 59b8637dae..a88a38327e 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.cpp +++ b/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.cpp @@ -32,8 +32,9 @@ #include "wiimote_hid.h" #include "main.h" +#include "Config.h" #include "EmuMain.h" -#define EXCLUDE_H // Avoid certain declarations in main.h +#define EXCLUDE_H // Avoid certain declarations in wiimote_real.h #include "wiimote_real.h" #if defined(HAVE_WX) && HAVE_WX #include "ConfigDlg.h" @@ -67,6 +68,7 @@ int g_NumberOfWiiMotes; CWiiMote* g_WiiMotes[MAX_WIIMOTES]; bool g_Shutdown = false; bool g_LocalThread = true; +bool g_MotionSensing = false; //****************************************************************************** // Probably this class should be in its own file @@ -121,8 +123,10 @@ void SendData(u16 _channelID, const u8* _pData, u32 _Size) ///////////////////// -////////////////////////////////////////// -// Read data from wiimote (but don't send it to the core, just filter and queue) +////////////////////////////////////////////////// +/* Read data from wiimote (but don't send it to the core, just filter and queue). If we are not currently + using the real Wiimote we only allow it to receive data mode changes, but don't ask for any data in + return */ // --------------- void ReadData() { @@ -131,6 +135,7 @@ void ReadData() // Send data to the Wiimote if (!m_EventWriteQueue.empty()) { + Console::Print("Writing data to the Wiimote\n"); SEvent& rEvent = m_EventWriteQueue.front(); wiiuse_io_write(m_pWiiMote, (byte*)rEvent.m_PayLoad, MAX_PAYLOAD); m_EventWriteQueue.pop(); @@ -138,35 +143,37 @@ void ReadData() m_pCriticalSection->Leave(); - if (wiiuse_io_read(m_pWiiMote)) - { - const byte* pBuffer = m_pWiiMote->event_buf; + // Don't queue up data if we are not using the real Wiimote + if(g_Config.bUseRealWiimote) + if (wiiuse_io_read(m_pWiiMote)) + { + const byte* pBuffer = m_pWiiMote->event_buf; - // Check if we have a channel (connection) if so save the data... - if (m_channelID > 0) - { - m_pCriticalSection->Enter(); + // Check if we have a channel (connection) if so save the data... + if (m_channelID > 0) + { + m_pCriticalSection->Enter(); - // Filter out reports - if (pBuffer[0] >= 0x30) - { - // Copy Buffer to LastReport - memcpy(m_LastReport.m_PayLoad, pBuffer, MAX_PAYLOAD); - m_LastReportValid = true; - } - else - { - // Copy Buffer to ImportantEvent - SEvent ImportantEvent; - memcpy(ImportantEvent.m_PayLoad, pBuffer, MAX_PAYLOAD); - m_EventReadQueue.push(ImportantEvent); - } - m_pCriticalSection->Leave(); - } + // Filter out reports + if (pBuffer[0] >= 0x30) + { + // Copy Buffer to LastReport + memcpy(m_LastReport.m_PayLoad, pBuffer, MAX_PAYLOAD); + m_LastReportValid = true; + } + else + { + // Copy Buffer to ImportantEvent + SEvent ImportantEvent; + memcpy(ImportantEvent.m_PayLoad, pBuffer, MAX_PAYLOAD); + m_EventReadQueue.push(ImportantEvent); + } + m_pCriticalSection->Leave(); + } - //std::string Temp = ArrayToString(pBuffer, sizeof(pBuffer), 0); - //Console::Print("Data:\n%s\n", Temp.c_str()); - } + //std::string Temp = ArrayToString(pBuffer, sizeof(pBuffer), 0); + //Console::Print("Data:\n%s\n", Temp.c_str()); + } }; ///////////////////// @@ -181,10 +188,12 @@ void Update() if (m_EventReadQueue.empty()) { + // Send the same data as last time if (m_LastReportValid) SendEvent(m_LastReport); } else { + // Send all the new data we have collected SendEvent(m_EventReadQueue.front()); m_EventReadQueue.pop(); } @@ -352,7 +361,11 @@ void Update() } ////////////////////////////////// -// Continuously read the Wiimote status +/* Continuously read the Wiimote status. However, the actual sending of data occurs in Update(). If we are + not currently using the real Wiimote we allow the separate ReadWiimote() function to run. Todo: Figure + out how to manually send the current data reporting mode to the real Wiimote so that we can entirely turn + off ReadData() (including wiiuse_io_write()) while we are not using the real wiimote. For example to risk + interrupting accelerometer recordings by a wiiuse_io_write(). */ // --------------- #ifdef _WIN32 DWORD WINAPI ReadWiimote_ThreadFunc(void* arg) @@ -364,7 +377,7 @@ void Update() { if(g_EmulatorRunning) for (int i = 0; i < g_NumberOfWiiMotes; i++) g_WiiMotes[i]->ReadData(); - else + else if (!g_Config.bUseRealWiimote) ReadWiimote(); } return 0; diff --git a/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.h b/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.h index 6ccdf89668..efdf384fe9 100644 --- a/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.h +++ b/Source/Plugins/Plugin_Wiimote/Src/wiimote_real.h @@ -43,6 +43,7 @@ void ReadWiimote(); #ifndef EXCLUDE_H extern wiimote_t** g_WiiMotesFromWiiUse; extern int g_NumberOfWiiMotes; + extern bool g_MotionSensing; #endif }; // WiiMoteReal