#include "stdafx.h" #include #include "BaseRenderer.h" #include "Console.h" #include "EmulationSettings.h" #include "VideoDecoder.h" #include "PPU.h" BaseRenderer::BaseRenderer(shared_ptr console, bool registerAsMessageManager) { _console = console; if(registerAsMessageManager) { //Only display messages on the master CPU's screen MessageManager::RegisterMessageManager(this); } } BaseRenderer::~BaseRenderer() { MessageManager::UnregisterMessageManager(this); } void BaseRenderer::DisplayMessage(string title, string message) { shared_ptr toast(new ToastInfo(title, message, 4000)); _toasts.push_front(toast); } void BaseRenderer::RemoveOldToasts() { _toasts.remove_if([](shared_ptr toast) { return toast->IsToastExpired(); }); } void BaseRenderer::DrawToasts() { RemoveOldToasts(); int counter = 0; int lastHeight = 5; for(shared_ptr toast : _toasts) { if(counter < 6) { DrawToast(toast, lastHeight); } else { break; } counter++; } } std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount) { using std::wstring; wstring text = utf8::utf8::decode(utf8Text); wstring wrappedText; list words; wstring currentWord; for(size_t i = 0, len = text.length(); i < len; i++) { if(text[i] == L' ' || text[i] == L'\n') { if(currentWord.length() > 0) { words.push_back(currentWord); currentWord.clear(); } } else { currentWord += text[i]; } } if(currentWord.length() > 0) { words.push_back(currentWord); } lineCount = 1; float spaceWidth = MeasureString(L" "); float lineWidth = 0.0f; for(wstring word : words) { for(unsigned int i = 0; i < word.size(); i++) { if(!ContainsCharacter(word[i])) { word[i] = L'?'; } } float wordWidth = MeasureString(word.c_str()); if(lineWidth + wordWidth < maxLineWidth) { wrappedText += word + L" "; lineWidth += wordWidth + spaceWidth; } else { wrappedText += L"\n" + word + L" "; lineWidth = wordWidth + spaceWidth; lineCount++; } } return wrappedText; } void BaseRenderer::DrawToast(shared_ptr toast, int &lastHeight) { //Get opacity for fade in/out effect uint8_t opacity = (uint8_t)(toast->GetOpacity()*255); int textLeftMargin = 4; int lineHeight = 25; string text = "[" + toast->GetToastTitle() + "] " + toast->GetToastMessage(); uint32_t lineCount = 0; std::wstring wrappedText = WrapText(text, (float)(_screenWidth - textLeftMargin * 2 - 20), lineCount); lastHeight += lineCount * lineHeight; DrawString(wrappedText, textLeftMargin, _screenHeight - lastHeight, opacity, opacity, opacity, opacity); } void BaseRenderer::DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity) { std::wstring textStr = utf8::utf8::decode(message); DrawString(textStr, x, y, r, g, b, opacity); } void BaseRenderer::ShowFpsCounter(int lineNumber) { int yPos = 13 + 24 * lineNumber; if(_fpsTimer.GetElapsedMS() > 1000) { //Update fps every sec uint32_t frameCount = _console->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; } string fpsString = string("FPS: ") + std::to_string(_currentFPS) + " / " + std::to_string(_currentRenderedFPS); DrawString(fpsString, _screenWidth - 125, yPos, 250, 235, 215); } void BaseRenderer::ShowGameTimer(int lineNumber) { int yPos = 13 + 24 * lineNumber; double frameCount = _console->GetFrameCount(); double frameRate = _console->GetModel() == NesModel::NTSC ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333; //uint32_t milliseconds = (uint32_t)(frameCount / 60.1 * 1000) % 1000; 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; //ss << "." << std::setw(3) << std::setfill('0') << milliseconds; DrawString(ss.str(), _screenWidth - 95, yPos, 250, 235, 215); } void BaseRenderer::ShowLagCounter(int lineNumber) { int yPos = 13 + 24 * lineNumber; string lagCounter = MessageManager::Localize("Lag") + ": " + std::to_string(_console->GetLagCounter()); DrawString(lagCounter, _screenWidth - 123, yPos, 250, 235, 215); } void BaseRenderer::ShowFrameCounter(int lineNumber) { int yPos = 13 + 24 * lineNumber; string lagCounter = MessageManager::Localize("Frame") + ": " + std::to_string(_console->GetFrameCount()); DrawString(lagCounter, _screenWidth - 146, yPos, 250, 235, 215); } void BaseRenderer::DrawCounters() { int lineNumber = 0; EmulationSettings* settings = _console->GetSettings(); if(settings->CheckFlag(EmulationFlags::ShowGameTimer)) { ShowGameTimer(lineNumber++); } if(settings->CheckFlag(EmulationFlags::ShowFPS)) { ShowFpsCounter(lineNumber++); } if(settings->CheckFlag(EmulationFlags::ShowLagCounter)) { ShowLagCounter(lineNumber++); } if(settings->CheckFlag(EmulationFlags::ShowFrameCounter)) { ShowFrameCounter(lineNumber++); } } bool BaseRenderer::IsMessageShown() { return !_toasts.empty(); }