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