1 #include "stdafx.h"
2 #include <cmath>
3 #include "BaseRenderer.h"
4 #include "Console.h"
5 #include "EmulationSettings.h"
6 #include "VideoDecoder.h"
7 #include "PPU.h"
8
BaseRenderer(shared_ptr<Console> console,bool registerAsMessageManager)9 BaseRenderer::BaseRenderer(shared_ptr<Console> console, bool registerAsMessageManager)
10 {
11 _console = console;
12
13 if(registerAsMessageManager) {
14 //Only display messages on the master CPU's screen
15 MessageManager::RegisterMessageManager(this);
16 }
17 }
18
~BaseRenderer()19 BaseRenderer::~BaseRenderer()
20 {
21 MessageManager::UnregisterMessageManager(this);
22 }
23
DisplayMessage(string title,string message)24 void BaseRenderer::DisplayMessage(string title, string message)
25 {
26 shared_ptr<ToastInfo> toast(new ToastInfo(title, message, 4000));
27 _toasts.push_front(toast);
28 }
29
RemoveOldToasts()30 void BaseRenderer::RemoveOldToasts()
31 {
32 _toasts.remove_if([](shared_ptr<ToastInfo> toast) { return toast->IsToastExpired(); });
33 }
34
DrawToasts()35 void BaseRenderer::DrawToasts()
36 {
37 RemoveOldToasts();
38
39 int counter = 0;
40 int lastHeight = 5;
41 for(shared_ptr<ToastInfo> toast : _toasts) {
42 if(counter < 6) {
43 DrawToast(toast, lastHeight);
44 } else {
45 break;
46 }
47 counter++;
48 }
49 }
50
WrapText(string utf8Text,float maxLineWidth,uint32_t & lineCount)51 std::wstring BaseRenderer::WrapText(string utf8Text, float maxLineWidth, uint32_t &lineCount)
52 {
53 using std::wstring;
54 wstring text = utf8::utf8::decode(utf8Text);
55 wstring wrappedText;
56 list<wstring> words;
57 wstring currentWord;
58 for(size_t i = 0, len = text.length(); i < len; i++) {
59 if(text[i] == L' ' || text[i] == L'\n') {
60 if(currentWord.length() > 0) {
61 words.push_back(currentWord);
62 currentWord.clear();
63 }
64 } else {
65 currentWord += text[i];
66 }
67 }
68 if(currentWord.length() > 0) {
69 words.push_back(currentWord);
70 }
71
72 lineCount = 1;
73 float spaceWidth = MeasureString(L" ");
74
75 float lineWidth = 0.0f;
76 for(wstring word : words) {
77 for(unsigned int i = 0; i < word.size(); i++) {
78 if(!ContainsCharacter(word[i])) {
79 word[i] = L'?';
80 }
81 }
82
83 float wordWidth = MeasureString(word.c_str());
84
85 if(lineWidth + wordWidth < maxLineWidth) {
86 wrappedText += word + L" ";
87 lineWidth += wordWidth + spaceWidth;
88 } else {
89 wrappedText += L"\n" + word + L" ";
90 lineWidth = wordWidth + spaceWidth;
91 lineCount++;
92 }
93 }
94
95 return wrappedText;
96 }
97
DrawToast(shared_ptr<ToastInfo> toast,int & lastHeight)98 void BaseRenderer::DrawToast(shared_ptr<ToastInfo> toast, int &lastHeight)
99 {
100 //Get opacity for fade in/out effect
101 uint8_t opacity = (uint8_t)(toast->GetOpacity()*255);
102 int textLeftMargin = 4;
103
104 int lineHeight = 25;
105 string text = "[" + toast->GetToastTitle() + "] " + toast->GetToastMessage();
106 uint32_t lineCount = 0;
107 std::wstring wrappedText = WrapText(text, (float)(_screenWidth - textLeftMargin * 2 - 20), lineCount);
108 lastHeight += lineCount * lineHeight;
109 DrawString(wrappedText, textLeftMargin, _screenHeight - lastHeight, opacity, opacity, opacity, opacity);
110 }
111
DrawString(std::string message,int x,int y,uint8_t r,uint8_t g,uint8_t b,uint8_t opacity)112 void BaseRenderer::DrawString(std::string message, int x, int y, uint8_t r, uint8_t g, uint8_t b, uint8_t opacity)
113 {
114 std::wstring textStr = utf8::utf8::decode(message);
115 DrawString(textStr, x, y, r, g, b, opacity);
116 }
117
ShowFpsCounter(int lineNumber)118 void BaseRenderer::ShowFpsCounter(int lineNumber)
119 {
120 int yPos = 13 + 24 * lineNumber;
121 if(_fpsTimer.GetElapsedMS() > 1000) {
122 //Update fps every sec
123 uint32_t frameCount = _console->GetFrameCount();
124 if(_lastFrameCount > frameCount) {
125 _currentFPS = 0;
126 } else {
127 _currentFPS = (int)(std::round((double)(frameCount - _lastFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
128 _currentRenderedFPS = (int)(std::round((double)(_renderedFrameCount - _lastRenderedFrameCount) / (_fpsTimer.GetElapsedMS() / 1000)));
129 }
130 _lastFrameCount = frameCount;
131 _lastRenderedFrameCount = _renderedFrameCount;
132 _fpsTimer.Reset();
133 }
134
135 if(_currentFPS > 5000) {
136 _currentFPS = 0;
137 }
138 if(_currentRenderedFPS > 5000) {
139 _currentRenderedFPS = 0;
140 }
141
142 string fpsString = string("FPS: ") + std::to_string(_currentFPS) + " / " + std::to_string(_currentRenderedFPS);
143 DrawString(fpsString, _screenWidth - 125, yPos, 250, 235, 215);
144 }
145
ShowGameTimer(int lineNumber)146 void BaseRenderer::ShowGameTimer(int lineNumber)
147 {
148 int yPos = 13 + 24 * lineNumber;
149 double frameCount = _console->GetFrameCount();
150 double frameRate = _console->GetModel() == NesModel::NTSC ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333;
151 //uint32_t milliseconds = (uint32_t)(frameCount / 60.1 * 1000) % 1000;
152 uint32_t seconds = (uint32_t)(frameCount / frameRate) % 60;
153 uint32_t minutes = (uint32_t)(frameCount / frameRate / 60) % 60;
154 uint32_t hours = (uint32_t)(frameCount / frameRate / 3600);
155
156 std::stringstream ss;
157 ss << std::setw(2) << std::setfill('0') << hours << ":";
158 ss << std::setw(2) << std::setfill('0') << minutes << ":";
159 ss << std::setw(2) << std::setfill('0') << seconds;
160 //ss << "." << std::setw(3) << std::setfill('0') << milliseconds;
161 DrawString(ss.str(), _screenWidth - 95, yPos, 250, 235, 215);
162 }
163
ShowLagCounter(int lineNumber)164 void BaseRenderer::ShowLagCounter(int lineNumber)
165 {
166 int yPos = 13 + 24 * lineNumber;
167 string lagCounter = MessageManager::Localize("Lag") + ": " + std::to_string(_console->GetLagCounter());
168 DrawString(lagCounter, _screenWidth - 123, yPos, 250, 235, 215);
169 }
170
ShowFrameCounter(int lineNumber)171 void BaseRenderer::ShowFrameCounter(int lineNumber)
172 {
173 int yPos = 13 + 24 * lineNumber;
174 string lagCounter = MessageManager::Localize("Frame") + ": " + std::to_string(_console->GetFrameCount());
175 DrawString(lagCounter, _screenWidth - 146, yPos, 250, 235, 215);
176 }
177
DrawCounters()178 void BaseRenderer::DrawCounters()
179 {
180 int lineNumber = 0;
181 EmulationSettings* settings = _console->GetSettings();
182 if(settings->CheckFlag(EmulationFlags::ShowGameTimer)) {
183 ShowGameTimer(lineNumber++);
184 }
185 if(settings->CheckFlag(EmulationFlags::ShowFPS)) {
186 ShowFpsCounter(lineNumber++);
187 }
188 if(settings->CheckFlag(EmulationFlags::ShowLagCounter)) {
189 ShowLagCounter(lineNumber++);
190 }
191 if(settings->CheckFlag(EmulationFlags::ShowFrameCounter)) {
192 ShowFrameCounter(lineNumber++);
193 }
194 }
195
IsMessageShown()196 bool BaseRenderer::IsMessageShown()
197 {
198 return !_toasts.empty();
199 }
200