From 718aa585e2f3b65eecb672729a0481d76aacc6f8 Mon Sep 17 00:00:00 2001 From: John Peterson Date: Mon, 16 Feb 2009 06:18:18 +0000 Subject: [PATCH] Rerecording: Added frame step function and status bar for the input recording. Turn on frame stepping with Ctrl, step with Space. Build the Rerecording version with the setting in Setup.h. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@2273 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/Setup.h | 3 + Source/Core/Common/Src/StringUtil.cpp | 11 +- Source/Core/Common/Src/Timer.cpp | 85 ++++++- Source/Core/Common/Src/Timer.h | 11 +- Source/Core/Core/Core.vcproj | 214 +----------------- Source/Core/Core/Src/Core.cpp | 6 +- Source/Core/Core/Src/Core.h | 13 +- Source/Core/Core/Src/CoreRerecording.cpp | 211 +++++++++++++++++ Source/Core/Core/Src/Host.h | 2 +- Source/Core/DolphinWX/Src/Frame.cpp | 32 ++- Source/Core/DolphinWX/Src/Frame.h | 1 - Source/Core/DolphinWX/Src/FrameTools.cpp | 39 +++- Source/Core/DolphinWX/Src/FrameWiimote.cpp | 105 ++++++++- Source/Core/DolphinWX/Src/Main.cpp | 22 +- Source/MusicMod.sln | 4 - .../Plugin_PadSimple/Src/GUI/ConfigDlg.cpp | 112 +++++---- .../Plugin_PadSimple/Src/PadSimple.cpp | 60 ++++- .../Plugins/Plugin_PadSimple/Src/PadSimple.h | 3 + 18 files changed, 624 insertions(+), 310 deletions(-) create mode 100644 Source/Core/Core/Src/CoreRerecording.cpp diff --git a/Source/Core/Common/Src/Setup.h b/Source/Core/Common/Src/Setup.h index 30f3f65159..2fee9e9706 100644 --- a/Source/Core/Common/Src/Setup.h +++ b/Source/Core/Common/Src/Setup.h @@ -46,6 +46,9 @@ // This may remove sound artifacts in Wario Land Shake It and perhaps other games //#define SETUP_AVOID_SOUND_ARTIFACTS +// Build with playback rerecording options +//#define RERECORDING + // Build with music modification //#define MUSICMOD diff --git a/Source/Core/Common/Src/StringUtil.cpp b/Source/Core/Common/Src/StringUtil.cpp index 9a7da21740..7dc468fc75 100644 --- a/Source/Core/Common/Src/StringUtil.cpp +++ b/Source/Core/Common/Src/StringUtil.cpp @@ -405,13 +405,12 @@ int ChooseStringFrom(const char* str, const char* * items) // Thousand separator. Turns 12345678 into 12,345,678. -std::string ThS(int a, bool b) +std::string ThS(int Integer, bool Unsigned) { - char cbuf[20]; - - // determine treatment of signed or unsigned - if(b) sprintf(cbuf, "%u", a); else sprintf(cbuf, "%i", a); - + // Create storage space + char cbuf[20]; + // Determine treatment of signed or unsigned + if(Unsigned) sprintf(cbuf, "%u", Integer); else sprintf(cbuf, "%i", Integer); std::string sbuf = cbuf; for (u32 i = 0; i < sbuf.length(); ++i) diff --git a/Source/Core/Common/Src/Timer.cpp b/Source/Core/Common/Src/Timer.cpp index 641a28e8ae..28eb67c33b 100644 --- a/Source/Core/Common/Src/Timer.cpp +++ b/Source/Core/Common/Src/Timer.cpp @@ -25,6 +25,7 @@ #include "Common.h" #include "Timer.h" +#include "StringUtil.h" #ifdef __GNUC__ u32 timeGetTime() @@ -38,8 +39,15 @@ u32 timeGetTime() namespace Common { + + +////////////////////////////////////////////////////////////////////////////////////////// +// Initiate, Start, Stop, and Update the time +// --------------- + +// Set initial values for the class Timer::Timer(void) - : m_LastTime(0) + : m_LastTime(0), m_StartTime(0), m_Running(false) { Update(); @@ -48,20 +56,90 @@ Timer::Timer(void) #endif } +// Write the starting time +void Timer::Start() +{ + m_StartTime = timeGetTime(); + m_Running = true; +} +// Stop the timer +void Timer::Stop() +{ + // Write the final time + m_LastTime = timeGetTime(); + m_Running = false; +} + +// Update the last time variable void Timer::Update(void) { m_LastTime = timeGetTime(); //TODO(ector) - QPF } +///////////////////////////////////// + +////////////////////////////////////////////////////////////////////////////////////////// +// Get time difference and elapsed time +// --------------- + +// Get the number of milliseconds since the last Update() s64 Timer::GetTimeDifference(void) { return(timeGetTime() - m_LastTime); } +// Add the time difference since the last Update() to the starting time +void Timer::AddTimeDifference() +{ + m_StartTime += GetTimeDifference(); +} +// Get the time elapsed since the Start() +u64 Timer::GetTimeElapsed(void) +{ + /* If we have not started yet return 1 (because then I don't have to change the FPS + calculation in CoreRerecording.cpp */ + if (m_StartTime == 0) return 1; + + // Rrturn the final timer time if the timer is stopped + if (!m_Running) return (m_LastTime - m_StartTime); + + return (timeGetTime() - m_StartTime); +} + +// Get the formattet time elapsed since the Start() +std::string Timer::GetTimeElapsedFormatted(void) +{ + // If we have not started yet, return zero + if(m_StartTime == 0) return "00:00:00:000"; + + // The number of milliseconds since the start, use a different value if the timer is stopped + u32 Milliseconds; + if(m_Running) + Milliseconds = timeGetTime() - m_StartTime; + else + Milliseconds = m_LastTime - m_StartTime; + // Seconds + u32 Seconds = Milliseconds / 1000; + // Minutes + u32 Minutes = Seconds / 60; + // Hours + u32 Hours = Minutes / 60; + + std::string TmpStr = StringFromFormat("%02i:%02i:%02i:%03i", Hours, Minutes % 60, Seconds % 60, Milliseconds % 1000); + return TmpStr; +} + +///////////////////////////////////// + + + +////////////////////////////////////////////////////////////////////////////////////////// +// Get current time +// --------------- void Timer::IncreaseResolution() { #ifdef _WIN32 @@ -86,6 +164,7 @@ void _time64(u64* t) #endif +// Get the number of seconds since January 1 1970 u64 Timer::GetTimeSinceJan1970(void) { time_t ltime; @@ -106,6 +185,7 @@ u64 Timer::GetLocalTimeSinceJan1970(void) return (u64)(sysTime + tzDiff); } +// Return the current time formatted as Minutes:Seconds:Milliseconds in the form 00:00:000 std::string Timer::GetTimeFormatted(void) { struct timeb tp; @@ -115,4 +195,7 @@ std::string Timer::GetTimeFormatted(void) return std::string(temp); } +///////////////////////////////////// + + } // end of namespace Common diff --git a/Source/Core/Common/Src/Timer.h b/Source/Core/Common/Src/Timer.h index be8ee4a11c..946191d79d 100644 --- a/Source/Core/Common/Src/Timer.h +++ b/Source/Core/Common/Src/Timer.h @@ -29,11 +29,13 @@ class Timer Timer(); + void Start(); + void Stop(); void Update(); - - // Always in milliseconds, regardless of alternative internal representation + // The time difference is always returned in milliseconds, regardless of alternative internal representation s64 GetTimeDifference(void); + void AddTimeDifference(); static void IncreaseResolution(); static void RestoreResolution(); @@ -41,12 +43,15 @@ class Timer static u64 GetLocalTimeSinceJan1970(); static std::string GetTimeFormatted(); - + std::string GetTimeElapsedFormatted(); + u64 Timer::GetTimeElapsed(); public: u64 m_LastTime; + u64 m_StartTime; u64 m_frequency; + bool m_Running; }; } // end of namespace Common diff --git a/Source/Core/Core/Core.vcproj b/Source/Core/Core/Core.vcproj index 6e7aaa5404..ae38ec2be0 100644 --- a/Source/Core/Core/Core.vcproj +++ b/Source/Core/Core/Core.vcproj @@ -1433,20 +1433,6 @@ Name="VCCLCompilerTool" /> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + diff --git a/Source/Core/Core/Src/Core.cpp b/Source/Core/Core/Src/Core.cpp index 313908ab23..0995a36412 100644 --- a/Source/Core/Core/Src/Core.cpp +++ b/Source/Core/Core/Src/Core.cpp @@ -78,7 +78,7 @@ namespace Core ////////////////////////////////////////////////////////////////////////////////////////// // Declarations and definitions -// +// ------------ // Function forwarding //void Callback_VideoRequestWindowSize(int _iWidth, int _iHeight, BOOL _bFullscreen); @@ -587,6 +587,10 @@ void Callback_VideoLog(const TCHAR *_szMessage, int _bDoBreak) // We do not touch anything outside this function here void Callback_VideoCopiedToXFB() { + #ifdef RERECORDING + FrameUpdate(); + #endif + SCoreStartupParameter& _CoreParameter = SConfig::GetInstance().m_LocalCoreStartupParameter; //count FPS static Common::Timer Timer; diff --git a/Source/Core/Core/Src/Core.h b/Source/Core/Core/Src/Core.h index 0cd70634d9..aedd8ffc8a 100644 --- a/Source/Core/Core/Src/Core.h +++ b/Source/Core/Core/Src/Core.h @@ -55,7 +55,6 @@ namespace Core const SCoreStartupParameter& GetStartupParameter(); extern SCoreStartupParameter g_CoreStartupParameter; - // Make a screen shot bool MakeScreenshot(const std::string& _rFilename); void* GetWindowHandle(); @@ -73,6 +72,18 @@ namespace Core int SyncTrace(); void SetBlockStart(u32 addr); void StopTrace(); + + #ifdef RERECORDING + void FrameUpdate(); + void FrameAdvance(); + void FrameStepOnOff(); + void WriteStatus(); + void RerecordingStart(); + void RerecordingStop(); + extern int g_FrameCounter; + extern bool g_FrameStep; + #endif + } // namespace #endif diff --git a/Source/Core/Core/Src/CoreRerecording.cpp b/Source/Core/Core/Src/CoreRerecording.cpp new file mode 100644 index 0000000000..e5d720afab --- /dev/null +++ b/Source/Core/Core/Src/CoreRerecording.cpp @@ -0,0 +1,211 @@ +// Copyright (C) 2003-2008 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/ + + +#include "Setup.h" +#ifdef RERECORDING + + +////////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +#ifdef _WIN32 + #include +#endif + +#include "Thread.h" // Common + +#include "Timer.h" +#include "Common.h" +#include "ConsoleWindow.h" + +#include "Console.h" +#include "Core.h" +#include "CPUDetect.h" +#include "CoreTiming.h" +#include "Boot/Boot.h" +#include "PatchEngine.h" + +#include "HW/Memmap.h" +#include "HW/PeripheralInterface.h" +#include "HW/GPFifo.h" +#include "HW/CPU.h" +#include "HW/CPUCompare.h" +#include "HW/HW.h" +#include "HW/DSP.h" +#include "HW/GPFifo.h" +#include "HW/AudioInterface.h" +#include "HW/VideoInterface.h" +#include "HW/CommandProcessor.h" +#include "HW/PixelEngine.h" +#include "HW/SystemTimers.h" + +#include "PowerPC/PowerPC.h" + +#include "PluginManager.h" +#include "ConfigManager.h" + +#include "MemTools.h" +#include "Host.h" +#include "LogManager.h" +//////////////////////////////////////// + + + +/////////////////////////////////////////////////////////////////////////////////////////// +// File description: Rerecording Functions +/* ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +How the timer works: We measure the time between drawn frames, not when the game is paused. So time +should be a fairly comparable measure of the time it took to play the game. However the time it takes +to draw a frame will be lower on a fast computer. Therefore we could perhaps measure time as an +internal game time that is adjusted by the average time it takes to draw a frame. Also if it only takes +ten or twenty milliseconds to draw a frame I'm not certain about how accurate the mmsystem timers are for +such short periods. + +//////////////////////////////////////*/ + + + +namespace Core +{ + + +/////////////////////////////////////////////////////////////////////////////////////////// +// Declarations and definitions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +int g_FrameCounter = 0; +bool g_FrameStep = false; +Common::Timer ReRecTimer; +//////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////// +// Control Run, Pause, Stop and the Timer. +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +// Subtract the paused time when we run again +void Run() +{ + ReRecTimer.AddTimeDifference(); +} +// Update the time +void Pause() +{ + ReRecTimer.Update(); +} + +// Start the timer when a game is booted +void RerecordingStart() +{ + g_FrameCounter == 0; + ReRecTimer.Start(); +} + +// Reset the frame counter +void RerecordingStop() +{ + // Write the final time and Stop the timer + ReRecTimer.Stop(); + + // Update status bar + WriteStatus(); +} +//////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////// +// Frame advance +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ +void FrameAdvance() +{ + // Update status bar + WriteStatus(); + + // If a game is not started, return + if(Core::GetState() == Core::CORE_UNINITIALIZED) return; + + // Play to the next frame + if(g_FrameStep) + { + Run(); + Core::SetState(Core::CORE_RUN); + } + +} +// Turn on frame stepping +void FrameStepOnOff() +{ + /* Turn frame step on or off. If a game is running and we turn this on it means that the game + will pause after the next frame update */ + g_FrameStep = !g_FrameStep; + + // Update status bar + WriteStatus(); + + // If a game is not started, return + if(Core::GetState() == Core::CORE_UNINITIALIZED) return; + + // Run the emulation if we turned off framestepping + if (!g_FrameStep) + { + Run(); + Core::SetState(Core::CORE_RUN); + } +} +//////////////////////////////////////// + + +/////////////////////////////////////////////////////////////////////////////////////////// +// General functions +// ŻŻŻŻŻŻŻŻŻŻŻŻŻŻŻ + +// Write to the status bar +void WriteStatus() +{ + std::string TmpStr = "Time: " + ReRecTimer.GetTimeElapsedFormatted(); + TmpStr += StringFromFormat(" Frame: %s", ThS(g_FrameCounter).c_str()); + // The FPS is the total average since the game was booted + TmpStr += StringFromFormat(" FPS: %i", (g_FrameCounter * 1000) / ReRecTimer.GetTimeElapsed()); + TmpStr += StringFromFormat(" FrameStep: %s", g_FrameStep ? "On" : "Off"); + Host_UpdateStatusBar(TmpStr.c_str(), 1); +} + + +// When a new frame is drawn +void FrameUpdate() +{ + // Write to the status bar + WriteStatus(); + + // Pause if frame stepping is on + if(g_FrameStep) + { + Pause(); + Core::SetState(Core::CORE_PAUSE); + } + + // Count one frame + g_FrameCounter++; +} +//////////////////////////////////////// + + +} // Core + + +#endif // RERECORDING \ No newline at end of file diff --git a/Source/Core/Core/Src/Host.h b/Source/Core/Core/Src/Host.h index 9b35e2b705..2fc9933236 100644 --- a/Source/Core/Core/Src/Host.h +++ b/Source/Core/Core/Src/Host.h @@ -46,7 +46,7 @@ void Host_SetDebugMode(bool enable); void Host_SetWaitCursor(bool enable); -void Host_UpdateStatusBar(const char* _pText); +void Host_UpdateStatusBar(const char* _pText, int Filed = 0); void Host_SysMessage(const char *fmt, ...); void Host_SetWiiMoteConnectionState(int _State); diff --git a/Source/Core/DolphinWX/Src/Frame.cpp b/Source/Core/DolphinWX/Src/Frame.cpp index ffee57e50a..cafe8065f7 100644 --- a/Source/Core/DolphinWX/Src/Frame.cpp +++ b/Source/Core/DolphinWX/Src/Frame.cpp @@ -47,6 +47,8 @@ be accessed from Core::GetWindowHandle(). #include "Common.h" // Common #include "FileUtil.h" #include "Timer.h" +#include "Setup.h" +#include "ConsoleWindow.h" #include "ConfigManager.h" // Core #include "Core.h" @@ -352,6 +354,13 @@ CFrame::CFrame(wxFrame* parent, // ---------- UpdateGUI(); + + // If we are rerecording create the status bar now instead of later when a game starts + #ifdef RERECORDING + ModifyStatusBar(); + // It's to early for the OnHostMessage(), we will update the status when Ctrl or Space is pressed + //Core::WriteStatus(); + #endif } // Destructor @@ -439,18 +448,27 @@ void CFrame::OnKeyDown(wxKeyEvent& event) UpdateGUI(); } #ifdef _WIN32 - else if(event.GetKeyCode() == 'E') // Send this to the video plugin WndProc + if(event.GetKeyCode() == 'E') // Send this to the video plugin WndProc { PostMessage((HWND)Core::GetWindowHandle(), WM_KEYDOWN, event.GetKeyCode(), 0); event.Skip(); // Don't block the E key } #endif - else - { - if(Core::GetState() != Core::CORE_UNINITIALIZED) - CPluginManager::GetInstance().GetPad(0)->PAD_Input(event.GetKeyCode(), 1); // 1 = Down - event.Skip(); - } + +#ifdef RERECORDING + // Turn on or off frame advance + if (event.GetKeyCode() == WXK_CONTROL) Core::FrameStepOnOff(); + + // Step forward + if (event.GetKeyCode() == WXK_SPACE) Core::FrameAdvance(); +#endif + + // Send the keyboard status to the Input plugin + if(Core::GetState() != Core::CORE_UNINITIALIZED) + CPluginManager::GetInstance().GetPad(0)->PAD_Input(event.GetKeyCode(), 1); // 1 = Down + + // Don't block other events + event.Skip(); } void CFrame::OnKeyUp(wxKeyEvent& event) diff --git a/Source/Core/DolphinWX/Src/Frame.h b/Source/Core/DolphinWX/Src/Frame.h index 193fe08471..980e12066e 100644 --- a/Source/Core/DolphinWX/Src/Frame.h +++ b/Source/Core/DolphinWX/Src/Frame.h @@ -219,7 +219,6 @@ class CFrame : public wxFrame wxToolBarToolBase* m_pToolPlay; void UpdateGUI(); - void BootGame(); // Double click and mouse move options diff --git a/Source/Core/DolphinWX/Src/FrameTools.cpp b/Source/Core/DolphinWX/Src/FrameTools.cpp index 40b7a70f72..6af9108111 100644 --- a/Source/Core/DolphinWX/Src/FrameTools.cpp +++ b/Source/Core/DolphinWX/Src/FrameTools.cpp @@ -49,6 +49,7 @@ be accessed from Core::GetWindowHandle(). #include "FileUtil.h" #include "Timer.h" #include "ConsoleWindow.h" +#include "Setup.h" #include "ConfigManager.h" // Core #include "Core.h" @@ -316,7 +317,7 @@ void CFrame::InitBitmaps() } ////////////////////////////////////////////////// - // Music modification + // Music modification // ------------- #ifdef MUSICMOD MM_InitBitmaps(Theme); @@ -327,12 +328,21 @@ void CFrame::InitBitmaps() if (GetToolBar() != NULL) RecreateToolbar(); } + +////////////////////////////////////////////////////////////////////////////////////// +// Start the game or change the disc +// ------------- void CFrame::BootGame() { - #ifdef MUSICMOD // Music modification + // Music modification + #ifdef MUSICMOD MM_OnPlay(); #endif + // Rerecording + #ifdef RERECORDING + Core::RerecordingStart(); + #endif // shuffle2: wxBusyInfo is meant to be created on the stack // and only stay around for the life of the scope it's in. @@ -447,8 +457,16 @@ void CFrame::OnChangeDisc(wxCommandEvent& WXUNUSED (event)) DVDInterface::SetLidOpen(false); } +void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event)) +{ + BootGame(); +} +//////////////////////////////////////////////////// +////////////////////////////////////////////////////////////////////////////////////// +// Refresh the file list and browse for a favorites directory +// ------------- void CFrame::OnRefresh(wxCommandEvent& WXUNUSED (event)) { if (m_GameListCtrl) @@ -462,17 +480,23 @@ void CFrame::OnBrowse(wxCommandEvent& WXUNUSED (event)) { m_GameListCtrl->BrowseForDirectory(); } +//////////////////////////////////////////////////// -void CFrame::OnPlay(wxCommandEvent& WXUNUSED (event)) -{ - BootGame(); -} +////////////////////////////////////////////////////////////////////////////////////// +// Stop the emulation +// ------------- void CFrame::DoStop() { - #ifdef MUSICMOD // Music modification + // Music modification + #ifdef MUSICMOD MM_OnStop(); #endif + + // Rerecording + #ifdef RERECORDING + Core::RerecordingStop(); + #endif if (Core::GetState() != Core::CORE_UNINITIALIZED) { @@ -506,6 +530,7 @@ void CFrame::OnStop(wxCommandEvent& WXUNUSED (event)) if (answer) DoStop(); } +//////////////////////////////////////////////////// void CFrame::OnConfigMain(wxCommandEvent& WXUNUSED (event)) diff --git a/Source/Core/DolphinWX/Src/FrameWiimote.cpp b/Source/Core/DolphinWX/Src/FrameWiimote.cpp index 8e9c627e2e..d4d60dd3ec 100644 --- a/Source/Core/DolphinWX/Src/FrameWiimote.cpp +++ b/Source/Core/DolphinWX/Src/FrameWiimote.cpp @@ -16,15 +16,20 @@ // http://code.google.com/p/dolphin-emu/ +//////////////////////////////////////////////////////////////////////////////////////// +// Include +// ŻŻŻŻŻŻŻŻŻŻŻŻŻ #include "Globals.h" #include "Frame.h" #include "FileUtil.h" #include "StringUtil.h" +#include "ConsoleWindow.h" #include "GameListCtrl.h" #include "BootManager.h" #include "Common.h" +#include "Setup.h" #include "ConfigManager.h" #include "Core.h" #include "State.h" @@ -35,6 +40,7 @@ #include "AboutDolphin.h" #include +///////////////////////////////////////// namespace WiimoteLeds @@ -50,10 +56,18 @@ namespace WiimoteLeds int SpIconMargin = 11; int LedIconMargin = 11; + // The necessary recording status width, allow Frame to be at last of the form 100,000 + #ifdef RERECORDING + static const int RerecordingStatusWidth = 340; + #endif + // Leds only static const int LdWidthsOn[] = { -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif ConnectionStatusWidth, (LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin }; @@ -63,32 +77,61 @@ namespace WiimoteLeds static const int SpWidthsOn[] = { -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif ConnectionStatusWidth, ( SpIconMargin + SPEAKER_SIZE_X ) * 3 + RightmostMargin }; - static const int SpStylesFieldOn[] = { wxSB_NORMAL, wxSB_NORMAL, wxSB_NORMAL }; + static const int SpStylesFieldOn[] = { wxSB_NORMAL, + #ifdef RERECORDING + wxSB_NORMAL, + #endif + wxSB_NORMAL, wxSB_NORMAL }; // Both static const int LdSpWidthsOn[] = { -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif ConnectionStatusWidth, (SpIconMargin + SPEAKER_SIZE_X) * 3, (LedIconMargin + LED_SIZE_X) * 4 + RightmostMargin }; - static const int LdSpStylesFieldOn[] = { wxSB_NORMAL, wxSB_NORMAL, wxSB_NORMAL }; + static const int LdSpStylesFieldOn[] = { wxSB_NORMAL, + #ifdef RERECORDING + wxSB_NORMAL, + #endif + wxSB_NORMAL, wxSB_NORMAL }; // Only the Wiimote connection Status static const int WidthsOff[] = { -1, + #ifdef RERECORDING + RerecordingStatusWidth, + #endif ConnectionStatusWidth + ConnectionStatusOnlyAdj + RightmostMargin }; - static const int StylesFieldOff[] = { wxSB_NORMAL, wxSB_NORMAL }; + static const int StylesFieldOff[] = { wxSB_NORMAL, + #ifdef RERECORDING + wxSB_NORMAL, + #endif + wxSB_NORMAL }; // GC mode - static const int WidthsOffGC[] = { -1 }; - static const int StylesFieldOffGC[] = { wxSB_NORMAL }; + static const int WidthsOffGC[] = { -1 + #ifdef RERECORDING + , RerecordingStatusWidth + #endif + }; + static const int StylesFieldOffGC[] = { wxSB_NORMAL + #ifdef RERECORDING + , wxSB_NORMAL + #endif + }; }; // ======================================================= @@ -154,6 +197,11 @@ void CFrame::ModifyStatusBar() } } + // Add a filed for the rerecording status + #ifdef RERECORDING + Fields++; + #endif + // Update the settings m_pStatusBar->SetFieldsCount(Fields); m_pStatusBar->SetStatusWidths(Fields, Widths); @@ -352,13 +400,49 @@ void CFrame::DoMoveIcons() { if(HaveLeds) MoveLeds(); if(HaveSpeakers) MoveSpeakers(); + + // If there is not room for the led icons hide them + if(m_pStatusBar->GetFieldsCount() >= 2 && HaveLeds) + { + wxRect Rect; + #ifdef RERECORDING + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect); + #else + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); + #endif + if(Rect.GetWidth() < 20) + for (int i = 0; i < 4; i++) m_StatBmp[i]->Hide(); + else // if(!m_StatBmp[0]->IsShown()) + for (int i = 0; i < 4; i++) m_StatBmp[i]->Show(); + //Console::Print("LED: %i ", Rect.GetWidth()); + } + + // If there is not room for the speaker icons hide them + if(m_pStatusBar->GetFieldsCount() >= 2 && HaveSpeakers) + { + wxRect Rect; + #ifdef RERECORDING + m_pStatusBar->GetFieldRect(3, Rect); + #else + m_pStatusBar->GetFieldRect(2, Rect); + #endif + if(Rect.GetWidth() < 20) + for(int i = 0; i < 3; i++) m_StatBmp[i + 4]->Hide(); + else // if(!m_StatBmp[4]->IsShown()) + for (int i = 0; i < 3; i++) m_StatBmp[i + 4]->Show(); + //Console::Print("Speaker: %i\n", Rect.GetWidth()); + } } void CFrame::MoveLeds() { wxRect Rect; // Get the bitmap field coordinates - m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); + #ifdef RERECORDING + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 4 : 3, Rect); + #else + m_pStatusBar->GetFieldRect((HaveLeds && HaveSpeakers) ? 3 : 2, Rect); + #endif wxSize Size = m_StatBmp[0]->GetSize(); // Get the bitmap size //wxMessageBox(wxString::Format("%i", Rect.x)); @@ -376,7 +460,12 @@ void CFrame::MoveLeds() void CFrame::MoveSpeakers() { wxRect Rect; - m_pStatusBar->GetFieldRect(2, Rect); // Get the bitmap field coordinates + // Get the bitmap field coordinates + #ifdef RERECORDING + m_pStatusBar->GetFieldRect(3, Rect); + #else + m_pStatusBar->GetFieldRect(2, Rect); + #endif // Get the actual bitmap size, currently it's the same as SPEAKER_SIZE_Y wxSize Size = m_StatBmp[4]->GetSize(); @@ -389,7 +478,7 @@ void CFrame::MoveSpeakers() for(int i = 0; i < 3; i++) { if(i > 0) x = m_StatBmp[i-1+4]->GetPosition().x + Dist; - m_StatBmp[i+4]->Move(x, y); + m_StatBmp[i + 4]->Move(x, y); } } // ============== diff --git a/Source/Core/DolphinWX/Src/Main.cpp b/Source/Core/DolphinWX/Src/Main.cpp index 6668df4844..c238ef5174 100644 --- a/Source/Core/DolphinWX/Src/Main.cpp +++ b/Source/Core/DolphinWX/Src/Main.cpp @@ -38,6 +38,7 @@ #include "CPUDetect.h" #include "IniFile.h" #include "FileUtil.h" +#include "ConsoleWindow.h" #include "Main.h" // Local #include "Frame.h" @@ -92,10 +93,12 @@ LONG WINAPI MyUnhandledExceptionFilter(LPEXCEPTION_POINTERS e) { ///////////////////////////////////////////////////////////// -/* The `main program' equivalent that creates the mai nwindow and return the main frame */ +/* The `main program' equivalent that creates the main window and return the main frame */ // ŻŻŻŻŻŻŻŻŻ bool DolphinApp::OnInit() { + //Console::Open(); + // Declarations and definitions bool UseDebugger = false; bool UseLogger = false; @@ -442,15 +445,16 @@ void Host_SetWaitCursor(bool enable) SetCursor(LoadCursor(NULL, IDC_ARROW)); } #endif - } -void Host_UpdateStatusBar(const char* _pText) +void Host_UpdateStatusBar(const char* _pText, int Field) { wxCommandEvent event(wxEVT_HOST_COMMAND, IDM_UPDATESTATUSBAR); + // Set the event string event.SetString(wxString::FromAscii(_pText)); - event.SetInt(0); - + // Update statusbar field + event.SetInt(Field); + // Post message wxPostEvent(main_frame, event); } @@ -482,8 +486,12 @@ void Host_SetWiiMoteConnectionState(int _State) case 1: event.SetString(wxString::FromAscii("Connecting...")); break; case 2: event.SetString(wxString::FromAscii("Wiimote Connected")); break; } - - event.SetInt(1); + // Update field 1 or 2 + #ifdef RERECORDING + event.SetInt(2); + #else + event.SetInt(1); + #endif wxPostEvent(main_frame, event); } diff --git a/Source/MusicMod.sln b/Source/MusicMod.sln index b790a4d106..28cc39824f 100644 --- a/Source/MusicMod.sln +++ b/Source/MusicMod.sln @@ -351,7 +351,6 @@ Global {D6E56527-BBB9-4EAD-A6EC-49D4BF6AFCD8}.Release JITIL|x64.ActiveCfg = Release|x64 {D6E56527-BBB9-4EAD-A6EC-49D4BF6AFCD8}.Release JITIL|x64.Build.0 = Release|x64 {D6E56527-BBB9-4EAD-A6EC-49D4BF6AFCD8}.Release|Win32.ActiveCfg = Release|Win32 - {D6E56527-BBB9-4EAD-A6EC-49D4BF6AFCD8}.Release|Win32.Build.0 = Release|Win32 {D6E56527-BBB9-4EAD-A6EC-49D4BF6AFCD8}.Release|x64.ActiveCfg = Release|x64 {33546D62-7F34-4EA6-A88E-D538B36E16BF}.Debug|Win32.ActiveCfg = Debug|Win32 {33546D62-7F34-4EA6-A88E-D538B36E16BF}.Debug|x64.ActiveCfg = Debug|x64 @@ -454,7 +453,6 @@ Global {95CCAABC-7062-47C4-B8C1-A064DD5F16FF}.Release JITIL|x64.ActiveCfg = Release|x64 {95CCAABC-7062-47C4-B8C1-A064DD5F16FF}.Release JITIL|x64.Build.0 = Release|x64 {95CCAABC-7062-47C4-B8C1-A064DD5F16FF}.Release|Win32.ActiveCfg = Release|Win32 - {95CCAABC-7062-47C4-B8C1-A064DD5F16FF}.Release|Win32.Build.0 = Release|Win32 {95CCAABC-7062-47C4-B8C1-A064DD5F16FF}.Release|x64.ActiveCfg = Release|x64 {95CCAABC-7062-47C4-B8C1-A064DD5F16FF}.Release|x64.Build.0 = Release|x64 {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Debug|Win32.ActiveCfg = Debug|Win32 @@ -469,7 +467,6 @@ Global {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Release JITIL|x64.ActiveCfg = Release|x64 {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Release JITIL|x64.Build.0 = Release|x64 {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Release|Win32.ActiveCfg = Release|Win32 - {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Release|Win32.Build.0 = Release|Win32 {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Release|x64.ActiveCfg = Release|x64 {0B72B5D6-5D72-4391-84A7-9CCA5392668A}.Release|x64.Build.0 = Release|x64 {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Debug|Win32.ActiveCfg = Debug|Win32 @@ -484,7 +481,6 @@ Global {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release JITIL|x64.ActiveCfg = Release|x64 {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release JITIL|x64.Build.0 = Release|x64 {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|Win32.ActiveCfg = Release|Win32 - {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|Win32.Build.0 = Release|Win32 {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|x64.ActiveCfg = Release|x64 {0D14F1E9-490B-4A2D-A4EF-0535E8B3C718}.Release|x64.Build.0 = Release|x64 EndGlobalSection diff --git a/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp b/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp index 9366906aa5..70550972f4 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp +++ b/Source/Plugins/Plugin_PadSimple/Src/GUI/ConfigDlg.cpp @@ -36,10 +36,13 @@ BEGIN_EVENT_TABLE(ConfigDialog,wxDialog) EVT_CHOICE(ID_X360PAD_CHOICE,ConfigDialog::ControllerSettingsChanged) EVT_CHECKBOX(ID_RUMBLE,ConfigDialog::ControllerSettingsChanged) EVT_CHECKBOX(ID_DISABLE,ConfigDialog::ControllerSettingsChanged) - //Recording - EVT_CHECKBOX(ID_RECORDING,ConfigDialog::ControllerSettingsChanged) - EVT_CHECKBOX(ID_PLAYBACK,ConfigDialog::ControllerSettingsChanged) - EVT_BUTTON(ID_SAVE_RECORDING,ConfigDialog::ControllerSettingsChanged) + + // Input recording + #ifdef RERECORDING + EVT_CHECKBOX(ID_RECORDING,ConfigDialog::ControllerSettingsChanged) + EVT_CHECKBOX(ID_PLAYBACK,ConfigDialog::ControllerSettingsChanged) + EVT_BUTTON(ID_SAVE_RECORDING,ConfigDialog::ControllerSettingsChanged) + #endif EVT_BUTTON(CTL_A,ConfigDialog::OnButtonClick) EVT_BUTTON(CTL_B,ConfigDialog::OnButtonClick) @@ -182,36 +185,9 @@ void ConfigDialog::CreateGUIControls() m_SizeXInput[i]->Add(m_X360PadC[i], 0, wxEXPAND | wxALL, 1); m_SizeXInput[i]->Add(m_Rumble[i], 0, wxEXPAND | wxALL, 1); #endif - - m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording")); - m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input")); - m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input")); - m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize); - - // Tool tips - m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game")); - m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir")); - m_BtnSaveRecording[i]->SetToolTip(wxT( - "This will save the current recording to pad-record.bin. Your recording will\n" - "also be automatically saved every 60 * 10 frames. And when you shut down the\n" - "game.")); - - m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1); - m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1); - m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1); - // Set values m_Attached[i]->SetValue(pad[i].bAttached); m_Disable[i]->SetValue(pad[i].bDisable); - m_CheckRecording[i]->SetValue(pad[i].bRecording); - m_CheckPlayback[i]->SetValue(pad[i].bPlayback); - - // Only enable these options for pad 0 - m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true); - m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true); - m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true); - // Don't allow saving when we are not recording - m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && pad[0].bRecording); #ifdef _WIN32 // Check if any XInput pad was found @@ -239,12 +215,50 @@ void ConfigDialog::CreateGUIControls() //sDevice[i]->AddStretchSpacer(); #ifdef _WIN32 sDevice[i]->Add(m_SizeXInput[i], 0, wxEXPAND | wxALL, 1); - sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1); - #endif // ----------------------------------- + ///////////////////////////////////////////////////////////////////////////////////// + // Rerecording + // ŻŻŻŻŻŻŻŻŻ + #ifdef RERECORDING + // Create controls + m_SizeRecording[i] = new wxStaticBoxSizer(wxVERTICAL, m_Controller[i], wxT("Input Recording")); + m_CheckRecording[i] = new wxCheckBox(m_Controller[i], ID_RECORDING, wxT("Record input")); + m_CheckPlayback[i] = new wxCheckBox(m_Controller[i], ID_PLAYBACK, wxT("Play back input")); + m_BtnSaveRecording[i] = new wxButton(m_Controller[i], ID_SAVE_RECORDING, wxT("Save recording"), wxDefaultPosition, wxDefaultSize); + + // Tool tips + m_CheckRecording[i]->SetToolTip(wxT("Your recording will be saved to pad-record.bin in the Dolphin dir when you stop the game")); + m_CheckPlayback[i]->SetToolTip(wxT("Play back the pad-record.bin file from the Dolphin dir")); + m_BtnSaveRecording[i]->SetToolTip(wxT( + "This will save the current recording to pad-record.bin. Your recording will\n" + "also be automatically saved every 60 * 10 frames. And when you shut down the\n" + "game.")); + + // Sizers + m_SizeRecording[i]->Add(m_CheckRecording[i], 0, wxEXPAND | wxALL, 1); + m_SizeRecording[i]->Add(m_CheckPlayback[i], 0, wxEXPAND | wxALL, 1); + m_SizeRecording[i]->Add(m_BtnSaveRecording[i], 0, wxEXPAND | wxALL, 1); + + // Only enable these options for pad 0 + m_CheckRecording[i]->Enable(false); m_CheckRecording[0]->Enable(true); + m_CheckPlayback[i]->Enable(false); m_CheckPlayback[0]->Enable(true); + m_BtnSaveRecording[i]->Enable(false); m_BtnSaveRecording[0]->Enable(true); + // Don't allow saving when we are not recording + m_BtnSaveRecording[i]->Enable(g_EmulatorRunning && pad[0].bRecording); + sDevice[i]->Add(m_SizeRecording[i], 0, wxEXPAND | wxALL, 1); + + // Set values + m_CheckRecording[0]->SetValue(pad[0].bRecording); + m_CheckPlayback[0]->SetValue(pad[0].bPlayback); + + Console::Print("m_CheckRecording: %i\n", pad[0].bRecording, pad[0].bPlayback); + #endif + ////////////////////////////////////// + + // -------------------------------------------------------------------- // Buttons // ----------------------------- @@ -400,21 +414,23 @@ void ConfigDialog::ControllerSettingsChanged(wxCommandEvent& event) pad[page].bRumble = m_Rumble[page]->GetValue(); break; - case ID_RECORDING: - pad[page].bRecording = m_CheckRecording[page]->GetValue(); - // Turn off the other option - pad[page].bPlayback = false; m_CheckPlayback[page]->SetValue(false); - break; - case ID_PLAYBACK: - pad[page].bPlayback = m_CheckPlayback[page]->GetValue(); - // Turn off the other option - pad[page].bRecording = false; m_CheckRecording[page]->SetValue(false); - break; - case ID_SAVE_RECORDING: - // Double check again that we are still running a game - if (g_EmulatorRunning) SaveRecord(); - break; - + // Input recording + #ifdef RERECORDING + case ID_RECORDING: + pad[page].bRecording = m_CheckRecording[page]->GetValue(); + // Turn off the other option + pad[page].bPlayback = false; m_CheckPlayback[page]->SetValue(false); + break; + case ID_PLAYBACK: + pad[page].bPlayback = m_CheckPlayback[page]->GetValue(); + // Turn off the other option + pad[page].bRecording = false; m_CheckRecording[page]->SetValue(false); + break; + case ID_SAVE_RECORDING: + // Double check again that we are still running a game + if (g_EmulatorRunning) SaveRecord(); + break; + #endif } } diff --git a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp index bdac428279..934a74baa2 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp +++ b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.cpp @@ -28,6 +28,7 @@ #include "IniFile.h" #include "ConsoleWindow.h" #include "StringUtil.h" +#include "FileUtil.h" #include "ChunkFile.h" #if defined(HAVE_WX) && HAVE_WX @@ -617,7 +618,10 @@ void DllConfig(HWND _hParent) { //Console::Open(70, 5000); + // Load configuration LoadConfig(); + + // Show wxDialog #ifdef _WIN32 wxWindow win; win.SetHWND(_hParent); @@ -628,6 +632,8 @@ void DllConfig(HWND _hParent) ConfigDialog frame(NULL); frame.ShowModal(); #endif + + // Save configuration SaveConfig(); } @@ -643,8 +649,29 @@ void Initialize(void *init) // Load configuration LoadConfig(); + // ------------------------------------------- + // Rerecording + // ---------------------- + #ifdef RERECORDING + /* Check if we are starting the pad to record the input, and an old file exists. In that case ask + if we really want to start the recording and eventually overwrite the file */ + if (pad[0].bRecording && File::Exists("pad-record.bin")) + { + if (!AskYesNo("An old version of '%s' aleady exists in your Dolphin directory. You can" + " now make a copy of it before you start a new recording and overwrite the file." + " Select Yes to continue and overwrite the file. Select No to turn off the input" + " recording and continue without recording anything.", + "pad-record.bin")) + { + // Turn off recording and continue + pad[0].bRecording = false; + } + } + // Load recorded input if we are to play it back, otherwise begin with a blank recording if (pad[0].bPlayback) LoadRecord(); + #endif + // ---------------------- g_PADInitialize = *(SPADInitialize*)init; @@ -668,10 +695,17 @@ void Shutdown() { //Console::Print("ShutDown()\n"); + // ------------------------------------------- + // Play back input instead of accepting any user input + // ---------------------- + #ifdef RERECORDING // Save recording if (pad[0].bRecording) SaveRecord(); // Reset the counter count = 0; + #endif + // ---------------------- + // We have stopped the game g_EmulatorRunning = false; @@ -699,12 +733,17 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) // Check if all is okay if (_pPADStatus == NULL) return; + // ------------------------------------------- // Play back input instead of accepting any user input + // ---------------------- + #ifdef RERECORDING if (pad[0].bPlayback) { *_pPADStatus = PlayRecord(); return; } + #endif + // ---------------------- const int base = 0x80; // Clear pad @@ -736,8 +775,14 @@ void PAD_GetStatus(u8 _numPAD, SPADStatus* _pPADStatus) cocoa_Read(_numPAD, _pPADStatus); #endif + // ------------------------------------------- + // Rerecording + // ---------------------- + #ifdef RERECORDING // Record input if (pad[0].bRecording) RecordInput(*_pPADStatus); + #endif + // ---------------------- } @@ -890,9 +935,12 @@ void LoadConfig() file.Get(SectionName, "DisableOnBackground", &pad[i].bDisable, false); file.Get(SectionName, "Rumble", &pad[i].bRumble, true); file.Get(SectionName, "XPad#", &pad[i].XPadPlayer); - - file.Get(SectionName, "Recording", &pad[i].bRecording, false); - file.Get(SectionName, "Playback", &pad[i].bPlayback, false); + + // Recording + #ifdef RERECORDING + file.Get(SectionName, "Recording", &pad[0].bRecording, false); + file.Get(SectionName, "Playback", &pad[0].bPlayback, false); + #endif for (int x = 0; x < NUMCONTROLS; x++) { @@ -924,8 +972,10 @@ void SaveConfig() file.Set(SectionName, "Rumble", pad[i].bRumble); file.Set(SectionName, "XPad#", pad[i].XPadPlayer); // Recording - file.Set(SectionName, "Recording", pad[i].bRecording); - file.Set(SectionName, "Playback", pad[i].bPlayback); + #ifdef RERECORDING + file.Set(SectionName, "Recording", pad[0].bRecording); + file.Set(SectionName, "Playback", pad[0].bPlayback); + #endif for (int x = 0; x < NUMCONTROLS; x++) { diff --git a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h index ee2b055659..0e503f0d17 100644 --- a/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h +++ b/Source/Plugins/Plugin_PadSimple/Src/PadSimple.h @@ -18,6 +18,9 @@ #ifndef __PADSIMPLE_H__ #define __PADSIMPLE_H__ +#include "Setup.h" // Common +#include "ConsoleWindow.h" + // Controls enum {