Ntsc emulation support + resolution scale options
This commit is contained in:
parent
c6e31e58da
commit
8d15b309c5
33 changed files with 2070 additions and 461 deletions
88
Core/BaseVideoFilter.cpp
Normal file
88
Core/BaseVideoFilter.cpp
Normal file
|
@ -0,0 +1,88 @@
|
|||
#include "stdafx.h"
|
||||
#include "BaseVideoFilter.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/PNGHelper.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
|
||||
BaseVideoFilter::BaseVideoFilter()
|
||||
{
|
||||
}
|
||||
|
||||
BaseVideoFilter::~BaseVideoFilter()
|
||||
{
|
||||
if(_outputBuffer) {
|
||||
delete[] _outputBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
void BaseVideoFilter::UpdateBufferSize()
|
||||
{
|
||||
uint32_t newBufferSize = GetFrameInfo().Width*GetFrameInfo().Height*GetFrameInfo().BitsPerPixel;
|
||||
if(_bufferSize != newBufferSize) {
|
||||
if(_outputBuffer) {
|
||||
delete[] _outputBuffer;
|
||||
}
|
||||
|
||||
_bufferSize = newBufferSize;
|
||||
_outputBuffer = new uint8_t[newBufferSize];
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ResolutionChanged);
|
||||
}
|
||||
}
|
||||
|
||||
OverscanDimensions BaseVideoFilter::GetOverscan()
|
||||
{
|
||||
return _overscan;
|
||||
}
|
||||
|
||||
void BaseVideoFilter::SendFrame(uint16_t *ppuOutputBuffer)
|
||||
{
|
||||
_frameLock.Acquire();
|
||||
_overscan = EmulationSettings::GetOverscanDimensions();
|
||||
UpdateBufferSize();
|
||||
ApplyFilter(ppuOutputBuffer);
|
||||
_frameLock.Release();
|
||||
}
|
||||
|
||||
uint8_t* BaseVideoFilter::GetOutputBuffer()
|
||||
{
|
||||
return _outputBuffer;
|
||||
}
|
||||
|
||||
void BaseVideoFilter::TakeScreenshot(string romFilename)
|
||||
{
|
||||
uint32_t* frameBuffer = (uint32_t*)new uint8_t[_bufferSize];
|
||||
|
||||
_frameLock.Acquire();
|
||||
memcpy(frameBuffer, GetOutputBuffer(), _bufferSize);
|
||||
_frameLock.Release();
|
||||
|
||||
//ARGB -> ABGR
|
||||
for(uint32_t i = 0; i < _bufferSize/GetFrameInfo().BitsPerPixel; i++) {
|
||||
frameBuffer[i] = 0xFF000000 | (frameBuffer[i] & 0xFF00) | ((frameBuffer[i] & 0xFF0000) >> 16) | ((frameBuffer[i] & 0xFF) << 16);
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
string baseFilename = 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++;
|
||||
}
|
||||
|
||||
PNGHelper::WritePNG(ssFilename, (uint8_t*)frameBuffer, GetFrameInfo().Width, GetFrameInfo().Height);
|
||||
delete[] frameBuffer;
|
||||
|
||||
MessageManager::DisplayMessage("Screenshot saved", FolderUtilities::GetFilename(ssFilename, true));
|
||||
}
|
||||
|
36
Core/BaseVideoFilter.h
Normal file
36
Core/BaseVideoFilter.h
Normal file
|
@ -0,0 +1,36 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
struct FrameInfo
|
||||
{
|
||||
uint32_t Width;
|
||||
uint32_t Height;
|
||||
uint32_t BitsPerPixel;
|
||||
};
|
||||
|
||||
class BaseVideoFilter
|
||||
{
|
||||
private:
|
||||
uint8_t* _outputBuffer = nullptr;
|
||||
uint32_t _bufferSize = 0;
|
||||
SimpleLock _frameLock;
|
||||
OverscanDimensions _overscan;
|
||||
|
||||
void UpdateBufferSize();
|
||||
|
||||
protected:
|
||||
OverscanDimensions GetOverscan();
|
||||
virtual void ApplyFilter(uint16_t *ppuOutputBuffer) = 0;
|
||||
|
||||
public:
|
||||
BaseVideoFilter();
|
||||
virtual ~BaseVideoFilter();
|
||||
|
||||
uint8_t* GetOutputBuffer();
|
||||
void SendFrame(uint16_t *ppuOutputBuffer);
|
||||
void TakeScreenshot(string romFilename);
|
||||
|
||||
virtual FrameInfo GetFrameInfo() = 0;
|
||||
};
|
|
@ -270,11 +270,14 @@
|
|||
<ClInclude Include="Bandai74161_7432.h" />
|
||||
<ClInclude Include="BF909x.h" />
|
||||
<ClInclude Include="BnRom.h" />
|
||||
<ClInclude Include="DefaultVideoFilter.h" />
|
||||
<ClInclude Include="HdVideoFilter.h" />
|
||||
<ClInclude Include="Namco108.h" />
|
||||
<ClInclude Include="Namco108_154.h" />
|
||||
<ClInclude Include="Namco108_76.h" />
|
||||
<ClInclude Include="Namco108_88.h" />
|
||||
<ClInclude Include="Namco108_95.h" />
|
||||
<ClInclude Include="NtscFilter.h" />
|
||||
<ClInclude Include="Sachen_145.h" />
|
||||
<ClInclude Include="CodeDataLogger.h" />
|
||||
<ClInclude Include="CpRom.h" />
|
||||
|
@ -357,6 +360,7 @@
|
|||
<ClInclude Include="UnlPci556.h" />
|
||||
<ClInclude Include="UNROM.h" />
|
||||
<ClInclude Include="VideoDecoder.h" />
|
||||
<ClInclude Include="BaseVideoFilter.h" />
|
||||
<ClInclude Include="VirtualController.h" />
|
||||
<ClInclude Include="VRC2_4.h" />
|
||||
</ItemGroup>
|
||||
|
@ -370,6 +374,7 @@
|
|||
<ClCompile Include="Console.cpp" />
|
||||
<ClCompile Include="ControlManager.cpp" />
|
||||
<ClCompile Include="Debugger.cpp" />
|
||||
<ClCompile Include="DefaultVideoFilter.cpp" />
|
||||
<ClCompile Include="DeltaModulationChannel.cpp" />
|
||||
<ClCompile Include="Disassembler.cpp" />
|
||||
<ClCompile Include="DisassemblyInfo.cpp" />
|
||||
|
@ -379,6 +384,8 @@
|
|||
<ClCompile Include="GameConnection.cpp" />
|
||||
<ClCompile Include="GameServer.cpp" />
|
||||
<ClCompile Include="GameServerConnection.cpp" />
|
||||
<ClCompile Include="HdVideoFilter.cpp" />
|
||||
<ClCompile Include="NtscFilter.cpp" />
|
||||
<ClCompile Include="StandardController.cpp" />
|
||||
<ClCompile Include="MapperFactory.cpp" />
|
||||
<ClCompile Include="MemoryManager.cpp" />
|
||||
|
@ -396,6 +403,7 @@
|
|||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release x64|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoDecoder.cpp" />
|
||||
<ClCompile Include="BaseVideoFilter.cpp" />
|
||||
<ClCompile Include="VirtualController.cpp" />
|
||||
<ClCompile Include="VRC1.h" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -9,31 +9,31 @@
|
|||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Interfaces">
|
||||
<UniqueIdentifier>{ca661408-b52a-4378-aef4-80fda1d64cd6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\Mappers">
|
||||
<UniqueIdentifier>{67b52e86-0ff2-4dbe-b9ed-7c92aace61d5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\NetPlay">
|
||||
<UniqueIdentifier>{43f375c6-d7c7-4bbf-8520-ad53e4e1b4a3}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\NetPlay">
|
||||
<UniqueIdentifier>{44908561-f739-4c26-83db-588a9ef3e33a}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\NetPlay\Messages">
|
||||
<UniqueIdentifier>{8455d832-c72b-4ec2-b90d-ac30ad3d3ad8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Debugger">
|
||||
<UniqueIdentifier>{ff3c6e48-3987-41d2-8916-b588a457ff30}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\APU">
|
||||
<Filter Include="VideoDecoder">
|
||||
<UniqueIdentifier>{de7ff5ea-3ef4-4181-86f6-b00335d15f4b}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="NetPlay">
|
||||
<UniqueIdentifier>{00fd928d-e9aa-45ba-84e9-34f1519709e2}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="NetPlay\Messages">
|
||||
<UniqueIdentifier>{8455d832-c72b-4ec2-b90d-ac30ad3d3ad8}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Nes">
|
||||
<UniqueIdentifier>{efa932b2-780a-45f1-b95e-51a0e7be4922}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Nes\Mappers">
|
||||
<UniqueIdentifier>{67b52e86-0ff2-4dbe-b9ed-7c92aace61d5}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Nes\APU">
|
||||
<UniqueIdentifier>{d9dec4ba-97e7-4a80-85e1-6b53f5ed7218}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\APU">
|
||||
<UniqueIdentifier>{b99fc308-b28a-48b7-9ca8-6e8005bbc2bf}</UniqueIdentifier>
|
||||
<Filter Include="Nes\Interfaces">
|
||||
<UniqueIdentifier>{ca661408-b52a-4378-aef4-80fda1d64cd6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\HD">
|
||||
<Filter Include="VideoDecoder\HD">
|
||||
<UniqueIdentifier>{a6994cb5-f9d2-416c-84ab-c1abe4975eb1}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
|
@ -41,125 +41,86 @@
|
|||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CPU.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PPU.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemoryManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ROMLoader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControlManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IAudioDevice.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IControlDevice.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IMemoryHandler.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseMapper.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MapperFactory.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC1.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NROM.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CNROM.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UNROM.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC3.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Snapshotable.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AXROM.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC2.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ColorDreams.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Movie.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameConnection.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameClient.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameServer.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualController.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IGameBroadcaster.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameClientConnection.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameServerConnection.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IMessageManager.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VRC2_4.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetMessage.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HandShakeMessage.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="InputDataMessage.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SaveStateMessage.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MovieDataMessage.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameInformationMessage.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageType.h">
|
||||
<Filter>Header Files\NetPlay\Messages</Filter>
|
||||
<Filter>NetPlay\Messages</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="INotificationListener.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Nanjing.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC3_189.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Debugger.h">
|
||||
<Filter>Debugger</Filter>
|
||||
|
@ -173,197 +134,212 @@
|
|||
<ClInclude Include="Breakpoint.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ClientConnectionData.h">
|
||||
<Filter>Header Files\NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SaveStateManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CheatManager.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IKeyManager.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StandardController.h">
|
||||
<Filter>Header Files</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SquareChannel.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="APU.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ApuLengthCounter.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ApuEnvelope.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ApuFrameCounter.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TriangleChannel.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NoiseChannel.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseApuChannel.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DeltaModulationChannel.h">
|
||||
<Filter>Header Files\APU</Filter>
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="EmulationSettings.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoDecoder.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BF909x.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC5.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HdNesPack.h">
|
||||
<Filter>Header Files\HD</Filter>
|
||||
<Filter>VideoDecoder\HD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HdPpu.h">
|
||||
<Filter>Header Files\HD</Filter>
|
||||
<Filter>VideoDecoder\HD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CodeDataLogger.h">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IRenderingDevice.h">
|
||||
<Filter>Header Files\Interfaces</Filter>
|
||||
<Filter>Nes\Interfaces</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="AutoRomTest.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MMC4.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CpRom.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JalecoSs88006.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IremG101.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TaitoTc0190.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GxRom.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="UnlPci556.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Nina03_06.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="JalecoJfxx.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Bandai74161_7432.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TaitoX1005.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft89.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft93.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sunsoft184.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BnRom.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Nina01.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sachen_147.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sachen_145.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sachen_149.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Sachen_148.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco108.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco108_76.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco108_88.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco108_154.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Namco108_95.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DefaultVideoFilter.h">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VideoDecoder.h">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="BaseVideoFilter.h">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NtscFilter.h">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ClientConnectionData.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameClient.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameClientConnection.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameConnection.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameServer.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="GameServerConnection.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="IGameBroadcaster.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualController.h">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Console.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ControlManager.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CheatManager.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MemoryManager.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PPU.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ROMLoader.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="StandardController.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="CPU.h">
|
||||
<Filter>Nes</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="HdVideoFilter.h">
|
||||
<Filter>VideoDecoder\HD</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="CPU.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PPU.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ControlManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Movie.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameServer.cpp">
|
||||
<Filter>Source Files\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameClient.cpp">
|
||||
<Filter>Source Files\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameClientConnection.cpp">
|
||||
<Filter>Source Files\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameConnection.cpp">
|
||||
<Filter>Source Files\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameServerConnection.cpp">
|
||||
<Filter>Source Files\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualController.cpp">
|
||||
<Filter>Source Files\NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MapperFactory.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Debugger.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
|
@ -382,27 +358,9 @@
|
|||
<ClCompile Include="MessageManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CheatManager.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StandardController.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="APU.cpp">
|
||||
<Filter>Source Files\APU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="EmulationSettings.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ApuLengthCounter.cpp">
|
||||
<Filter>Source Files\APU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoDecoder.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DeltaModulationChannel.cpp">
|
||||
<Filter>Source Files\APU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CodeDataLogger.cpp">
|
||||
<Filter>Debugger</Filter>
|
||||
</ClCompile>
|
||||
|
@ -410,7 +368,73 @@
|
|||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VRC1.h">
|
||||
<Filter>Header Files\Mappers</Filter>
|
||||
<Filter>Nes\Mappers</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="BaseVideoFilter.cpp">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DefaultVideoFilter.cpp">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VideoDecoder.cpp">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NtscFilter.cpp">
|
||||
<Filter>VideoDecoder</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameClient.cpp">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameClientConnection.cpp">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameConnection.cpp">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameServer.cpp">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="GameServerConnection.cpp">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="VirtualController.cpp">
|
||||
<Filter>NetPlay</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Console.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CPU.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ControlManager.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MapperFactory.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MemoryManager.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PPU.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="StandardController.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="CheatManager.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="APU.cpp">
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ApuLengthCounter.cpp">
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DeltaModulationChannel.cpp">
|
||||
<Filter>Nes\APU</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HdVideoFilter.cpp">
|
||||
<Filter>VideoDecoder\HD</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
60
Core/DefaultVideoFilter.cpp
Normal file
60
Core/DefaultVideoFilter.cpp
Normal file
|
@ -0,0 +1,60 @@
|
|||
#include "stdafx.h"
|
||||
#include "DefaultVideoFilter.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
extern const uint32_t PPU_PALETTE_ARGB[];
|
||||
|
||||
FrameInfo DefaultVideoFilter::GetFrameInfo()
|
||||
{
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
return { overscan.GetScreenWidth(), overscan.GetScreenHeight(), 4 };
|
||||
}
|
||||
|
||||
void DefaultVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
||||
{
|
||||
OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions();
|
||||
|
||||
uint32_t* outputBuffer = (uint32_t*)GetOutputBuffer();
|
||||
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
|
||||
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
||||
*outputBuffer = ProcessIntensifyBits(ppuOutputBuffer[i * 256 + j]);
|
||||
outputBuffer++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DefaultVideoFilter::ProcessIntensifyBits(uint16_t ppuPixel)
|
||||
{
|
||||
uint32_t pixelOutput = PPU_PALETTE_ARGB[ppuPixel & 0x3F];
|
||||
|
||||
//Incorrect emphasis bit implementation, but will do for now.
|
||||
float redChannel = (float)((pixelOutput & 0xFF0000) >> 16);
|
||||
float greenChannel = (float)((pixelOutput & 0xFF00) >> 8);
|
||||
float blueChannel = (float)(pixelOutput & 0xFF);
|
||||
|
||||
if(ppuPixel & 0x40) {
|
||||
//Intensify red
|
||||
redChannel *= 1.1f;
|
||||
greenChannel *= 0.9f;
|
||||
blueChannel *= 0.9f;
|
||||
}
|
||||
if(ppuPixel & 0x80) {
|
||||
//Intensify green
|
||||
greenChannel *= 1.1f;
|
||||
redChannel *= 0.9f;
|
||||
blueChannel *= 0.9f;
|
||||
}
|
||||
if(ppuPixel & 0x100) {
|
||||
//Intensify blue
|
||||
blueChannel *= 1.1f;
|
||||
redChannel *= 0.9f;
|
||||
greenChannel *= 0.9f;
|
||||
}
|
||||
|
||||
uint8_t r, g, b;
|
||||
r = (uint8_t)(redChannel > 255 ? 255 : redChannel);
|
||||
g = (uint8_t)(greenChannel > 255 ? 255 : greenChannel);
|
||||
b = (uint8_t)(blueChannel > 255 ? 255 : blueChannel);
|
||||
|
||||
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
14
Core/DefaultVideoFilter.h
Normal file
14
Core/DefaultVideoFilter.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "BaseVideoFilter.h"
|
||||
|
||||
class DefaultVideoFilter : public BaseVideoFilter
|
||||
{
|
||||
private:
|
||||
uint32_t ProcessIntensifyBits(uint16_t ppuPixel);
|
||||
|
||||
public:
|
||||
void ApplyFilter(uint16_t *ppuOutputBuffer);
|
||||
FrameInfo GetFrameInfo();
|
||||
};
|
|
@ -1,10 +1,16 @@
|
|||
#include "stdafx.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
uint32_t EmulationSettings::Flags = 0;
|
||||
uint32_t EmulationSettings::AudioLatency = 20000;
|
||||
double EmulationSettings::ChannelVolume[5] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };
|
||||
NesModel EmulationSettings::Model = NesModel::Auto;
|
||||
OverscanDimensions EmulationSettings::Overscan;
|
||||
uint32_t EmulationSettings::EmulationSpeed = 100;
|
||||
bool EmulationSettings::AudioEnabled = true;
|
||||
uint32_t EmulationSettings::_flags = 0;
|
||||
|
||||
bool EmulationSettings::_audioEnabled = true;
|
||||
uint32_t EmulationSettings::_audioLatency = 20000;
|
||||
double EmulationSettings::_channelVolume[5] = { 0.5f, 0.5f, 0.5f, 0.5f, 0.5f };
|
||||
|
||||
NesModel EmulationSettings::_model = NesModel::Auto;
|
||||
|
||||
uint32_t EmulationSettings::_emulationSpeed = 100;
|
||||
|
||||
OverscanDimensions EmulationSettings::_overscan;
|
||||
VideoFilterType EmulationSettings::_videoFilterType = VideoFilterType::None;
|
||||
uint32_t EmulationSettings::_videoScale = 1;
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "MessageManager.h"
|
||||
|
||||
enum EmulationFlags
|
||||
{
|
||||
|
@ -24,6 +25,13 @@ enum class NesModel
|
|||
PAL = 2,
|
||||
};
|
||||
|
||||
enum class VideoFilterType
|
||||
{
|
||||
None = 0,
|
||||
NTSC = 1,
|
||||
HdPack = 999
|
||||
};
|
||||
|
||||
struct OverscanDimensions
|
||||
{
|
||||
uint32_t Left = 0;
|
||||
|
@ -50,87 +58,113 @@ struct OverscanDimensions
|
|||
class EmulationSettings
|
||||
{
|
||||
private:
|
||||
static uint32_t Flags;
|
||||
static bool AudioEnabled;
|
||||
static uint32_t AudioLatency;
|
||||
static double ChannelVolume[5];
|
||||
static NesModel Model;
|
||||
static uint32_t EmulationSpeed;
|
||||
static OverscanDimensions Overscan;
|
||||
static uint32_t _flags;
|
||||
static bool _audioEnabled;
|
||||
static uint32_t _audioLatency;
|
||||
static double _channelVolume[5];
|
||||
|
||||
static NesModel _model;
|
||||
|
||||
static uint32_t _emulationSpeed;
|
||||
|
||||
static OverscanDimensions _overscan;
|
||||
static VideoFilterType _videoFilterType;
|
||||
static uint32_t _videoScale;
|
||||
|
||||
public:
|
||||
static void SetFlags(uint32_t flags)
|
||||
{
|
||||
Flags |= flags;
|
||||
_flags |= flags;
|
||||
}
|
||||
|
||||
static void ClearFlags(uint32_t flags)
|
||||
{
|
||||
Flags &= ~flags;
|
||||
_flags &= ~flags;
|
||||
}
|
||||
|
||||
static bool CheckFlag(uint32_t flag)
|
||||
{
|
||||
return (Flags & flag) == flag;
|
||||
return (_flags & flag) == flag;
|
||||
}
|
||||
|
||||
static void SetNesModel(NesModel model)
|
||||
{
|
||||
Model = model;
|
||||
_model = model;
|
||||
}
|
||||
|
||||
static NesModel GetNesModel()
|
||||
{
|
||||
return Model;
|
||||
return _model;
|
||||
}
|
||||
|
||||
static void SetAudioState(bool enabled)
|
||||
{
|
||||
AudioEnabled = enabled;
|
||||
_audioEnabled = enabled;
|
||||
}
|
||||
|
||||
//0: Muted, 0.5: Default, 1.0: Max volume
|
||||
static void SetChannelVolume(AudioChannel channel, double volume)
|
||||
{
|
||||
ChannelVolume[(int)channel] = volume;
|
||||
_channelVolume[(int)channel] = volume;
|
||||
}
|
||||
|
||||
static void SetAudioLatency(uint32_t msLatency)
|
||||
{
|
||||
AudioLatency = msLatency;
|
||||
_audioLatency = msLatency;
|
||||
}
|
||||
|
||||
//0: No limit, Number: % of default speed (50/60fps)
|
||||
static void SetEmulationSpeed(uint32_t emulationSpeed)
|
||||
{
|
||||
EmulationSpeed = emulationSpeed;
|
||||
_emulationSpeed = emulationSpeed;
|
||||
}
|
||||
|
||||
static uint32_t GetEmulationSpeed()
|
||||
{
|
||||
return EmulationSpeed;
|
||||
return _emulationSpeed;
|
||||
}
|
||||
|
||||
static void SetOverscanDimensions(uint8_t left, uint8_t right, uint8_t top, uint8_t bottom)
|
||||
{
|
||||
Overscan.Left = left;
|
||||
Overscan.Right = right;
|
||||
Overscan.Top = top;
|
||||
Overscan.Bottom = bottom;
|
||||
_overscan.Left = left;
|
||||
_overscan.Right = right;
|
||||
_overscan.Top = top;
|
||||
_overscan.Bottom = bottom;
|
||||
}
|
||||
|
||||
static OverscanDimensions GetOverscanDimensions()
|
||||
{
|
||||
return Overscan;
|
||||
return _overscan;
|
||||
}
|
||||
|
||||
static double GetChannelVolume(AudioChannel channel)
|
||||
{
|
||||
return AudioEnabled ? ChannelVolume[(int)channel] : 0;
|
||||
return _audioEnabled ? _channelVolume[(int)channel] : 0;
|
||||
}
|
||||
|
||||
static uint32_t GetAudioLatency()
|
||||
{
|
||||
return AudioLatency;
|
||||
return _audioLatency;
|
||||
}
|
||||
|
||||
static void SetVideoFilterType(VideoFilterType videoFilterType)
|
||||
{
|
||||
_videoFilterType = videoFilterType;
|
||||
}
|
||||
|
||||
static VideoFilterType GetVideoFilterType()
|
||||
{
|
||||
return _videoFilterType;
|
||||
}
|
||||
|
||||
static void SetVideoScale(uint32_t scale)
|
||||
{
|
||||
_videoScale = scale;
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ResolutionChanged);
|
||||
}
|
||||
|
||||
static uint32_t GetVideoScale()
|
||||
{
|
||||
return _videoScale;
|
||||
}
|
||||
};
|
||||
|
|
39
Core/HdVideoFilter.cpp
Normal file
39
Core/HdVideoFilter.cpp
Normal file
|
@ -0,0 +1,39 @@
|
|||
#include "stdafx.h"
|
||||
#include "HdNesPack.h"
|
||||
#include "HdVideoFilter.h"
|
||||
|
||||
extern const uint32_t PPU_PALETTE_ARGB[];
|
||||
|
||||
HdVideoFilter::HdVideoFilter()
|
||||
{
|
||||
_hdNesPack.reset(new HdNesPack());
|
||||
}
|
||||
|
||||
FrameInfo HdVideoFilter::GetFrameInfo()
|
||||
{
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
uint32_t hdScale = _hdNesPack->GetScale();
|
||||
|
||||
return { overscan.GetScreenWidth() * hdScale, overscan.GetScreenHeight() * hdScale, 4 };
|
||||
}
|
||||
|
||||
void HdVideoFilter::SetHdScreenTiles(HdPpuPixelInfo *screenTiles)
|
||||
{
|
||||
_hdScreenTiles = screenTiles;
|
||||
}
|
||||
|
||||
void HdVideoFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
||||
{
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
|
||||
uint32_t hdScale = _hdNesPack->GetScale();
|
||||
uint32_t screenWidth = overscan.GetScreenWidth() * hdScale;
|
||||
|
||||
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
|
||||
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
||||
uint32_t sdPixel = PPU_PALETTE_ARGB[ppuOutputBuffer[i * 256 + j] & 0x3F]; //ProcessIntensifyBits(inputBuffer[i * 256 + j]);
|
||||
uint32_t bufferIndex = (i - overscan.Top) * screenWidth * hdScale + (j - overscan.Left) * hdScale;
|
||||
_hdNesPack->GetPixels(_hdScreenTiles[i * 256 + j], sdPixel, (uint32_t*)GetOutputBuffer() + bufferIndex, screenWidth);
|
||||
}
|
||||
}
|
||||
}
|
20
Core/HdVideoFilter.h
Normal file
20
Core/HdVideoFilter.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseVideoFilter.h"
|
||||
|
||||
class HdNesPack;
|
||||
|
||||
class HdVideoFilter : public BaseVideoFilter
|
||||
{
|
||||
private:
|
||||
HdPpuPixelInfo *_hdScreenTiles = nullptr;
|
||||
unique_ptr<HdNesPack> _hdNesPack = nullptr;
|
||||
|
||||
public:
|
||||
HdVideoFilter();
|
||||
|
||||
void ApplyFilter(uint16_t *ppuOutputBuffer);
|
||||
FrameInfo GetFrameInfo();
|
||||
|
||||
void SetHdScreenTiles(HdPpuPixelInfo *screenTiles);
|
||||
};
|
|
@ -14,6 +14,7 @@ enum class ConsoleNotificationType
|
|||
CheatRemoved = 8,
|
||||
PpuFrameDone = 9,
|
||||
MovieEnded = 10,
|
||||
ResolutionChanged = 11,
|
||||
};
|
||||
|
||||
class INotificationListener
|
||||
|
|
|
@ -5,6 +5,6 @@
|
|||
class IRenderingDevice
|
||||
{
|
||||
public:
|
||||
virtual void UpdateFrame(void *frameBuffer) = 0;
|
||||
virtual void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height) = 0;
|
||||
virtual void Render() = 0;
|
||||
};
|
|
@ -21,7 +21,7 @@ void MessageManager::DisplayMessage(string title, string message)
|
|||
void MessageManager::DisplayToast(string title, string message, uint8_t* iconData, uint32_t iconSize)
|
||||
{
|
||||
if(MessageManager::_messageManager) {
|
||||
MessageManager::_messageManager->DisplayToast(shared_ptr<ToastInfo>(new ToastInfo(title, message, 4000, iconData, iconSize)));
|
||||
MessageManager::_messageManager->DisplayToast(shared_ptr<ToastInfo>(new ToastInfo(title, message, 2500, iconData, iconSize)));
|
||||
}
|
||||
}
|
||||
void MessageManager::RegisterNotificationListener(INotificationListener* notificationListener)
|
||||
|
|
63
Core/NtscFilter.cpp
Normal file
63
Core/NtscFilter.cpp
Normal file
|
@ -0,0 +1,63 @@
|
|||
#include "stdafx.h"
|
||||
#include "NtscFilter.h"
|
||||
#include "PPU.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
NtscFilter::NtscFilter()
|
||||
{
|
||||
_ntscData = new nes_ntsc_t();
|
||||
_ntscSetup = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
nes_ntsc_init(_ntscData, &_ntscSetup);
|
||||
}
|
||||
|
||||
FrameInfo NtscFilter::GetFrameInfo()
|
||||
{
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
int overscanLeft = overscan.Left > 0 ? NES_NTSC_OUT_WIDTH(overscan.Left) : 0;
|
||||
int overscanRight = overscan.Right > 0 ? NES_NTSC_OUT_WIDTH(overscan.Right) : 0;
|
||||
return { NES_NTSC_OUT_WIDTH(PPU::ScreenWidth) - overscanLeft - overscanRight, (PPU::ScreenHeight - overscan.Top - overscan.Bottom) * 2, 4 };
|
||||
}
|
||||
|
||||
void NtscFilter::ApplyFilter(uint16_t *ppuOutputBuffer)
|
||||
{
|
||||
static bool oddFrame = false;
|
||||
oddFrame = !oddFrame;
|
||||
|
||||
uint32_t* ntscBuffer = new uint32_t[NES_NTSC_OUT_WIDTH(256) * 240];
|
||||
nes_ntsc_blit(_ntscData, ppuOutputBuffer, PPU::ScreenWidth, oddFrame ? 0 : 1, PPU::ScreenWidth, 240, ntscBuffer, NES_NTSC_OUT_WIDTH(PPU::ScreenWidth)*4);
|
||||
DoubleOutputHeight(ntscBuffer);
|
||||
delete[] ntscBuffer;
|
||||
}
|
||||
|
||||
void NtscFilter::DoubleOutputHeight(uint32_t *ntscBuffer)
|
||||
{
|
||||
uint32_t* outputBuffer = (uint32_t*)GetOutputBuffer();
|
||||
OverscanDimensions overscan = GetOverscan();
|
||||
int overscanLeft = overscan.Left > 0 ? NES_NTSC_OUT_WIDTH(overscan.Left) : 0;
|
||||
int overscanRight = overscan.Right > 0 ? NES_NTSC_OUT_WIDTH(overscan.Right) : 0;
|
||||
int rowWidth = NES_NTSC_OUT_WIDTH(PPU::ScreenWidth);
|
||||
int rowWidthOverscan = rowWidth - overscanLeft - overscanRight;
|
||||
|
||||
for(int y = PPU::ScreenHeight - 1 - overscan.Bottom; y >= (int)overscan.Top; y--) {
|
||||
uint32_t const* in = ntscBuffer + y * rowWidth;
|
||||
uint32_t* out = outputBuffer + (y - overscan.Top) * 2 * rowWidthOverscan;
|
||||
|
||||
for(int x = 0; x < rowWidthOverscan; x++) {
|
||||
uint32_t prev = in[overscanLeft];
|
||||
uint32_t next = y < 239 ? in[overscanLeft + rowWidth] : 0;
|
||||
|
||||
/* mix 24-bit rgb without losing low bits */
|
||||
uint64_t mixed = prev + next + ((prev ^ next) & 0x030303);
|
||||
/* darken color */
|
||||
*out = prev;
|
||||
*(out + rowWidthOverscan) = (uint32_t)((mixed >> 1) - (mixed >> 4 & 0x0F0F0F));
|
||||
in++;
|
||||
out++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NtscFilter::~NtscFilter()
|
||||
{
|
||||
delete _ntscData;
|
||||
}
|
20
Core/NtscFilter.h
Normal file
20
Core/NtscFilter.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseVideoFilter.h"
|
||||
#include "../NesNtsc/nes_ntsc.h"
|
||||
|
||||
class NtscFilter : public BaseVideoFilter
|
||||
{
|
||||
private:
|
||||
nes_ntsc_setup_t _ntscSetup;
|
||||
nes_ntsc_t* _ntscData;
|
||||
|
||||
void DoubleOutputHeight(uint32_t *outputBuffer);
|
||||
|
||||
public:
|
||||
NtscFilter();
|
||||
virtual ~NtscFilter();
|
||||
|
||||
virtual void ApplyFilter(uint16_t *ppuOutputBuffer);
|
||||
virtual FrameInfo GetFrameInfo();
|
||||
};
|
|
@ -2,11 +2,11 @@
|
|||
#include "IRenderingDevice.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "EmulationSettings.h"
|
||||
#include "MessageManager.h"
|
||||
#include "../Utilities/PNGHelper.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "DefaultVideoFilter.h"
|
||||
#include "NtscFilter.h"
|
||||
#include "HdVideoFilter.h"
|
||||
|
||||
const uint32_t PPU_PALETTE_ARGB[] = {
|
||||
const uint32_t PPU_PALETTE_ARGB[64] = {
|
||||
0xFF666666, 0xFF002A88, 0xFF1412A7, 0xFF3B00A4, 0xFF5C007E,
|
||||
0xFF6E0040, 0xFF6C0600, 0xFF561D00, 0xFF333500, 0xFF0B4800,
|
||||
0xFF005200, 0xFF004F08, 0xFF00404D, 0xFF000000, 0xFF000000,
|
||||
|
@ -34,108 +34,53 @@ VideoDecoder* VideoDecoder::GetInstance()
|
|||
|
||||
VideoDecoder::VideoDecoder()
|
||||
{
|
||||
UpdateVideoFilter();
|
||||
}
|
||||
|
||||
VideoDecoder::~VideoDecoder()
|
||||
{
|
||||
StopThread();
|
||||
if(_frameBuffer) {
|
||||
delete[] _frameBuffer;
|
||||
_frameBuffer = nullptr;
|
||||
}
|
||||
|
||||
void VideoDecoder::GetScreenSize(ScreenSize &size)
|
||||
{
|
||||
if(_videoFilter) {
|
||||
size.Width = _videoFilter->GetFrameInfo().Width * EmulationSettings::GetVideoScale();
|
||||
size.Height = _videoFilter->GetFrameInfo().Height * EmulationSettings::GetVideoScale();
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t VideoDecoder::ProcessIntensifyBits(uint16_t ppuPixel)
|
||||
void VideoDecoder::UpdateVideoFilter()
|
||||
{
|
||||
uint32_t pixelOutput = PPU_PALETTE_ARGB[ppuPixel & 0x3F];
|
||||
|
||||
//Incorrect emphasis bit implementation, but will do for now.
|
||||
float redChannel = (float)((pixelOutput & 0xFF0000) >> 16);
|
||||
float greenChannel = (float)((pixelOutput & 0xFF00) >> 8);
|
||||
float blueChannel = (float)(pixelOutput & 0xFF);
|
||||
|
||||
if(ppuPixel & 0x40) {
|
||||
//Intensify red
|
||||
redChannel *= 1.1f;
|
||||
greenChannel *= 0.9f;
|
||||
blueChannel *= 0.9f;
|
||||
}
|
||||
if(ppuPixel & 0x80) {
|
||||
//Intensify green
|
||||
greenChannel *= 1.1f;
|
||||
redChannel *= 0.9f;
|
||||
blueChannel *= 0.9f;
|
||||
}
|
||||
if(ppuPixel & 0x100) {
|
||||
//Intensify blue
|
||||
blueChannel *= 1.1f;
|
||||
redChannel *= 0.9f;
|
||||
greenChannel *= 0.9f;
|
||||
VideoFilterType newFilter = EmulationSettings::GetVideoFilterType();
|
||||
if(_hdScreenTiles) {
|
||||
newFilter = VideoFilterType::HdPack;
|
||||
}
|
||||
|
||||
uint8_t r, g, b;
|
||||
r = (uint8_t)(redChannel > 255 ? 255 : redChannel);
|
||||
g = (uint8_t)(greenChannel > 255 ? 255 : greenChannel);
|
||||
b = (uint8_t)(blueChannel > 255 ? 255 : blueChannel);
|
||||
if(_videoFilterType != newFilter || _videoFilter == nullptr) {
|
||||
_videoFilterType = newFilter;
|
||||
|
||||
return 0xFF000000 | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
void VideoDecoder::UpdateBufferSize()
|
||||
{
|
||||
OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions();
|
||||
uint8_t hdScale = GetScale();
|
||||
|
||||
if(!_frameBuffer || _hdScale != hdScale || _overscan.GetPixelCount() != overscan.GetPixelCount()) {
|
||||
_hdScale = hdScale;
|
||||
_overscan = overscan;
|
||||
if(_frameBuffer) {
|
||||
delete[] _frameBuffer;
|
||||
switch(_videoFilterType) {
|
||||
case VideoFilterType::None: _videoFilter.reset(new DefaultVideoFilter()); break;
|
||||
case VideoFilterType::NTSC: _videoFilter.reset(new NtscFilter()); break;
|
||||
case VideoFilterType::HdPack: _videoFilter.reset(new HdVideoFilter()); break;
|
||||
}
|
||||
_frameBuffer = new uint32_t[_overscan.GetPixelCount()*hdScale*hdScale];
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDecoder::DecodeFrame()
|
||||
{
|
||||
if(_isHD && _hdNesPack == nullptr) {
|
||||
_hdNesPack.reset(new HdNesPack());
|
||||
}
|
||||
UpdateVideoFilter();
|
||||
|
||||
//Update the current output buffer based on overscan settings & HD packs
|
||||
UpdateBufferSize();
|
||||
uint32_t* outputBuffer = _frameBuffer;
|
||||
|
||||
_screenshotLock.Acquire();
|
||||
if(_isHD) {
|
||||
uint32_t screenWidth = _overscan.GetScreenWidth() * _hdScale;
|
||||
for(uint32_t i = _overscan.Top, iMax = 240 - _overscan.Bottom; i < iMax; i++) {
|
||||
for(uint32_t j = _overscan.Left, jMax = 256 - _overscan.Right; j < jMax; j++) {
|
||||
uint32_t sdPixel = PPU_PALETTE_ARGB[_ppuOutputBuffer[i * 256 + j] & 0x3F]; //ProcessIntensifyBits(inputBuffer[i * 256 + j]);
|
||||
uint32_t bufferIndex = (i - _overscan.Top) * screenWidth * _hdScale + (j - _overscan.Left) * _hdScale;
|
||||
_hdNesPack->GetPixels(_hdScreenTiles[i * 256 + j], sdPixel, outputBuffer + bufferIndex, screenWidth);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Regular SD code
|
||||
uint32_t* outputBuffer = _frameBuffer;
|
||||
for(uint32_t i = _overscan.Top, iMax = 240 - _overscan.Bottom; i < iMax; i++) {
|
||||
for(uint32_t j = _overscan.Left, jMax = 256 - _overscan.Right; j < jMax; j++) {
|
||||
*outputBuffer = ProcessIntensifyBits(_ppuOutputBuffer[i * 256 + j]);
|
||||
outputBuffer++;
|
||||
}
|
||||
}
|
||||
if(_videoFilterType == VideoFilterType::HdPack) {
|
||||
((HdVideoFilter*)_videoFilter.get())->SetHdScreenTiles(_hdScreenTiles);
|
||||
}
|
||||
_videoFilter->SendFrame(_ppuOutputBuffer);
|
||||
|
||||
_frameChanged = false;
|
||||
_screenshotLock.Release();
|
||||
}
|
||||
|
||||
uint32_t VideoDecoder::GetScale()
|
||||
{
|
||||
if(_isHD && _hdNesPack) {
|
||||
return _hdNesPack->GetScale();
|
||||
} else {
|
||||
return 1;
|
||||
if(_renderer) {
|
||||
_renderer->UpdateFrame(_videoFilter->GetOutputBuffer(), _videoFilter->GetFrameInfo().Width, _videoFilter->GetFrameInfo().Height);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,44 +91,6 @@ void VideoDecoder::DebugDecodeFrame(uint16_t* inputBuffer, uint32_t* outputBuffe
|
|||
}
|
||||
}
|
||||
|
||||
void VideoDecoder::TakeScreenshot(string romFilename)
|
||||
{
|
||||
uint32_t bufferSize = _overscan.GetPixelCount() * 4;
|
||||
uint32_t* frameBuffer = new uint32_t[bufferSize];
|
||||
|
||||
_screenshotLock.Acquire();
|
||||
memcpy(frameBuffer, _frameBuffer, bufferSize);
|
||||
_screenshotLock.Release();
|
||||
|
||||
//ARGB -> ABGR
|
||||
for(uint32_t i = 0; i < bufferSize; i++) {
|
||||
frameBuffer[i] = (frameBuffer[i] & 0xFF00FF00) | ((frameBuffer[i] & 0xFF0000) >> 16) | ((frameBuffer[i] & 0xFF) << 16);
|
||||
}
|
||||
|
||||
int counter = 0;
|
||||
string baseFilename = 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++;
|
||||
}
|
||||
|
||||
PNGHelper::WritePNG(ssFilename, (uint8_t*)frameBuffer, _overscan.GetScreenWidth(), _overscan.GetScreenHeight());
|
||||
delete[] frameBuffer;
|
||||
|
||||
MessageManager::DisplayMessage("Screenshot saved", FolderUtilities::GetFilename(ssFilename, true));
|
||||
}
|
||||
|
||||
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)
|
||||
|
@ -197,10 +104,6 @@ void VideoDecoder::DecodeThread()
|
|||
}
|
||||
|
||||
DecodeFrame();
|
||||
if(_renderer) {
|
||||
_renderer->UpdateFrame(_frameBuffer);
|
||||
}
|
||||
|
||||
_waitForRender.Signal();
|
||||
}
|
||||
}
|
||||
|
@ -216,10 +119,8 @@ bool VideoDecoder::UpdateFrame(void *ppuOutputBuffer, HdPpuPixelInfo *hdPixelInf
|
|||
|
||||
if(readyForNewFrame) {
|
||||
//The PPU sends us a new frame via this function when a full frame is done drawing
|
||||
bool isHD = (hdPixelInfo != nullptr);
|
||||
_isHD = isHD;
|
||||
_ppuOutputBuffer = (uint16_t*)ppuOutputBuffer;
|
||||
_hdScreenTiles = hdPixelInfo;
|
||||
_ppuOutputBuffer = (uint16_t*)ppuOutputBuffer;
|
||||
_frameChanged = true;
|
||||
_waitForFrame.Signal();
|
||||
}
|
||||
|
@ -255,10 +156,8 @@ void VideoDecoder::StopThread()
|
|||
_renderThread.release();
|
||||
|
||||
if(_renderer && _ppuOutputBuffer != nullptr) {
|
||||
//Set screen to black
|
||||
memset(_ppuOutputBuffer, 13, PPU::PixelCount * sizeof(uint16_t));
|
||||
memset(_ppuOutputBuffer, 0, PPU::PixelCount * sizeof(uint16_t));
|
||||
DecodeFrame();
|
||||
_renderer->UpdateFrame(_frameBuffer);
|
||||
_renderer->Render();
|
||||
}
|
||||
}
|
||||
|
@ -284,4 +183,11 @@ void VideoDecoder::UnregisterRenderingDevice(IRenderingDevice *renderer)
|
|||
if(_renderer == renderer) {
|
||||
_renderer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void VideoDecoder::TakeScreenshot(string romFilename)
|
||||
{
|
||||
if(_videoFilter) {
|
||||
_videoFilter->TakeScreenshot(romFilename);
|
||||
}
|
||||
}
|
|
@ -8,9 +8,15 @@ using std::thread;
|
|||
#include "EmulationSettings.h"
|
||||
#include "HdNesPack.h"
|
||||
|
||||
|
||||
class BaseVideoFilter;
|
||||
class IRenderingDevice;
|
||||
|
||||
struct ScreenSize
|
||||
{
|
||||
int32_t Width;
|
||||
int32_t Height;
|
||||
};
|
||||
|
||||
class VideoDecoder
|
||||
{
|
||||
private:
|
||||
|
@ -24,22 +30,17 @@ private:
|
|||
unique_ptr<thread> _decodeThread;
|
||||
unique_ptr<thread> _renderThread;
|
||||
|
||||
OverscanDimensions _overscan;
|
||||
uint32_t* _frameBuffer = nullptr;
|
||||
SimpleLock _screenshotLock;
|
||||
AutoResetEvent _waitForFrame;
|
||||
AutoResetEvent _waitForRender;
|
||||
|
||||
bool _isHD = false;
|
||||
|
||||
atomic<bool> _frameChanged = false;
|
||||
atomic<bool> _stopFlag = false;
|
||||
uint32_t _frameCount = 0;
|
||||
|
||||
unique_ptr<HdNesPack> _hdNesPack = nullptr;
|
||||
uint32_t _hdScale = 1;
|
||||
VideoFilterType _videoFilterType = VideoFilterType::None;
|
||||
unique_ptr<BaseVideoFilter> _videoFilter = nullptr;
|
||||
|
||||
uint32_t ProcessIntensifyBits(uint16_t ppuPixel);
|
||||
void UpdateBufferSize();
|
||||
void UpdateVideoFilter();
|
||||
|
||||
void DecodeThread();
|
||||
void RenderThread();
|
||||
|
@ -55,6 +56,8 @@ public:
|
|||
uint32_t GetScale();
|
||||
uint32_t GetFrameCount();
|
||||
|
||||
void GetScreenSize(ScreenSize &size);
|
||||
|
||||
void DebugDecodeFrame(uint16_t* inputBuffer, uint32_t* outputBuffer, uint32_t length);
|
||||
|
||||
bool UpdateFrame(void* frameBuffer, HdPpuPixelInfo *screenTiles = nullptr);
|
||||
|
|
|
@ -17,6 +17,8 @@ namespace Mesen.GUI.Config
|
|||
public UInt32 OverscanRight = 0;
|
||||
public UInt32 OverscanTop = 8;
|
||||
public UInt32 OverscanBottom = 8;
|
||||
public UInt32 VideoScale = 2;
|
||||
public VideoFilterType VideoFilter = VideoFilterType.None;
|
||||
|
||||
public VideoInfo()
|
||||
{
|
||||
|
@ -35,12 +37,9 @@ namespace Mesen.GUI.Config
|
|||
}
|
||||
|
||||
InteropEmu.SetOverscanDimensions(videoInfo.OverscanLeft, videoInfo.OverscanRight, videoInfo.OverscanTop, videoInfo.OverscanBottom);
|
||||
}
|
||||
|
||||
static public Size GetViewerSize()
|
||||
{
|
||||
VideoInfo videoInfo = ConfigManager.Config.VideoInfo;
|
||||
return new Size((int)(256-videoInfo.OverscanLeft-videoInfo.OverscanRight)*4, (int)(240-videoInfo.OverscanTop-videoInfo.OverscanBottom)*4);
|
||||
InteropEmu.SetVideoFilter(videoInfo.VideoFilter);
|
||||
InteropEmu.SetVideoScale(videoInfo.VideoScale);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
100
GUI.NET/Forms/frmMain.Designer.cs
generated
100
GUI.NET/Forms/frmMain.Designer.cs
generated
|
@ -63,6 +63,14 @@
|
|||
this.mnuEmuSpeedDouble = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuEmuSpeedHalf = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuEmuSpeedQuarter = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuVideoScale = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuScale1x = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuScale2x = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuScale3x = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuScale4x = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuVideoFilter = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuNoneFilter = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuNtscFilter = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuShowFPS = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.toolStripMenuItem10 = new System.Windows.Forms.ToolStripSeparator();
|
||||
this.mnuAudioConfig = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -99,6 +107,7 @@
|
|||
this.mnuTestRecordMovie = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTestRecordTest = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTestStopRecording = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuRunAllTests = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuDebugger = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuTakeScreenshot = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.mnuHelp = new System.Windows.Forms.ToolStripMenuItem();
|
||||
|
@ -107,7 +116,6 @@
|
|||
this.mnuAbout = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menuTimer = new System.Windows.Forms.Timer(this.components);
|
||||
this.dxViewer = new Mesen.GUI.Controls.DXViewer();
|
||||
this.mnuRunAllTests = new System.Windows.Forms.ToolStripMenuItem();
|
||||
this.menuStrip.SuspendLayout();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
|
@ -229,6 +237,8 @@
|
|||
//
|
||||
this.mnuOptions.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuEmulationSpeed,
|
||||
this.mnuVideoScale,
|
||||
this.mnuVideoFilter,
|
||||
this.mnuShowFPS,
|
||||
this.toolStripMenuItem10,
|
||||
this.mnuAudioConfig,
|
||||
|
@ -328,6 +338,72 @@
|
|||
this.mnuEmuSpeedQuarter.Text = "Quarter (25%)";
|
||||
this.mnuEmuSpeedQuarter.Click += new System.EventHandler(this.mnuEmulationSpeedOption_Click);
|
||||
//
|
||||
// mnuVideoScale
|
||||
//
|
||||
this.mnuVideoScale.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuScale1x,
|
||||
this.mnuScale2x,
|
||||
this.mnuScale3x,
|
||||
this.mnuScale4x});
|
||||
this.mnuVideoScale.Name = "mnuVideoScale";
|
||||
this.mnuVideoScale.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuVideoScale.Text = "Video Scale";
|
||||
//
|
||||
// mnuScale1x
|
||||
//
|
||||
this.mnuScale1x.Name = "mnuScale1x";
|
||||
this.mnuScale1x.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuScale1x.Tag = "1";
|
||||
this.mnuScale1x.Text = "1x";
|
||||
this.mnuScale1x.Click += new System.EventHandler(this.mnuScale_Click);
|
||||
//
|
||||
// mnuScale2x
|
||||
//
|
||||
this.mnuScale2x.Name = "mnuScale2x";
|
||||
this.mnuScale2x.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuScale2x.Tag = "2";
|
||||
this.mnuScale2x.Text = "2x";
|
||||
this.mnuScale2x.Click += new System.EventHandler(this.mnuScale_Click);
|
||||
//
|
||||
// mnuScale3x
|
||||
//
|
||||
this.mnuScale3x.Name = "mnuScale3x";
|
||||
this.mnuScale3x.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuScale3x.Tag = "3";
|
||||
this.mnuScale3x.Text = "3x";
|
||||
this.mnuScale3x.Click += new System.EventHandler(this.mnuScale_Click);
|
||||
//
|
||||
// mnuScale4x
|
||||
//
|
||||
this.mnuScale4x.Name = "mnuScale4x";
|
||||
this.mnuScale4x.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuScale4x.Tag = "4";
|
||||
this.mnuScale4x.Text = "4x";
|
||||
this.mnuScale4x.Click += new System.EventHandler(this.mnuScale_Click);
|
||||
//
|
||||
// mnuVideoFilter
|
||||
//
|
||||
this.mnuVideoFilter.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] {
|
||||
this.mnuNoneFilter,
|
||||
this.mnuNtscFilter});
|
||||
this.mnuVideoFilter.Name = "mnuVideoFilter";
|
||||
this.mnuVideoFilter.Size = new System.Drawing.Size(163, 22);
|
||||
this.mnuVideoFilter.Text = "Video Filter";
|
||||
//
|
||||
// mnuNoneFilter
|
||||
//
|
||||
this.mnuNoneFilter.Name = "mnuNoneFilter";
|
||||
this.mnuNoneFilter.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuNoneFilter.Text = "None";
|
||||
this.mnuNoneFilter.Click += new System.EventHandler(this.mnuNoneFilter_Click);
|
||||
//
|
||||
// mnuNtscFilter
|
||||
//
|
||||
this.mnuNtscFilter.Name = "mnuNtscFilter";
|
||||
this.mnuNtscFilter.Size = new System.Drawing.Size(152, 22);
|
||||
this.mnuNtscFilter.Text = "NTSC";
|
||||
this.mnuNtscFilter.Click += new System.EventHandler(this.mnuNtscFilter_Click);
|
||||
//
|
||||
// mnuShowFPS
|
||||
//
|
||||
this.mnuShowFPS.CheckOnClick = true;
|
||||
|
@ -606,6 +682,13 @@
|
|||
this.mnuTestStopRecording.Text = "Stop recording";
|
||||
this.mnuTestStopRecording.Click += new System.EventHandler(this.mnuTestStopRecording_Click);
|
||||
//
|
||||
// mnuRunAllTests
|
||||
//
|
||||
this.mnuRunAllTests.Name = "mnuRunAllTests";
|
||||
this.mnuRunAllTests.Size = new System.Drawing.Size(193, 22);
|
||||
this.mnuRunAllTests.Text = "Run all tests";
|
||||
this.mnuRunAllTests.Click += new System.EventHandler(this.mnuRunAllTests_Click);
|
||||
//
|
||||
// mnuDebugger
|
||||
//
|
||||
this.mnuDebugger.Name = "mnuDebugger";
|
||||
|
@ -663,13 +746,6 @@
|
|||
this.dxViewer.Size = new System.Drawing.Size(1024, 960);
|
||||
this.dxViewer.TabIndex = 1;
|
||||
//
|
||||
// mnuRunAllTests
|
||||
//
|
||||
this.mnuRunAllTests.Name = "mnuRunAllTests";
|
||||
this.mnuRunAllTests.Size = new System.Drawing.Size(193, 22);
|
||||
this.mnuRunAllTests.Text = "Run all tests";
|
||||
this.mnuRunAllTests.Click += new System.EventHandler(this.mnuRunAllTests_Click);
|
||||
//
|
||||
// frmMain
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
|
@ -762,6 +838,14 @@
|
|||
private System.Windows.Forms.ToolStripSeparator toolStripMenuItem11;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuPreferences;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuRunAllTests;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuVideoScale;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuScale1x;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuScale2x;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuScale3x;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuScale4x;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuVideoFilter;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNoneFilter;
|
||||
private System.Windows.Forms.ToolStripMenuItem mnuNtscFilter;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -172,7 +172,8 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
mnuShowFPS.Checked = ConfigManager.Config.VideoInfo.ShowFPS;
|
||||
UpdateEmulationSpeedMenu();
|
||||
dxViewer.Size = VideoInfo.GetViewerSize();
|
||||
UpdateScaleMenu(ConfigManager.Config.VideoInfo.VideoScale);
|
||||
UpdateFilterMenu(ConfigManager.Config.VideoInfo.VideoFilter);
|
||||
}
|
||||
|
||||
private void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
|
||||
|
@ -189,6 +190,11 @@ namespace Mesen.GUI.Forms
|
|||
this.StartEmuThread();
|
||||
} else if(e.NotificationType == InteropEmu.ConsoleNotificationType.GameStopped) {
|
||||
CheatInfo.ClearCheats();
|
||||
} else if(e.NotificationType == InteropEmu.ConsoleNotificationType.ResolutionChanged) {
|
||||
this.BeginInvoke((MethodInvoker)(() => {
|
||||
InteropEmu.ScreenSize size = InteropEmu.GetScreenSize();
|
||||
dxViewer.Size = new Size(size.Width, size.Height);
|
||||
}));
|
||||
}
|
||||
UpdateMenus();
|
||||
}
|
||||
|
@ -683,5 +689,45 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
Process.Start("TestHelper.exe");
|
||||
}
|
||||
|
||||
private void UpdateScaleMenu(UInt32 scale)
|
||||
{
|
||||
mnuScale1x.Checked = (scale == 1);
|
||||
mnuScale2x.Checked = (scale == 2);
|
||||
mnuScale3x.Checked = (scale == 3);
|
||||
mnuScale4x.Checked = (scale == 4);
|
||||
|
||||
ConfigManager.Config.VideoInfo.VideoScale = scale;
|
||||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
|
||||
private void UpdateFilterMenu(VideoFilterType filterType)
|
||||
{
|
||||
mnuNoneFilter.Checked = (filterType == VideoFilterType.None);
|
||||
mnuNtscFilter.Checked = (filterType == VideoFilterType.NTSC);
|
||||
|
||||
ConfigManager.Config.VideoInfo.VideoFilter = filterType;
|
||||
ConfigManager.ApplyChanges();
|
||||
}
|
||||
|
||||
private void mnuScale_Click(object sender, EventArgs e)
|
||||
{
|
||||
UInt32 scale = UInt32.Parse((string)((ToolStripMenuItem)sender).Tag);
|
||||
InteropEmu.SetVideoScale(scale);
|
||||
|
||||
UpdateScaleMenu(scale);
|
||||
}
|
||||
|
||||
private void mnuNoneFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
InteropEmu.SetVideoFilter(VideoFilterType.None);
|
||||
UpdateFilterMenu(VideoFilterType.None);
|
||||
}
|
||||
|
||||
private void mnuNtscFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
InteropEmu.SetVideoFilter(VideoFilterType.NTSC);
|
||||
UpdateFilterMenu(VideoFilterType.NTSC);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -75,6 +75,9 @@ namespace Mesen.GUI
|
|||
[DllImport(DLLPath)] public static extern void SetNesModel(NesModel model);
|
||||
[DllImport(DLLPath)] public static extern void SetEmulationSpeed(UInt32 emulationSpeed);
|
||||
[DllImport(DLLPath)] public static extern void SetOverscanDimensions(UInt32 left, UInt32 right, UInt32 top, UInt32 bottom);
|
||||
[DllImport(DLLPath)] public static extern void SetVideoScale(UInt32 scale);
|
||||
[DllImport(DLLPath)] public static extern void SetVideoFilter(VideoFilterType filter);
|
||||
[DllImport(DLLPath, EntryPoint="GetScreenSize")] private static extern void GetScreenSizeWrapper(out ScreenSize size);
|
||||
|
||||
[DllImport(DLLPath)] public static extern void DebugInitialize();
|
||||
[DllImport(DLLPath)] public static extern void DebugRelease();
|
||||
|
@ -192,6 +195,13 @@ namespace Mesen.GUI
|
|||
}
|
||||
}
|
||||
|
||||
public static ScreenSize GetScreenSize()
|
||||
{
|
||||
ScreenSize size;
|
||||
GetScreenSizeWrapper(out size);
|
||||
return size;
|
||||
}
|
||||
|
||||
public static string GetROMPath() { return PtrToStringUtf8(InteropEmu.GetROMPathWrapper()); }
|
||||
public static string GetKeyName(UInt32 key) { return PtrToStringUtf8(InteropEmu.GetKeyNameWrapper(key)); }
|
||||
|
||||
|
@ -227,6 +237,8 @@ namespace Mesen.GUI
|
|||
CheatAdded = 7,
|
||||
CheatRemoved = 8,
|
||||
PpuFrameDone = 9,
|
||||
MovieEnded = 10,
|
||||
ResolutionChanged = 11,
|
||||
}
|
||||
|
||||
public struct KeyMapping
|
||||
|
@ -246,6 +258,12 @@ namespace Mesen.GUI
|
|||
public UInt32 TurboSpeed;
|
||||
}
|
||||
|
||||
public struct ScreenSize
|
||||
{
|
||||
public Int32 Width;
|
||||
public Int32 Height;
|
||||
}
|
||||
|
||||
public class NotificationEventArgs
|
||||
{
|
||||
public ConsoleNotificationType NotificationType;
|
||||
|
@ -408,6 +426,12 @@ namespace Mesen.GUI
|
|||
PAL = 2
|
||||
}
|
||||
|
||||
public enum VideoFilterType
|
||||
{
|
||||
None = 0,
|
||||
NTSC = 1,
|
||||
}
|
||||
|
||||
public enum DebugMemoryType
|
||||
{
|
||||
CpuMemory = 0,
|
||||
|
|
|
@ -208,6 +208,9 @@ namespace InteropEmu {
|
|||
DllExport void __stdcall SetNesModel(uint32_t model) { EmulationSettings::SetNesModel((NesModel)model); }
|
||||
DllExport void __stdcall SetOverscanDimensions(uint32_t left, uint32_t right, uint32_t top, uint32_t bottom) { EmulationSettings::SetOverscanDimensions(left, right, top, bottom); }
|
||||
DllExport void __stdcall SetEmulationSpeed(uint32_t emulationSpeed) { EmulationSettings::SetEmulationSpeed(emulationSpeed); }
|
||||
DllExport void __stdcall SetVideoScale(uint32_t scale) { EmulationSettings::SetVideoScale(scale); }
|
||||
DllExport void __stdcall SetVideoFilter(VideoFilterType filter) { EmulationSettings::SetVideoFilterType(filter); }
|
||||
DllExport void __stdcall GetScreenSize(ScreenSize &size) { VideoDecoder::GetInstance()->GetScreenSize(size); }
|
||||
|
||||
}
|
||||
}
|
|
@ -263,6 +263,9 @@
|
|||
<LinkLibraryDependencies>true</LinkLibraryDependencies>
|
||||
<UseLibraryDependencyInputs>false</UseLibraryDependencyInputs>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\NesNtsc\NesNtsc.vcxproj">
|
||||
<Project>{65db72b1-a45a-4475-90c1-60596b3abeb3}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
|
|
|
@ -9,10 +9,6 @@
|
|||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
|
|
11
NES.sln
11
NES.sln
|
@ -8,6 +8,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Core", "Core\Core.vcxproj",
|
|||
{B5330148-E8C7-46BA-B54E-69BE59EA337D} = {B5330148-E8C7-46BA-B54E-69BE59EA337D}
|
||||
{CF35D78C-F710-41D2-968F-C46ACCFF6F07} = {CF35D78C-F710-41D2-968F-C46ACCFF6F07}
|
||||
{7761E790-B42C-4179-8550-8365FF9EB23E} = {7761E790-B42C-4179-8550-8365FF9EB23E}
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3} = {65DB72B1-A45A-4475-90C1-60596B3ABEB3}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Utilities", "Utilities\Utilities.vcxproj", "{B5330148-E8C7-46BA-B54E-69BE59EA337D}"
|
||||
|
@ -37,6 +38,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestHelper", "TestHelper\Te
|
|||
{37749BB2-FA78-4EC9-8990-5628FC0BBA19} = {37749BB2-FA78-4EC9-8990-5628FC0BBA19}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "NesNtsc", "NesNtsc\NesNtsc.vcxproj", "{65DB72B1-A45A-4475-90C1-60596B3ABEB3}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
|
@ -108,6 +111,14 @@ Global
|
|||
{2A607369-8B5D-494A-9E40-C5DC8D821AA3}.Release|x64.Build.0 = Release|x64
|
||||
{2A607369-8B5D-494A-9E40-C5DC8D821AA3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{2A607369-8B5D-494A-9E40-C5DC8D821AA3}.Release|x86.Build.0 = Release|Win32
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Debug|x64.Build.0 = Debug|x64
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Debug|x86.Build.0 = Debug|Win32
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Release|x64.ActiveCfg = Release|x64
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Release|x64.Build.0 = Release|x64
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Release|x86.ActiveCfg = Release|Win32
|
||||
{65DB72B1-A45A-4475-90C1-60596B3ABEB3}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
164
NesNtsc/NesNtsc.vcxproj
Normal file
164
NesNtsc/NesNtsc.vcxproj
Normal file
|
@ -0,0 +1,164 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="12.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{65DB72B1-A45A-4475-90C1-60596B3ABEB3}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>NesNtsc</RootNamespace>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v120</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)\bin\$(PlatformTarget)\$(Configuration)\</OutDir>
|
||||
<IntDir>obj\$(Platform)\$(Configuration)\</IntDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NESNTSC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;NESNTSC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NESNTSC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>
|
||||
</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;NESNTSC_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="nes_ntsc.c" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="nes_ntsc.h" />
|
||||
<ClInclude Include="nes_ntsc_config.h" />
|
||||
<ClInclude Include="nes_ntsc_impl.h" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
29
NesNtsc/NesNtsc.vcxproj.filters
Normal file
29
NesNtsc/NesNtsc.vcxproj.filters
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="nes_ntsc.c">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="nes_ntsc.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nes_ntsc_config.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="nes_ntsc_impl.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
</Project>
|
289
NesNtsc/nes_ntsc.c
Normal file
289
NesNtsc/nes_ntsc.c
Normal file
|
@ -0,0 +1,289 @@
|
|||
/* nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
|
||||
|
||||
#include "nes_ntsc.h"
|
||||
|
||||
/* Copyright (C) 2006-2007 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
nes_ntsc_setup_t const nes_ntsc_monochrome = { 0,-1, 0, 0,.2, 0,.2,-.2,-.2,-1, 1, 0, 0, 0, 0 };
|
||||
nes_ntsc_setup_t const nes_ntsc_composite = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0 };
|
||||
nes_ntsc_setup_t const nes_ntsc_svideo = { 0, 0, 0, 0,.2, 0,.2, -1, -1, 0, 1, 0, 0, 0, 0 };
|
||||
nes_ntsc_setup_t const nes_ntsc_rgb = { 0, 0, 0, 0,.2, 0,.7, -1, -1,-1, 1, 0, 0, 0, 0 };
|
||||
|
||||
#define alignment_count 3
|
||||
#define burst_count 3
|
||||
#define rescale_in 8
|
||||
#define rescale_out 7
|
||||
|
||||
#define artifacts_mid 1.0f
|
||||
#define fringing_mid 1.0f
|
||||
#define std_decoder_hue -15
|
||||
|
||||
#define STD_HUE_CONDITION( setup ) !(setup->base_palette || setup->palette)
|
||||
|
||||
#include "nes_ntsc_impl.h"
|
||||
|
||||
/* 3 input pixels -> 8 composite samples */
|
||||
pixel_info_t const nes_ntsc_pixels [alignment_count] = {
|
||||
{ PIXEL_OFFSET( -4, -9 ), { 1, 1, .6667f, 0 } },
|
||||
{ PIXEL_OFFSET( -2, -7 ), { .3333f, 1, 1, .3333f } },
|
||||
{ PIXEL_OFFSET( 0, -5 ), { 0, .6667f, 1, 1 } },
|
||||
};
|
||||
|
||||
static void merge_kernel_fields( nes_ntsc_rgb_t* io )
|
||||
{
|
||||
int n;
|
||||
for ( n = burst_size; n; --n )
|
||||
{
|
||||
nes_ntsc_rgb_t p0 = io [burst_size * 0] + rgb_bias;
|
||||
nes_ntsc_rgb_t p1 = io [burst_size * 1] + rgb_bias;
|
||||
nes_ntsc_rgb_t p2 = io [burst_size * 2] + rgb_bias;
|
||||
/* merge colors without losing precision */
|
||||
io [burst_size * 0] =
|
||||
((p0 + p1 - ((p0 ^ p1) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io [burst_size * 1] =
|
||||
((p1 + p2 - ((p1 ^ p2) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
io [burst_size * 2] =
|
||||
((p2 + p0 - ((p2 ^ p0) & nes_ntsc_rgb_builder)) >> 1) - rgb_bias;
|
||||
++io;
|
||||
}
|
||||
}
|
||||
|
||||
static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out )
|
||||
{
|
||||
int n;
|
||||
for ( n = burst_count; n; --n )
|
||||
{
|
||||
unsigned i;
|
||||
for ( i = 0; i < rgb_kernel_size / 2; i++ )
|
||||
{
|
||||
nes_ntsc_rgb_t error = color -
|
||||
out [i ] - out [(i+12)%14+14] - out [(i+10)%14+28] -
|
||||
out [i + 7] - out [i + 5 +14] - out [i + 3 +28];
|
||||
DISTRIBUTE_ERROR( i+3+28, i+5+14, i+7 );
|
||||
}
|
||||
out += alignment_count * rgb_kernel_size;
|
||||
}
|
||||
}
|
||||
|
||||
void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup )
|
||||
{
|
||||
int merge_fields;
|
||||
int entry;
|
||||
init_t impl;
|
||||
float gamma_factor;
|
||||
|
||||
if ( !setup )
|
||||
setup = &nes_ntsc_composite;
|
||||
init( &impl, setup );
|
||||
|
||||
/* setup fast gamma */
|
||||
{
|
||||
float gamma = (float) setup->gamma * -0.5f;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
gamma += 0.1333f;
|
||||
|
||||
gamma_factor = (float) pow( (float) fabs( gamma ), 0.73f );
|
||||
if ( gamma < 0 )
|
||||
gamma_factor = -gamma_factor;
|
||||
}
|
||||
|
||||
merge_fields = setup->merge_fields;
|
||||
if ( setup->artifacts <= -1 && setup->fringing <= -1 )
|
||||
merge_fields = 1;
|
||||
|
||||
for ( entry = 0; entry < nes_ntsc_palette_size; entry++ )
|
||||
{
|
||||
/* Base 64-color generation */
|
||||
static float const lo_levels [4] = { -0.12f, 0.00f, 0.31f, 0.72f };
|
||||
static float const hi_levels [4] = { 0.40f, 0.68f, 1.00f, 1.00f };
|
||||
int level = entry >> 4 & 0x03;
|
||||
float lo = lo_levels [level];
|
||||
float hi = hi_levels [level];
|
||||
|
||||
int color = entry & 0x0F;
|
||||
if ( color == 0 )
|
||||
lo = hi;
|
||||
if ( color == 0x0D )
|
||||
hi = lo;
|
||||
if ( color > 0x0D )
|
||||
hi = lo = 0.0f;
|
||||
|
||||
{
|
||||
/* phases [i] = cos( i * PI / 6 ) */
|
||||
static float const phases [0x10 + 3] = {
|
||||
-1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f,
|
||||
1.0f, 0.866025f, 0.5f, 0.0f, -0.5f, -0.866025f,
|
||||
-1.0f, -0.866025f, -0.5f, 0.0f, 0.5f, 0.866025f,
|
||||
1.0f
|
||||
};
|
||||
#define TO_ANGLE_SIN( color ) phases [color]
|
||||
#define TO_ANGLE_COS( color ) phases [(color) + 3]
|
||||
|
||||
/* Convert raw waveform to YIQ */
|
||||
float sat = (hi - lo) * 0.5f;
|
||||
float i = TO_ANGLE_SIN( color ) * sat;
|
||||
float q = TO_ANGLE_COS( color ) * sat;
|
||||
float y = (hi + lo) * 0.5f;
|
||||
|
||||
/* Optionally use base palette instead */
|
||||
if ( setup->base_palette )
|
||||
{
|
||||
unsigned char const* in = &setup->base_palette [(entry & 0x3F) * 3];
|
||||
static float const to_float = 1.0f / 0xFF;
|
||||
float r = to_float * in [0];
|
||||
float g = to_float * in [1];
|
||||
float b = to_float * in [2];
|
||||
q = RGB_TO_YIQ( r, g, b, y, i );
|
||||
}
|
||||
|
||||
/* Apply color emphasis */
|
||||
#ifdef NES_NTSC_EMPHASIS
|
||||
{
|
||||
int tint = entry >> 6 & 7;
|
||||
if ( tint && color <= 0x0D )
|
||||
{
|
||||
static float const atten_mul = 0.79399f;
|
||||
static float const atten_sub = 0.0782838f;
|
||||
|
||||
if ( tint == 7 )
|
||||
{
|
||||
y = y * (atten_mul * 1.13f) - (atten_sub * 1.13f);
|
||||
}
|
||||
else
|
||||
{
|
||||
static unsigned char const tints [8] = { 0, 6, 10, 8, 2, 4, 0, 0 };
|
||||
int const tint_color = tints [tint];
|
||||
float sat = hi * (0.5f - atten_mul * 0.5f) + atten_sub * 0.5f;
|
||||
y -= sat * 0.5f;
|
||||
if ( tint >= 3 && tint != 4 )
|
||||
{
|
||||
/* combined tint bits */
|
||||
sat *= 0.6f;
|
||||
y -= sat;
|
||||
}
|
||||
i += TO_ANGLE_SIN( tint_color ) * sat;
|
||||
q += TO_ANGLE_COS( tint_color ) * sat;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Optionally use palette instead */
|
||||
if ( setup->palette )
|
||||
{
|
||||
unsigned char const* in = &setup->palette [entry * 3];
|
||||
static float const to_float = 1.0f / 0xFF;
|
||||
float r = to_float * in [0];
|
||||
float g = to_float * in [1];
|
||||
float b = to_float * in [2];
|
||||
q = RGB_TO_YIQ( r, g, b, y, i );
|
||||
}
|
||||
|
||||
/* Apply brightness, contrast, and gamma */
|
||||
y *= (float) setup->contrast * 0.5f + 1;
|
||||
/* adjustment reduces error when using input palette */
|
||||
y += (float) setup->brightness * 0.5f - 0.5f / 256;
|
||||
|
||||
{
|
||||
float r, g, b = YIQ_TO_RGB( y, i, q, default_decoder, float, r, g );
|
||||
|
||||
/* fast approximation of n = pow( n, gamma ) */
|
||||
r = (r * gamma_factor - gamma_factor) * r + r;
|
||||
g = (g * gamma_factor - gamma_factor) * g + g;
|
||||
b = (b * gamma_factor - gamma_factor) * b + b;
|
||||
|
||||
q = RGB_TO_YIQ( r, g, b, y, i );
|
||||
}
|
||||
|
||||
i *= rgb_unit;
|
||||
q *= rgb_unit;
|
||||
y *= rgb_unit;
|
||||
y += rgb_offset;
|
||||
|
||||
/* Generate kernel */
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, impl.to_rgb, int, r, g );
|
||||
/* blue tends to overflow, so clamp it */
|
||||
nes_ntsc_rgb_t rgb = PACK_RGB( r, g, (b < 0x3E0 ? b: 0x3E0) );
|
||||
|
||||
if ( setup->palette_out )
|
||||
RGB_PALETTE_OUT( rgb, &setup->palette_out [entry * 3] );
|
||||
|
||||
if ( ntsc )
|
||||
{
|
||||
nes_ntsc_rgb_t* kernel = ntsc->table [entry];
|
||||
gen_kernel( &impl, y, i, q, kernel );
|
||||
if ( merge_fields )
|
||||
merge_kernel_fields( kernel );
|
||||
correct_errors( rgb, kernel );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef NES_NTSC_NO_BLITTERS
|
||||
|
||||
void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* input, long in_row_width,
|
||||
int burst_phase, int in_width, int in_height, void* rgb_out, long out_pitch )
|
||||
{
|
||||
int chunk_count = (in_width - 1) / nes_ntsc_in_chunk;
|
||||
for ( ; in_height; --in_height )
|
||||
{
|
||||
NES_NTSC_IN_T const* line_in = input;
|
||||
NES_NTSC_BEGIN_ROW( ntsc, burst_phase,
|
||||
nes_ntsc_black, nes_ntsc_black, NES_NTSC_ADJ_IN( *line_in ) );
|
||||
nes_ntsc_out_t* restrict line_out = (nes_ntsc_out_t*) rgb_out;
|
||||
int n;
|
||||
++line_in;
|
||||
|
||||
for ( n = chunk_count; n; --n )
|
||||
{
|
||||
/* order of input and output pixels must not be altered */
|
||||
NES_NTSC_COLOR_IN( 0, NES_NTSC_ADJ_IN( line_in [0] ) );
|
||||
NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH );
|
||||
|
||||
NES_NTSC_COLOR_IN( 1, NES_NTSC_ADJ_IN( line_in [1] ) );
|
||||
NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH );
|
||||
|
||||
NES_NTSC_COLOR_IN( 2, NES_NTSC_ADJ_IN( line_in [2] ) );
|
||||
NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH );
|
||||
|
||||
line_in += 3;
|
||||
line_out += 7;
|
||||
}
|
||||
|
||||
/* finish final pixels */
|
||||
NES_NTSC_COLOR_IN( 0, nes_ntsc_black );
|
||||
NES_NTSC_RGB_OUT( 0, line_out [0], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 1, line_out [1], NES_NTSC_OUT_DEPTH );
|
||||
|
||||
NES_NTSC_COLOR_IN( 1, nes_ntsc_black );
|
||||
NES_NTSC_RGB_OUT( 2, line_out [2], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 3, line_out [3], NES_NTSC_OUT_DEPTH );
|
||||
|
||||
NES_NTSC_COLOR_IN( 2, nes_ntsc_black );
|
||||
NES_NTSC_RGB_OUT( 4, line_out [4], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 5, line_out [5], NES_NTSC_OUT_DEPTH );
|
||||
NES_NTSC_RGB_OUT( 6, line_out [6], NES_NTSC_OUT_DEPTH );
|
||||
|
||||
burst_phase = (burst_phase + 1) % nes_ntsc_burst_count;
|
||||
input += in_row_width;
|
||||
rgb_out = (char*) rgb_out + out_pitch;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
198
NesNtsc/nes_ntsc.h
Normal file
198
NesNtsc/nes_ntsc.h
Normal file
|
@ -0,0 +1,198 @@
|
|||
/* NES NTSC video filter */
|
||||
|
||||
/* nes_ntsc 0.2.2 */
|
||||
#ifndef NES_NTSC_H
|
||||
#define NES_NTSC_H
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#include "nes_ntsc_config.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* Image parameters, ranging from -1.0 to 1.0. Actual internal values shown
|
||||
in parenthesis and should remain fairly stable in future versions. */
|
||||
typedef struct nes_ntsc_setup_t
|
||||
{
|
||||
/* Basic parameters */
|
||||
double hue; /* -1 = -180 degrees +1 = +180 degrees */
|
||||
double saturation; /* -1 = grayscale (0.0) +1 = oversaturated colors (2.0) */
|
||||
double contrast; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double brightness; /* -1 = dark (0.5) +1 = light (1.5) */
|
||||
double sharpness; /* edge contrast enhancement/blurring */
|
||||
|
||||
/* Advanced parameters */
|
||||
double gamma; /* -1 = dark (1.5) +1 = light (0.5) */
|
||||
double resolution; /* image resolution */
|
||||
double artifacts; /* artifacts caused by color changes */
|
||||
double fringing; /* color artifacts caused by brightness changes */
|
||||
double bleed; /* color bleed (color resolution reduction) */
|
||||
int merge_fields; /* if 1, merges even and odd fields together to reduce flicker */
|
||||
float const* decoder_matrix; /* optional RGB decoder matrix, 6 elements */
|
||||
|
||||
unsigned char* palette_out; /* optional RGB palette out, 3 bytes per color */
|
||||
|
||||
/* You can replace the standard NES color generation with an RGB palette. The
|
||||
first replaces all color generation, while the second replaces only the core
|
||||
64-color generation and does standard color emphasis calculations on it. */
|
||||
unsigned char const* palette;/* optional 512-entry RGB palette in, 3 bytes per color */
|
||||
unsigned char const* base_palette;/* optional 64-entry RGB palette in, 3 bytes per color */
|
||||
} nes_ntsc_setup_t;
|
||||
|
||||
/* Video format presets */
|
||||
extern nes_ntsc_setup_t const nes_ntsc_composite; /* color bleeding + artifacts */
|
||||
extern nes_ntsc_setup_t const nes_ntsc_svideo; /* color bleeding only */
|
||||
extern nes_ntsc_setup_t const nes_ntsc_rgb; /* crisp image */
|
||||
extern nes_ntsc_setup_t const nes_ntsc_monochrome;/* desaturated + artifacts */
|
||||
|
||||
#ifdef NES_NTSC_EMPHASIS
|
||||
enum { nes_ntsc_palette_size = 64 * 8 };
|
||||
#else
|
||||
enum { nes_ntsc_palette_size = 64 };
|
||||
#endif
|
||||
|
||||
/* Initializes and adjusts parameters. Can be called multiple times on the same
|
||||
nes_ntsc_t object. Can pass NULL for either parameter. */
|
||||
typedef struct nes_ntsc_t nes_ntsc_t;
|
||||
EXPORT void nes_ntsc_init( nes_ntsc_t* ntsc, nes_ntsc_setup_t const* setup );
|
||||
|
||||
/* Filters one or more rows of pixels. Input pixels are 6/9-bit palette indicies.
|
||||
In_row_width is the number of pixels to get to the next input row. Out_pitch
|
||||
is the number of *bytes* to get to the next output row. Output pixel format
|
||||
is set by NES_NTSC_OUT_DEPTH (defaults to 16-bit RGB). */
|
||||
EXPORT void nes_ntsc_blit( nes_ntsc_t const* ntsc, NES_NTSC_IN_T const* nes_in,
|
||||
long in_row_width, int burst_phase, int in_width, int in_height,
|
||||
void* rgb_out, long out_pitch );
|
||||
|
||||
/* Number of output pixels written by blitter for given input width. Width might
|
||||
be rounded down slightly; use NES_NTSC_IN_WIDTH() on result to find rounded
|
||||
value. Guaranteed not to round 256 down at all. */
|
||||
#define NES_NTSC_OUT_WIDTH( in_width ) \
|
||||
((((in_width) - 1) / nes_ntsc_in_chunk + 1) * nes_ntsc_out_chunk)
|
||||
|
||||
/* Number of input pixels that will fit within given output width. Might be
|
||||
rounded down slightly; use NES_NTSC_OUT_WIDTH() on result to find rounded
|
||||
value. */
|
||||
#define NES_NTSC_IN_WIDTH( out_width ) \
|
||||
(((out_width) / nes_ntsc_out_chunk - 1) * nes_ntsc_in_chunk + 1)
|
||||
|
||||
|
||||
/* Interface for user-defined custom blitters */
|
||||
|
||||
enum { nes_ntsc_in_chunk = 3 }; /* number of input pixels read per chunk */
|
||||
enum { nes_ntsc_out_chunk = 7 }; /* number of output pixels generated per chunk */
|
||||
enum { nes_ntsc_black = 15 }; /* palette index for black */
|
||||
enum { nes_ntsc_burst_count = 3 }; /* burst phase cycles through 0, 1, and 2 */
|
||||
|
||||
/* Begins outputting row and starts three pixels. First pixel will be cut off a bit.
|
||||
Use nes_ntsc_black for unused pixels. Declares variables, so must be before first
|
||||
statement in a block (unless you're using C++). */
|
||||
#define NES_NTSC_BEGIN_ROW( ntsc, burst, pixel0, pixel1, pixel2 ) \
|
||||
char const* const ktable = \
|
||||
(char const*) (ntsc)->table [0] + burst * (nes_ntsc_burst_size * sizeof (nes_ntsc_rgb_t));\
|
||||
NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, NES_NTSC_ENTRY_, ktable )
|
||||
|
||||
/* Begins input pixel */
|
||||
#define NES_NTSC_COLOR_IN( in_index, color_in ) \
|
||||
NES_NTSC_COLOR_IN_( in_index, color_in, NES_NTSC_ENTRY_, ktable )
|
||||
|
||||
/* Generates output pixel. Bits can be 24, 16, 15, 32 (treated as 24), or 0:
|
||||
24: RRRRRRRR GGGGGGGG BBBBBBBB (8-8-8 RGB)
|
||||
16: RRRRRGGG GGGBBBBB (5-6-5 RGB)
|
||||
15: RRRRRGG GGGBBBBB (5-5-5 RGB)
|
||||
0: xxxRRRRR RRRxxGGG GGGGGxxB BBBBBBBx (native internal format; x = junk bits) */
|
||||
#define NES_NTSC_RGB_OUT( index, rgb_out, bits ) \
|
||||
NES_NTSC_RGB_OUT_14_( index, rgb_out, bits, 0 )
|
||||
|
||||
|
||||
/* private */
|
||||
enum { nes_ntsc_entry_size = 128 };
|
||||
typedef unsigned long nes_ntsc_rgb_t;
|
||||
struct nes_ntsc_t {
|
||||
nes_ntsc_rgb_t table [nes_ntsc_palette_size] [nes_ntsc_entry_size];
|
||||
};
|
||||
enum { nes_ntsc_burst_size = nes_ntsc_entry_size / nes_ntsc_burst_count };
|
||||
|
||||
#define NES_NTSC_ENTRY_( ktable, n ) \
|
||||
(nes_ntsc_rgb_t const*) (ktable + (n) * (nes_ntsc_entry_size * sizeof (nes_ntsc_rgb_t)))
|
||||
|
||||
/* deprecated */
|
||||
#define NES_NTSC_RGB24_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 24 )
|
||||
#define NES_NTSC_RGB16_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 16 )
|
||||
#define NES_NTSC_RGB15_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 15 )
|
||||
#define NES_NTSC_RAW_OUT( x, out ) NES_NTSC_RGB_OUT( x, out, 0 )
|
||||
|
||||
enum { nes_ntsc_min_in_width = 256 };
|
||||
enum { nes_ntsc_min_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_min_in_width ) };
|
||||
|
||||
enum { nes_ntsc_640_in_width = 271 };
|
||||
enum { nes_ntsc_640_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_640_in_width ) };
|
||||
enum { nes_ntsc_640_overscan_left = 8 };
|
||||
enum { nes_ntsc_640_overscan_right = nes_ntsc_640_in_width - 256 - nes_ntsc_640_overscan_left };
|
||||
|
||||
enum { nes_ntsc_full_in_width = 283 };
|
||||
enum { nes_ntsc_full_out_width = NES_NTSC_OUT_WIDTH( nes_ntsc_full_in_width ) };
|
||||
enum { nes_ntsc_full_overscan_left = 16 };
|
||||
enum { nes_ntsc_full_overscan_right = nes_ntsc_full_in_width - 256 - nes_ntsc_full_overscan_left };
|
||||
|
||||
/* common 3->7 ntsc macros */
|
||||
#define NES_NTSC_BEGIN_ROW_6_( pixel0, pixel1, pixel2, ENTRY, table ) \
|
||||
unsigned const nes_ntsc_pixel0_ = (pixel0);\
|
||||
nes_ntsc_rgb_t const* kernel0 = ENTRY( table, nes_ntsc_pixel0_ );\
|
||||
unsigned const nes_ntsc_pixel1_ = (pixel1);\
|
||||
nes_ntsc_rgb_t const* kernel1 = ENTRY( table, nes_ntsc_pixel1_ );\
|
||||
unsigned const nes_ntsc_pixel2_ = (pixel2);\
|
||||
nes_ntsc_rgb_t const* kernel2 = ENTRY( table, nes_ntsc_pixel2_ );\
|
||||
nes_ntsc_rgb_t const* kernelx0;\
|
||||
nes_ntsc_rgb_t const* kernelx1 = kernel0;\
|
||||
nes_ntsc_rgb_t const* kernelx2 = kernel0
|
||||
|
||||
#define NES_NTSC_RGB_OUT_14_( x, rgb_out, bits, shift ) {\
|
||||
nes_ntsc_rgb_t raw_ =\
|
||||
kernel0 [x ] + kernel1 [(x+12)%7+14] + kernel2 [(x+10)%7+28] +\
|
||||
kernelx0 [(x+7)%14] + kernelx1 [(x+ 5)%7+21] + kernelx2 [(x+ 3)%7+35];\
|
||||
NES_NTSC_CLAMP_( raw_, shift );\
|
||||
NES_NTSC_RGB_OUT_( rgb_out, bits, shift );\
|
||||
}
|
||||
|
||||
/* common ntsc macros */
|
||||
#define nes_ntsc_rgb_builder ((1L << 21) | (1 << 11) | (1 << 1))
|
||||
#define nes_ntsc_clamp_mask (nes_ntsc_rgb_builder * 3 / 2)
|
||||
#define nes_ntsc_clamp_add (nes_ntsc_rgb_builder * 0x101)
|
||||
#define NES_NTSC_CLAMP_( io, shift ) {\
|
||||
nes_ntsc_rgb_t sub = (io) >> (9-(shift)) & nes_ntsc_clamp_mask;\
|
||||
nes_ntsc_rgb_t clamp = nes_ntsc_clamp_add - sub;\
|
||||
io |= clamp;\
|
||||
clamp -= sub;\
|
||||
io &= clamp;\
|
||||
}
|
||||
|
||||
#define NES_NTSC_COLOR_IN_( index, color, ENTRY, table ) {\
|
||||
unsigned color_;\
|
||||
kernelx##index = kernel##index;\
|
||||
kernel##index = (color_ = (color), ENTRY( table, color_ ));\
|
||||
}
|
||||
|
||||
/* x is always zero except in snes_ntsc library */
|
||||
#define NES_NTSC_RGB_OUT_( rgb_out, bits, x ) {\
|
||||
if ( bits == 16 )\
|
||||
rgb_out = (raw_>>(13-x)& 0xF800)|(raw_>>(8-x)&0x07E0)|(raw_>>(4-x)&0x001F);\
|
||||
if ( bits == 24 || bits == 32 )\
|
||||
rgb_out = (raw_>>(5-x)&0xFF0000)|(raw_>>(3-x)&0xFF00)|(raw_>>(1-x)&0xFF);\
|
||||
if ( bits == 15 )\
|
||||
rgb_out = (raw_>>(14-x)& 0x7C00)|(raw_>>(9-x)&0x03E0)|(raw_>>(4-x)&0x001F);\
|
||||
if ( bits == 0 )\
|
||||
rgb_out = raw_ << x;\
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
27
NesNtsc/nes_ntsc_config.h
Normal file
27
NesNtsc/nes_ntsc_config.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* Configure library by modifying this file */
|
||||
|
||||
#ifndef NES_NTSC_CONFIG_H
|
||||
#define NES_NTSC_CONFIG_H
|
||||
|
||||
/* Uncomment to enable emphasis support and use a 512 color palette instead
|
||||
of the base 64 color palette. */
|
||||
#define NES_NTSC_EMPHASIS 1
|
||||
|
||||
/* The following affect the built-in blitter only; a custom blitter can
|
||||
handle things however it wants. */
|
||||
|
||||
/* Bits per pixel of output. Can be 15, 16, 32, or 24 (same as 32). */
|
||||
#define NES_NTSC_OUT_DEPTH 32
|
||||
|
||||
/* Type of input pixel values. You'll probably use unsigned short
|
||||
if you enable emphasis above. */
|
||||
#define NES_NTSC_IN_T unsigned short
|
||||
|
||||
/* Each raw pixel input value is passed through this. You might want to mask
|
||||
the pixel index if you use the high bits as flags, etc. */
|
||||
#define NES_NTSC_ADJ_IN( in ) in
|
||||
|
||||
/* For each pixel, this is the basic operation:
|
||||
output_color = color_palette [NES_NTSC_ADJ_IN( NES_NTSC_IN_T )] */
|
||||
|
||||
#endif
|
439
NesNtsc/nes_ntsc_impl.h
Normal file
439
NesNtsc/nes_ntsc_impl.h
Normal file
|
@ -0,0 +1,439 @@
|
|||
/* nes_ntsc 0.2.2. http://www.slack.net/~ant/ */
|
||||
|
||||
/* Common implementation of NTSC filters */
|
||||
|
||||
#include <assert.h>
|
||||
#include <math.h>
|
||||
|
||||
/* Copyright (C) 2006 Shay Green. This module is free software; you
|
||||
can redistribute it and/or modify it under the terms of the GNU Lesser
|
||||
General Public License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version. This
|
||||
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
||||
details. You should have received a copy of the GNU Lesser General Public
|
||||
License along with this module; if not, write to the Free Software Foundation,
|
||||
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
#define DISABLE_CORRECTION 0
|
||||
|
||||
#undef PI
|
||||
#define PI 3.14159265358979323846f
|
||||
|
||||
#ifndef LUMA_CUTOFF
|
||||
#define LUMA_CUTOFF 0.20
|
||||
#endif
|
||||
#ifndef gamma_size
|
||||
#define gamma_size 1
|
||||
#endif
|
||||
#ifndef rgb_bits
|
||||
#define rgb_bits 8
|
||||
#endif
|
||||
#ifndef artifacts_max
|
||||
#define artifacts_max (artifacts_mid * 1.5f)
|
||||
#endif
|
||||
#ifndef fringing_max
|
||||
#define fringing_max (fringing_mid * 2)
|
||||
#endif
|
||||
#ifndef STD_HUE_CONDITION
|
||||
#define STD_HUE_CONDITION( setup ) 1
|
||||
#endif
|
||||
|
||||
#define ext_decoder_hue (std_decoder_hue + 15)
|
||||
#define rgb_unit (1 << rgb_bits)
|
||||
#define rgb_offset (rgb_unit * 2 + 0.5f)
|
||||
|
||||
enum { burst_size = nes_ntsc_entry_size / burst_count };
|
||||
enum { kernel_half = 16 };
|
||||
enum { kernel_size = kernel_half * 2 + 1 };
|
||||
|
||||
typedef struct init_t
|
||||
{
|
||||
float to_rgb [burst_count * 6];
|
||||
float to_float [gamma_size];
|
||||
float contrast;
|
||||
float brightness;
|
||||
float artifacts;
|
||||
float fringing;
|
||||
float kernel [rescale_out * kernel_size * 2];
|
||||
} init_t;
|
||||
|
||||
#define ROTATE_IQ( i, q, sin_b, cos_b ) {\
|
||||
float t;\
|
||||
t = i * cos_b - q * sin_b;\
|
||||
q = i * sin_b + q * cos_b;\
|
||||
i = t;\
|
||||
}
|
||||
|
||||
static void init_filters( init_t* impl, nes_ntsc_setup_t const* setup )
|
||||
{
|
||||
#if rescale_out > 1
|
||||
float kernels [kernel_size * 2];
|
||||
#else
|
||||
float* const kernels = impl->kernel;
|
||||
#endif
|
||||
|
||||
/* generate luma (y) filter using sinc kernel */
|
||||
{
|
||||
/* sinc with rolloff (dsf) */
|
||||
float const rolloff = 1 + (float) setup->sharpness * (float) 0.032;
|
||||
float const maxh = 32;
|
||||
float const pow_a_n = (float) pow( rolloff, maxh );
|
||||
float sum;
|
||||
int i;
|
||||
/* quadratic mapping to reduce negative (blurring) range */
|
||||
float to_angle = (float) setup->resolution + 1;
|
||||
to_angle = PI / maxh * (float) LUMA_CUTOFF * (to_angle * to_angle + 1);
|
||||
|
||||
kernels [kernel_size * 3 / 2] = maxh; /* default center value */
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = i - kernel_half;
|
||||
float angle = x * to_angle;
|
||||
/* instability occurs at center point with rolloff very close to 1.0 */
|
||||
if ( x || pow_a_n > (float) 1.056 || pow_a_n < (float) 0.981 )
|
||||
{
|
||||
float rolloff_cos_a = rolloff * (float) cos( angle );
|
||||
float num = 1 - rolloff_cos_a -
|
||||
pow_a_n * (float) cos( maxh * angle ) +
|
||||
pow_a_n * rolloff * (float) cos( (maxh - 1) * angle );
|
||||
float den = 1 - rolloff_cos_a - rolloff_cos_a + rolloff * rolloff;
|
||||
float dsf = num / den;
|
||||
kernels [kernel_size * 3 / 2 - kernel_half + i] = dsf - (float) 0.5;
|
||||
}
|
||||
}
|
||||
|
||||
/* apply blackman window and find sum */
|
||||
sum = 0;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
float x = PI * 2 / (kernel_half * 2) * i;
|
||||
float blackman = 0.42f - 0.5f * (float) cos( x ) + 0.08f * (float) cos( x * 2 );
|
||||
sum += (kernels [kernel_size * 3 / 2 - kernel_half + i] *= blackman);
|
||||
}
|
||||
|
||||
/* normalize kernel */
|
||||
sum = 1.0f / sum;
|
||||
for ( i = 0; i < kernel_half * 2 + 1; i++ )
|
||||
{
|
||||
int x = kernel_size * 3 / 2 - kernel_half + i;
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
|
||||
/* generate chroma (iq) filter using gaussian kernel */
|
||||
{
|
||||
float const cutoff_factor = -0.03125f;
|
||||
float cutoff = (float) setup->bleed;
|
||||
int i;
|
||||
|
||||
if ( cutoff < 0 )
|
||||
{
|
||||
/* keep extreme value accessible only near upper end of scale (1.0) */
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= cutoff;
|
||||
cutoff *= -30.0f / 0.65f;
|
||||
}
|
||||
cutoff = cutoff_factor - 0.65f * cutoff_factor * cutoff;
|
||||
|
||||
for ( i = -kernel_half; i <= kernel_half; i++ )
|
||||
kernels [kernel_size / 2 + i] = (float) exp( i * i * cutoff );
|
||||
|
||||
/* normalize even and odd phases separately */
|
||||
for ( i = 0; i < 2; i++ )
|
||||
{
|
||||
float sum = 0;
|
||||
int x;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
sum += kernels [x];
|
||||
|
||||
sum = 1.0f / sum;
|
||||
for ( x = i; x < kernel_size; x += 2 )
|
||||
{
|
||||
kernels [x] *= sum;
|
||||
assert( kernels [x] == kernels [x] ); /* catch numerical instability */
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
printf( "luma:\n" );
|
||||
for ( i = kernel_size; i < kernel_size * 2; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
printf( "chroma:\n" );
|
||||
for ( i = 0; i < kernel_size; i++ )
|
||||
printf( "%f\n", kernels [i] );
|
||||
*/
|
||||
|
||||
/* generate linear rescale kernels */
|
||||
#if rescale_out > 1
|
||||
{
|
||||
float weight = 1.0f;
|
||||
float* out = impl->kernel;
|
||||
int n = rescale_out;
|
||||
do
|
||||
{
|
||||
float remain = 0;
|
||||
int i;
|
||||
weight -= 1.0f / rescale_in;
|
||||
for ( i = 0; i < kernel_size * 2; i++ )
|
||||
{
|
||||
float cur = kernels [i];
|
||||
float m = cur * weight;
|
||||
*out++ = m + remain;
|
||||
remain = cur - m;
|
||||
}
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
static float const default_decoder [6] =
|
||||
{ 0.956f, 0.621f, -0.272f, -0.647f, -1.105f, 1.702f };
|
||||
|
||||
static void init( init_t* impl, nes_ntsc_setup_t const* setup )
|
||||
{
|
||||
impl->brightness = (float) setup->brightness * (0.5f * rgb_unit) + rgb_offset;
|
||||
impl->contrast = (float) setup->contrast * (0.5f * rgb_unit) + rgb_unit;
|
||||
#ifdef default_palette_contrast
|
||||
if ( !setup->palette )
|
||||
impl->contrast *= default_palette_contrast;
|
||||
#endif
|
||||
|
||||
impl->artifacts = (float) setup->artifacts;
|
||||
if ( impl->artifacts > 0 )
|
||||
impl->artifacts *= artifacts_max - artifacts_mid;
|
||||
impl->artifacts = impl->artifacts * artifacts_mid + artifacts_mid;
|
||||
|
||||
impl->fringing = (float) setup->fringing;
|
||||
if ( impl->fringing > 0 )
|
||||
impl->fringing *= fringing_max - fringing_mid;
|
||||
impl->fringing = impl->fringing * fringing_mid + fringing_mid;
|
||||
|
||||
init_filters( impl, setup );
|
||||
|
||||
/* generate gamma table */
|
||||
if ( gamma_size > 1 )
|
||||
{
|
||||
float const to_float = 1.0f / (gamma_size - (gamma_size > 1));
|
||||
float const gamma = 1.1333f - (float) setup->gamma * 0.5f;
|
||||
/* match common PC's 2.2 gamma to TV's 2.65 gamma */
|
||||
int i;
|
||||
for ( i = 0; i < gamma_size; i++ )
|
||||
impl->to_float [i] =
|
||||
(float) pow( i * to_float, gamma ) * impl->contrast + impl->brightness;
|
||||
}
|
||||
|
||||
/* setup decoder matricies */
|
||||
{
|
||||
float hue = (float) setup->hue * PI + PI / 180 * ext_decoder_hue;
|
||||
float sat = (float) setup->saturation + 1;
|
||||
float const* decoder = setup->decoder_matrix;
|
||||
if ( !decoder )
|
||||
{
|
||||
decoder = default_decoder;
|
||||
if ( STD_HUE_CONDITION( setup ) )
|
||||
hue += PI / 180 * (std_decoder_hue - ext_decoder_hue);
|
||||
}
|
||||
|
||||
{
|
||||
float s = (float) sin( hue ) * sat;
|
||||
float c = (float) cos( hue ) * sat;
|
||||
float* out = impl->to_rgb;
|
||||
int n;
|
||||
|
||||
n = burst_count;
|
||||
do
|
||||
{
|
||||
float const* in = decoder;
|
||||
int n = 3;
|
||||
do
|
||||
{
|
||||
float i = *in++;
|
||||
float q = *in++;
|
||||
*out++ = i * c - q * s;
|
||||
*out++ = i * s + q * c;
|
||||
}
|
||||
while ( --n );
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
ROTATE_IQ( s, c, 0.866025f, -0.5f ); /* +120 degrees */
|
||||
}
|
||||
while ( --n );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* kernel generation */
|
||||
|
||||
#define RGB_TO_YIQ( r, g, b, y, i ) (\
|
||||
(y = (r) * 0.299f + (g) * 0.587f + (b) * 0.114f),\
|
||||
(i = (r) * 0.596f - (g) * 0.275f - (b) * 0.321f),\
|
||||
((r) * 0.212f - (g) * 0.523f + (b) * 0.311f)\
|
||||
)
|
||||
|
||||
#define YIQ_TO_RGB( y, i, q, to_rgb, type, r, g ) (\
|
||||
r = (type) (y + to_rgb [0] * i + to_rgb [1] * q),\
|
||||
g = (type) (y + to_rgb [2] * i + to_rgb [3] * q),\
|
||||
(type) (y + to_rgb [4] * i + to_rgb [5] * q)\
|
||||
)
|
||||
|
||||
#define PACK_RGB( r, g, b ) ((r) << 21 | (g) << 11 | (b) << 1)
|
||||
|
||||
enum { rgb_kernel_size = burst_size / alignment_count };
|
||||
enum { rgb_bias = rgb_unit * 2 * nes_ntsc_rgb_builder };
|
||||
|
||||
typedef struct pixel_info_t
|
||||
{
|
||||
int offset;
|
||||
float negate;
|
||||
float kernel [4];
|
||||
} pixel_info_t;
|
||||
|
||||
#if rescale_in > 1
|
||||
#define PIXEL_OFFSET_( ntsc, scaled ) \
|
||||
(kernel_size / 2 + ntsc + (scaled != 0) + (rescale_out - scaled) % rescale_out + \
|
||||
(kernel_size * 2 * scaled))
|
||||
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
PIXEL_OFFSET_( ((ntsc) - (scaled) / rescale_out * rescale_in),\
|
||||
(((scaled) + rescale_out * 10) % rescale_out) ),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#else
|
||||
#define PIXEL_OFFSET( ntsc, scaled ) \
|
||||
(kernel_size / 2 + (ntsc) - (scaled)),\
|
||||
(1.0f - (((ntsc) + 100) & 2))
|
||||
#endif
|
||||
|
||||
extern pixel_info_t const nes_ntsc_pixels [alignment_count];
|
||||
|
||||
/* Generate pixel at all burst phases and column alignments */
|
||||
static void gen_kernel( init_t* impl, float y, float i, float q, nes_ntsc_rgb_t* out )
|
||||
{
|
||||
/* generate for each scanline burst phase */
|
||||
float const* to_rgb = impl->to_rgb;
|
||||
int burst_remain = burst_count;
|
||||
y -= rgb_offset;
|
||||
do
|
||||
{
|
||||
/* Encode yiq into *two* composite signals (to allow control over artifacting).
|
||||
Convolve these with kernels which: filter respective components, apply
|
||||
sharpening, and rescale horizontally. Convert resulting yiq to rgb and pack
|
||||
into integer. Based on algorithm by NewRisingSun. */
|
||||
pixel_info_t const* pixel = nes_ntsc_pixels;
|
||||
int alignment_remain = alignment_count;
|
||||
do
|
||||
{
|
||||
/* negate is -1 when composite starts at odd multiple of 2 */
|
||||
float const yy = y * impl->fringing * pixel->negate;
|
||||
float const ic0 = (i + yy) * pixel->kernel [0];
|
||||
float const qc1 = (q + yy) * pixel->kernel [1];
|
||||
float const ic2 = (i - yy) * pixel->kernel [2];
|
||||
float const qc3 = (q - yy) * pixel->kernel [3];
|
||||
|
||||
float const factor = impl->artifacts * pixel->negate;
|
||||
float const ii = i * factor;
|
||||
float const yc0 = (y + ii) * pixel->kernel [0];
|
||||
float const yc2 = (y - ii) * pixel->kernel [2];
|
||||
|
||||
float const qq = q * factor;
|
||||
float const yc1 = (y + qq) * pixel->kernel [1];
|
||||
float const yc3 = (y - qq) * pixel->kernel [3];
|
||||
|
||||
float const* k = &impl->kernel [pixel->offset];
|
||||
int n;
|
||||
++pixel;
|
||||
for ( n = rgb_kernel_size; n; --n )
|
||||
{
|
||||
float i = k[0]*ic0 + k[2]*ic2;
|
||||
float q = k[1]*qc1 + k[3]*qc3;
|
||||
float y = k[kernel_size+0]*yc0 + k[kernel_size+1]*yc1 +
|
||||
k[kernel_size+2]*yc2 + k[kernel_size+3]*yc3 + rgb_offset;
|
||||
if ( rescale_out <= 1 )
|
||||
k--;
|
||||
else if ( k < &impl->kernel [kernel_size * 2 * (rescale_out - 1)] )
|
||||
k += kernel_size * 2 - 1;
|
||||
else
|
||||
k -= kernel_size * 2 * (rescale_out - 1) + 2;
|
||||
{
|
||||
int r, g, b = YIQ_TO_RGB( y, i, q, to_rgb, int, r, g );
|
||||
*out++ = PACK_RGB( r, g, b ) - rgb_bias;
|
||||
}
|
||||
}
|
||||
}
|
||||
while ( alignment_count > 1 && --alignment_remain );
|
||||
|
||||
if ( burst_count <= 1 )
|
||||
break;
|
||||
|
||||
to_rgb += 6;
|
||||
|
||||
ROTATE_IQ( i, q, -0.866025f, -0.5f ); /* -120 degrees */
|
||||
}
|
||||
while ( --burst_remain );
|
||||
}
|
||||
|
||||
static void correct_errors( nes_ntsc_rgb_t color, nes_ntsc_rgb_t* out );
|
||||
|
||||
#if DISABLE_CORRECTION
|
||||
#define CORRECT_ERROR( a ) { out [i] += rgb_bias; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) { out [i] += rgb_bias; }
|
||||
#else
|
||||
#define CORRECT_ERROR( a ) { out [a] += error; }
|
||||
#define DISTRIBUTE_ERROR( a, b, c ) {\
|
||||
nes_ntsc_rgb_t fourth = (error + 2 * nes_ntsc_rgb_builder) >> 2;\
|
||||
fourth &= (rgb_bias >> 1) - nes_ntsc_rgb_builder;\
|
||||
fourth -= rgb_bias >> 2;\
|
||||
out [a] += fourth;\
|
||||
out [b] += fourth;\
|
||||
out [c] += fourth;\
|
||||
out [i] += error - (fourth * 3);\
|
||||
}
|
||||
#endif
|
||||
|
||||
#define RGB_PALETTE_OUT( rgb, out_ )\
|
||||
{\
|
||||
unsigned char* out = (out_);\
|
||||
nes_ntsc_rgb_t clamped = (rgb);\
|
||||
NES_NTSC_CLAMP_( clamped, (8 - rgb_bits) );\
|
||||
out [0] = (unsigned char) (clamped >> 21);\
|
||||
out [1] = (unsigned char) (clamped >> 11);\
|
||||
out [2] = (unsigned char) (clamped >> 1);\
|
||||
}
|
||||
|
||||
/* blitter related */
|
||||
|
||||
#ifndef restrict
|
||||
#if defined (__GNUC__)
|
||||
#define restrict __restrict__
|
||||
#elif defined (_MSC_VER) && _MSC_VER > 1300
|
||||
#define restrict __restrict
|
||||
#else
|
||||
/* no support for restricted pointers */
|
||||
#define restrict
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#if NES_NTSC_OUT_DEPTH <= 16
|
||||
#if USHRT_MAX == 0xFFFF
|
||||
typedef unsigned short nes_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 16-bit int type"
|
||||
#endif
|
||||
|
||||
#else
|
||||
#if UINT_MAX == 0xFFFFFFFF
|
||||
typedef unsigned int nes_ntsc_out_t;
|
||||
#elif ULONG_MAX == 0xFFFFFFFF
|
||||
typedef unsigned long nes_ntsc_out_t;
|
||||
#else
|
||||
#error "Need 32-bit int type"
|
||||
#endif
|
||||
|
||||
#endif
|
|
@ -19,7 +19,7 @@ namespace NES
|
|||
{
|
||||
_hWnd = hWnd;
|
||||
|
||||
SetScreenSize();
|
||||
SetScreenSize(256, 240);
|
||||
|
||||
VideoDecoder::GetInstance()->RegisterRenderingDevice(this);
|
||||
MessageManager::RegisterMessageManager(this);
|
||||
|
@ -31,18 +31,19 @@ namespace NES
|
|||
CleanupDevice();
|
||||
}
|
||||
|
||||
void Renderer::SetScreenSize()
|
||||
void Renderer::SetScreenSize(uint32_t width, uint32_t height)
|
||||
{
|
||||
OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions();
|
||||
uint32_t scale = EmulationSettings::GetVideoScale();
|
||||
|
||||
if(_hdScreenBufferSize == 0 || _hdScreenBufferSize != overscan.GetPixelCount() * 64) {
|
||||
uint32_t screenWidth = overscan.GetScreenWidth();
|
||||
uint32_t screenHeight = overscan.GetScreenHeight();
|
||||
|
||||
_hdScreenWidth = screenWidth * 4;
|
||||
_hdScreenHeight = screenHeight * 4;
|
||||
_hdScreenBufferSize = _hdScreenWidth * _hdScreenHeight * _bytesPerPixel;
|
||||
if(_screenHeight != height*scale || _screenWidth != width*scale) {
|
||||
_nesFrameHeight = height;
|
||||
_nesFrameWidth = width;
|
||||
_newFrameBufferSize = width*height;
|
||||
|
||||
_screenHeight = height * scale;
|
||||
_screenWidth = width * scale;
|
||||
_screenBufferSize = _screenHeight*_screenWidth;
|
||||
|
||||
_frameLock.Acquire();
|
||||
CleanupDevice();
|
||||
if(FAILED(InitDevice())) {
|
||||
|
@ -56,12 +57,12 @@ namespace NES
|
|||
{
|
||||
if(_pTexture) _pTexture->Release();
|
||||
if(_overlayTexture) _overlayTexture->Release();
|
||||
if(_toastTexture) { _toastTexture->Release(); }
|
||||
if(_toastTexture) _toastTexture->Release();
|
||||
|
||||
if(_samplerState) _samplerState->Release();
|
||||
if(_pRenderTargetView) _pRenderTargetView->Release();
|
||||
if(_pSwapChain) _pSwapChain->Release();
|
||||
if(_pDeviceContext) _pDeviceContext->ClearState();
|
||||
if(_pDeviceContext) _pDeviceContext->Release();
|
||||
if(_pDeviceContext1) _pDeviceContext1->Release();
|
||||
if(_pd3dDevice1) _pd3dDevice1->Release();
|
||||
if(_pd3dDevice) _pd3dDevice->Release();
|
||||
|
@ -111,8 +112,8 @@ namespace NES
|
|||
DXGI_SWAP_CHAIN_DESC sd;
|
||||
ZeroMemory(&sd, sizeof(sd));
|
||||
sd.BufferCount = 1;
|
||||
sd.BufferDesc.Width = _hdScreenWidth;
|
||||
sd.BufferDesc.Height = _hdScreenHeight;
|
||||
sd.BufferDesc.Width = _screenWidth;
|
||||
sd.BufferDesc.Height = _screenHeight;
|
||||
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
|
||||
sd.BufferDesc.RefreshRate.Numerator = 60;
|
||||
sd.BufferDesc.RefreshRate.Denominator = 1;
|
||||
|
@ -213,26 +214,26 @@ namespace NES
|
|||
|
||||
// Setup the viewport
|
||||
D3D11_VIEWPORT vp;
|
||||
vp.Width = (FLOAT)_hdScreenWidth;
|
||||
vp.Height = (FLOAT)_hdScreenHeight;
|
||||
vp.Width = (FLOAT)_screenWidth;
|
||||
vp.Height = (FLOAT)_screenHeight;
|
||||
vp.MinDepth = 0.0f;
|
||||
vp.MaxDepth = 1.0f;
|
||||
vp.TopLeftX = 0;
|
||||
vp.TopLeftY = 0;
|
||||
_pDeviceContext->RSSetViewports(1, &vp);
|
||||
|
||||
_videoRAM = new uint32_t[PPU::PixelCount*4*4];
|
||||
memset(_videoRAM, 0x00, PPU::PixelCount * sizeof(uint32_t) * 4 * 4);
|
||||
_videoRAM = new uint32_t[_nesFrameWidth*_nesFrameHeight];
|
||||
memset(_videoRAM, 0x00, _nesFrameWidth * _nesFrameHeight * 4);
|
||||
|
||||
_pTexture = CreateTexture(_hdScreenWidth, _hdScreenHeight);
|
||||
_pTexture = CreateTexture(_nesFrameWidth, _nesFrameHeight);
|
||||
if(!_pTexture) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
_overlayBuffer = new uint8_t[_hdScreenBufferSize]; //High res overlay for UI elements (4x res)
|
||||
memset(_overlayBuffer, 0x00, _hdScreenBufferSize);
|
||||
_overlayBuffer = new uint8_t[8*8*4]; //High res overlay for UI elements (4x res)
|
||||
memset(_overlayBuffer, 0x00, 8*8*4);
|
||||
|
||||
_overlayTexture = CreateTexture(_hdScreenWidth, _hdScreenHeight);
|
||||
_overlayTexture = CreateTexture(8, 8);
|
||||
if(!_overlayTexture) {
|
||||
return 0;
|
||||
}
|
||||
|
@ -263,23 +264,6 @@ namespace NES
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
ID3DBlob* vertexShaderBlob = nullptr;
|
||||
ID3D11VertexShader* vertexShader = nullptr;
|
||||
CompileShader(L"PixelShader.hlsl", "VS", "vs_4_0", &vertexShaderBlob);
|
||||
if(vertexShaderBlob) {
|
||||
_pd3dDevice->CreateVertexShader(vertexShaderBlob->GetBufferPointer(), vertexShaderBlob->GetBufferSize(), nullptr, &vertexShader);
|
||||
_pDeviceContext->VSSetShader(vertexShader, nullptr, 0);
|
||||
//vertexShaderBlob->Release();
|
||||
}
|
||||
|
||||
ID3DBlob* pixelShaderBlob = nullptr;
|
||||
CompileShader(L"PixelShader.hlsl", "PShader", "ps_4_0", &pixelShaderBlob);
|
||||
if(pixelShaderBlob) {
|
||||
_pd3dDevice->CreatePixelShader(pixelShaderBlob->GetBufferPointer(), pixelShaderBlob->GetBufferSize(), nullptr, &_pixelShader);
|
||||
//pixelShaderBlob->Release();
|
||||
}*/
|
||||
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
|
@ -331,7 +315,7 @@ namespace NES
|
|||
|
||||
void Renderer::DisplayMessage(string title, string message)
|
||||
{
|
||||
shared_ptr<ToastInfo> toast(new ToastInfo(title, message, 4000, "Resources\\MesenIcon.bmp"));
|
||||
shared_ptr<ToastInfo> toast(new ToastInfo(title, message, 2500, "Resources\\MesenIcon.bmp"));
|
||||
DisplayToast(toast);
|
||||
}
|
||||
|
||||
|
@ -361,25 +345,24 @@ namespace NES
|
|||
_font->DrawString(spritebatch, text, XMFLOAT2(x, y), color, 0.0f, XMFLOAT2(0, 0), scale);
|
||||
}
|
||||
|
||||
void Renderer::UpdateFrame(void *frameBuffer)
|
||||
void Renderer::UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height)
|
||||
{
|
||||
uint8_t hdScale = VideoDecoder::GetInstance()->GetScale();
|
||||
OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions();
|
||||
SetScreenSize(width, height);
|
||||
|
||||
uint32_t bpp = 4;
|
||||
uint8_t* outputBuffer = (uint8_t*)frameBuffer;
|
||||
|
||||
_frameLock.Acquire();
|
||||
|
||||
uint32_t rowPitch = width * bpp;
|
||||
D3D11_MAPPED_SUBRESOURCE dd;
|
||||
dd.pData = (void *)_videoRAM;
|
||||
dd.RowPitch = overscan.GetScreenWidth() * _bytesPerPixel * hdScale;
|
||||
dd.DepthPitch = overscan.GetPixelCount() * _bytesPerPixel * hdScale * hdScale;
|
||||
dd.RowPitch = rowPitch;
|
||||
dd.DepthPitch = height * width * bpp;
|
||||
|
||||
uint32_t rowPitch = overscan.GetScreenWidth() * hdScale * _bytesPerPixel;
|
||||
|
||||
_pDeviceContext->Map(_pTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd);
|
||||
uint8_t* surfacePointer = (uint8_t*)dd.pData;
|
||||
for(uint32_t i = 0, iMax = overscan.GetScreenHeight()*hdScale; i < iMax; i++) {
|
||||
for(uint32_t i = 0, iMax = height; i < iMax; i++) {
|
||||
memcpy(surfacePointer, outputBuffer, rowPitch);
|
||||
outputBuffer += rowPitch;
|
||||
surfacePointer += dd.RowPitch;
|
||||
|
@ -393,24 +376,15 @@ namespace NES
|
|||
|
||||
void Renderer::DrawNESScreen()
|
||||
{
|
||||
OverscanDimensions overscan = EmulationSettings::GetOverscanDimensions();
|
||||
uint8_t hdScale = VideoDecoder::GetInstance()->GetScale();
|
||||
|
||||
ID3D11ShaderResourceView *nesOutputBuffer = GetShaderResourceView(_pTexture);
|
||||
|
||||
RECT destRect;
|
||||
destRect.left = 0;
|
||||
destRect.top = 0;
|
||||
destRect.right = overscan.GetScreenWidth() * 4;
|
||||
destRect.bottom = overscan.GetScreenHeight() * 4;
|
||||
destRect.right = _screenWidth;
|
||||
destRect.bottom = _screenHeight;
|
||||
|
||||
RECT sourceRect;
|
||||
sourceRect.left = 0;
|
||||
sourceRect.top = 0;
|
||||
sourceRect.right = overscan.GetScreenWidth() * hdScale;
|
||||
sourceRect.bottom = overscan.GetScreenHeight() * hdScale;
|
||||
|
||||
_spriteBatch->Draw(nesOutputBuffer, destRect, &sourceRect);
|
||||
_spriteBatch->Draw(nesOutputBuffer, destRect);
|
||||
nesOutputBuffer->Release();
|
||||
}
|
||||
|
||||
|
@ -418,19 +392,19 @@ namespace NES
|
|||
{
|
||||
RECT destRect;
|
||||
destRect.left = 0;
|
||||
destRect.right = _hdScreenWidth;
|
||||
destRect.bottom = _hdScreenHeight;
|
||||
destRect.right = _screenWidth;
|
||||
destRect.bottom = _screenHeight;
|
||||
destRect.top = 0;
|
||||
|
||||
XMVECTOR position{ { 0, 0 } };
|
||||
|
||||
D3D11_MAPPED_SUBRESOURCE dd;
|
||||
dd.pData = (void *)_overlayBuffer;
|
||||
dd.RowPitch = _hdScreenWidth * _bytesPerPixel;
|
||||
dd.DepthPitch = _hdScreenBufferSize;
|
||||
dd.RowPitch = 8 * _bytesPerPixel;
|
||||
dd.DepthPitch = 8 * 8 * _bytesPerPixel;
|
||||
|
||||
_pDeviceContext->Map(_overlayTexture, 0, D3D11_MAP_WRITE_DISCARD, 0, &dd);
|
||||
for(uint32_t i = 0, len = _hdScreenHeight*_hdScreenWidth; i < len; i++) {
|
||||
for(uint32_t i = 0, len = 8*8; i < len; i++) {
|
||||
//Gray transparent overlay
|
||||
((uint32_t*)dd.pData)[i] = 0x99222222;
|
||||
}
|
||||
|
@ -440,7 +414,7 @@ namespace NES
|
|||
_spriteBatch->Draw(shaderResourceView, destRect); // , position, &sourceRect, Colors::White, 0.0f, position, 4.0f);
|
||||
shaderResourceView->Release();
|
||||
|
||||
DrawOutlinedString("PAUSED", (float)_hdScreenWidth / 2 - 145, (float)_hdScreenHeight / 2 - 47, Colors::AntiqueWhite, 4.5f);
|
||||
DrawOutlinedString("PAUSED", (float)_screenWidth / 2 - 145, (float)_screenHeight / 2 - 47, Colors::AntiqueWhite, 4.5f);
|
||||
}
|
||||
|
||||
void Renderer::Render()
|
||||
|
@ -448,8 +422,6 @@ namespace NES
|
|||
if(_frameChanged || EmulationSettings::CheckFlag(EmulationFlags::Paused) || !_toasts.empty()) {
|
||||
_frameLock.Acquire();
|
||||
|
||||
SetScreenSize();
|
||||
|
||||
if(_frameChanged) {
|
||||
_frameChanged = false;
|
||||
_renderedFrameCount++;
|
||||
|
@ -495,7 +467,7 @@ namespace NES
|
|||
}
|
||||
|
||||
string fpsString = string("FPS: ") + std::to_string(_currentFPS) + " / " + std::to_string(_currentRenderedFPS);
|
||||
DrawOutlinedString(fpsString, (float)(_hdScreenWidth - 120), 13, Colors::AntiqueWhite, 1.0f);
|
||||
DrawOutlinedString(fpsString, (float)(_screenWidth - 120), 13, Colors::AntiqueWhite, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -576,8 +548,8 @@ namespace NES
|
|||
void Renderer::DrawToast(shared_ptr<ToastInfo> toast, int posIndex)
|
||||
{
|
||||
RECT dest;
|
||||
dest.top = _hdScreenHeight - (100 * (posIndex + 1)) - 50;
|
||||
dest.left = (_hdScreenWidth - 340) / 2;
|
||||
dest.top = _screenHeight - (100 * (posIndex + 1)) - 50;
|
||||
dest.left = (_screenWidth - 340) / 2;
|
||||
dest.bottom = dest.top + 70;
|
||||
dest.right = dest.left + 340;
|
||||
|
||||
|
|
|
@ -53,12 +53,15 @@ namespace NES {
|
|||
byte* _overlayBuffer = nullptr;
|
||||
|
||||
unique_ptr<SpriteBatch> _spriteBatch;
|
||||
//ID3D11PixelShader* _pixelShader = nullptr;
|
||||
|
||||
const uint32_t _bytesPerPixel = 4;
|
||||
uint32_t _hdScreenWidth = 0;
|
||||
uint32_t _hdScreenHeight = 0;
|
||||
uint32_t _hdScreenBufferSize = 0;
|
||||
uint32_t _screenWidth = 0;
|
||||
uint32_t _screenHeight = 0;
|
||||
uint32_t _screenBufferSize = 0;
|
||||
|
||||
uint32_t _nesFrameHeight = 0;
|
||||
uint32_t _nesFrameWidth = 0;
|
||||
uint32_t _newFrameBufferSize = 0;
|
||||
|
||||
list<shared_ptr<ToastInfo>> _toasts;
|
||||
ID3D11ShaderResourceView* _toastTexture = nullptr;
|
||||
|
@ -66,7 +69,7 @@ namespace NES {
|
|||
HRESULT InitDevice();
|
||||
void CleanupDevice();
|
||||
|
||||
void SetScreenSize();
|
||||
void SetScreenSize(uint32_t width, uint32_t height);
|
||||
|
||||
ID3D11Texture2D* CreateTexture(uint32_t width, uint32_t height);
|
||||
ID3D11ShaderResourceView* GetShaderResourceView(ID3D11Texture2D* texture);
|
||||
|
@ -88,6 +91,6 @@ namespace NES {
|
|||
void DisplayMessage(string title, string message);
|
||||
void DisplayToast(shared_ptr<ToastInfo> toast);
|
||||
|
||||
void UpdateFrame(void *frameBuffer);
|
||||
void UpdateFrame(void *frameBuffer, uint32_t width, uint32_t height);
|
||||
};
|
||||
}
|
Loading…
Add table
Reference in a new issue