1 #pragma once
2 #include "stdafx.h"
3 #include "../Core/IRenderingDevice.h"
4 #include "../Core/VideoRenderer.h"
5 #include "../Core/EmulationSettings.h"
6 #include "../Core/Console.h"
7 #include "../Utilities/nes_ntsc.h"
8 #include "libretro.h"
9 
10 class LibretroRenderer : public IRenderingDevice
11 {
12 private:
13 	shared_ptr<Console> _console;
14 	retro_video_refresh_t _sendFrame = nullptr;
15 	retro_environment_t _retroEnv = nullptr;
16 	bool _skipMode = false;
17 	int32_t _previousHeight = -1;
18 	int32_t _previousWidth = -1;
19 
20 public:
LibretroRenderer(shared_ptr<Console> console,retro_environment_t retroEnv)21 	LibretroRenderer(shared_ptr<Console> console, retro_environment_t retroEnv)
22 	{
23 		_console = console;
24 		_retroEnv = retroEnv;
25 		_console->GetVideoRenderer()->RegisterRenderingDevice(this);
26 	}
27 
~LibretroRenderer()28 	~LibretroRenderer()
29 	{
30 		_console->GetVideoRenderer()->UnregisterRenderingDevice(this);
31 	}
32 
33 	// Inherited via IRenderingDevice
UpdateFrame(void * frameBuffer,uint32_t width,uint32_t height)34 	virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) override
35 	{
36 		if(!_skipMode && _sendFrame) {
37 			//Use Blargg's NTSC filter's max size as a minimum resolution, to prevent changing resolution too often
38 			int32_t newWidth = std::max<int32_t>(width, NES_NTSC_OUT_WIDTH(256));
39 			int32_t newHeight = std::max<int32_t>(height, 240);
40 			if(_retroEnv != nullptr && (_previousWidth != newWidth || _previousHeight != newHeight)) {
41 				//Resolution change is needed
42 				retro_system_av_info avInfo = {};
43 				GetSystemAudioVideoInfo(avInfo, newWidth, newHeight);
44 				_retroEnv(RETRO_ENVIRONMENT_SET_SYSTEM_AV_INFO, &avInfo);
45 
46 				_previousWidth = newWidth;
47 				_previousHeight = newHeight;
48 			}
49 
50 			_sendFrame(frameBuffer, width, height, sizeof(uint32_t) * width);
51 		}
52 	}
53 
54 	void GetSystemAudioVideoInfo(retro_system_av_info &info, int32_t maxWidth = 0, int32_t maxHeight = 0)
55 	{
56 		info.timing.fps = _console->GetModel() == NesModel::NTSC ? 60.098811862348404716732985230828 : 50.006977968268290848936010226333;
57 		info.timing.sample_rate = _console->GetSettings()->GetSampleRate();
58 
59 		float ratio = (float)_console->GetSettings()->GetAspectRatio(_console);
60 		if(ratio == 0.0f) {
61 			ratio = (float)256 / 240;
62 		}
63 		ratio *= (float)_console->GetSettings()->GetOverscanDimensions().GetScreenWidth() / _console->GetSettings()->GetOverscanDimensions().GetScreenHeight() / 256 * 240;
64 
65 		if(_console->GetSettings()->GetScreenRotation() % 180) {
66 			info.geometry.aspect_ratio = ratio == 0.0f ? 0.0f : 1.0f / ratio;
67 		} else {
68 			info.geometry.aspect_ratio = ratio;
69 		}
70 
71 		info.geometry.base_width = _console->GetSettings()->GetOverscanDimensions().GetScreenWidth();
72 		info.geometry.base_height = _console->GetSettings()->GetOverscanDimensions().GetScreenHeight();
73 
74 		info.geometry.max_width = maxWidth;
75 		info.geometry.max_height = maxHeight;
76 
77 		if(maxHeight > 0 && maxWidth > 0) {
78 			_previousWidth = maxWidth;
79 			_previousHeight = maxHeight;
80 		}
81 	}
82 
SetVideoCallback(retro_video_refresh_t sendFrame)83 	void SetVideoCallback(retro_video_refresh_t sendFrame)
84 	{
85 		_sendFrame = sendFrame;
86 	}
87 
SetSkipMode(bool skip)88 	void SetSkipMode(bool skip)
89 	{
90 		_skipMode = skip;
91 	}
92 
Render()93 	virtual void Render() override
94 	{
95 	}
96 
Reset()97 	virtual void Reset() override
98 	{
99 	}
100 
SetFullscreenMode(bool fullscreen,void * windowHandle,uint32_t monitorWidth,uint32_t monitorHeight)101 	virtual void SetFullscreenMode(bool fullscreen, void *windowHandle, uint32_t monitorWidth, uint32_t monitorHeight) override
102 	{
103 	}
104 };