Imported video decode/renderer classes and related utilities from Mesen
This commit is contained in:
parent
69cf69fa6f
commit
aed9270e52
28 changed files with 1609 additions and 58 deletions
|
@ -1,16 +1,10 @@
|
|||
#pragma once
|
||||
#include "../Core/IMessageManager.h"
|
||||
#include "IMessageManager.h"
|
||||
#include "SettingTypes.h"
|
||||
#include "../Utilities/Timer.h"
|
||||
|
||||
class Console;
|
||||
|
||||
//TODO
|
||||
enum class VideoResizeFilter
|
||||
{
|
||||
NearestNeighbor = 0,
|
||||
Bilinear = 1
|
||||
};
|
||||
|
||||
class BaseRenderer : public IMessageManager
|
||||
{
|
||||
private:
|
||||
|
|
141
Core/BaseVideoFilter.cpp
Normal file
141
Core/BaseVideoFilter.cpp
Normal file
|
@ -0,0 +1,141 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseVideoFilter.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/PNGHelper.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "Console.h"
|
||||
|
||||
BaseVideoFilter::BaseVideoFilter(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_overscan = {}; //TODO _console->GetSettings()->GetOverscanDimensions();
|
||||
}
|
||||
|
||||
BaseVideoFilter::~BaseVideoFilter()
|
||||
{
|
||||
auto lock = _frameLock.AcquireSafe();
|
||||
if(_outputBuffer) {
|
||||
delete[] _outputBuffer;
|
||||
_outputBuffer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseVideoFilter::UpdateBufferSize()
|
||||
{
|
||||
uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height;
|
||||
if(_bufferSize != newBufferSize) {
|
||||
_frameLock.Acquire();
|
||||
if(_outputBuffer) {
|
||||
delete[] _outputBuffer;
|
||||
}
|
||||
|
||||
_bufferSize = newBufferSize;
|
||||
_outputBuffer = new uint32_t[newBufferSize];
|
||||
_frameLock.Release();
|
||||
}
|
||||
}
|
||||
|
||||
OverscanDimensions BaseVideoFilter::GetOverscan()
|
||||
{
|
||||
return _overscan;
|
||||
}
|
||||
|
||||
void BaseVideoFilter::OnBeforeApplyFilter()
|
||||
{
|
||||
}
|
||||
|
||||
bool BaseVideoFilter::IsOddFrame()
|
||||
{
|
||||
return _isOddFrame;
|
||||
}
|
||||
|
||||
void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber)
|
||||
{
|
||||
_frameLock.Acquire();
|
||||
_overscan = {}; //TODO _console->GetSettings()->GetOverscanDimensions();
|
||||
_isOddFrame = frameNumber % 2;
|
||||
UpdateBufferSize();
|
||||
OnBeforeApplyFilter();
|
||||
ApplyFilter(ppuOutputBuffer);
|
||||
|
||||
_frameLock.Release();
|
||||
}
|
||||
|
||||
uint32_t* BaseVideoFilter::GetOutputBuffer()
|
||||
{
|
||||
return _outputBuffer;
|
||||
}
|
||||
|
||||
void BaseVideoFilter::TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream)
|
||||
{
|
||||
uint32_t* pngBuffer;
|
||||
FrameInfo frameInfo;
|
||||
uint32_t* frameBuffer = nullptr;
|
||||
{
|
||||
auto lock = _frameLock.AcquireSafe();
|
||||
if(_bufferSize == 0 || !GetOutputBuffer()) {
|
||||
return;
|
||||
}
|
||||
|
||||
frameBuffer = new uint32_t[_bufferSize];
|
||||
memcpy(frameBuffer, GetOutputBuffer(), _bufferSize * sizeof(frameBuffer[0]));
|
||||
frameInfo = GetFrameInfo();
|
||||
}
|
||||
|
||||
pngBuffer = frameBuffer;
|
||||
|
||||
//TODO
|
||||
/*
|
||||
uint32_t rotationAngle = _console->GetSettings()->GetScreenRotation();
|
||||
shared_ptr<RotateFilter> rotateFilter;
|
||||
if(rotationAngle > 0) {
|
||||
rotateFilter.reset(new RotateFilter(rotationAngle));
|
||||
pngBuffer = rotateFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height);
|
||||
frameInfo = rotateFilter->GetFrameInfo(frameInfo);
|
||||
}
|
||||
|
||||
shared_ptr<ScaleFilter> scaleFilter = ScaleFilter::GetScaleFilter(filterType);
|
||||
if(scaleFilter) {
|
||||
pngBuffer = scaleFilter->ApplyFilter(pngBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetPictureSettings().ScanlineIntensity);
|
||||
frameInfo = scaleFilter->GetFrameInfo(frameInfo);
|
||||
}
|
||||
|
||||
VideoHud hud;
|
||||
hud.DrawHud(_console, pngBuffer, frameInfo, _console->GetSettings()->GetOverscanDimensions());
|
||||
*/
|
||||
if(!filename.empty()) {
|
||||
PNGHelper::WritePNG(filename, pngBuffer, frameInfo.Width, frameInfo.Height);
|
||||
} else {
|
||||
PNGHelper::WritePNG(*stream, pngBuffer, frameInfo.Width, frameInfo.Height);
|
||||
}
|
||||
|
||||
delete[] frameBuffer;
|
||||
}
|
||||
|
||||
void BaseVideoFilter::TakeScreenshot(string romName, VideoFilterType filterType)
|
||||
{
|
||||
string romFilename = FolderUtilities::GetFilename(romName, false);
|
||||
|
||||
int counter = 0;
|
||||
string baseFilename = FolderUtilities::CombinePath(FolderUtilities::GetScreenshotFolder(), romFilename);
|
||||
string ssFilename;
|
||||
while(true) {
|
||||
string counterStr = std::to_string(counter);
|
||||
while(counterStr.length() < 3) {
|
||||
counterStr = "0" + counterStr;
|
||||
}
|
||||
ssFilename = baseFilename + "_" + counterStr + ".png";
|
||||
ifstream file(ssFilename, ios::in);
|
||||
if(file) {
|
||||
file.close();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
counter++;
|
||||
}
|
||||
|
||||
TakeScreenshot(filterType, ssFilename);
|
||||
|
||||
MessageManager::DisplayMessage("ScreenshotSaved", FolderUtilities::GetFilename(ssFilename, true));
|
||||
}
|
||||
|
37
Core/BaseVideoFilter.h
Normal file
37
Core/BaseVideoFilter.h
Normal file
|
@ -0,0 +1,37 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "SettingTypes.h"
|
||||
|
||||
class Console;
|
||||
|
||||
class BaseVideoFilter
|
||||
{
|
||||
private:
|
||||
uint32_t* _outputBuffer = nullptr;
|
||||
uint32_t _bufferSize = 0;
|
||||
SimpleLock _frameLock;
|
||||
OverscanDimensions _overscan;
|
||||
bool _isOddFrame;
|
||||
|
||||
void UpdateBufferSize();
|
||||
|
||||
protected:
|
||||
shared_ptr<Console> _console;
|
||||
|
||||
virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0;
|
||||
virtual void OnBeforeApplyFilter();
|
||||
bool IsOddFrame();
|
||||
|
||||
public:
|
||||
BaseVideoFilter(shared_ptr<Console> console);
|
||||
virtual ~BaseVideoFilter();
|
||||
|
||||
uint32_t* GetOutputBuffer();
|
||||
void SendFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber);
|
||||
void TakeScreenshot(string romName, VideoFilterType filterType);
|
||||
void TakeScreenshot(VideoFilterType filterType, string filename, std::stringstream *stream = nullptr);
|
||||
|
||||
virtual OverscanDimensions GetOverscan();
|
||||
virtual FrameInfo GetFrameInfo() = 0;
|
||||
};
|
|
@ -3,9 +3,22 @@
|
|||
#include "Cpu.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "Debugger.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "VideoRenderer.h"
|
||||
#include "DebugHud.h"
|
||||
#include "../Utilities/Timer.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
|
||||
void Console::Initialize()
|
||||
{
|
||||
_videoDecoder.reset(new VideoDecoder(shared_from_this()));
|
||||
_videoRenderer.reset(new VideoRenderer(shared_from_this()));
|
||||
_debugHud.reset(new DebugHud());
|
||||
|
||||
_videoDecoder->StartThread();
|
||||
_videoRenderer->StartThread();
|
||||
}
|
||||
|
||||
void Console::Run()
|
||||
{
|
||||
if(!_cpu) {
|
||||
|
@ -50,6 +63,21 @@ void Console::LoadRom(VirtualFile romFile, VirtualFile patchFile)
|
|||
}
|
||||
}
|
||||
|
||||
shared_ptr<VideoRenderer> Console::GetVideoRenderer()
|
||||
{
|
||||
return _videoRenderer;
|
||||
}
|
||||
|
||||
shared_ptr<VideoDecoder> Console::GetVideoDecoder()
|
||||
{
|
||||
return _videoDecoder;
|
||||
}
|
||||
|
||||
shared_ptr<DebugHud> Console::GetDebugHud()
|
||||
{
|
||||
return _debugHud;
|
||||
}
|
||||
|
||||
shared_ptr<Cpu> Console::GetCpu()
|
||||
{
|
||||
return _cpu;
|
||||
|
@ -60,6 +88,11 @@ shared_ptr<Ppu> Console::GetPpu()
|
|||
return _ppu;
|
||||
}
|
||||
|
||||
shared_ptr<MemoryManager> Console::GetMemoryManager()
|
||||
{
|
||||
return _memoryManager;
|
||||
}
|
||||
|
||||
shared_ptr<Debugger> Console::GetDebugger(bool allowStart)
|
||||
{
|
||||
return _debugger;
|
||||
|
|
|
@ -7,6 +7,9 @@ class Cpu;
|
|||
class Ppu;
|
||||
class MemoryManager;
|
||||
class Debugger;
|
||||
class DebugHud;
|
||||
class VideoRenderer;
|
||||
class VideoDecoder;
|
||||
enum class MemoryOperationType;
|
||||
|
||||
class Console : public std::enable_shared_from_this<Console>
|
||||
|
@ -17,17 +20,28 @@ private:
|
|||
shared_ptr<MemoryManager> _memoryManager;
|
||||
shared_ptr<Debugger> _debugger;
|
||||
|
||||
shared_ptr<VideoRenderer> _videoRenderer;
|
||||
shared_ptr<VideoDecoder> _videoDecoder;
|
||||
shared_ptr<DebugHud> _debugHud;
|
||||
|
||||
SimpleLock _runLock;
|
||||
atomic<bool> _stopFlag;
|
||||
|
||||
public:
|
||||
void Initialize();
|
||||
|
||||
void Run();
|
||||
void Stop();
|
||||
|
||||
void LoadRom(VirtualFile romFile, VirtualFile patchFile);
|
||||
|
||||
shared_ptr<VideoRenderer> GetVideoRenderer();
|
||||
shared_ptr<VideoDecoder> GetVideoDecoder();
|
||||
shared_ptr<DebugHud> GetDebugHud();
|
||||
|
||||
shared_ptr<Cpu> GetCpu();
|
||||
shared_ptr<Ppu> GetPpu();
|
||||
shared_ptr<MemoryManager> GetMemoryManager();
|
||||
shared_ptr<Debugger> GetDebugger(bool allowStart = true);
|
||||
|
||||
void ProcessCpuRead(uint32_t addr, uint8_t value, MemoryOperationType type);
|
||||
|
|
|
@ -45,11 +45,20 @@
|
|||
<ItemGroup>
|
||||
<ClInclude Include="BaseRenderer.h" />
|
||||
<ClInclude Include="BaseSoundManager.h" />
|
||||
<ClInclude Include="BaseVideoFilter.h" />
|
||||
<ClInclude Include="Console.h" />
|
||||
<ClInclude Include="Cpu.h" />
|
||||
<ClInclude Include="CpuTypes.h" />
|
||||
<ClInclude Include="Debugger.h" />
|
||||
<ClInclude Include="DebugHud.h" />
|
||||
<ClInclude Include="DefaultVideoFilter.h" />
|
||||
<ClInclude Include="DisassemblyInfo.h" />
|
||||
<ClInclude Include="DrawCommand.h" />
|
||||
<ClInclude Include="DrawLineCommand.h" />
|
||||
<ClInclude Include="DrawPixelCommand.h" />
|
||||
<ClInclude Include="DrawRectangleCommand.h" />
|
||||
<ClInclude Include="DrawScreenBufferCommand.h" />
|
||||
<ClInclude Include="DrawStringCommand.h" />
|
||||
<ClInclude Include="IAudioDevice.h" />
|
||||
<ClInclude Include="IInputProvider.h" />
|
||||
<ClInclude Include="IInputRecorder.h" />
|
||||
|
@ -62,16 +71,22 @@
|
|||
<ClInclude Include="MessageManager.h" />
|
||||
<ClInclude Include="Ppu.h" />
|
||||
<ClInclude Include="PpuTypes.h" />
|
||||
<ClInclude Include="SettingTypes.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="TraceLogger.h" />
|
||||
<ClInclude Include="VideoDecoder.h" />
|
||||
<ClInclude Include="VideoRenderer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="BaseRenderer.cpp" />
|
||||
<ClCompile Include="BaseSoundManager.cpp" />
|
||||
<ClCompile Include="BaseVideoFilter.cpp" />
|
||||
<ClCompile Include="Console.cpp" />
|
||||
<ClCompile Include="Cpu.cpp" />
|
||||
<ClCompile Include="Cpu.Instructions.cpp" />
|
||||
<ClCompile Include="Debugger.cpp" />
|
||||
<ClCompile Include="DebugHud.cpp" />
|
||||
<ClCompile Include="DefaultVideoFilter.cpp" />
|
||||
<ClCompile Include="DisassemblyInfo.cpp" />
|
||||
<ClCompile Include="KeyManager.cpp" />
|
||||
<ClCompile Include="MessageManager.cpp" />
|
||||
|
@ -89,6 +104,8 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='PGO Optimize|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TraceLogger.cpp" />
|
||||
<ClCompile Include="VideoDecoder.cpp" />
|
||||
<ClCompile Include="VideoRenderer.cpp" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{78FEF1A1-6DF1-4CBB-A373-AE6FA7CE5CE0}</ProjectGuid>
|
||||
|
|
|
@ -44,9 +44,6 @@
|
|||
<ClInclude Include="IRenderingDevice.h">
|
||||
<Filter>Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseRenderer.h">
|
||||
<Filter>Misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseSoundManager.h">
|
||||
<Filter>Misc</Filter>
|
||||
</ClInclude>
|
||||
|
@ -62,6 +59,45 @@
|
|||
<ClInclude Include="PpuTypes.h">
|
||||
<Filter>SNES</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoRenderer.h">
|
||||
<Filter>Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoDecoder.h">
|
||||
<Filter>Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseRenderer.h">
|
||||
<Filter>Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DefaultVideoFilter.h">
|
||||
<Filter>Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseVideoFilter.h">
|
||||
<Filter>Video</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SettingTypes.h">
|
||||
<Filter>Misc</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DebugHud.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawCommand.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawLineCommand.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawPixelCommand.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawRectangleCommand.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawScreenBufferCommand.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DrawStringCommand.h">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp" />
|
||||
|
@ -80,9 +116,6 @@
|
|||
<ClCompile Include="Console.cpp">
|
||||
<Filter>SNES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseRenderer.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseSoundManager.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
|
@ -98,6 +131,24 @@
|
|||
<ClCompile Include="Ppu.cpp">
|
||||
<Filter>SNES</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoDecoder.cpp">
|
||||
<Filter>Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoRenderer.cpp">
|
||||
<Filter>Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseRenderer.cpp">
|
||||
<Filter>Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DefaultVideoFilter.cpp">
|
||||
<Filter>Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseVideoFilter.cpp">
|
||||
<Filter>Video</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DebugHud.cpp">
|
||||
<Filter>Video\DebugHud</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="SNES">
|
||||
|
@ -112,5 +163,11 @@
|
|||
<Filter Include="Misc">
|
||||
<UniqueIdentifier>{0da6a615-3092-40f7-936c-253eb03a8784}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Video">
|
||||
<UniqueIdentifier>{7aa5124a-c2c1-418e-b7bb-5ba7846aa9b0}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Video\DebugHud">
|
||||
<UniqueIdentifier>{0d0cf24e-4126-4bfb-b391-27a015e7722a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
</Project>
|
74
Core/DebugHud.cpp
Normal file
74
Core/DebugHud.cpp
Normal file
|
@ -0,0 +1,74 @@
|
|||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include "DebugHud.h"
|
||||
#include "DrawCommand.h"
|
||||
#include "DrawLineCommand.h"
|
||||
#include "DrawPixelCommand.h"
|
||||
#include "DrawRectangleCommand.h"
|
||||
#include "DrawStringCommand.h"
|
||||
#include "DrawScreenBufferCommand.h"
|
||||
|
||||
DebugHud::DebugHud()
|
||||
{
|
||||
}
|
||||
|
||||
DebugHud::~DebugHud()
|
||||
{
|
||||
_commandLock.Acquire();
|
||||
_commandLock.Release();
|
||||
}
|
||||
|
||||
void DebugHud::ClearScreen()
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
_commands.clear();
|
||||
}
|
||||
|
||||
void DebugHud::Draw(uint32_t* argbBuffer, OverscanDimensions overscan, uint32_t lineWidth, uint32_t frameNumber)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
for(unique_ptr<DrawCommand> &command : _commands) {
|
||||
command->Draw(argbBuffer, overscan, lineWidth, frameNumber);
|
||||
}
|
||||
_commands.erase(std::remove_if(_commands.begin(), _commands.end(), [](const unique_ptr<DrawCommand>& c) { return c->Expired(); }), _commands.end());
|
||||
}
|
||||
|
||||
void DebugHud::DrawPixel(int x, int y, int color, int frameCount, int startFrame)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
if(_commands.size() < DebugHud::MaxCommandCount) {
|
||||
_commands.push_back(unique_ptr<DrawPixelCommand>(new DrawPixelCommand(x, y, color, frameCount, startFrame)));
|
||||
}
|
||||
}
|
||||
|
||||
void DebugHud::DrawLine(int x, int y, int x2, int y2, int color, int frameCount, int startFrame)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
if(_commands.size() < DebugHud::MaxCommandCount) {
|
||||
_commands.push_back(unique_ptr<DrawLineCommand>(new DrawLineCommand(x, y, x2, y2, color, frameCount, startFrame)));
|
||||
}
|
||||
}
|
||||
|
||||
void DebugHud::DrawRectangle(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
if(_commands.size() < DebugHud::MaxCommandCount) {
|
||||
_commands.push_back(unique_ptr<DrawRectangleCommand>(new DrawRectangleCommand(x, y, width, height, color, fill, frameCount, startFrame)));
|
||||
}
|
||||
}
|
||||
|
||||
void DebugHud::DrawScreenBuffer(uint32_t* screenBuffer, int startFrame)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
if(_commands.size() < DebugHud::MaxCommandCount) {
|
||||
_commands.push_back(unique_ptr<DrawScreenBufferCommand>(new DrawScreenBufferCommand(screenBuffer, startFrame)));
|
||||
}
|
||||
}
|
||||
|
||||
void DebugHud::DrawString(int x, int y, string text, int color, int backColor, int frameCount, int startFrame)
|
||||
{
|
||||
auto lock = _commandLock.AcquireSafe();
|
||||
if(_commands.size() < DebugHud::MaxCommandCount) {
|
||||
_commands.push_back(unique_ptr<DrawStringCommand>(new DrawStringCommand(x, y, text, color, backColor, frameCount, startFrame)));
|
||||
}
|
||||
}
|
27
Core/DebugHud.h
Normal file
27
Core/DebugHud.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "SettingTypes.h"
|
||||
|
||||
class DrawCommand;
|
||||
|
||||
class DebugHud
|
||||
{
|
||||
private:
|
||||
static constexpr size_t MaxCommandCount = 500000;
|
||||
vector<unique_ptr<DrawCommand>> _commands;
|
||||
SimpleLock _commandLock;
|
||||
|
||||
public:
|
||||
DebugHud();
|
||||
~DebugHud();
|
||||
|
||||
void Draw(uint32_t* argbBuffer, OverscanDimensions overscan, uint32_t width, uint32_t frameNumber);
|
||||
void ClearScreen();
|
||||
|
||||
void DrawPixel(int x, int y, int color, int frameCount, int startFrame);
|
||||
void DrawLine(int x, int y, int x2, int y2, int color, int frameCount, int startFrame);
|
||||
void DrawRectangle(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame);
|
||||
void DrawScreenBuffer(uint32_t* screenBuffer, int startFrame);
|
||||
void DrawString(int x, int y, string text, int color, int backColor, int frameCount, int startFrame);
|
||||
};
|
|
@ -14,7 +14,7 @@ Debugger::Debugger(shared_ptr<Cpu> cpu, shared_ptr<Ppu> ppu, shared_ptr<MemoryMa
|
|||
_memoryManager = memoryManager;
|
||||
_traceLogger.reset(new TraceLogger(this, memoryManager));
|
||||
|
||||
_cpuStepCount = 1;
|
||||
_cpuStepCount = 0;
|
||||
}
|
||||
|
||||
Debugger::~Debugger()
|
||||
|
|
136
Core/DefaultVideoFilter.cpp
Normal file
136
Core/DefaultVideoFilter.cpp
Normal file
|
@ -0,0 +1,136 @@
|
|||
#include "stdafx.h"
|
||||
#include "DefaultVideoFilter.h"
|
||||
#define _USE_MATH_DEFINES
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include "DebugHud.h"
|
||||
#include "Console.h"
|
||||
|
||||
DefaultVideoFilter::DefaultVideoFilter(shared_ptr<Console> console) : BaseVideoFilter(console)
|
||||
{
|
||||
InitConversionMatrix(_pictureSettings.Hue, _pictureSettings.Saturation);
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::InitConversionMatrix(double hueShift, double saturationShift)
|
||||
{
|
||||
_pictureSettings.Hue = hueShift;
|
||||
_pictureSettings.Saturation = saturationShift;
|
||||
|
||||
double hue = hueShift * M_PI;
|
||||
double sat = saturationShift + 1;
|
||||
|
||||
double baseValues[6] = { 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
double s = sin(hue) * sat;
|
||||
double c = cos(hue) * sat;
|
||||
|
||||
double *output = _yiqToRgbMatrix;
|
||||
double *input = baseValues;
|
||||
for(int n = 0; n < 3; n++) {
|
||||
double i = *input++;
|
||||
double q = *input++;
|
||||
*output++ = i * c - q * s;
|
||||
*output++ = i * s + q * c;
|
||||
}
|
||||
}
|
||||
|
||||
FrameInfo DefaultVideoFilter::GetFrameInfo()
|
||||
{
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
return { overscan.GetScreenWidth(), overscan.GetScreenHeight(), OverscanDimensions::ScreenWidth, OverscanDimensions::ScreenHeight, 4 };
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::OnBeforeApplyFilter()
|
||||
{
|
||||
/*PictureSettings currentSettings = _console->GetSettings()->GetPictureSettings();
|
||||
if(_pictureSettings.Hue != currentSettings.Hue || _pictureSettings.Saturation != currentSettings.Saturation) {
|
||||
InitConversionMatrix(currentSettings.Hue, currentSettings.Saturation);
|
||||
}
|
||||
_pictureSettings = currentSettings;
|
||||
_needToProcess = _pictureSettings.Hue != 0 || _pictureSettings.Saturation != 0 || _pictureSettings.Brightness || _pictureSettings.Contrast;
|
||||
|
||||
if(_needToProcess) {
|
||||
double y, i, q;
|
||||
uint32_t* originalPalette = _console->GetSettings()->GetRgbPalette();
|
||||
|
||||
for(int pal = 0; pal < 512; pal++) {
|
||||
uint32_t pixelOutput = originalPalette[pal];
|
||||
double redChannel = ((pixelOutput & 0xFF0000) >> 16) / 255.0;
|
||||
double greenChannel = ((pixelOutput & 0xFF00) >> 8) / 255.0;
|
||||
double blueChannel = (pixelOutput & 0xFF) / 255.0;
|
||||
|
||||
//Apply brightness, contrast, hue & saturation
|
||||
RgbToYiq(redChannel, greenChannel, blueChannel, y, i, q);
|
||||
y *= _pictureSettings.Contrast * 0.5f + 1;
|
||||
y += _pictureSettings.Brightness * 0.5f;
|
||||
YiqToRgb(y, i, q, redChannel, greenChannel, blueChannel);
|
||||
|
||||
int r = std::min(255, (int)(redChannel * 255));
|
||||
int g = std::min(255, (int)(greenChannel * 255));
|
||||
int b = std::min(255, (int)(blueChannel * 255));
|
||||
|
||||
_calculatedPalette[pal] = 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
} else {
|
||||
memcpy(_calculatedPalette, _console->GetSettings()->GetRgbPalette(), sizeof(_calculatedPalette));
|
||||
}*/
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, bool displayScanlines)
|
||||
{
|
||||
/*uint32_t* out = outputBuffer;
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
uint8_t scanlineIntensity = (uint8_t)((1.0 - _console->GetSettings()->GetPictureSettings().ScanlineIntensity) * 255);
|
||||
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
|
||||
if(displayScanlines && (i + overscan.Top) % 2 == 0) {
|
||||
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
||||
*out = ApplyScanlineEffect(ppuOutputBuffer[i * 256 + j], scanlineIntensity);
|
||||
out++;
|
||||
}
|
||||
} else {
|
||||
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
||||
*out = _calculatedPalette[ppuOutputBuffer[i * 256 + j]];
|
||||
out++;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
||||
{
|
||||
uint32_t *out = GetOutputBuffer();
|
||||
for(int i = 0; i < 256 * 224; i++) {
|
||||
uint16_t rgb555 = ppuOutputBuffer[i];
|
||||
uint8_t b = (rgb555 >> 10) * 256 / 32;
|
||||
uint8_t g = ((rgb555 >> 5) & 0x1F) * 256 / 32;
|
||||
uint8_t r = (rgb555 & 0x1F) * 256 / 32;
|
||||
|
||||
out[i] = 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
//DecodePpuBuffer(ppuOutputBuffer, GetOutputBuffer(), _console->GetSettings()->GetVideoFilterType() <= VideoFilterType::BisqwitNtsc);
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::RgbToYiq(double r, double g, double b, double &y, double &i, double &q)
|
||||
{
|
||||
y = r * 0.299f + g * 0.587f + b * 0.114f;
|
||||
i = r * 0.596f - g * 0.275f - b * 0.321f;
|
||||
q = r * 0.212f - g * 0.523f + b * 0.311f;
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::YiqToRgb(double y, double i, double q, double &r, double &g, double &b)
|
||||
{
|
||||
r = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[0] * i + _yiqToRgbMatrix[1] * q)));
|
||||
g = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[2] * i + _yiqToRgbMatrix[3] * q)));
|
||||
b = std::max(0.0, std::min(1.0, (y + _yiqToRgbMatrix[4] * i + _yiqToRgbMatrix[5] * q)));
|
||||
}
|
||||
|
||||
uint32_t DefaultVideoFilter::ApplyScanlineEffect(uint16_t ppuPixel, uint8_t scanlineIntensity)
|
||||
{
|
||||
uint32_t pixelOutput = _calculatedPalette[ppuPixel];
|
||||
|
||||
uint8_t r = ((pixelOutput & 0xFF0000) >> 16) * scanlineIntensity / 255;
|
||||
uint8_t g = ((pixelOutput & 0xFF00) >> 8) * scanlineIntensity / 255;
|
||||
uint8_t b = (pixelOutput & 0xFF) * scanlineIntensity / 255;
|
||||
|
||||
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
28
Core/DefaultVideoFilter.h
Normal file
28
Core/DefaultVideoFilter.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "BaseVideoFilter.h"
|
||||
|
||||
class DefaultVideoFilter : public BaseVideoFilter
|
||||
{
|
||||
private:
|
||||
double _yiqToRgbMatrix[6];
|
||||
uint32_t _calculatedPalette[512];
|
||||
PictureSettings _pictureSettings;
|
||||
bool _needToProcess = false;
|
||||
|
||||
void InitConversionMatrix(double hueShift, double saturationShift);
|
||||
|
||||
void RgbToYiq(double r, double g, double b, double &y, double &i, double &q);
|
||||
void YiqToRgb(double y, double i, double q, double &r, double &g, double &b);
|
||||
|
||||
protected:
|
||||
void DecodePpuBuffer(uint16_t *ppuOutputBuffer, uint32_t* outputBuffer, bool displayScanlines);
|
||||
uint32_t ApplyScanlineEffect(uint16_t ppuPixel, uint8_t scanlineIntensity);
|
||||
void OnBeforeApplyFilter();
|
||||
|
||||
public:
|
||||
DefaultVideoFilter(shared_ptr<Console> console);
|
||||
void ApplyFilter(uint16_t *ppuOutputBuffer);
|
||||
FrameInfo GetFrameInfo();
|
||||
};
|
98
Core/DrawCommand.h
Normal file
98
Core/DrawCommand.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "SettingTypes.h"
|
||||
#include "Console.h"
|
||||
|
||||
class DrawCommand
|
||||
{
|
||||
private:
|
||||
int _frameCount;
|
||||
uint32_t* _argbBuffer;
|
||||
OverscanDimensions _overscan;
|
||||
uint32_t _lineWidth;
|
||||
uint32_t _startFrame;
|
||||
|
||||
protected:
|
||||
bool _useIntegerScaling;
|
||||
float _xScale;
|
||||
int _yScale;
|
||||
|
||||
virtual void InternalDraw() = 0;
|
||||
__forceinline void DrawPixel(uint32_t x, uint32_t y, int color)
|
||||
{
|
||||
if(x < _overscan.Left || x >= _overscan.Left + _overscan.GetScreenWidth() ||
|
||||
y < _overscan.Top || y >= _overscan.Top + _overscan.GetScreenHeight()) {
|
||||
//In overscan (out of bounds), skip drawing
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t alpha = (color & 0xFF000000);
|
||||
if(alpha > 0) {
|
||||
if(_yScale == 1) {
|
||||
if(alpha != 0xFF000000) {
|
||||
BlendColors((uint8_t*)&_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)], (uint8_t*)&color);
|
||||
} else {
|
||||
_argbBuffer[(y - _overscan.Top)*_lineWidth + (x - _overscan.Left)] = color;
|
||||
}
|
||||
} else {
|
||||
int xPixelCount = _useIntegerScaling ? _yScale : (int)((x + 1)*_xScale) - (int)(x*_xScale);
|
||||
x = (int)(x * (_useIntegerScaling ? _yScale : _xScale));
|
||||
y = (int)(y * _yScale);
|
||||
int top = (int)(_overscan.Top * _yScale);
|
||||
int left = (int)(_overscan.Left * _xScale);
|
||||
|
||||
for(int i = 0; i < _yScale; i++) {
|
||||
for(int j = 0; j < xPixelCount; j++) {
|
||||
if(alpha != 0xFF000000) {
|
||||
BlendColors((uint8_t*)&_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left)+j], (uint8_t*)&color);
|
||||
} else {
|
||||
_argbBuffer[(y - top)*_lineWidth + i*_lineWidth + (x - left) +j] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__forceinline void BlendColors(uint8_t output[4], uint8_t input[4])
|
||||
{
|
||||
uint8_t alpha = input[3] + 1;
|
||||
uint8_t invertedAlpha = 256 - input[3];
|
||||
output[0] = (uint8_t)((alpha * input[0] + invertedAlpha * output[0]) >> 8);
|
||||
output[1] = (uint8_t)((alpha * input[1] + invertedAlpha * output[1]) >> 8);
|
||||
output[2] = (uint8_t)((alpha * input[2] + invertedAlpha * output[2]) >> 8);
|
||||
output[3] = 0xFF;
|
||||
}
|
||||
|
||||
public:
|
||||
DrawCommand(int startFrame, int frameCount, bool useIntegerScaling = false)
|
||||
{
|
||||
_frameCount = frameCount > 0 ? frameCount : 1;
|
||||
_startFrame = startFrame;
|
||||
_useIntegerScaling = useIntegerScaling;
|
||||
}
|
||||
|
||||
virtual ~DrawCommand()
|
||||
{
|
||||
}
|
||||
|
||||
void Draw(uint32_t* argbBuffer, OverscanDimensions &overscan, uint32_t lineWidth, uint32_t frameNumber)
|
||||
{
|
||||
if(_startFrame <= frameNumber) {
|
||||
_argbBuffer = argbBuffer;
|
||||
_overscan = overscan;
|
||||
_lineWidth = lineWidth;
|
||||
_yScale = lineWidth / overscan.GetScreenWidth();
|
||||
_xScale = (float)lineWidth / overscan.GetScreenWidth();
|
||||
|
||||
InternalDraw();
|
||||
|
||||
_frameCount--;
|
||||
}
|
||||
}
|
||||
|
||||
bool Expired()
|
||||
{
|
||||
return _frameCount <= 0;
|
||||
}
|
||||
};
|
42
Core/DrawLineCommand.h
Normal file
42
Core/DrawLineCommand.h
Normal file
|
@ -0,0 +1,42 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawLineCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _x2, _y2, _color;
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
int x = _x;
|
||||
int y = _y;
|
||||
int dx = abs(_x2 - x), sx = x < _x2 ? 1 : -1;
|
||||
int dy = abs(_y2 - y), sy = y < _y2 ? 1 : -1;
|
||||
int err = (dx > dy ? dx : -dy) / 2, e2;
|
||||
|
||||
while(true) {
|
||||
DrawPixel(x, y, _color);
|
||||
if(x == _x2 && y == _y2) {
|
||||
break;
|
||||
}
|
||||
|
||||
e2 = err;
|
||||
if(e2 > -dx) {
|
||||
err -= dy; x += sx;
|
||||
}
|
||||
if(e2 < dy) {
|
||||
err += dx; y += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawLineCommand(int x, int y, int x2, int y2, int color, int frameCount, int startFrame) :
|
||||
DrawCommand(startFrame, frameCount), _x(x), _y(y), _x2(x2), _y2(y2), _color(color)
|
||||
{
|
||||
//Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time)
|
||||
_color = (~color & 0xFF000000) | (color & 0xFFFFFF);
|
||||
}
|
||||
};
|
23
Core/DrawPixelCommand.h
Normal file
23
Core/DrawPixelCommand.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawPixelCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _color;
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
DrawPixel(_x, _y, _color);
|
||||
}
|
||||
|
||||
public:
|
||||
DrawPixelCommand(int x, int y, int color, int frameCount, int startFrame) :
|
||||
DrawCommand(startFrame, frameCount), _x(x), _y(y), _color(color)
|
||||
{
|
||||
//Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time)
|
||||
_color = (~color & 0xFF000000) | (color & 0xFFFFFF);
|
||||
}
|
||||
};
|
48
Core/DrawRectangleCommand.h
Normal file
48
Core/DrawRectangleCommand.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawRectangleCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _width, _height, _color;
|
||||
bool _fill;
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
if(_fill) {
|
||||
for(int j = 0; j < _height; j++) {
|
||||
for(int i = 0; i < _width; i++) {
|
||||
DrawPixel(_x + i, _y + j, _color);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i = 0; i < _width; i++) {
|
||||
DrawPixel(_x + i, _y, _color);
|
||||
DrawPixel(_x + i, _y + _height - 1, _color);
|
||||
}
|
||||
for(int i = 1; i < _height - 1; i++) {
|
||||
DrawPixel(_x, _y + i, _color);
|
||||
DrawPixel(_x + _width - 1, _y + i, _color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawRectangleCommand(int x, int y, int width, int height, int color, bool fill, int frameCount, int startFrame) :
|
||||
DrawCommand(startFrame, frameCount), _x(x), _y(y), _width(width), _height(height), _color(color), _fill(fill)
|
||||
{
|
||||
if(width < 0) {
|
||||
_x += width + 1;
|
||||
_width = -width;
|
||||
}
|
||||
if(height < 0) {
|
||||
_y += height + 1;
|
||||
_height = -height;
|
||||
}
|
||||
|
||||
//Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time)
|
||||
_color = (~color & 0xFF000000) | (color & 0xFFFFFF);
|
||||
}
|
||||
};
|
25
Core/DrawScreenBufferCommand.h
Normal file
25
Core/DrawScreenBufferCommand.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawScreenBufferCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
uint32_t _screenBuffer[256*240];
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
for(int y = 0; y < 240; y++) {
|
||||
for(int x = 0; x < 256; x++) {
|
||||
DrawPixel(x, y, _screenBuffer[(y << 8) + x]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawScreenBufferCommand(uint32_t* screenBuffer, int startFrame) : DrawCommand(startFrame, 1)
|
||||
{
|
||||
memcpy(_screenBuffer, screenBuffer, 256 * 240 * sizeof(uint32_t));
|
||||
}
|
||||
};
|
161
Core/DrawStringCommand.h
Normal file
161
Core/DrawStringCommand.h
Normal file
|
@ -0,0 +1,161 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "DrawCommand.h"
|
||||
|
||||
class DrawStringCommand : public DrawCommand
|
||||
{
|
||||
private:
|
||||
int _x, _y, _color, _backColor;
|
||||
string _text;
|
||||
|
||||
//Taken from FCEUX's LUA code
|
||||
const int _tabSpace = 4;
|
||||
const uint8_t _font[792] = {
|
||||
6, 0, 0, 0, 0, 0, 0, 0, // 0x20 - Spacebar
|
||||
3, 64, 64, 64, 64, 64, 0, 64,
|
||||
5, 80, 80, 80, 0, 0, 0, 0,
|
||||
6, 80, 80,248, 80,248, 80, 80,
|
||||
6, 32,120,160,112, 40,240, 32,
|
||||
6, 64,168, 80, 32, 80,168, 16,
|
||||
6, 96,144,160, 64,168,144,104,
|
||||
3, 64, 64, 0, 0, 0, 0, 0,
|
||||
4, 32, 64, 64, 64, 64, 64, 32,
|
||||
4, 64, 32, 32, 32, 32, 32, 64,
|
||||
6, 0, 80, 32,248, 32, 80, 0,
|
||||
6, 0, 32, 32,248, 32, 32, 0,
|
||||
3, 0, 0, 0, 0, 0, 64,128,
|
||||
5, 0, 0, 0,240, 0, 0, 0,
|
||||
3, 0, 0, 0, 0, 0, 0, 64,
|
||||
5, 16, 16, 32, 32, 32, 64, 64,
|
||||
6,112,136,136,136,136,136,112, // 0x30 - 0
|
||||
6, 32, 96, 32, 32, 32, 32, 32,
|
||||
6,112,136, 8, 48, 64,128,248,
|
||||
6,112,136, 8, 48, 8,136,112,
|
||||
6, 16, 48, 80,144,248, 16, 16,
|
||||
6,248,128,128,240, 8, 8,240,
|
||||
6, 48, 64,128,240,136,136,112,
|
||||
6,248, 8, 16, 16, 32, 32, 32,
|
||||
6,112,136,136,112,136,136,112,
|
||||
6,112,136,136,120, 8, 16, 96,
|
||||
3, 0, 0, 64, 0, 0, 64, 0,
|
||||
3, 0, 0, 64, 0, 0, 64,128,
|
||||
4, 0, 32, 64,128, 64, 32, 0,
|
||||
5, 0, 0,240, 0,240, 0, 0,
|
||||
4, 0,128, 64, 32, 64,128, 0,
|
||||
6,112,136, 8, 16, 32, 0, 32, // 0x3F - ?
|
||||
6,112,136,136,184,176,128,112, // 0x40 - @
|
||||
6,112,136,136,248,136,136,136, // 0x41 - A
|
||||
6,240,136,136,240,136,136,240,
|
||||
6,112,136,128,128,128,136,112,
|
||||
6,224,144,136,136,136,144,224,
|
||||
6,248,128,128,240,128,128,248,
|
||||
6,248,128,128,240,128,128,128,
|
||||
6,112,136,128,184,136,136,120,
|
||||
6,136,136,136,248,136,136,136,
|
||||
4,224, 64, 64, 64, 64, 64,224,
|
||||
6, 8, 8, 8, 8, 8,136,112,
|
||||
6,136,144,160,192,160,144,136,
|
||||
6,128,128,128,128,128,128,248,
|
||||
6,136,216,168,168,136,136,136,
|
||||
6,136,136,200,168,152,136,136,
|
||||
7, 48, 72,132,132,132, 72, 48,
|
||||
6,240,136,136,240,128,128,128,
|
||||
6,112,136,136,136,168,144,104,
|
||||
6,240,136,136,240,144,136,136,
|
||||
6,112,136,128,112, 8,136,112,
|
||||
6,248, 32, 32, 32, 32, 32, 32,
|
||||
6,136,136,136,136,136,136,112,
|
||||
6,136,136,136, 80, 80, 32, 32,
|
||||
6,136,136,136,136,168,168, 80,
|
||||
6,136,136, 80, 32, 80,136,136,
|
||||
6,136,136, 80, 32, 32, 32, 32,
|
||||
6,248, 8, 16, 32, 64,128,248,
|
||||
3,192,128,128,128,128,128,192,
|
||||
5, 64, 64, 32, 32, 32, 16, 16,
|
||||
3,192, 64, 64, 64, 64, 64,192,
|
||||
4, 64,160, 0, 0, 0, 0, 0,
|
||||
6, 0, 0, 0, 0, 0, 0,248,
|
||||
3,128, 64, 0, 0, 0, 0, 0,
|
||||
5, 0, 0, 96, 16,112,144,112, // 0x61 - a
|
||||
5,128,128,224,144,144,144,224,
|
||||
5, 0, 0,112,128,128,128,112,
|
||||
5, 16, 16,112,144,144,144,112,
|
||||
5, 0, 0, 96,144,240,128,112,
|
||||
5, 48, 64,224, 64, 64, 64, 64,
|
||||
5, 0,112,144,144,112, 16,224,
|
||||
5,128,128,224,144,144,144,144,
|
||||
2,128, 0,128,128,128,128,128,
|
||||
4, 32, 0, 32, 32, 32, 32,192,
|
||||
5,128,128,144,160,192,160,144,
|
||||
2,128,128,128,128,128,128,128,
|
||||
6, 0, 0,208,168,168,168,168,
|
||||
5, 0, 0,224,144,144,144,144,
|
||||
5, 0, 0, 96,144,144,144, 96,
|
||||
5, 0,224,144,144,224,128,128,
|
||||
5, 0,112,144,144,112, 16, 16,
|
||||
5, 0, 0,176,192,128,128,128,
|
||||
5, 0, 0,112,128, 96, 16,224,
|
||||
4, 64, 64,224, 64, 64, 64, 32,
|
||||
5, 0, 0,144,144,144,144,112,
|
||||
5, 0, 0,144,144,144,160,192,
|
||||
6, 0, 0,136,136,168,168, 80,
|
||||
5, 0, 0,144,144, 96,144,144,
|
||||
5, 0,144,144,144,112, 16, 96,
|
||||
5, 0, 0,240, 32, 64,128,240,
|
||||
4, 32, 64, 64,128, 64, 64, 32,
|
||||
3, 64, 64, 64, 64, 64, 64, 64,
|
||||
4,128, 64, 64, 32, 64, 64,128,
|
||||
6, 0,104,176, 0, 0, 0, 0
|
||||
};
|
||||
|
||||
int GetCharNumber(char ch)
|
||||
{
|
||||
ch -= 32;
|
||||
return (ch < 0 || ch > 98) ? 0 : ch;
|
||||
}
|
||||
|
||||
int GetCharWidth(char ch)
|
||||
{
|
||||
return _font[GetCharNumber(ch) * 8];
|
||||
}
|
||||
|
||||
protected:
|
||||
void InternalDraw()
|
||||
{
|
||||
int startX = (int)(_x * _xScale / _yScale);
|
||||
int x = startX;
|
||||
int y = _y;
|
||||
for(char c : _text) {
|
||||
if(c == '\n') {
|
||||
x = startX;
|
||||
y += 9;
|
||||
} else if(c == '\t') {
|
||||
x += (_tabSpace - (((x - startX) / 8) % _tabSpace)) * 8;
|
||||
} else {
|
||||
int ch = GetCharNumber(c);
|
||||
int width = GetCharWidth(c);
|
||||
int rowOffset = (c == 'y' || c == 'g' || c == 'p' || c == 'q') ? 1 : 0;
|
||||
for(int j = 0; j < 8; j++) {
|
||||
uint8_t rowData = ((j == 7 && rowOffset == 0) || (j == 0 && rowOffset == 1)) ? 0 : _font[ch * 8 + 1 + j - rowOffset];
|
||||
for(int i = 0; i < width; i++) {
|
||||
int drawFg = (rowData >> (7 - i)) & 0x01;
|
||||
DrawPixel(x + i, y + j, drawFg ? _color : _backColor);
|
||||
}
|
||||
}
|
||||
for(int i = 0; i < width; i++) {
|
||||
DrawPixel(x + i, y - 1, _backColor);
|
||||
}
|
||||
x += width;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
DrawStringCommand(int x, int y, string text, int color, int backColor, int frameCount, int startFrame) :
|
||||
DrawCommand(startFrame, frameCount, true), _x(x), _y(y), _color(color), _backColor(backColor), _text(text)
|
||||
{
|
||||
//Invert alpha byte - 0 = opaque, 255 = transparent (this way, no need to specifiy alpha channel all the time)
|
||||
_color = (~color & 0xFF000000) | (color & 0xFFFFFF);
|
||||
_backColor = (~backColor & 0xFF000000) | (backColor & 0xFFFFFF);
|
||||
}
|
||||
};
|
129
Core/SettingTypes.h
Normal file
129
Core/SettingTypes.h
Normal file
|
@ -0,0 +1,129 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
enum class ScaleFilterType
|
||||
{
|
||||
xBRZ = 0,
|
||||
HQX = 1,
|
||||
Scale2x = 2,
|
||||
_2xSai = 3,
|
||||
Super2xSai = 4,
|
||||
SuperEagle = 5,
|
||||
Prescale = 6,
|
||||
};
|
||||
|
||||
enum class VideoFilterType
|
||||
{
|
||||
None = 0,
|
||||
NTSC = 1,
|
||||
BisqwitNtscQuarterRes = 2,
|
||||
BisqwitNtscHalfRes = 3,
|
||||
BisqwitNtsc = 4,
|
||||
xBRZ2x = 5,
|
||||
xBRZ3x = 6,
|
||||
xBRZ4x = 7,
|
||||
xBRZ5x = 8,
|
||||
xBRZ6x = 9,
|
||||
HQ2x = 10,
|
||||
HQ3x = 11,
|
||||
HQ4x = 12,
|
||||
Scale2x = 13,
|
||||
Scale3x = 14,
|
||||
Scale4x = 15,
|
||||
_2xSai = 16,
|
||||
Super2xSai = 17,
|
||||
SuperEagle = 18,
|
||||
Prescale2x = 19,
|
||||
Prescale3x = 20,
|
||||
Prescale4x = 21,
|
||||
Prescale6x = 22,
|
||||
Prescale8x = 23,
|
||||
Prescale10x = 24,
|
||||
Raw = 25,
|
||||
HdPack = 999
|
||||
};
|
||||
|
||||
enum class VideoResizeFilter
|
||||
{
|
||||
NearestNeighbor = 0,
|
||||
Bilinear = 1
|
||||
};
|
||||
|
||||
enum class VideoAspectRatio
|
||||
{
|
||||
NoStretching = 0,
|
||||
Auto = 1,
|
||||
NTSC = 2,
|
||||
PAL = 3,
|
||||
Standard = 4,
|
||||
Widescreen = 5,
|
||||
Custom = 6
|
||||
};
|
||||
|
||||
struct OverscanDimensions
|
||||
{
|
||||
static const int ScreenWidth = 256;
|
||||
static const int ScreenHeight = 224;
|
||||
|
||||
uint32_t Left = 0;
|
||||
uint32_t Right = 0;
|
||||
uint32_t Top = 0;
|
||||
uint32_t Bottom = 0;
|
||||
|
||||
uint32_t GetPixelCount()
|
||||
{
|
||||
return GetScreenWidth() * GetScreenHeight();
|
||||
}
|
||||
|
||||
uint32_t GetScreenWidth()
|
||||
{
|
||||
return 256 - Left - Right;
|
||||
}
|
||||
|
||||
uint32_t GetScreenHeight()
|
||||
{
|
||||
return 224 - Top - Bottom;
|
||||
}
|
||||
};
|
||||
|
||||
struct PictureSettings
|
||||
{
|
||||
double Brightness = 0;
|
||||
double Contrast = 0;
|
||||
double Saturation = 0;
|
||||
double Hue = 0;
|
||||
double ScanlineIntensity = 0;
|
||||
};
|
||||
|
||||
struct NtscFilterSettings
|
||||
{
|
||||
double Sharpness = 0;
|
||||
double Gamma = 0;
|
||||
double Resolution = 0;
|
||||
double Artifacts = 0;
|
||||
double Fringing = 0;
|
||||
double Bleed = 0;
|
||||
bool MergeFields = false;
|
||||
bool VerticalBlend = false;
|
||||
bool KeepVerticalResolution = false;
|
||||
|
||||
double YFilterLength = 0;
|
||||
double IFilterLength = 0;
|
||||
double QFilterLength = 0;
|
||||
};
|
||||
|
||||
struct FrameInfo
|
||||
{
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint32_t OriginalWidth;
|
||||
uint32_t OriginalHeight;
|
||||
uint32_t BitsPerPixel;
|
||||
};
|
||||
|
||||
struct ScreenSize
|
||||
{
|
||||
int32_t Width;
|
||||
int32_t Height;
|
||||
double Scale;
|
||||
};
|
240
Core/VideoDecoder.cpp
Normal file
240
Core/VideoDecoder.cpp
Normal file
|
@ -0,0 +1,240 @@
|
|||
#include "stdafx.h"
|
||||
#include "IRenderingDevice.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "VideoRenderer.h"
|
||||
#include "DefaultVideoFilter.h"
|
||||
#include "Console.h"
|
||||
#include "Ppu.h"
|
||||
#include "DebugHud.h"
|
||||
|
||||
VideoDecoder::VideoDecoder(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_frameChanged = false;
|
||||
_stopFlag = false;
|
||||
UpdateVideoFilter();
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder()
|
||||
{
|
||||
StopThread();
|
||||
}
|
||||
|
||||
FrameInfo VideoDecoder::GetFrameInfo()
|
||||
{
|
||||
return _lastFrameInfo;
|
||||
}
|
||||
|
||||
void VideoDecoder::GetScreenSize(ScreenSize &size, bool ignoreScale)
|
||||
{
|
||||
if(_videoFilter) {
|
||||
/*OverscanDimensions overscan = ignoreScale ? _videoFilter->GetOverscan() : _console->GetSettings()->GetOverscanDimensions();
|
||||
FrameInfo frameInfo{ overscan.GetScreenWidth(), overscan.GetScreenHeight(), PPU::ScreenWidth, PPU::ScreenHeight, 4 };
|
||||
double aspectRatio = _console->GetSettings()->GetAspectRatio(_console);
|
||||
double scale = (ignoreScale ? 1 : _console->GetSettings()->GetVideoScale());
|
||||
size.Width = (int32_t)(frameInfo.Width * scale);
|
||||
size.Height = (int32_t)(frameInfo.Height * scale);
|
||||
if(aspectRatio != 0.0) {
|
||||
size.Width = (uint32_t)(frameInfo.OriginalHeight * scale * aspectRatio * ((double)frameInfo.Width / frameInfo.OriginalWidth));
|
||||
}
|
||||
|
||||
if(_console->GetSettings()->GetScreenRotation() % 180) {
|
||||
std::swap(size.Width, size.Height);
|
||||
}
|
||||
|
||||
size.Scale = scale;*/
|
||||
|
||||
if(true || ignoreScale) {
|
||||
size.Width = 256;
|
||||
size.Height = 224;
|
||||
} else {
|
||||
size.Width = 512;
|
||||
size.Height = 448;
|
||||
}
|
||||
size.Scale = 2;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDecoder::UpdateVideoFilter()
|
||||
{
|
||||
VideoFilterType newFilter = VideoFilterType::None;
|
||||
|
||||
if(_videoFilterType != newFilter || _videoFilter == nullptr) {
|
||||
_videoFilterType = newFilter;
|
||||
_videoFilter.reset(new DefaultVideoFilter(_console));
|
||||
//_scaleFilter.reset();
|
||||
|
||||
switch(_videoFilterType) {
|
||||
case VideoFilterType::None: break;
|
||||
|
||||
//TODO
|
||||
/*
|
||||
case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter(_console)); break;
|
||||
case VideoFilterType::BisqwitNtsc: _videoFilter.reset(new BisqwitNtscFilter(_console, 1)); break;
|
||||
case VideoFilterType::BisqwitNtscHalfRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 2)); break;
|
||||
case VideoFilterType::BisqwitNtscQuarterRes: _videoFilter.reset(new BisqwitNtscFilter(_console, 4)); break;
|
||||
case VideoFilterType::Raw: _videoFilter.reset(new RawVideoFilter(_console)); break;
|
||||
default: _scaleFilter = ScaleFilter::GetScaleFilter(_videoFilterType); break;*/
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*
|
||||
if(_console->GetSettings()->GetScreenRotation() == 0 && _rotateFilter) {
|
||||
_rotateFilter.reset();
|
||||
} else if(_console->GetSettings()->GetScreenRotation() > 0) {
|
||||
if(!_rotateFilter || _rotateFilter->GetAngle() != _console->GetSettings()->GetScreenRotation()) {
|
||||
_rotateFilter.reset(new RotateFilter(_console->GetSettings()->GetScreenRotation()));
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
void VideoDecoder::DecodeFrame(bool synchronous)
|
||||
{
|
||||
UpdateVideoFilter();
|
||||
|
||||
_videoFilter->SendFrame(_ppuOutputBuffer, _frameNumber);
|
||||
|
||||
uint32_t* outputBuffer = _videoFilter->GetOutputBuffer();
|
||||
FrameInfo frameInfo = _videoFilter->GetFrameInfo();
|
||||
_console->GetDebugHud()->Draw(outputBuffer, _videoFilter->GetOverscan(), frameInfo.Width, _frameNumber);
|
||||
|
||||
/*
|
||||
if(_rotateFilter) {
|
||||
outputBuffer = _rotateFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height);
|
||||
frameInfo = _rotateFilter->GetFrameInfo(frameInfo);
|
||||
}
|
||||
|
||||
if(_scaleFilter) {
|
||||
outputBuffer = _scaleFilter->ApplyFilter(outputBuffer, frameInfo.Width, frameInfo.Height, _console->GetSettings()->GetPictureSettings().ScanlineIntensity);
|
||||
frameInfo = _scaleFilter->GetFrameInfo(frameInfo);
|
||||
}
|
||||
|
||||
if(_hud) {
|
||||
_hud->DrawHud(_console, outputBuffer, frameInfo, _videoFilter->GetOverscan());
|
||||
}*/
|
||||
|
||||
ScreenSize screenSize;
|
||||
GetScreenSize(screenSize, true);
|
||||
/*if(_previousScale != _console->GetSettings()->GetVideoScale() || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) {
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ResolutionChanged);
|
||||
}*/
|
||||
_previousScale = 1; // _console->GetSettings()->GetVideoScale();
|
||||
_previousScreenSize = screenSize;
|
||||
_lastFrameInfo = frameInfo;
|
||||
|
||||
_frameChanged = false;
|
||||
|
||||
//Rewind manager will take care of sending the correct frame to the video renderer
|
||||
_console->GetVideoRenderer()->UpdateFrame(outputBuffer, frameInfo.Width, frameInfo.Height);
|
||||
}
|
||||
|
||||
void VideoDecoder::DecodeThread()
|
||||
{
|
||||
//This thread will decode the PPU's output (color ID to RGB, intensify r/g/b and produce a HD version of the frame if needed)
|
||||
while(!_stopFlag.load()) {
|
||||
//DecodeFrame returns the final ARGB frame we want to display in the emulator window
|
||||
while(!_frameChanged) {
|
||||
_waitForFrame.Wait();
|
||||
if(_stopFlag.load()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
DecodeFrame();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VideoDecoder::GetFrameCount()
|
||||
{
|
||||
return _frameCount;
|
||||
}
|
||||
|
||||
void VideoDecoder::UpdateFrameSync(uint16_t *ppuOutputBuffer, uint32_t frameNumber)
|
||||
{
|
||||
_frameNumber = frameNumber;
|
||||
_ppuOutputBuffer = ppuOutputBuffer;
|
||||
DecodeFrame(true);
|
||||
_frameCount++;
|
||||
}
|
||||
|
||||
void VideoDecoder::UpdateFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber)
|
||||
{
|
||||
if(_frameChanged) {
|
||||
//Last frame isn't done decoding yet - sometimes Signal() introduces a 25-30ms delay
|
||||
while(_frameChanged) {
|
||||
//Spin until decode is done
|
||||
}
|
||||
//At this point, we are sure that the decode thread is no longer busy
|
||||
}
|
||||
|
||||
_frameNumber = frameNumber;
|
||||
_ppuOutputBuffer = ppuOutputBuffer;
|
||||
_frameChanged = true;
|
||||
_waitForFrame.Signal();
|
||||
|
||||
_frameCount++;
|
||||
}
|
||||
|
||||
void VideoDecoder::StartThread()
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
if(!_decodeThread) {
|
||||
_stopFlag = false;
|
||||
_frameChanged = false;
|
||||
_frameCount = 0;
|
||||
_waitForFrame.Reset();
|
||||
|
||||
//TODO
|
||||
//_hud.reset(new VideoHud());
|
||||
|
||||
_decodeThread.reset(new thread(&VideoDecoder::DecodeThread, this));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VideoDecoder::StopThread()
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
_stopFlag = true;
|
||||
if(_decodeThread) {
|
||||
_waitForFrame.Signal();
|
||||
_decodeThread->join();
|
||||
|
||||
_decodeThread.reset();
|
||||
|
||||
|
||||
//TODO
|
||||
//_hud.reset();
|
||||
/*UpdateVideoFilter();
|
||||
if(_ppuOutputBuffer != nullptr) {
|
||||
//Clear whole screen
|
||||
for(uint32_t i = 0; i < PPU::PixelCount; i++) {
|
||||
_ppuOutputBuffer[i] = 14; //Black
|
||||
}
|
||||
DecodeFrame();
|
||||
}*/
|
||||
_ppuOutputBuffer = nullptr;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
bool VideoDecoder::IsRunning()
|
||||
{
|
||||
return _decodeThread != nullptr;
|
||||
}
|
||||
|
||||
void VideoDecoder::TakeScreenshot()
|
||||
{
|
||||
if(_videoFilter) {
|
||||
//TODO
|
||||
//_videoFilter->TakeScreenshot(_console->GetRomPath().GetFileName(), _videoFilterType);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDecoder::TakeScreenshot(std::stringstream &stream)
|
||||
{
|
||||
if(_videoFilter) {
|
||||
_videoFilter->TakeScreenshot(_videoFilterType, "", &stream);
|
||||
}
|
||||
}
|
63
Core/VideoDecoder.h
Normal file
63
Core/VideoDecoder.h
Normal file
|
@ -0,0 +1,63 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "../Utilities/AutoResetEvent.h"
|
||||
#include "SettingTypes.h"
|
||||
|
||||
class BaseVideoFilter;
|
||||
//class ScaleFilter;
|
||||
//class RotateFilter;
|
||||
class IRenderingDevice;
|
||||
//class VideoHud;
|
||||
class Console;
|
||||
|
||||
class VideoDecoder
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
||||
uint16_t *_ppuOutputBuffer = nullptr;
|
||||
uint32_t _frameNumber = 0;
|
||||
|
||||
unique_ptr<thread> _decodeThread;
|
||||
//unique_ptr<VideoHud> _hud;
|
||||
|
||||
AutoResetEvent _waitForFrame;
|
||||
|
||||
atomic<bool> _frameChanged;
|
||||
atomic<bool> _stopFlag;
|
||||
uint32_t _frameCount = 0;
|
||||
|
||||
ScreenSize _previousScreenSize = {};
|
||||
double _previousScale = 0;
|
||||
FrameInfo _lastFrameInfo;
|
||||
|
||||
VideoFilterType _videoFilterType = VideoFilterType::None;
|
||||
unique_ptr<BaseVideoFilter> _videoFilter;
|
||||
//shared_ptr<ScaleFilter> _scaleFilter;
|
||||
//shared_ptr<RotateFilter> _rotateFilter;
|
||||
|
||||
void UpdateVideoFilter();
|
||||
|
||||
void DecodeThread();
|
||||
|
||||
public:
|
||||
VideoDecoder(shared_ptr<Console> console);
|
||||
~VideoDecoder();
|
||||
|
||||
void DecodeFrame(bool synchronous = false);
|
||||
void TakeScreenshot();
|
||||
void TakeScreenshot(std::stringstream &stream);
|
||||
|
||||
uint32_t GetFrameCount();
|
||||
|
||||
FrameInfo GetFrameInfo();
|
||||
void GetScreenSize(ScreenSize &size, bool ignoreScale);
|
||||
|
||||
void UpdateFrameSync(uint16_t *ppuOutputBuffer, uint32_t frameNumber);
|
||||
void UpdateFrame(uint16_t *ppuOutputBuffer, uint32_t frameNumber);
|
||||
|
||||
bool IsRunning();
|
||||
void StartThread();
|
||||
void StopThread();
|
||||
};
|
116
Core/VideoRenderer.cpp
Normal file
116
Core/VideoRenderer.cpp
Normal file
|
@ -0,0 +1,116 @@
|
|||
#include "stdafx.h"
|
||||
#include "IRenderingDevice.h"
|
||||
#include "VideoRenderer.h"
|
||||
//#include "AviRecorder.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "Console.h"
|
||||
|
||||
VideoRenderer::VideoRenderer(shared_ptr<Console> console)
|
||||
{
|
||||
_console = console;
|
||||
_stopFlag = false;
|
||||
StartThread();
|
||||
}
|
||||
|
||||
VideoRenderer::~VideoRenderer()
|
||||
{
|
||||
_stopFlag = true;
|
||||
StopThread();
|
||||
}
|
||||
|
||||
void VideoRenderer::StartThread()
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
if(!_renderThread) {
|
||||
_stopFlag = false;
|
||||
_waitForRender.Reset();
|
||||
|
||||
_renderThread.reset(new std::thread(&VideoRenderer::RenderThread, this));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VideoRenderer::StopThread()
|
||||
{
|
||||
#ifndef LIBRETRO
|
||||
_stopFlag = true;
|
||||
if(_renderThread) {
|
||||
_renderThread->join();
|
||||
_renderThread.reset();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void VideoRenderer::RenderThread()
|
||||
{
|
||||
if(_renderer) {
|
||||
_renderer->Reset();
|
||||
}
|
||||
|
||||
while(!_stopFlag.load()) {
|
||||
//Wait until a frame is ready, or until 16ms have passed (to allow UI to run at a minimum of 60fps)
|
||||
_waitForRender.Wait(16);
|
||||
if(_renderer) {
|
||||
_renderer->Render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VideoRenderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height)
|
||||
{
|
||||
//TODO
|
||||
/*shared_ptr<AviRecorder> aviRecorder = _aviRecorder;
|
||||
if(aviRecorder) {
|
||||
aviRecorder->AddFrame(frameBuffer, width, height);
|
||||
}*/
|
||||
|
||||
if(_renderer) {
|
||||
_renderer->UpdateFrame(frameBuffer, width, height);
|
||||
_waitForRender.Signal();
|
||||
}
|
||||
}
|
||||
|
||||
void VideoRenderer::RegisterRenderingDevice(IRenderingDevice *renderer)
|
||||
{
|
||||
_renderer = renderer;
|
||||
StartThread();
|
||||
}
|
||||
|
||||
void VideoRenderer::UnregisterRenderingDevice(IRenderingDevice *renderer)
|
||||
{
|
||||
if(_renderer == renderer) {
|
||||
StopThread();
|
||||
_renderer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
//TODO
|
||||
/*
|
||||
void VideoRenderer::StartRecording(string filename, VideoCodec codec, uint32_t compressionLevel)
|
||||
{
|
||||
shared_ptr<AviRecorder> recorder(new AviRecorder(_console));
|
||||
|
||||
FrameInfo frameInfo = _console->GetVideoDecoder()->GetFrameInfo();
|
||||
if(recorder->StartRecording(filename, codec, frameInfo.Width, frameInfo.Height, frameInfo.BitsPerPixel, _console->GetSettings()->GetSampleRate(), compressionLevel)) {
|
||||
_aviRecorder = recorder;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoRenderer::AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate)
|
||||
{
|
||||
shared_ptr<AviRecorder> aviRecorder = _aviRecorder;
|
||||
if(aviRecorder) {
|
||||
aviRecorder->AddSound(soundBuffer, sampleCount, sampleRate);
|
||||
}
|
||||
}
|
||||
|
||||
void VideoRenderer::StopRecording()
|
||||
{
|
||||
_aviRecorder.reset();
|
||||
}
|
||||
|
||||
bool VideoRenderer::IsRecording()
|
||||
{
|
||||
return _aviRecorder != nullptr && _aviRecorder->IsRecording();
|
||||
}
|
||||
*/
|
45
Core/VideoRenderer.h
Normal file
45
Core/VideoRenderer.h
Normal file
|
@ -0,0 +1,45 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <thread>
|
||||
#include "../Utilities/AutoResetEvent.h"
|
||||
|
||||
class IRenderingDevice;
|
||||
class Console;
|
||||
|
||||
//TODO
|
||||
//class AviRecorder;
|
||||
//enum class VideoCodec;
|
||||
|
||||
class VideoRenderer
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
||||
AutoResetEvent _waitForRender;
|
||||
unique_ptr<std::thread> _renderThread;
|
||||
IRenderingDevice* _renderer = nullptr;
|
||||
atomic<bool> _stopFlag;
|
||||
|
||||
//TODO
|
||||
//shared_ptr<AviRecorder> _aviRecorder;
|
||||
|
||||
void RenderThread();
|
||||
|
||||
public:
|
||||
VideoRenderer(shared_ptr<Console> console);
|
||||
~VideoRenderer();
|
||||
|
||||
void StartThread();
|
||||
void StopThread();
|
||||
|
||||
void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height);
|
||||
void RegisterRenderingDevice(IRenderingDevice *renderer);
|
||||
void UnregisterRenderingDevice(IRenderingDevice *renderer);
|
||||
|
||||
//TODO
|
||||
/*
|
||||
void StartRecording(string filename, VideoCodec codec, uint32_t compressionLevel);
|
||||
void AddRecordingSound(int16_t* soundBuffer, uint32_t sampleCount, uint32_t sampleRate);
|
||||
void StopRecording();
|
||||
bool IsRecording();*/
|
||||
};
|
|
@ -16,6 +16,7 @@
|
|||
#include <sstream>
|
||||
#include <list>
|
||||
#include <atomic>
|
||||
#include <thread>
|
||||
|
||||
#include "../Utilities/UTF8Util.h"
|
||||
|
||||
|
@ -42,6 +43,7 @@ using std::max;
|
|||
using std::string;
|
||||
using std::atomic_flag;
|
||||
using std::atomic;
|
||||
using std::thread;
|
||||
|
||||
#ifdef _DEBUG
|
||||
#pragma comment(lib, "C:\\Code\\Mesen-S\\bin\\x64\\Debug\\Utilities.lib")
|
||||
|
|
|
@ -62,6 +62,7 @@ namespace InteropEmu {
|
|||
DllExport void __stdcall InitDll()
|
||||
{
|
||||
_console.reset(new Console());
|
||||
_console->Initialize();
|
||||
}
|
||||
|
||||
DllExport void __stdcall InitializeEmu(const char* homeFolder, void *windowHandle, void *viewerHandle, bool noAudio, bool noVideo, bool noInput)
|
||||
|
|
53
UI/Forms/frmMain.Designer.cs
generated
53
UI/Forms/frmMain.Designer.cs
generated
|
@ -34,10 +34,10 @@
|
|||
this.debugToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuRun = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuStep = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuRun100Instructions = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem1 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTraceLogger = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuRun100Instructions = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuMain.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
|
@ -55,7 +55,7 @@
|
|||
this.debugToolStripMenuItem});
|
||||
this.mnuMain.Location = new System.Drawing.Point(0, 0);
|
||||
this.mnuMain.Name = "mnuMain";
|
||||
this.mnuMain.Size = new System.Drawing.Size(514, 24);
|
||||
this.mnuMain.Size = new System.Drawing.Size(512, 24);
|
||||
this.mnuMain.TabIndex = 1;
|
||||
this.mnuMain.Text = "ctrlMesenMenuStrip1";
|
||||
//
|
||||
|
@ -71,7 +71,8 @@
|
|||
//
|
||||
this.mnuOpen.Image = global::Mesen.GUI.Properties.Resources.Folder;
|
||||
this.mnuOpen.Name = "mnuOpen";
|
||||
this.mnuOpen.Size = new System.Drawing.Size(103, 22);
|
||||
this.mnuOpen.ShortcutKeys = ((System.Windows.Forms.Keys)((System.Windows.Forms.Keys.Control | System.Windows.Forms.Keys.O)));
|
||||
this.mnuOpen.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuOpen.Text = "Open";
|
||||
this.mnuOpen.Click += new System.EventHandler(this.mnuOpen_Click);
|
||||
//
|
||||
|
@ -92,7 +93,7 @@
|
|||
//
|
||||
this.mnuRun.Name = "mnuRun";
|
||||
this.mnuRun.ShortcutKeys = System.Windows.Forms.Keys.F5;
|
||||
this.mnuRun.Size = new System.Drawing.Size(157, 22);
|
||||
this.mnuRun.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuRun.Text = "Run";
|
||||
this.mnuRun.Click += new System.EventHandler(this.mnuRun_Click);
|
||||
//
|
||||
|
@ -100,41 +101,41 @@
|
|||
//
|
||||
this.mnuStep.Name = "mnuStep";
|
||||
this.mnuStep.ShortcutKeys = System.Windows.Forms.Keys.F11;
|
||||
this.mnuStep.Size = new System.Drawing.Size(157, 22);
|
||||
this.mnuStep.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuStep.Text = "Step";
|
||||
this.mnuStep.Click += new System.EventHandler(this.mnuStep_Click);
|
||||
//
|
||||
// toolStripMenuItem1
|
||||
//
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(154, 6);
|
||||
//
|
||||
// mnuDebugger
|
||||
//
|
||||
this.mnuDebugger.Name = "mnuDebugger";
|
||||
this.mnuDebugger.Size = new System.Drawing.Size(157, 22);
|
||||
this.mnuDebugger.Text = "Debugger";
|
||||
//
|
||||
// mnuTraceLogger
|
||||
//
|
||||
this.mnuTraceLogger.Name = "mnuTraceLogger";
|
||||
this.mnuTraceLogger.Size = new System.Drawing.Size(157, 22);
|
||||
this.mnuTraceLogger.Text = "Trace Logger";
|
||||
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
|
||||
//
|
||||
// mnuRun100Instructions
|
||||
//
|
||||
this.mnuRun100Instructions.Name = "mnuRun100Instructions";
|
||||
this.mnuRun100Instructions.ShortcutKeys = System.Windows.Forms.Keys.F6;
|
||||
this.mnuRun100Instructions.Size = new System.Drawing.Size(157, 22);
|
||||
this.mnuRun100Instructions.Text = "Run 100 ops";
|
||||
this.mnuRun100Instructions.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuRun100Instructions.Text = "Run 1000 ops";
|
||||
this.mnuRun100Instructions.Click += new System.EventHandler(this.mnuRun100Instructions_Click);
|
||||
//
|
||||
// toolStripMenuItem1
|
||||
//
|
||||
this.toolStripMenuItem1.Name = "toolStripMenuItem1";
|
||||
this.toolStripMenuItem1.Size = new System.Drawing.Size(160, 6);
|
||||
//
|
||||
// mnuDebugger
|
||||
//
|
||||
this.mnuDebugger.Name = "mnuDebugger";
|
||||
this.mnuDebugger.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuDebugger.Text = "Debugger";
|
||||
//
|
||||
// mnuTraceLogger
|
||||
//
|
||||
this.mnuTraceLogger.Name = "mnuTraceLogger";
|
||||
this.mnuTraceLogger.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuTraceLogger.Text = "Trace Logger";
|
||||
this.mnuTraceLogger.Click += new System.EventHandler(this.mnuTraceLogger_Click);
|
||||
//
|
||||
// frmMain
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.ClientSize = new System.Drawing.Size(514, 476);
|
||||
this.ClientSize = new System.Drawing.Size(512, 475);
|
||||
this.Controls.Add(this.ctrlRenderer);
|
||||
this.Controls.Add(this.mnuMain);
|
||||
this.MainMenuStrip = this.mnuMain;
|
||||
|
|
|
@ -30,7 +30,8 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
private void mnuTraceLogger_Click(object sender, EventArgs e)
|
||||
{
|
||||
|
||||
frmTraceLogger frm = new frmTraceLogger();
|
||||
frm.Show();
|
||||
}
|
||||
|
||||
private void mnuStep_Click(object sender, EventArgs e)
|
||||
|
@ -47,9 +48,6 @@ namespace Mesen.GUI.Forms
|
|||
Task.Run(() => {
|
||||
EmuApi.Run();
|
||||
});
|
||||
|
||||
frmTraceLogger frm = new frmTraceLogger();
|
||||
frm.Show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +59,7 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
private void mnuRun100Instructions_Click(object sender, EventArgs e)
|
||||
{
|
||||
DebugApi.Step(100);
|
||||
DebugApi.Step(1000);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
#include "DirectXTK/SpriteBatch.h"
|
||||
#include "DirectXTK/SpriteFont.h"
|
||||
#include "../Core/Console.h"
|
||||
#include "../Core/VideoDecoder.h"
|
||||
#include "../Core/VideoRenderer.h"
|
||||
#include "../Core/Debugger.h"
|
||||
#include "../Core/MessageManager.h"
|
||||
#include "../Core/SettingTypes.h"
|
||||
#include "../Utilities/UTF8Util.h"
|
||||
|
||||
using namespace DirectX;
|
||||
|
@ -13,16 +16,15 @@ Renderer::Renderer(shared_ptr<Console> console, HWND hWnd, bool registerAsMessag
|
|||
{
|
||||
_hWnd = hWnd;
|
||||
|
||||
SetScreenSize(256, 240);
|
||||
SetScreenSize(256, 224);
|
||||
}
|
||||
|
||||
Renderer::~Renderer()
|
||||
{
|
||||
//TODO
|
||||
/*shared_ptr<VideoRenderer> videoRenderer = _console->GetVideoRenderer();
|
||||
shared_ptr<VideoRenderer> videoRenderer = _console->GetVideoRenderer();
|
||||
if(videoRenderer) {
|
||||
videoRenderer->UnregisterRenderingDevice(this);
|
||||
}*/
|
||||
}
|
||||
CleanupDevice();
|
||||
}
|
||||
|
||||
|
@ -38,20 +40,20 @@ void Renderer::SetFullscreenMode(bool fullscreen, void* windowHandle, uint32_t m
|
|||
|
||||
void Renderer::SetScreenSize(uint32_t width, uint32_t height)
|
||||
{
|
||||
//TODO
|
||||
/*ScreenSize screenSize;
|
||||
ScreenSize screenSize;
|
||||
_console->GetVideoDecoder()->GetScreenSize(screenSize, false);
|
||||
|
||||
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _resizeFilter != _console->GetSettings()->GetVideoResizeFilter() || _newFullscreen != _fullscreen) {
|
||||
//TODO _resizeFilter != _console->GetSettings()->GetVideoResizeFilter()
|
||||
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen) {
|
||||
auto frameLock = _frameLock.AcquireSafe();
|
||||
auto textureLock = _textureLock.AcquireSafe();
|
||||
_console->GetVideoDecoder()->GetScreenSize(screenSize, false);
|
||||
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _resizeFilter != _console->GetSettings()->GetVideoResizeFilter() || _newFullscreen != _fullscreen) {
|
||||
if(_screenHeight != screenSize.Height || _screenWidth != screenSize.Width || _nesFrameHeight != height || _nesFrameWidth != width || _newFullscreen != _fullscreen) {
|
||||
_nesFrameHeight = height;
|
||||
_nesFrameWidth = width;
|
||||
_newFrameBufferSize = width*height;
|
||||
|
||||
bool needReset = _fullscreen != _newFullscreen || _resizeFilter != _console->GetSettings()->GetVideoResizeFilter();
|
||||
bool needReset = _fullscreen != _newFullscreen;//TODO || _resizeFilter != _console->GetSettings()->GetVideoResizeFilter();
|
||||
bool fullscreenResizeMode = _fullscreen && _newFullscreen;
|
||||
|
||||
if(_pSwapChain && _fullscreen && !_newFullscreen) {
|
||||
|
@ -94,7 +96,7 @@ void Renderer::SetScreenSize(uint32_t width, uint32_t height)
|
|||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
void Renderer::Reset()
|
||||
|
@ -104,8 +106,7 @@ void Renderer::Reset()
|
|||
if(FAILED(InitDevice())) {
|
||||
CleanupDevice();
|
||||
} else {
|
||||
//TODO
|
||||
//_console->GetVideoRenderer()->RegisterRenderingDevice(this);
|
||||
_console->GetVideoRenderer()->RegisterRenderingDevice(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue