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
This commit is contained in:
John Peterson 2009-02-16 06:18:18 +00:00
parent 7d3e84c182
commit 718aa585e2
18 changed files with 624 additions and 310 deletions

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -1433,20 +1433,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\IR.h"
@ -1503,20 +1489,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit.h"
@ -1573,20 +1545,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_FloatingPoint.cpp"
@ -1639,20 +1597,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_Integer.cpp"
@ -1705,20 +1649,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_LoadStore.cpp"
@ -1771,20 +1701,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_LoadStoreFloating.cpp"
@ -1837,20 +1753,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_LoadStorePaired.cpp"
@ -1903,20 +1805,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_Paired.cpp"
@ -1969,20 +1857,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_SystemRegisters.cpp"
@ -2035,20 +1909,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\Jit_Util.cpp"
@ -2101,20 +1961,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\JitAsm.cpp"
@ -2167,20 +2013,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\JitAsm.h"
@ -2237,20 +2069,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\JitCache.cpp"
@ -2303,20 +2121,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\JitCache.h"
@ -2373,20 +2177,6 @@
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|Win32"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
<FileConfiguration
Name="Release_JITIL|x64"
>
<Tool
Name="VCCLCompilerTool"
/>
</FileConfiguration>
</File>
<File
RelativePath=".\Src\PowerPC\Jit64IL\JitRegCache.h"
@ -2646,6 +2436,10 @@
RelativePath=".\Src\CoreParameter.h"
>
</File>
<File
RelativePath=".\Src\CoreRerecording.cpp"
>
</File>
<File
RelativePath=".\Src\CoreTiming.cpp"
>

View File

@ -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;

View File

@ -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

View File

@ -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 <windows.h>
#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

View File

@ -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);

View File

@ -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)

View File

@ -219,7 +219,6 @@ class CFrame : public wxFrame
wxToolBarToolBase* m_pToolPlay;
void UpdateGUI();
void BootGame();
// Double click and mouse move options

View File

@ -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))

View File

@ -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 <wx/statusbr.h>
/////////////////////////////////////////
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);
}
}
// ==============

View File

@ -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);
}

View File

@ -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

View File

@ -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
}
}

View File

@ -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++)
{

View File

@ -18,6 +18,9 @@
#ifndef __PADSIMPLE_H__
#define __PADSIMPLE_H__
#include "Setup.h" // Common
#include "ConsoleWindow.h"
// Controls
enum
{