Mesen2/Core/Shared/Video/SystemHud.cpp

307 lines
No EOL
9.1 KiB
C++

#include "pch.h"
#include "Shared/Video/SystemHud.h"
#include "Shared/Video/DebugHud.h"
#include "Shared/Movies/MovieManager.h"
#include "Shared/MessageManager.h"
#include "Shared/BaseControlManager.h"
#include "Shared/Video/DrawStringCommand.h"
#include "Shared/Interfaces/IMessageManager.h"
SystemHud::SystemHud(Emulator* emu)
{
_emu = emu;
MessageManager::RegisterMessageManager(this);
}
SystemHud::~SystemHud()
{
MessageManager::UnregisterMessageManager(this);
}
void SystemHud::Draw(DebugHud* hud, uint32_t width, uint32_t height) const
{
DrawCounters(hud, width);
DrawMessages(hud, width, height);
if(_emu->IsRunning()) {
EmuSettings* settings = _emu->GetSettings();
bool showMovieIcons = settings->GetPreferences().ShowMovieIcons;
int xOffset = 0;
if(_emu->IsPaused()) {
DrawPauseIcon(hud);
} else if(showMovieIcons && _emu->GetMovieManager()->Playing()) {
DrawPlayIcon(hud);
xOffset += 12;
} else if(showMovieIcons && _emu->GetMovieManager()->Recording()) {
DrawRecordIcon(hud);
xOffset += 12;
}
bool showTurboRewindIcons = settings->GetPreferences().ShowTurboRewindIcons;
if(!_emu->IsPaused() && showTurboRewindIcons) {
if(settings->CheckFlag(EmulationFlags::Rewind)) {
DrawTurboRewindIcon(hud, true, xOffset);
} else if(settings->CheckFlag(EmulationFlags::Turbo)) {
DrawTurboRewindIcon(hud, false, xOffset);
}
}
}
}
void SystemHud::DrawMessage(DebugHud* hud, MessageInfo &msg, uint32_t screenWidth, uint32_t screenHeight, int& lastHeight) const
{
//Get opacity for fade in/out effect
uint8_t opacity = (uint8_t)(msg.GetOpacity() * 255);
int textLeftMargin = 4;
string text = "[" + msg.GetTitle() + "] " + msg.GetMessage();
int maxWidth = screenWidth - textLeftMargin;
TextSize size = DrawStringCommand::MeasureString(text, maxWidth);
lastHeight += size.Y;
DrawString(hud, screenWidth, text, textLeftMargin, screenHeight - lastHeight, opacity);
}
void SystemHud::DrawString(DebugHud* hud, uint32_t screenWidth, string text, int x, int y, uint8_t opacity) const
{
int maxWidth = screenWidth - x;
opacity = 255 - opacity;
for(int i = -1; i <= 1; i++) {
for(int j = -1; j <= 1; j++) {
hud->DrawString(x + i, y + j, text, 0 | (opacity << 24), 0xFF000000, 1, -1, maxWidth, true);
}
}
hud->DrawString(x, y, text, 0xFFFFFF | (opacity << 24), 0xFF000000, 1, -1, maxWidth, true);
}
void SystemHud::ShowFpsCounter(DebugHud* hud, uint32_t screenWidth, int lineNumber) const
{
int yPos = 10 + 10 * lineNumber;
string fpsString = string("FPS: ") + std::to_string(_currentFPS); // +" / " + std::to_string(_currentRenderedFPS);
uint32_t length = DrawStringCommand::MeasureString(fpsString).X;
DrawString(hud, screenWidth, fpsString, screenWidth - 8 - length, yPos);
}
void SystemHud::ShowGameTimer(DebugHud* hud, uint32_t screenWidth, int lineNumber) const
{
int yPos = 10 + 10 * lineNumber;
uint32_t frameCount = _emu->GetFrameCount();
double frameRate = _emu->GetFps();
uint32_t seconds = (uint32_t)(frameCount / frameRate) % 60;
uint32_t minutes = (uint32_t)(frameCount / frameRate / 60) % 60;
uint32_t hours = (uint32_t)(frameCount / frameRate / 3600);
std::stringstream ss;
ss << std::setw(2) << std::setfill('0') << hours << ":";
ss << std::setw(2) << std::setfill('0') << minutes << ":";
ss << std::setw(2) << std::setfill('0') << seconds;
string text = ss.str();
uint32_t length = DrawStringCommand::MeasureString(text).X;
DrawString(hud, screenWidth, ss.str(), screenWidth - 8 - length, yPos);
}
void SystemHud::ShowFrameCounter(DebugHud* hud, uint32_t screenWidth, int lineNumber) const
{
int yPos = 10 + 10 * lineNumber;
uint32_t frameCount = _emu->GetFrameCount();
string frameCounter = MessageManager::Localize("Frame") + ": " + std::to_string(frameCount);
uint32_t length = DrawStringCommand::MeasureString(frameCounter).X;
DrawString(hud, screenWidth, frameCounter, screenWidth - 8 - length, yPos);
}
void SystemHud::ShowLagCounter(DebugHud* hud, uint32_t screenWidth, int lineNumber) const
{
int yPos = 10 + 10 * lineNumber;
uint32_t count = _emu->GetLagCounter();
string lagCounter = MessageManager::Localize("Lag") + ": " + std::to_string(count);
uint32_t length = DrawStringCommand::MeasureString(lagCounter).X;
DrawString(hud, screenWidth, lagCounter, screenWidth - 8 - length, yPos);
}
void SystemHud::DrawCounters(DebugHud* hud, uint32_t screenWidth) const
{
int lineNumber = 0;
PreferencesConfig cfg = _emu->GetSettings()->GetPreferences();
if(_emu->IsRunning()) {
if(cfg.ShowFps) {
ShowFpsCounter(hud, screenWidth, lineNumber++);
}
if(cfg.ShowGameTimer) {
ShowGameTimer(hud, screenWidth, lineNumber++);
}
if(cfg.ShowFrameCounter) {
ShowFrameCounter(hud, screenWidth, lineNumber++);
}
if(cfg.ShowLagCounter) {
ShowLagCounter(hud, screenWidth, lineNumber++);
}
}
}
void SystemHud::DisplayMessage(string title, string message)
{
auto lock = _msgLock.AcquireSafe();
_messages.push_front(std::make_unique<MessageInfo>(title, message, 3000));
}
void SystemHud::DrawMessages(DebugHud* hud, uint32_t screenWidth, uint32_t screenHeight) const
{
int counter = 0;
int lastHeight = 3;
for(auto& msg : _messages) {
if(counter < 4) {
DrawMessage(hud, *msg.get(), screenWidth, screenHeight, lastHeight);
} else {
break;
}
counter++;
}
}
void SystemHud::DrawBar(DebugHud* hud, int x, int y, int width, int height) const
{
hud->DrawRectangle(x, y, width, height, 0xFFFFFF, true, 1);
hud->DrawLine(x, y + 1, x + width, y + 1, 0x4FBECE, 1);
hud->DrawLine(x+1, y, x+1, y + height, 0x4FBECE, 1);
hud->DrawLine(x + width - 1, y, x + width - 1, y + height, 0xCC9E22, 1);
hud->DrawLine(x, y + height - 1, x + width, y + height - 1, 0xCC9E22, 1);
hud->DrawLine(x, y, x + width, y, 0x303030, 1);
hud->DrawLine(x, y, x, y + height, 0x303030, 1);
hud->DrawLine(x + width, y, x + width, y + height, 0x303030, 1);
hud->DrawLine(x, y + height, x + width, y + height, 0x303030, 1);
}
void SystemHud::DrawPauseIcon(DebugHud* hud) const
{
DrawBar(hud, 10, 7, 5, 12);
DrawBar(hud, 17, 7, 5, 12);
}
void SystemHud::DrawPlayIcon(DebugHud* hud) const
{
int x = 12;
int y = 12;
int width = 5;
int height = 8;
int borderColor = 0x00000;
int color = 0xFFFFFF;
for(int i = 0; i < width; i++) {
int left = x + i * 2;
int top = y + i;
hud->DrawLine(left, top - 1, left, y + height - i + 1, borderColor, 1);
hud->DrawLine(left + 1, top - 1, left + 1, y + height - i + 1, borderColor, 1);
if(i > 0) {
hud->DrawLine(left, top, left, y + height - i, color, 1);
}
if(i < width - 1) {
hud->DrawLine(left + 1, top, left + 1, y + height - i, color, 1);
}
}
}
void SystemHud::DrawRecordIcon(DebugHud* hud) const
{
int x = 12;
int y = 11;
int borderColor = 0x00000;
int color = 0xFF0000;
hud->DrawRectangle(x + 3, y, 4, 10, borderColor, true, 1);
hud->DrawRectangle(x, y + 3, 10, 4, borderColor, true, 1);
hud->DrawRectangle(x + 2, y + 1, 6, 8, borderColor, true, 1);
hud->DrawRectangle(x + 1, y + 2, 8, 6, borderColor, true, 1);
hud->DrawRectangle(x + 3, y + 1, 4, 8, color, true, 1);
hud->DrawRectangle(x + 2, y + 2, 6, 6, color, true, 1);
hud->DrawRectangle(x + 1, y + 3, 8, 4, color, true, 1);
}
void SystemHud::DrawTurboRewindIcon(DebugHud* hud, bool forRewind, int xOffset) const
{
int x = 12 + xOffset;
int y = 12;
int width = 3;
int height = 8;
int frameId = (int)(_animationTimer.GetElapsedMS() / 75) % 16;
if(frameId >= 8) {
frameId = (~frameId & 0x07);
}
static constexpr uint32_t rewindColors[8] = { 0xFF8080, 0xFF9080, 0xFFA080, 0xFFB080, 0xFFC080, 0xFFD080, 0xFFE080, 0xFFF080 };
static constexpr uint32_t turboColors[8] = { 0x80FF80, 0x90FF80, 0xA0FF80, 0xB0FF80, 0xC0FF80, 0xD0FF80, 0xE0FF80, 0xF0FF80 };
int color;
if(forRewind) {
color = rewindColors[frameId];
x += 5;
} else {
color = turboColors[frameId];
}
int borderColor = 0x333333;
int sign = forRewind ? -1 : 1;
for(int j = 0; j < 2; j++) {
for(int i = 0; i < width; i++) {
int left = x + i*sign * 2;
int top = y + i * 2;
hud->DrawLine(left, top - 2, left, y + height - i*2 + 2, borderColor, 1);
hud->DrawLine(left + 1 * sign, top - 1, left + 1 * sign, y + height - i*2 + 1, borderColor, 1);
if(i > 0) {
hud->DrawLine(left, top - 1, left, y + height + 1 - i*2, color, 1);
}
if(i < width - 1) {
hud->DrawLine(left + 1 * sign, top, left + 1 * sign, y + height - i*2, color, 1);
}
}
x += 6;
}
}
void SystemHud::UpdateHud()
{
{
auto lock = _msgLock.AcquireSafe();
_messages.remove_if([](unique_ptr<MessageInfo>& msg) { return msg->IsExpired(); });
}
if(_emu->IsRunning()) {
if(_fpsTimer.GetElapsedMS() > 1000) {
//Update fps every sec
uint32_t frameCount = _emu->GetFrameCount();
if(_lastFrameCount > frameCount) {
_currentFPS = 0;
} else {
_currentFPS = (int)(std::round((double)(frameCount - _lastFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
_currentRenderedFPS = (int)(std::round((double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
}
_lastFrameCount = frameCount;
_lastRenderedFrameCount = _renderedFrameCount;
_fpsTimer.Reset();
}
if(_currentFPS > 5000) {
_currentFPS = 0;
}
if(_currentRenderedFPS > 5000) {
_currentRenderedFPS = 0;
}
_renderedFrameCount++;
}
}