Split part of MessageManager into non-static NotificationManager
+ Fixed movie recording/playback (for .mmo files)
This commit is contained in:
parent
04310eddb4
commit
c877f73891
36 changed files with 727 additions and 590 deletions
|
@ -6,6 +6,7 @@
|
|||
#include "PPU.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "StandardController.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
AutomaticRomTest::AutomaticRomTest()
|
||||
{
|
||||
|
@ -104,6 +105,7 @@ int32_t AutomaticRomTest::Run(string filename)
|
|||
{
|
||||
EmulationSettings::SetMasterVolume(0);
|
||||
_console.reset(new Console());
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(shared_from_this());
|
||||
if(_console->Initialize(filename)) {
|
||||
_console->GetControlManager()->RegisterInputProvider(this);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
class Console;
|
||||
|
||||
class AutomaticRomTest : public INotificationListener, public IInputProvider
|
||||
class AutomaticRomTest : public INotificationListener, public IInputProvider, public std::enable_shared_from_this<AutomaticRomTest>
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "CheatManager.h"
|
||||
#include "Console.h"
|
||||
#include "MessageManager.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
CheatManager::CheatManager(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -97,7 +98,7 @@ void CheatManager::AddCode(CodeInfo &code)
|
|||
} else {
|
||||
_absoluteCheatCodes.push_back(code);
|
||||
}
|
||||
MessageManager::SendNotification(ConsoleNotificationType::CheatAdded);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CheatAdded);
|
||||
}
|
||||
|
||||
void CheatManager::AddGameGenieCode(string code)
|
||||
|
@ -138,7 +139,7 @@ void CheatManager::ClearCodes()
|
|||
_absoluteCheatCodes.clear();
|
||||
|
||||
if(cheatRemoved) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::CheatRemoved);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CheatRemoved);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,7 @@
|
|||
#include "VideoDecoder.h"
|
||||
#include "VideoRenderer.h"
|
||||
#include "DebugHud.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
Console::Console()
|
||||
{
|
||||
|
@ -57,6 +58,7 @@ Console::~Console()
|
|||
|
||||
void Console::Init()
|
||||
{
|
||||
_notificationManager.reset(new NotificationManager());
|
||||
_saveStateManager.reset(new SaveStateManager(shared_from_this()));
|
||||
_videoRenderer.reset(new VideoRenderer(shared_from_this()));
|
||||
_videoDecoder.reset(new VideoDecoder(shared_from_this()));
|
||||
|
@ -235,7 +237,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
|||
}
|
||||
|
||||
//Send notification only if a game was already running and we successfully loaded the new one
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameStopped, (void*)1);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::GameStopped, (void*)1);
|
||||
}
|
||||
|
||||
if(isDifferentGame) {
|
||||
|
@ -321,7 +323,7 @@ bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
|
|||
ResetComponents(false);
|
||||
|
||||
_rewindManager.reset(new RewindManager(shared_from_this()));
|
||||
MessageManager::RegisterNotificationListener(_rewindManager);
|
||||
_notificationManager->RegisterNotificationListener(_rewindManager);
|
||||
|
||||
_videoDecoder->StartThread();
|
||||
|
||||
|
@ -377,6 +379,11 @@ shared_ptr<SoundMixer> Console::GetSoundMixer()
|
|||
return _soundMixer;
|
||||
}
|
||||
|
||||
shared_ptr<NotificationManager> Console::GetNotificationManager()
|
||||
{
|
||||
return _notificationManager;
|
||||
}
|
||||
|
||||
BaseMapper* Console::GetMapper()
|
||||
{
|
||||
return _mapper.get();
|
||||
|
@ -473,7 +480,8 @@ void Console::ResetComponents(bool softReset)
|
|||
|
||||
KeyManager::UpdateDevices();
|
||||
|
||||
MessageManager::SendNotification(softReset ? ConsoleNotificationType::GameReset : ConsoleNotificationType::GameLoaded);
|
||||
//This notification MUST be sent before the UpdateInputState() below to allow MovieRecorder to grab the first frame's worth of inputs
|
||||
_notificationManager->SendNotification(softReset ? ConsoleNotificationType::GameReset : ConsoleNotificationType::GameLoaded);
|
||||
|
||||
if(softReset) {
|
||||
shared_ptr<Debugger> debugger = _debugger;
|
||||
|
@ -603,7 +611,7 @@ void Console::Run()
|
|||
|
||||
bool paused = EmulationSettings::IsPaused();
|
||||
if(paused && !_stop) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GamePaused);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::GamePaused);
|
||||
|
||||
//Prevent audio from looping endlessly while game is paused
|
||||
_soundMixer->StopAudio();
|
||||
|
@ -625,7 +633,7 @@ void Console::Run()
|
|||
|
||||
PlatformUtilities::DisableScreensaver();
|
||||
_runLock.Acquire();
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameResumed);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::GameResumed);
|
||||
lastFrameTimer.Reset();
|
||||
}
|
||||
|
||||
|
@ -668,7 +676,7 @@ void Console::Run()
|
|||
|
||||
_running = false;
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::BeforeEmulationStop);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::BeforeEmulationStop);
|
||||
|
||||
if(!crashed) {
|
||||
_saveStateManager->SaveRecentGame(GetMapperInfo().RomName, _romFilepath, _patchFilename);
|
||||
|
@ -703,8 +711,8 @@ void Console::Run()
|
|||
|
||||
_emulationThreadId = std::thread::id();
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
|
||||
MessageManager::SendNotification(ConsoleNotificationType::EmulationStopped);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::GameStopped);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::EmulationStopped);
|
||||
}
|
||||
|
||||
bool Console::IsRunning()
|
||||
|
@ -747,7 +755,7 @@ void Console::UpdateNesModel(bool sendNotification)
|
|||
_apu->SetNesModel(model);
|
||||
|
||||
if(configChanged && sendNotification) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::ConfigChanged);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -813,7 +821,7 @@ void Console::LoadState(istream &loadStream, uint32_t stateVersion)
|
|||
debugger->ResetCounters();
|
||||
}
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::StateLoaded);
|
||||
_notificationManager->SendNotification(ConsoleNotificationType::StateLoaded);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ class VideoDecoder;
|
|||
class VideoRenderer;
|
||||
class DebugHud;
|
||||
class SoundMixer;
|
||||
class NotificationManager;
|
||||
|
||||
struct HdPackData;
|
||||
enum class NesModel;
|
||||
|
@ -59,6 +60,7 @@ private:
|
|||
shared_ptr<CheatManager> _cheatManager;
|
||||
shared_ptr<DebugHud> _debugHud;
|
||||
shared_ptr<SoundMixer> _soundMixer;
|
||||
shared_ptr<NotificationManager> _notificationManager;
|
||||
|
||||
shared_ptr<HdPackBuilder> _hdPackBuilder;
|
||||
shared_ptr<HdPackData> _hdData;
|
||||
|
@ -96,6 +98,7 @@ public:
|
|||
shared_ptr<VideoRenderer> GetVideoRenderer();
|
||||
shared_ptr<DebugHud> GetDebugHud();
|
||||
shared_ptr<SoundMixer> GetSoundMixer();
|
||||
shared_ptr<NotificationManager> GetNotificationManager();
|
||||
|
||||
void ProcessCpuClock();
|
||||
CPU* GetCpu();
|
||||
|
|
|
@ -546,6 +546,7 @@
|
|||
<ClInclude Include="MMC3_224.h" />
|
||||
<ClInclude Include="MovieRecorder.h" />
|
||||
<ClInclude Include="AsciiTurboFile.h" />
|
||||
<ClInclude Include="NotificationManager.h" />
|
||||
<ClInclude Include="OpenBusHandler.h" />
|
||||
<ClInclude Include="RawVideoFilter.h" />
|
||||
<ClInclude Include="Sachen9602.h" />
|
||||
|
@ -959,15 +960,20 @@
|
|||
<ClCompile Include="DebugHud.cpp" />
|
||||
<ClCompile Include="DrawRectangleCommand.h" />
|
||||
<ClCompile Include="FceuxMovie.cpp" />
|
||||
<ClCompile Include="FdsLoader.cpp" />
|
||||
<ClCompile Include="HdAudioDevice.cpp" />
|
||||
<ClCompile Include="HdNesPack.cpp" />
|
||||
<ClCompile Include="HdPackBuilder.cpp" />
|
||||
<ClCompile Include="HdPackLoader.cpp" />
|
||||
<ClCompile Include="HdPpu.cpp" />
|
||||
<ClCompile Include="KeyManager.cpp" />
|
||||
<ClCompile Include="LuaApi.cpp" />
|
||||
<ClCompile Include="LuaCallHelper.cpp" />
|
||||
<ClCompile Include="LuaScriptingContext.cpp" />
|
||||
<ClCompile Include="MovieRecorder.cpp" />
|
||||
<ClCompile Include="NotificationManager.cpp" />
|
||||
<ClCompile Include="NsfLoader.cpp" />
|
||||
<ClCompile Include="NsfPpu.cpp" />
|
||||
<ClCompile Include="OggMixer.cpp" />
|
||||
<ClCompile Include="OggReader.cpp" />
|
||||
<ClCompile Include="RawVideoFilter.cpp" />
|
||||
|
|
|
@ -1453,6 +1453,9 @@
|
|||
<ClInclude Include="Bmc60311C.h">
|
||||
<Filter>Nes\Mappers\Unif</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NotificationManager.h">
|
||||
<Filter>Misc</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1722,5 +1725,20 @@
|
|||
<ClCompile Include="BaseExpansionAudio.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NotificationManager.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NsfPpu.cpp">
|
||||
<Filter>Nes</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="HdPpu.cpp">
|
||||
<Filter>HdPacks</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NsfLoader.cpp">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FdsLoader.cpp">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -27,6 +27,7 @@
|
|||
#include "TraceLogger.h"
|
||||
#include "Breakpoint.h"
|
||||
#include "CodeDataLogger.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
#ifndef UINT32_MAX
|
||||
#define UINT32_MAX ((uint32_t)-1)
|
||||
|
@ -445,7 +446,7 @@ void Debugger::ProcessPpuCycle()
|
|||
int32_t currentCycle = (_ppu->GetCurrentCycle() << 9) + _ppu->GetCurrentScanline();
|
||||
for(auto updateCycle : _ppuViewerUpdateCycle) {
|
||||
if(updateCycle.second == currentCycle) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame, (void*)(uint64_t)updateCycle.first);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuViewerDisplayFrame, (void*)(uint64_t)updateCycle.first);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -691,7 +692,7 @@ bool Debugger::SleepUntilResume(BreakSource source)
|
|||
|
||||
if(_preventResume == 0) {
|
||||
_console->GetSoundMixer()->StopAudio();
|
||||
MessageManager::SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)source);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::CodeBreak, (void*)(uint64_t)source);
|
||||
ProcessEvent(EventType::CodeBreak);
|
||||
_stepOverAddr = -1;
|
||||
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
|
||||
|
@ -1340,7 +1341,7 @@ void Debugger::ProcessEvent(EventType type)
|
|||
_memoryDumper->GatherChrPaletteInfo();
|
||||
} else if(type == EventType::StartFrame) {
|
||||
//Update the event viewer
|
||||
MessageManager::SendNotification(ConsoleNotificationType::EventViewerDisplayFrame);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::EventViewerDisplayFrame);
|
||||
|
||||
//Clear the current frame/event log
|
||||
if(CheckFlag(DebuggerFlags::PpuPartialDraw)) {
|
||||
|
|
|
@ -1039,7 +1039,8 @@ public:
|
|||
|
||||
UpdateEffectiveOverclockRate();
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
|
||||
//TODOCONSOLE
|
||||
//MessageManager::SendNotification(ConsoleNotificationType::ConfigChanged);
|
||||
|
||||
MessageManager::DisplayMessage("ClockRate", std::to_string((uint32_t)EmulationSettings::GetOverclockRate()) + "%");
|
||||
}
|
||||
|
|
160
Core/FdsLoader.cpp
Normal file
160
Core/FdsLoader.cpp
Normal file
|
@ -0,0 +1,160 @@
|
|||
#include "stdafx.h"
|
||||
#include "FdsLoader.h"
|
||||
#include <algorithm>
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/CRC32.h"
|
||||
#include "../Utilities/sha1.h"
|
||||
#include "RomData.h"
|
||||
#include "MessageManager.h"
|
||||
#include "MapperFactory.h"
|
||||
#include "GameDatabase.h"
|
||||
#include "EmulationSettings.h"
|
||||
|
||||
void FdsLoader::AddGaps(vector<uint8_t>& diskSide, uint8_t * readBuffer)
|
||||
{
|
||||
//Start image with 28300 bits of gap
|
||||
diskSide.insert(diskSide.end(), 28300 / 8, 0);
|
||||
|
||||
for(size_t j = 0; j < FdsDiskSideCapacity;) {
|
||||
uint8_t blockType = readBuffer[j];
|
||||
uint32_t blockLength = 1;
|
||||
switch(blockType) {
|
||||
case 1: blockLength = 56; break; //Disk header
|
||||
case 2: blockLength = 2; break; //File count
|
||||
case 3: blockLength = 16; break; //File header
|
||||
case 4: blockLength = 1 + readBuffer[j - 3] + readBuffer[j - 2] * 0x100; break;
|
||||
default: return; //End parsing when we encounter an invalid block type (This is what Nestopia apppears to do)
|
||||
}
|
||||
|
||||
if(blockType == 0) {
|
||||
diskSide.push_back(blockType);
|
||||
} else {
|
||||
diskSide.push_back(0x80);
|
||||
diskSide.insert(diskSide.end(), &readBuffer[j], &readBuffer[j] + blockLength);
|
||||
|
||||
//Fake CRC value
|
||||
diskSide.push_back(0x4D);
|
||||
diskSide.push_back(0x62);
|
||||
|
||||
//Insert 976 bits of gap after a block
|
||||
diskSide.insert(diskSide.end(), 976 / 8, 0);
|
||||
}
|
||||
|
||||
j += blockLength;
|
||||
}
|
||||
}
|
||||
|
||||
vector<uint8_t> FdsLoader::LoadBios()
|
||||
{
|
||||
//For FDS, the PRG ROM is the FDS BIOS (8k)
|
||||
vector<uint8_t> biosData;
|
||||
|
||||
ifstream biosFile(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "FdsBios.bin"), ios::in | ios::binary);
|
||||
if(biosFile) {
|
||||
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
|
||||
} else {
|
||||
biosFile.open(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "disksys.rom"), ios::in | ios::binary);
|
||||
if(biosFile) {
|
||||
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
vector<uint8_t> FdsLoader::RebuildFdsFile(vector<vector<uint8_t>> diskData, bool needHeader)
|
||||
{
|
||||
vector<uint8_t> output;
|
||||
output.reserve(diskData.size() * FdsDiskSideCapacity + 16);
|
||||
|
||||
if(needHeader) {
|
||||
uint8_t header[16] = { 'F', 'D', 'S', '\x1a', (uint8_t)diskData.size(), '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
|
||||
output.insert(output.end(), header, header + sizeof(header));
|
||||
}
|
||||
|
||||
for(vector<uint8_t> &diskSide : diskData) {
|
||||
bool inGap = true;
|
||||
size_t i = 0, len = diskSide.size();
|
||||
size_t gapNeeded = FdsDiskSideCapacity;
|
||||
uint32_t fileSize = 0;
|
||||
while(i < len) {
|
||||
if(inGap) {
|
||||
if(diskSide[i] == 0x80) {
|
||||
inGap = false;
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
uint32_t blockLength = 1;
|
||||
switch(diskSide[i]) {
|
||||
case 1: blockLength = 56; break; //Disk header
|
||||
case 2: blockLength = 2; break; //File count
|
||||
case 3: blockLength = 16; fileSize = diskSide[i + 13] + diskSide[i + 14] * 0x100; break; //File header
|
||||
case 4: blockLength = 1 + fileSize; break;
|
||||
}
|
||||
output.insert(output.end(), &diskSide[i], &diskSide[i] + blockLength);
|
||||
gapNeeded -= blockLength;
|
||||
i += blockLength;
|
||||
i += 2; //Skip CRC after block
|
||||
|
||||
inGap = true;
|
||||
}
|
||||
}
|
||||
output.insert(output.end(), gapNeeded, 0);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void FdsLoader::LoadDiskData(vector<uint8_t>& romFile, vector<vector<uint8_t>>& diskData, vector<vector<uint8_t>>& diskHeaders)
|
||||
{
|
||||
uint8_t numberOfSides = 0;
|
||||
size_t fileOffset = 0;
|
||||
bool hasHeader = memcmp(romFile.data(), "FDS\x1a", 4) == 0;
|
||||
if(hasHeader) {
|
||||
numberOfSides = romFile[4];
|
||||
fileOffset = 16;
|
||||
} else {
|
||||
numberOfSides = (uint8_t)(romFile.size() / 65500);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < numberOfSides; i++) {
|
||||
diskData.push_back(vector<uint8_t>());
|
||||
vector<uint8_t> &fdsDiskImage = diskData.back();
|
||||
|
||||
diskHeaders.push_back(vector<uint8_t>(romFile.data() + fileOffset + 1, romFile.data() + fileOffset + 57));
|
||||
|
||||
AddGaps(fdsDiskImage, &romFile[fileOffset]);
|
||||
fileOffset += FdsDiskSideCapacity;
|
||||
|
||||
//Ensure the image is 65500 bytes
|
||||
if(fdsDiskImage.size() < FdsDiskSideCapacity) {
|
||||
fdsDiskImage.resize(FdsDiskSideCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RomData FdsLoader::LoadRom(vector<uint8_t>& romFile, string filename)
|
||||
{
|
||||
RomData romData;
|
||||
|
||||
romData.Sha1 = SHA1::GetHash(romFile);
|
||||
romData.Crc32 = CRC32::GetCRC(romFile.data(), romFile.size());
|
||||
romData.PrgCrc32 = CRC32::GetCRC(romFile.data(), romFile.size());
|
||||
|
||||
romData.Format = RomFormat::Fds;
|
||||
romData.MapperID = MapperFactory::FdsMapperID;
|
||||
romData.Mirroring = MirroringType::Vertical;
|
||||
romData.PrgRom = LoadBios();
|
||||
romData.System = GameSystem::FDS;
|
||||
|
||||
if(romData.PrgRom.size() != 0x2000) {
|
||||
romData.Error = true;
|
||||
romData.BiosMissing = true;
|
||||
}
|
||||
|
||||
//Setup default controllers
|
||||
if(!_checkOnly && EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
|
||||
GameDatabase::InitializeInputDevices("", GameSystem::FDS);
|
||||
}
|
||||
|
||||
return romData;
|
||||
}
|
167
Core/FdsLoader.h
167
Core/FdsLoader.h
|
@ -1,173 +1,22 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/CRC32.h"
|
||||
#include "../Utilities/sha1.h"
|
||||
#include "RomData.h"
|
||||
#include "MessageManager.h"
|
||||
#include "MapperFactory.h"
|
||||
#include "GameDatabase.h"
|
||||
#include "BaseLoader.h"
|
||||
|
||||
struct RomData;
|
||||
|
||||
class FdsLoader : public BaseLoader
|
||||
{
|
||||
private:
|
||||
const size_t FdsDiskSideCapacity = 65500;
|
||||
static constexpr size_t FdsDiskSideCapacity = 65500;
|
||||
|
||||
private:
|
||||
void AddGaps(vector<uint8_t>& diskSide, uint8_t* readBuffer)
|
||||
{
|
||||
//Start image with 28300 bits of gap
|
||||
diskSide.insert(diskSide.end(), 28300 / 8, 0);
|
||||
|
||||
for(size_t j = 0; j < FdsDiskSideCapacity;) {
|
||||
uint8_t blockType = readBuffer[j];
|
||||
uint32_t blockLength = 1;
|
||||
switch(blockType) {
|
||||
case 1: blockLength = 56; break; //Disk header
|
||||
case 2: blockLength = 2; break; //File count
|
||||
case 3: blockLength = 16; break; //File header
|
||||
case 4: blockLength = 1 + readBuffer[j - 3] + readBuffer[j - 2] * 0x100; break;
|
||||
default: return; //End parsing when we encounter an invalid block type (This is what Nestopia apppears to do)
|
||||
}
|
||||
|
||||
if(blockType == 0) {
|
||||
diskSide.push_back(blockType);
|
||||
} else {
|
||||
diskSide.push_back(0x80);
|
||||
diskSide.insert(diskSide.end(), &readBuffer[j], &readBuffer[j] + blockLength);
|
||||
|
||||
//Fake CRC value
|
||||
diskSide.push_back(0x4D);
|
||||
diskSide.push_back(0x62);
|
||||
|
||||
//Insert 976 bits of gap after a block
|
||||
diskSide.insert(diskSide.end(), 976 / 8, 0);
|
||||
}
|
||||
|
||||
j += blockLength;
|
||||
}
|
||||
}
|
||||
|
||||
vector<uint8_t> LoadBios()
|
||||
{
|
||||
//For FDS, the PRG ROM is the FDS BIOS (8k)
|
||||
vector<uint8_t> biosData;
|
||||
|
||||
ifstream biosFile(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "FdsBios.bin"), ios::in | ios::binary);
|
||||
if(biosFile) {
|
||||
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
|
||||
} else {
|
||||
biosFile.open(FolderUtilities::CombinePath(FolderUtilities::GetHomeFolder(), "disksys.rom"), ios::in | ios::binary);
|
||||
if(biosFile) {
|
||||
return vector<uint8_t>(std::istreambuf_iterator<char>(biosFile), {});
|
||||
} else {
|
||||
if(!_checkOnly) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::FdsBiosNotFound);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
void AddGaps(vector<uint8_t>& diskSide, uint8_t* readBuffer);
|
||||
vector<uint8_t> LoadBios();
|
||||
|
||||
public:
|
||||
using BaseLoader::BaseLoader;
|
||||
|
||||
vector<uint8_t> RebuildFdsFile(vector<vector<uint8_t>> diskData, bool needHeader)
|
||||
{
|
||||
vector<uint8_t> output;
|
||||
output.reserve(diskData.size() * FdsDiskSideCapacity + 16);
|
||||
|
||||
if(needHeader) {
|
||||
uint8_t header[16] = { 'F', 'D', 'S', '\x1a', (uint8_t)diskData.size(), '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0', '\0' };
|
||||
output.insert(output.end(), header, header + sizeof(header));
|
||||
}
|
||||
|
||||
for(vector<uint8_t> &diskSide : diskData) {
|
||||
bool inGap = true;
|
||||
size_t i = 0, len = diskSide.size();
|
||||
size_t gapNeeded = FdsDiskSideCapacity;
|
||||
uint32_t fileSize = 0;
|
||||
while(i < len) {
|
||||
if(inGap) {
|
||||
if(diskSide[i] == 0x80) {
|
||||
inGap = false;
|
||||
}
|
||||
i++;
|
||||
} else {
|
||||
uint32_t blockLength = 1;
|
||||
switch(diskSide[i]) {
|
||||
case 1: blockLength = 56; break; //Disk header
|
||||
case 2: blockLength = 2; break; //File count
|
||||
case 3: blockLength = 16; fileSize = diskSide[i + 13] + diskSide[i + 14] * 0x100; break; //File header
|
||||
case 4: blockLength = 1 + fileSize; break;
|
||||
}
|
||||
output.insert(output.end(), &diskSide[i], &diskSide[i] + blockLength);
|
||||
gapNeeded -= blockLength;
|
||||
i += blockLength;
|
||||
i += 2; //Skip CRC after block
|
||||
|
||||
inGap = true;
|
||||
}
|
||||
}
|
||||
output.insert(output.end(), gapNeeded, 0);
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
void LoadDiskData(vector<uint8_t>& romFile, vector<vector<uint8_t>> &diskData, vector<vector<uint8_t>> &diskHeaders)
|
||||
{
|
||||
uint8_t numberOfSides = 0;
|
||||
size_t fileOffset = 0;
|
||||
bool hasHeader = memcmp(romFile.data(), "FDS\x1a", 4) == 0;
|
||||
if(hasHeader) {
|
||||
numberOfSides = romFile[4];
|
||||
fileOffset = 16;
|
||||
} else {
|
||||
numberOfSides = (uint8_t)(romFile.size() / 65500);
|
||||
}
|
||||
|
||||
for(uint32_t i = 0; i < numberOfSides; i++) {
|
||||
diskData.push_back(vector<uint8_t>());
|
||||
vector<uint8_t> &fdsDiskImage = diskData.back();
|
||||
|
||||
diskHeaders.push_back(vector<uint8_t>(romFile.data() + fileOffset + 1, romFile.data() + fileOffset + 57));
|
||||
|
||||
AddGaps(fdsDiskImage, &romFile[fileOffset]);
|
||||
fileOffset += FdsDiskSideCapacity;
|
||||
|
||||
//Ensure the image is 65500 bytes
|
||||
if(fdsDiskImage.size() < FdsDiskSideCapacity) {
|
||||
fdsDiskImage.resize(FdsDiskSideCapacity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RomData LoadRom(vector<uint8_t> &romFile, string filename)
|
||||
{
|
||||
RomData romData;
|
||||
|
||||
romData.Sha1 = SHA1::GetHash(romFile);
|
||||
romData.Crc32 = CRC32::GetCRC(romFile.data(), romFile.size());
|
||||
romData.PrgCrc32 = CRC32::GetCRC(romFile.data(), romFile.size());
|
||||
|
||||
romData.Format = RomFormat::Fds;
|
||||
romData.MapperID = MapperFactory::FdsMapperID;
|
||||
romData.Mirroring = MirroringType::Vertical;
|
||||
romData.PrgRom = LoadBios();
|
||||
romData.System = GameSystem::FDS;
|
||||
|
||||
if(romData.PrgRom.size() != 0x2000) {
|
||||
romData.Error = true;
|
||||
}
|
||||
|
||||
//Setup default controllers
|
||||
if(!_checkOnly && EmulationSettings::CheckFlag(EmulationFlags::AutoConfigureInput)) {
|
||||
GameDatabase::InitializeInputDevices("", GameSystem::FDS);
|
||||
}
|
||||
|
||||
return romData;
|
||||
}
|
||||
vector<uint8_t> RebuildFdsFile(vector<vector<uint8_t>> diskData, bool needHeader);
|
||||
void LoadDiskData(vector<uint8_t>& romFile, vector<vector<uint8_t>> &diskData, vector<vector<uint8_t>> &diskHeaders);
|
||||
RomData LoadRom(vector<uint8_t> &romFile, string filename);
|
||||
};
|
|
@ -5,6 +5,7 @@ using std::thread;
|
|||
#include "MessageManager.h"
|
||||
#include "GameClient.h"
|
||||
#include "Console.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "../Utilities/Socket.h"
|
||||
#include "ClientConnectionData.h"
|
||||
#include "GameClientConnection.h"
|
||||
|
@ -34,7 +35,7 @@ bool GameClient::Connected()
|
|||
void GameClient::Connect(shared_ptr<Console> console, ClientConnectionData &connectionData)
|
||||
{
|
||||
_instance.reset(new GameClient(console));
|
||||
MessageManager::RegisterNotificationListener(_instance);
|
||||
console->GetNotificationManager()->RegisterNotificationListener(_instance);
|
||||
|
||||
shared_ptr<GameClient> instance = _instance;
|
||||
if(instance) {
|
||||
|
@ -60,7 +61,7 @@ void GameClient::PrivateConnect(ClientConnectionData &connectionData)
|
|||
shared_ptr<Socket> socket(new Socket());
|
||||
if(socket->Connect(connectionData.Host.c_str(), connectionData.Port)) {
|
||||
_connection.reset(new GameClientConnection(_console, socket, connectionData));
|
||||
MessageManager::RegisterNotificationListener(_connection);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(_connection);
|
||||
_connected = true;
|
||||
} else {
|
||||
MessageManager::DisplayMessage("NetPlay", "CouldNotConnect");
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "PlayerListMessage.h"
|
||||
#include "ForceDisconnectMessage.h"
|
||||
#include "ServerInformationMessage.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
GameClientConnection::GameClientConnection(shared_ptr<Console> console, shared_ptr<Socket> socket, ClientConnectionData &connectionData) : GameConnection(console, socket)
|
||||
{
|
||||
|
@ -41,7 +42,7 @@ void GameClientConnection::Shutdown()
|
|||
DisableControllers();
|
||||
|
||||
_console->GetControlManager()->UnregisterInputProvider(this);
|
||||
MessageManager::SendNotification(ConsoleNotificationType::DisconnectedFromServer);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::DisconnectedFromServer);
|
||||
MessageManager::DisplayMessage("NetPlay", "ConnectionLost");
|
||||
EmulationSettings::ClearFlags(EmulationFlags::ForceMaxSpeed);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ using std::thread;
|
|||
#include "ControlManager.h"
|
||||
#include "../Utilities/Socket.h"
|
||||
#include "PlayerListMessage.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
unique_ptr<GameServer> GameServer::Instance;
|
||||
|
||||
|
@ -40,7 +41,7 @@ void GameServer::AcceptConnections()
|
|||
shared_ptr<Socket> socket = _listener->Accept();
|
||||
if(!socket->ConnectionError()) {
|
||||
auto connection = shared_ptr<GameServerConnection>(new GameServerConnection(_console, socket, _password));
|
||||
MessageManager::RegisterNotificationListener(connection);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(connection);
|
||||
_openConnections.push_back(connection);
|
||||
} else {
|
||||
break;
|
||||
|
|
168
Core/HdPpu.cpp
Normal file
168
Core/HdPpu.cpp
Normal file
|
@ -0,0 +1,168 @@
|
|||
#include "stdafx.h"
|
||||
#include "HdPpu.h"
|
||||
#include "CPU.h"
|
||||
#include "Console.h"
|
||||
#include "HdNesPack.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "RewindManager.h"
|
||||
#include "HdPackConditions.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "MemoryManager.h"
|
||||
|
||||
void HdPpu::DrawPixel()
|
||||
{
|
||||
uint16_t bufferOffset = (_scanline << 8) + _cycle - 1;
|
||||
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
|
||||
_lastSprite = nullptr;
|
||||
|
||||
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
||||
bool isChrRam = !_console->GetMapper()->HasChrRom();
|
||||
BaseMapper *mapper = _console->GetMapper();
|
||||
|
||||
uint32_t color = GetPixelColor();
|
||||
pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
|
||||
|
||||
TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
|
||||
uint32_t backgroundColor = 0;
|
||||
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
|
||||
backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14);
|
||||
}
|
||||
|
||||
HdPpuPixelInfo &tileInfo = _info->ScreenTiles[bufferOffset];
|
||||
|
||||
tileInfo.Grayscale = _paletteRamMask == 0x30;
|
||||
tileInfo.EmphasisBits = _intensifyColorBits >> 6;
|
||||
tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0);
|
||||
tileInfo.Tile.BgColorIndex = backgroundColor;
|
||||
if(backgroundColor == 0) {
|
||||
tileInfo.Tile.BgColor = tileInfo.Tile.PpuBackgroundColor;
|
||||
} else {
|
||||
tileInfo.Tile.BgColor = ReadPaletteRAM(lastTile->PaletteOffset + backgroundColor);
|
||||
}
|
||||
|
||||
tileInfo.XScroll = _state.XScroll;
|
||||
tileInfo.TmpVideoRamAddr = _state.TmpVideoRamAddr;
|
||||
|
||||
if(_lastSprite && _flags.SpritesEnabled) {
|
||||
int j = 0;
|
||||
for(uint8_t i = 0; i < _spriteCount; i++) {
|
||||
int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
|
||||
SpriteInfo& sprite = _spriteTiles[i];
|
||||
if(shift >= 0 && shift < 8) {
|
||||
tileInfo.Sprite[j].TileIndex = sprite.AbsoluteTileAddr / 16;
|
||||
if(isChrRam) {
|
||||
mapper->CopyChrRamTile(sprite.AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Sprite[j].TileData);
|
||||
}
|
||||
if(_version >= 100) {
|
||||
tileInfo.Sprite[j].PaletteColors = 0xFF000000 | _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
|
||||
} else {
|
||||
tileInfo.Sprite[j].PaletteColors = _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
|
||||
}
|
||||
if(sprite.OffsetY >= 8) {
|
||||
tileInfo.Sprite[j].OffsetY = sprite.OffsetY - 8;
|
||||
} else {
|
||||
tileInfo.Sprite[j].OffsetY = sprite.OffsetY;
|
||||
}
|
||||
|
||||
tileInfo.Sprite[j].OffsetX = shift;
|
||||
tileInfo.Sprite[j].HorizontalMirroring = sprite.HorizontalMirror;
|
||||
tileInfo.Sprite[j].VerticalMirroring = sprite.VerticalMirror;
|
||||
tileInfo.Sprite[j].BackgroundPriority = sprite.BackgroundPriority;
|
||||
|
||||
int32_t shift = (int32_t)_cycle - sprite.SpriteX - 1;
|
||||
if(sprite.HorizontalMirror) {
|
||||
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte >> shift) & 0x01) | ((sprite.HighByte >> shift) & 0x01) << 1;
|
||||
} else {
|
||||
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte << shift) & 0x80) >> 7 | ((sprite.HighByte << shift) & 0x80) >> 6;
|
||||
}
|
||||
|
||||
if(tileInfo.Sprite[j].SpriteColorIndex == 0) {
|
||||
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(0);
|
||||
} else {
|
||||
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(sprite.PaletteOffset + tileInfo.Sprite[j].SpriteColorIndex);
|
||||
}
|
||||
|
||||
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
|
||||
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
|
||||
|
||||
j++;
|
||||
if(j >= 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tileInfo.SpriteCount = j;
|
||||
} else {
|
||||
tileInfo.SpriteCount = 0;
|
||||
}
|
||||
|
||||
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
|
||||
tileInfo.Tile.TileIndex = lastTile->AbsoluteTileAddr / 16;
|
||||
if(isChrRam) {
|
||||
mapper->CopyChrRamTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Tile.TileData);
|
||||
}
|
||||
if(_version >= 100) {
|
||||
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16) | (_paletteRAM[0] << 24);
|
||||
} else {
|
||||
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16);
|
||||
}
|
||||
tileInfo.Tile.OffsetY = lastTile->OffsetY;
|
||||
tileInfo.Tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
|
||||
} else {
|
||||
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
|
||||
}
|
||||
} else {
|
||||
//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
|
||||
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
|
||||
_info->ScreenTiles[bufferOffset].Tile.TileIndex = HdPpuTileInfo::NoTile;
|
||||
_info->ScreenTiles[bufferOffset].SpriteCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
HdPpu::HdPpu(shared_ptr<Console> console, HdPackData * hdData) : PPU(console)
|
||||
{
|
||||
_hdData = hdData;
|
||||
_version = _hdData->Version;
|
||||
|
||||
_screenInfo[0] = new HdScreenInfo();
|
||||
_screenInfo[1] = new HdScreenInfo();
|
||||
_info = _screenInfo[0];
|
||||
}
|
||||
|
||||
HdPpu::~HdPpu()
|
||||
{
|
||||
delete _screenInfo[0];
|
||||
delete _screenInfo[1];
|
||||
}
|
||||
|
||||
void HdPpu::SendFrame()
|
||||
{
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
||||
|
||||
_info->FrameNumber = _frameCount;
|
||||
_info->WatchedAddressValues.clear();
|
||||
for(uint32_t address : _hdData->WatchedMemoryAddresses) {
|
||||
if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
|
||||
if((address & 0x3FFF) >= 0x3F00) {
|
||||
_info->WatchedAddressValues[address] = ReadPaletteRAM(address);
|
||||
} else {
|
||||
_info->WatchedAddressValues[address] = _console->GetMapper()->DebugReadVRAM(address & 0x3FFF, true);
|
||||
}
|
||||
} else {
|
||||
_info->WatchedAddressValues[address] = _console->GetMemoryManager()->DebugRead(address);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBRETRO
|
||||
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
|
||||
#else
|
||||
if(_console->GetRewindManager()->IsRewinding()) {
|
||||
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
|
||||
} else {
|
||||
_console->GetVideoDecoder()->UpdateFrame(_currentOutputBuffer, _info);
|
||||
}
|
||||
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
|
||||
_info = (_info == _screenInfo[0]) ? _screenInfo[1] : _screenInfo[0];
|
||||
#endif
|
||||
}
|
166
Core/HdPpu.h
166
Core/HdPpu.h
|
@ -1,13 +1,11 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "PPU.h"
|
||||
#include "CPU.h"
|
||||
#include "HdNesPack.h"
|
||||
#include "VideoDecoder.h"
|
||||
#include "RewindManager.h"
|
||||
#include "HdPackConditions.h"
|
||||
|
||||
struct HdScreenInfo;
|
||||
struct HdPackData;
|
||||
class ControlManager;
|
||||
class Console;
|
||||
|
||||
class HdPpu : public PPU
|
||||
{
|
||||
|
@ -18,161 +16,11 @@ private:
|
|||
HdPackData *_hdData = nullptr;
|
||||
|
||||
protected:
|
||||
void DrawPixel()
|
||||
{
|
||||
uint16_t bufferOffset = (_scanline << 8) + _cycle - 1;
|
||||
uint16_t &pixel = _currentOutputBuffer[bufferOffset];
|
||||
_lastSprite = nullptr;
|
||||
|
||||
if(IsRenderingEnabled() || ((_state.VideoRamAddr & 0x3F00) != 0x3F00)) {
|
||||
bool isChrRam = !_console->GetMapper()->HasChrRom();
|
||||
BaseMapper *mapper = _console->GetMapper();
|
||||
|
||||
uint32_t color = GetPixelColor();
|
||||
pixel = (_paletteRAM[color & 0x03 ? color : 0] & _paletteRamMask) | _intensifyColorBits;
|
||||
|
||||
TileInfo* lastTile = &((_state.XScroll + ((_cycle - 1) & 0x07) < 8) ? _previousTile : _currentTile);
|
||||
uint32_t backgroundColor = 0;
|
||||
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
|
||||
backgroundColor = (((_state.LowBitShift << _state.XScroll) & 0x8000) >> 15) | (((_state.HighBitShift << _state.XScroll) & 0x8000) >> 14);
|
||||
}
|
||||
|
||||
HdPpuPixelInfo &tileInfo = _info->ScreenTiles[bufferOffset];
|
||||
|
||||
tileInfo.Grayscale = _paletteRamMask == 0x30;
|
||||
tileInfo.EmphasisBits = _intensifyColorBits >> 6;
|
||||
tileInfo.Tile.PpuBackgroundColor = ReadPaletteRAM(0);
|
||||
tileInfo.Tile.BgColorIndex = backgroundColor;
|
||||
if(backgroundColor == 0) {
|
||||
tileInfo.Tile.BgColor = tileInfo.Tile.PpuBackgroundColor;
|
||||
} else {
|
||||
tileInfo.Tile.BgColor = ReadPaletteRAM(lastTile->PaletteOffset + backgroundColor);
|
||||
}
|
||||
|
||||
tileInfo.XScroll = _state.XScroll;
|
||||
tileInfo.TmpVideoRamAddr = _state.TmpVideoRamAddr;
|
||||
|
||||
if(_lastSprite && _flags.SpritesEnabled) {
|
||||
int j = 0;
|
||||
for(uint8_t i = 0; i < _spriteCount; i++) {
|
||||
int32_t shift = (int32_t)_cycle - _spriteTiles[i].SpriteX - 1;
|
||||
SpriteInfo& sprite = _spriteTiles[i];
|
||||
if(shift >= 0 && shift < 8) {
|
||||
tileInfo.Sprite[j].TileIndex = sprite.AbsoluteTileAddr / 16;
|
||||
if(isChrRam) {
|
||||
mapper->CopyChrRamTile(sprite.AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Sprite[j].TileData);
|
||||
}
|
||||
if(_version >= 100) {
|
||||
tileInfo.Sprite[j].PaletteColors = 0xFF000000 | _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
|
||||
} else {
|
||||
tileInfo.Sprite[j].PaletteColors = _paletteRAM[sprite.PaletteOffset + 3] | (_paletteRAM[sprite.PaletteOffset + 2] << 8) | (_paletteRAM[sprite.PaletteOffset + 1] << 16);
|
||||
}
|
||||
if(sprite.OffsetY >= 8) {
|
||||
tileInfo.Sprite[j].OffsetY = sprite.OffsetY - 8;
|
||||
} else {
|
||||
tileInfo.Sprite[j].OffsetY = sprite.OffsetY;
|
||||
}
|
||||
|
||||
tileInfo.Sprite[j].OffsetX = shift;
|
||||
tileInfo.Sprite[j].HorizontalMirroring = sprite.HorizontalMirror;
|
||||
tileInfo.Sprite[j].VerticalMirroring = sprite.VerticalMirror;
|
||||
tileInfo.Sprite[j].BackgroundPriority = sprite.BackgroundPriority;
|
||||
|
||||
int32_t shift = (int32_t)_cycle - sprite.SpriteX - 1;
|
||||
if(sprite.HorizontalMirror) {
|
||||
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte >> shift) & 0x01) | ((sprite.HighByte >> shift) & 0x01) << 1;
|
||||
} else {
|
||||
tileInfo.Sprite[j].SpriteColorIndex = ((sprite.LowByte << shift) & 0x80) >> 7 | ((sprite.HighByte << shift) & 0x80) >> 6;
|
||||
}
|
||||
|
||||
if(tileInfo.Sprite[j].SpriteColorIndex == 0) {
|
||||
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(0);
|
||||
} else {
|
||||
tileInfo.Sprite[j].SpriteColor = ReadPaletteRAM(sprite.PaletteOffset + tileInfo.Sprite[j].SpriteColorIndex);
|
||||
}
|
||||
|
||||
tileInfo.Sprite[j].PpuBackgroundColor = tileInfo.Tile.PpuBackgroundColor;
|
||||
tileInfo.Sprite[j].BgColorIndex = tileInfo.Tile.BgColorIndex;
|
||||
|
||||
j++;
|
||||
if(j >= 4) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
tileInfo.SpriteCount = j;
|
||||
} else {
|
||||
tileInfo.SpriteCount = 0;
|
||||
}
|
||||
|
||||
if(_flags.BackgroundEnabled && _cycle > _minimumDrawBgCycle) {
|
||||
tileInfo.Tile.TileIndex = lastTile->AbsoluteTileAddr / 16;
|
||||
if(isChrRam) {
|
||||
mapper->CopyChrRamTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tileInfo.Tile.TileData);
|
||||
}
|
||||
if(_version >= 100) {
|
||||
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16) | (_paletteRAM[0] << 24);
|
||||
} else {
|
||||
tileInfo.Tile.PaletteColors = _paletteRAM[lastTile->PaletteOffset + 3] | (_paletteRAM[lastTile->PaletteOffset + 2] << 8) | (_paletteRAM[lastTile->PaletteOffset + 1] << 16);
|
||||
}
|
||||
tileInfo.Tile.OffsetY = lastTile->OffsetY;
|
||||
tileInfo.Tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
|
||||
} else {
|
||||
tileInfo.Tile.TileIndex = HdPpuTileInfo::NoTile;
|
||||
}
|
||||
} else {
|
||||
//"If the current VRAM address points in the range $3F00-$3FFF during forced blanking, the color indicated by this palette location will be shown on screen instead of the backdrop color."
|
||||
pixel = ReadPaletteRAM(_state.VideoRamAddr) | _intensifyColorBits;
|
||||
_info->ScreenTiles[bufferOffset].Tile.TileIndex = HdPpuTileInfo::NoTile;
|
||||
_info->ScreenTiles[bufferOffset].SpriteCount = 0;
|
||||
}
|
||||
}
|
||||
void DrawPixel() override;
|
||||
|
||||
public:
|
||||
HdPpu(shared_ptr<Console> console, HdPackData* hdData) : PPU(console)
|
||||
{
|
||||
_hdData = hdData;
|
||||
_version = _hdData->Version;
|
||||
|
||||
_screenInfo[0] = new HdScreenInfo();
|
||||
_screenInfo[1] = new HdScreenInfo();
|
||||
_info = _screenInfo[0];
|
||||
}
|
||||
HdPpu(shared_ptr<Console> console, HdPackData* hdData);
|
||||
~HdPpu();
|
||||
|
||||
~HdPpu()
|
||||
{
|
||||
delete _screenInfo[0];
|
||||
delete _screenInfo[1];
|
||||
}
|
||||
|
||||
void SendFrame()
|
||||
{
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
||||
|
||||
_info->FrameNumber = _frameCount;
|
||||
_info->WatchedAddressValues.clear();
|
||||
for(uint32_t address : _hdData->WatchedMemoryAddresses) {
|
||||
if(address & HdPackBaseMemoryCondition::PpuMemoryMarker) {
|
||||
if((address & 0x3FFF) >= 0x3F00) {
|
||||
_info->WatchedAddressValues[address] = ReadPaletteRAM(address);
|
||||
} else {
|
||||
_info->WatchedAddressValues[address] = _console->GetMapper()->DebugReadVRAM(address & 0x3FFF, true);
|
||||
}
|
||||
} else {
|
||||
_info->WatchedAddressValues[address] = _console->GetMemoryManager()->DebugRead(address);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef LIBRETRO
|
||||
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
|
||||
#else
|
||||
if(_console->GetRewindManager()->IsRewinding()) {
|
||||
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer, _info);
|
||||
} else {
|
||||
_console->GetVideoDecoder()->UpdateFrame(_currentOutputBuffer, _info);
|
||||
}
|
||||
_currentOutputBuffer = (_currentOutputBuffer == _outputBuffers[0]) ? _outputBuffers[1] : _outputBuffers[0];
|
||||
_info = (_info == _screenInfo[0]) ? _screenInfo[1] : _screenInfo[0];
|
||||
#endif
|
||||
}
|
||||
void SendFrame() override;
|
||||
};
|
|
@ -1,8 +1,10 @@
|
|||
#include "stdafx.h"
|
||||
#include "MessageManager.h"
|
||||
#include "NotificationManager.h"
|
||||
#include "MapperFactory.h"
|
||||
#include "RomLoader.h"
|
||||
#include "UnifBoards.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "RomData.h"
|
||||
|
||||
#include "A65AS.h"
|
||||
#include "Ac08.h"
|
||||
|
@ -624,9 +626,11 @@ shared_ptr<BaseMapper> MapperFactory::InitializeFromFile(shared_ptr<Console> con
|
|||
if(mapper) {
|
||||
mapper->SetConsole(console);
|
||||
mapper->Initialize(romData);
|
||||
MessageManager::RegisterNotificationListener(mapper);
|
||||
console->GetNotificationManager()->RegisterNotificationListener(mapper);
|
||||
return mapper;
|
||||
}
|
||||
} else if(loader.GetRomData().BiosMissing) {
|
||||
console->GetNotificationManager()->SendNotification(ConsoleNotificationType::FdsBiosNotFound);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "BaseMapper.h"
|
||||
#include "RomData.h"
|
||||
|
||||
class MemoryManager;
|
||||
class Console;
|
||||
class BaseMapper;
|
||||
struct RomData;
|
||||
|
||||
class MapperFactory
|
||||
{
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "MovieRecorder.h"
|
||||
#include "BatteryManager.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
MesenMovie::MesenMovie(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -63,6 +64,13 @@ vector<uint8_t> MesenMovie::LoadBattery(string extension)
|
|||
return batteryData;
|
||||
}
|
||||
|
||||
void MesenMovie::ProcessNotification(ConsoleNotificationType type, void * parameter)
|
||||
{
|
||||
if(type == ConsoleNotificationType::GameLoaded) {
|
||||
_console->GetControlManager()->RegisterInputProvider(this);
|
||||
}
|
||||
}
|
||||
|
||||
bool MesenMovie::Play(VirtualFile &file)
|
||||
{
|
||||
_movieFile = file;
|
||||
|
@ -98,7 +106,7 @@ bool MesenMovie::Play(VirtualFile &file)
|
|||
_console->Pause();
|
||||
|
||||
BatteryManager::SetBatteryProvider(shared_from_this());
|
||||
_console->GetControlManager()->RegisterInputProvider(this);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(shared_from_this());
|
||||
ApplySettings();
|
||||
|
||||
//Disable auto-configure input option (otherwise the movie file's input types are ignored)
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
#include "MovieManager.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "BatteryManager.h"
|
||||
#include "INotificationListener.h"
|
||||
|
||||
class ZipReader;
|
||||
class Console;
|
||||
struct CodeInfo;
|
||||
|
||||
class MesenMovie : public IMovie, public IBatteryProvider, public std::enable_shared_from_this<MesenMovie>
|
||||
class MesenMovie : public IMovie, public INotificationListener, public IBatteryProvider, public std::enable_shared_from_this<MesenMovie>
|
||||
{
|
||||
private:
|
||||
shared_ptr<Console> _console;
|
||||
|
@ -45,4 +46,7 @@ public:
|
|||
|
||||
// Inherited via IBatteryProvider
|
||||
virtual vector<uint8_t> LoadBattery(string extension) override;
|
||||
|
||||
// Inherited via INotificationListener
|
||||
virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override;
|
||||
};
|
|
@ -607,11 +607,7 @@ std::unordered_map<string, string> MessageManager::_caResources = {
|
|||
|
||||
std::list<string> MessageManager::_log;
|
||||
SimpleLock MessageManager::_logLock;
|
||||
SimpleLock MessageManager::_notificationLock;
|
||||
SimpleLock MessageManager::_addListenerLock;
|
||||
IMessageManager* MessageManager::_messageManager = nullptr;
|
||||
vector<weak_ptr<INotificationListener>> MessageManager::_listenersToAdd;
|
||||
vector<weak_ptr<INotificationListener>> MessageManager::_notificationListeners;
|
||||
|
||||
void MessageManager::RegisterMessageManager(IMessageManager* messageManager)
|
||||
{
|
||||
|
@ -697,50 +693,3 @@ string MessageManager::GetLog()
|
|||
}
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
void MessageManager::RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener)
|
||||
{
|
||||
auto lock = _notificationLock.AcquireSafe();
|
||||
|
||||
for(weak_ptr<INotificationListener> listener : _notificationListeners) {
|
||||
if(listener.lock() == notificationListener) {
|
||||
//This listener is already registered, do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_notificationListeners.push_back(notificationListener);
|
||||
}
|
||||
|
||||
void MessageManager::CleanupNotificationListeners()
|
||||
{
|
||||
auto lock = _notificationLock.AcquireSafe();
|
||||
|
||||
//Remove expired listeners
|
||||
_notificationListeners.erase(
|
||||
std::remove_if(
|
||||
_notificationListeners.begin(),
|
||||
_notificationListeners.end(),
|
||||
[](weak_ptr<INotificationListener> ptr) { return ptr.expired(); }
|
||||
),
|
||||
_notificationListeners.end()
|
||||
);
|
||||
}
|
||||
|
||||
void MessageManager::SendNotification(ConsoleNotificationType type, void* parameter)
|
||||
{
|
||||
vector<weak_ptr<INotificationListener>> listeners;
|
||||
{
|
||||
auto lock = _notificationLock.AcquireSafe();
|
||||
CleanupNotificationListeners();
|
||||
listeners = _notificationListeners;
|
||||
}
|
||||
|
||||
//Iterate on a copy without using a lock
|
||||
for(weak_ptr<INotificationListener> notificationListener : listeners) {
|
||||
shared_ptr<INotificationListener> listener = notificationListener.lock();
|
||||
if(listener) {
|
||||
listener->ProcessNotification(type, parameter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,8 +11,6 @@ class MessageManager
|
|||
{
|
||||
private:
|
||||
static IMessageManager* _messageManager;
|
||||
static vector<weak_ptr<INotificationListener>> _listenersToAdd;
|
||||
static vector<weak_ptr<INotificationListener>> _notificationListeners;
|
||||
static std::unordered_map<string, string> _enResources;
|
||||
static std::unordered_map<string, string> _frResources;
|
||||
static std::unordered_map<string, string> _jaResources;
|
||||
|
@ -23,12 +21,8 @@ private:
|
|||
static std::unordered_map<string, string> _caResources;
|
||||
|
||||
static SimpleLock _logLock;
|
||||
static SimpleLock _notificationLock;
|
||||
static SimpleLock _addListenerLock;
|
||||
static std::list<string> _log;
|
||||
|
||||
static void CleanupNotificationListeners();
|
||||
|
||||
|
||||
public:
|
||||
static string Localize(string key);
|
||||
|
||||
|
@ -37,7 +31,4 @@ public:
|
|||
|
||||
static void Log(string message = "");
|
||||
static string GetLog();
|
||||
|
||||
static void RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener);
|
||||
static void SendNotification(ConsoleNotificationType type, void* parameter = nullptr);
|
||||
};
|
||||
|
|
|
@ -15,7 +15,10 @@ protected:
|
|||
void EndMovie()
|
||||
{
|
||||
MessageManager::DisplayMessage("Movies", "MovieEnded");
|
||||
MessageManager::SendNotification(ConsoleNotificationType::MovieEnded);
|
||||
|
||||
//TODOCONSOLE
|
||||
//MessageManager::SendNotification(ConsoleNotificationType::MovieEnded);
|
||||
|
||||
if(EmulationSettings::CheckFlag(EmulationFlags::PauseOnMovieEnd)) {
|
||||
EmulationSettings::SetFlags(EmulationFlags::Paused);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include "CheatManager.h"
|
||||
#include "VirtualFile.h"
|
||||
#include "SaveStateManager.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
MovieRecorder::MovieRecorder(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -43,8 +44,10 @@ bool MovieRecorder::Record(RecordMovieOptions options)
|
|||
if(options.RecordFrom == RecordMovieFrom::StartWithSaveData) {
|
||||
BatteryManager::SetBatteryRecorder(shared_from_this());
|
||||
}
|
||||
_console->GetControlManager()->RegisterInputRecorder(this);
|
||||
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(shared_from_this());
|
||||
if(options.RecordFrom == RecordMovieFrom::CurrentState) {
|
||||
_console->GetControlManager()->RegisterInputRecorder(this);
|
||||
_console->GetSaveStateManager()->SaveState(_saveStateData);
|
||||
_hasSaveState = true;
|
||||
} else {
|
||||
|
@ -217,3 +220,10 @@ vector<uint8_t> MovieRecorder::LoadBattery(string extension)
|
|||
{
|
||||
return vector<uint8_t>();
|
||||
}
|
||||
|
||||
void MovieRecorder::ProcessNotification(ConsoleNotificationType type, void *parameter)
|
||||
{
|
||||
if(type == ConsoleNotificationType::GameLoaded) {
|
||||
_console->GetControlManager()->RegisterInputRecorder(this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,12 +4,13 @@
|
|||
#include "IInputRecorder.h"
|
||||
#include "BatteryManager.h"
|
||||
#include "Types.h"
|
||||
#include "INotificationListener.h"
|
||||
|
||||
class ZipWriter;
|
||||
class Console;
|
||||
struct CodeInfo;
|
||||
|
||||
class MovieRecorder : public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this<MovieRecorder>
|
||||
class MovieRecorder : public INotificationListener, public IInputRecorder, public IBatteryRecorder, public IBatteryProvider, public std::enable_shared_from_this<MovieRecorder>
|
||||
{
|
||||
private:
|
||||
static const uint32_t MovieFormatVersion = 1;
|
||||
|
@ -44,6 +45,9 @@ public:
|
|||
|
||||
// Inherited via IBatteryProvider
|
||||
virtual vector<uint8_t> LoadBattery(string extension) override;
|
||||
|
||||
// Inherited via INotificationListener
|
||||
virtual void ProcessNotification(ConsoleNotificationType type, void * parameter) override;
|
||||
};
|
||||
|
||||
namespace MovieKeys
|
||||
|
|
49
Core/NotificationManager.cpp
Normal file
49
Core/NotificationManager.cpp
Normal file
|
@ -0,0 +1,49 @@
|
|||
#include "stdafx.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
void NotificationManager::RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener)
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
|
||||
for(weak_ptr<INotificationListener> listener : _listeners) {
|
||||
if(listener.lock() == notificationListener) {
|
||||
//This listener is already registered, do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
_listeners.push_back(notificationListener);
|
||||
}
|
||||
|
||||
void NotificationManager::CleanupNotificationListeners()
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
|
||||
//Remove expired listeners
|
||||
_listeners.erase(
|
||||
std::remove_if(
|
||||
_listeners.begin(),
|
||||
_listeners.end(),
|
||||
[](weak_ptr<INotificationListener> ptr) { return ptr.expired(); }
|
||||
),
|
||||
_listeners.end()
|
||||
);
|
||||
}
|
||||
|
||||
void NotificationManager::SendNotification(ConsoleNotificationType type, void* parameter)
|
||||
{
|
||||
vector<weak_ptr<INotificationListener>> listeners;
|
||||
{
|
||||
auto lock = _lock.AcquireSafe();
|
||||
CleanupNotificationListeners();
|
||||
listeners = _listeners;
|
||||
}
|
||||
|
||||
//Iterate on a copy without using a lock
|
||||
for(weak_ptr<INotificationListener> notificationListener : listeners) {
|
||||
shared_ptr<INotificationListener> listener = notificationListener.lock();
|
||||
if(listener) {
|
||||
listener->ProcessNotification(type, parameter);
|
||||
}
|
||||
}
|
||||
}
|
18
Core/NotificationManager.h
Normal file
18
Core/NotificationManager.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "INotificationListener.h"
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
|
||||
class NotificationManager
|
||||
{
|
||||
private:
|
||||
SimpleLock _lock;
|
||||
vector<weak_ptr<INotificationListener>> _listenersToAdd;
|
||||
vector<weak_ptr<INotificationListener>> _listeners;
|
||||
|
||||
void CleanupNotificationListeners();
|
||||
|
||||
public:
|
||||
void RegisterNotificationListener(shared_ptr<INotificationListener> notificationListener);
|
||||
void SendNotification(ConsoleNotificationType type, void* parameter = nullptr);
|
||||
};
|
169
Core/NsfLoader.cpp
Normal file
169
Core/NsfLoader.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include "stdafx.h"
|
||||
#include "NsfLoader.h"
|
||||
#include "RomData.h"
|
||||
#include "MapperFactory.h"
|
||||
|
||||
void NsfLoader::Read(uint8_t *& data, uint8_t & dest)
|
||||
{
|
||||
dest = data[0];
|
||||
data++;
|
||||
}
|
||||
|
||||
void NsfLoader::Read(uint8_t *& data, uint16_t & dest)
|
||||
{
|
||||
dest = data[0] | (data[1] << 8);
|
||||
data += 2;
|
||||
}
|
||||
|
||||
void NsfLoader::Read(uint8_t *& data, char * dest, size_t len)
|
||||
{
|
||||
memcpy(dest, data, len);
|
||||
data += len;
|
||||
}
|
||||
|
||||
void NsfLoader::InitializeFromHeader(RomData & romData)
|
||||
{
|
||||
NsfHeader &header = romData.NsfInfo;
|
||||
|
||||
romData.Format = RomFormat::Nsf;
|
||||
romData.MapperID = MapperFactory::NsfMapperID;
|
||||
|
||||
if(header.LoadAddress < 0x6000 || header.TotalSongs == 0) {
|
||||
romData.Error = true;
|
||||
}
|
||||
|
||||
if(header.Flags == 0x01) {
|
||||
romData.System = GameSystem::NesPal;
|
||||
}
|
||||
|
||||
if(header.PlaySpeedNtsc == 0) {
|
||||
header.PlaySpeedNtsc = 16639;
|
||||
}
|
||||
|
||||
if(header.PlaySpeedPal == 0) {
|
||||
header.PlaySpeedPal = 19997;
|
||||
}
|
||||
|
||||
if(header.StartingSong > header.TotalSongs || header.StartingSong == 0) {
|
||||
header.StartingSong = 1;
|
||||
}
|
||||
|
||||
//Log window output
|
||||
Log("[NSF] Region: " + string(header.Flags == 0x00 ? "NTSC" : (header.Flags == 0x01 ? "PAL" : "NTSC & PAL")));
|
||||
if(header.PlaySpeedNtsc > 0) {
|
||||
Log("[NSF] Play speed (NTSC): " + std::to_string(1000000.0 / (double)header.PlaySpeedNtsc) + " Hz");
|
||||
}
|
||||
if(header.PlaySpeedPal > 0) {
|
||||
Log("[NSF] Play speed (PAL): " + std::to_string(1000000.0 / (double)header.PlaySpeedPal) + " Hz");
|
||||
}
|
||||
Log("[NSF] Title: " + string(header.SongName));
|
||||
Log("[NSF] Artist: " + string(header.ArtistName));
|
||||
Log("[NSF] Copyright: " + string(header.CopyrightHolder));
|
||||
Log("[NSF] Ripper: " + string(header.RipperName));
|
||||
|
||||
stringstream ss;
|
||||
ss << "[NSF] Load Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.LoadAddress;
|
||||
Log(ss.str());
|
||||
ss = stringstream();
|
||||
ss << "[NSF] Init Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.InitAddress;
|
||||
Log(ss.str());
|
||||
ss = stringstream();
|
||||
ss << "[NSF] Play Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.PlayAddress;
|
||||
Log(ss.str());
|
||||
|
||||
vector<string> chips;
|
||||
if(header.SoundChips & 0x01) {
|
||||
chips.push_back("VRC6");
|
||||
}
|
||||
if(header.SoundChips & 0x02) {
|
||||
chips.push_back("VRC7");
|
||||
}
|
||||
if(header.SoundChips & 0x04) {
|
||||
chips.push_back("FDS");
|
||||
}
|
||||
if(header.SoundChips & 0x08) {
|
||||
chips.push_back("MMC5");
|
||||
}
|
||||
if(header.SoundChips & 0x10) {
|
||||
chips.push_back("Namco 163");
|
||||
}
|
||||
if(header.SoundChips & 0x20) {
|
||||
chips.push_back("Sunsoft 5B");
|
||||
}
|
||||
if(chips.empty()) {
|
||||
chips.push_back("<none>");
|
||||
}
|
||||
|
||||
ss = stringstream();
|
||||
for(size_t i = 0; i < chips.size(); i++) {
|
||||
if(i > 0) {
|
||||
ss << ", ";
|
||||
}
|
||||
ss << chips[i];
|
||||
}
|
||||
|
||||
Log("[NSF] Sound Chips: " + ss.str());
|
||||
Log("[NSF] ROM size: " + std::to_string(romData.PrgRom.size() / 1024) + " KB");
|
||||
}
|
||||
|
||||
void NsfLoader::InitHeader(NsfHeader & header)
|
||||
{
|
||||
memset(&header, 0, sizeof(NsfHeader));
|
||||
for(int i = 0; i < 256; i++) {
|
||||
//Used by NSFE
|
||||
header.TrackLength[i] = -1;
|
||||
header.TrackFade[i] = -1;
|
||||
}
|
||||
}
|
||||
|
||||
RomData NsfLoader::LoadRom(vector<uint8_t>& romFile)
|
||||
{
|
||||
RomData romData;
|
||||
NsfHeader &header = romData.NsfInfo;
|
||||
|
||||
InitHeader(header);
|
||||
|
||||
uint8_t* data = romFile.data();
|
||||
Read(data, header.Header, 5);
|
||||
Read(data, header.Version);
|
||||
Read(data, header.TotalSongs);
|
||||
Read(data, header.StartingSong);
|
||||
Read(data, header.LoadAddress);
|
||||
Read(data, header.InitAddress);
|
||||
Read(data, header.PlayAddress);
|
||||
Read(data, header.SongName, 32);
|
||||
Read(data, header.ArtistName, 32);
|
||||
Read(data, header.CopyrightHolder, 32);
|
||||
Read(data, header.PlaySpeedNtsc);
|
||||
Read(data, (char*)header.BankSetup, 8);
|
||||
Read(data, header.PlaySpeedPal);
|
||||
Read(data, header.Flags);
|
||||
Read(data, header.SoundChips);
|
||||
Read(data, (char*)header.Padding, 4);
|
||||
|
||||
//Ensure strings are null terminated
|
||||
header.SongName[31] = 0;
|
||||
header.ArtistName[31] = 0;
|
||||
header.CopyrightHolder[31] = 0;
|
||||
|
||||
if(header.PlaySpeedNtsc == 16666 || header.PlaySpeedNtsc == 16667) {
|
||||
header.PlaySpeedNtsc = 16639;
|
||||
}
|
||||
if(header.PlaySpeedPal == 20000) {
|
||||
header.PlaySpeedPal = 19997;
|
||||
}
|
||||
|
||||
//Pad start of file to make the first block start at a multiple of 4k
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), header.LoadAddress % 4096, 0);
|
||||
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), data, data + romFile.size() - 0x80);
|
||||
|
||||
//Pad out the last block to be a multiple of 4k
|
||||
if(romData.PrgRom.size() % 4096 != 0) {
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), 4096 - (romData.PrgRom.size() % 4096), 0);
|
||||
}
|
||||
|
||||
InitializeFromHeader(romData);
|
||||
|
||||
return romData;
|
||||
}
|
171
Core/NsfLoader.h
171
Core/NsfLoader.h
|
@ -1,176 +1,23 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "RomData.h"
|
||||
#include "BaseLoader.h"
|
||||
|
||||
struct NsfHeader;
|
||||
struct RomData;
|
||||
|
||||
class NsfLoader : public BaseLoader
|
||||
{
|
||||
private:
|
||||
void Read(uint8_t* &data, uint8_t& dest)
|
||||
{
|
||||
dest = data[0];
|
||||
data++;
|
||||
}
|
||||
void Read(uint8_t* &data, uint8_t& dest);
|
||||
void Read(uint8_t* &data, uint16_t& dest);
|
||||
void Read(uint8_t* &data, char* dest, size_t len);
|
||||
|
||||
void Read(uint8_t* &data, uint16_t& dest)
|
||||
{
|
||||
dest = data[0] | (data[1] << 8);
|
||||
data += 2;
|
||||
}
|
||||
|
||||
void Read(uint8_t* &data, char* dest, size_t len)
|
||||
{
|
||||
memcpy(dest, data, len);
|
||||
data += len;
|
||||
}
|
||||
protected:
|
||||
void InitializeFromHeader(RomData& romData)
|
||||
{
|
||||
NsfHeader &header = romData.NsfInfo;
|
||||
|
||||
romData.Format = RomFormat::Nsf;
|
||||
romData.MapperID = MapperFactory::NsfMapperID;
|
||||
|
||||
if(header.LoadAddress < 0x6000 || header.TotalSongs == 0) {
|
||||
romData.Error = true;
|
||||
}
|
||||
|
||||
if(header.Flags == 0x01) {
|
||||
romData.System = GameSystem::NesPal;
|
||||
}
|
||||
|
||||
if(header.PlaySpeedNtsc == 0) {
|
||||
header.PlaySpeedNtsc = 16639;
|
||||
}
|
||||
|
||||
if(header.PlaySpeedPal == 0) {
|
||||
header.PlaySpeedPal = 19997;
|
||||
}
|
||||
|
||||
if(header.StartingSong > header.TotalSongs || header.StartingSong == 0) {
|
||||
header.StartingSong = 1;
|
||||
}
|
||||
|
||||
//Log window output
|
||||
Log("[NSF] Region: " + string(header.Flags == 0x00 ? "NTSC" : (header.Flags == 0x01 ? "PAL" : "NTSC & PAL")));
|
||||
if(header.PlaySpeedNtsc > 0) {
|
||||
Log("[NSF] Play speed (NTSC): " + std::to_string(1000000.0 / (double)header.PlaySpeedNtsc) + " Hz");
|
||||
}
|
||||
if(header.PlaySpeedPal > 0) {
|
||||
Log("[NSF] Play speed (PAL): " + std::to_string(1000000.0 / (double)header.PlaySpeedPal) + " Hz");
|
||||
}
|
||||
Log("[NSF] Title: " + string(header.SongName));
|
||||
Log("[NSF] Artist: " + string(header.ArtistName));
|
||||
Log("[NSF] Copyright: " + string(header.CopyrightHolder));
|
||||
Log("[NSF] Ripper: " + string(header.RipperName));
|
||||
|
||||
stringstream ss;
|
||||
ss << "[NSF] Load Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.LoadAddress;
|
||||
Log(ss.str());
|
||||
ss = stringstream();
|
||||
ss << "[NSF] Init Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.InitAddress;
|
||||
Log(ss.str());
|
||||
ss = stringstream();
|
||||
ss << "[NSF] Play Address: 0x" << std::hex << std::uppercase << std::setfill('0') << std::setw(4) << header.PlayAddress;
|
||||
Log(ss.str());
|
||||
|
||||
vector<string> chips;
|
||||
if(header.SoundChips & 0x01) {
|
||||
chips.push_back("VRC6");
|
||||
}
|
||||
if(header.SoundChips & 0x02) {
|
||||
chips.push_back("VRC7");
|
||||
}
|
||||
if(header.SoundChips & 0x04) {
|
||||
chips.push_back("FDS");
|
||||
}
|
||||
if(header.SoundChips & 0x08) {
|
||||
chips.push_back("MMC5");
|
||||
}
|
||||
if(header.SoundChips & 0x10) {
|
||||
chips.push_back("Namco 163");
|
||||
}
|
||||
if(header.SoundChips & 0x20) {
|
||||
chips.push_back("Sunsoft 5B");
|
||||
}
|
||||
if(chips.empty()) {
|
||||
chips.push_back("<none>");
|
||||
}
|
||||
|
||||
ss = stringstream();
|
||||
for(size_t i = 0; i < chips.size(); i++) {
|
||||
if(i > 0) {
|
||||
ss << ", ";
|
||||
}
|
||||
ss << chips[i];
|
||||
}
|
||||
|
||||
Log("[NSF] Sound Chips: " + ss.str());
|
||||
Log("[NSF] ROM size: " + std::to_string(romData.PrgRom.size() / 1024) + " KB");
|
||||
}
|
||||
|
||||
void InitHeader(NsfHeader& header)
|
||||
{
|
||||
memset(&header, 0, sizeof(NsfHeader));
|
||||
for(int i = 0; i < 256; i++) {
|
||||
//Used by NSFE
|
||||
header.TrackLength[i] = -1;
|
||||
header.TrackFade[i] = -1;
|
||||
}
|
||||
}
|
||||
void InitializeFromHeader(RomData& romData);
|
||||
void InitHeader(NsfHeader& header);
|
||||
|
||||
public:
|
||||
using BaseLoader::BaseLoader;
|
||||
|
||||
RomData LoadRom(vector<uint8_t>& romFile)
|
||||
{
|
||||
RomData romData;
|
||||
NsfHeader &header = romData.NsfInfo;
|
||||
|
||||
InitHeader(header);
|
||||
|
||||
uint8_t* data = romFile.data();
|
||||
Read(data, header.Header, 5);
|
||||
Read(data, header.Version);
|
||||
Read(data, header.TotalSongs);
|
||||
Read(data, header.StartingSong);
|
||||
Read(data, header.LoadAddress);
|
||||
Read(data, header.InitAddress);
|
||||
Read(data, header.PlayAddress);
|
||||
Read(data, header.SongName, 32);
|
||||
Read(data, header.ArtistName, 32);
|
||||
Read(data, header.CopyrightHolder, 32);
|
||||
Read(data, header.PlaySpeedNtsc);
|
||||
Read(data, (char*)header.BankSetup, 8);
|
||||
Read(data, header.PlaySpeedPal);
|
||||
Read(data, header.Flags);
|
||||
Read(data, header.SoundChips);
|
||||
Read(data, (char*)header.Padding, 4);
|
||||
|
||||
//Ensure strings are null terminated
|
||||
header.SongName[31] = 0;
|
||||
header.ArtistName[31] = 0;
|
||||
header.CopyrightHolder[31] = 0;
|
||||
|
||||
if(header.PlaySpeedNtsc == 16666 || header.PlaySpeedNtsc == 16667) {
|
||||
header.PlaySpeedNtsc = 16639;
|
||||
}
|
||||
if(header.PlaySpeedPal == 20000) {
|
||||
header.PlaySpeedPal = 19997;
|
||||
}
|
||||
|
||||
//Pad start of file to make the first block start at a multiple of 4k
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), header.LoadAddress % 4096, 0);
|
||||
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), data, data + romFile.size() - 0x80);
|
||||
|
||||
//Pad out the last block to be a multiple of 4k
|
||||
if(romData.PrgRom.size() % 4096 != 0) {
|
||||
romData.PrgRom.insert(romData.PrgRom.end(), 4096 - (romData.PrgRom.size() % 4096), 0);
|
||||
}
|
||||
|
||||
InitializeFromHeader(romData);
|
||||
|
||||
return romData;
|
||||
}
|
||||
RomData LoadRom(vector<uint8_t>& romFile);
|
||||
};
|
13
Core/NsfPpu.cpp
Normal file
13
Core/NsfPpu.cpp
Normal file
|
@ -0,0 +1,13 @@
|
|||
#include "stdafx.h"
|
||||
#include "NsfPpu.h"
|
||||
#include "Console.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
void NsfPpu::DrawPixel()
|
||||
{
|
||||
}
|
||||
|
||||
void NsfPpu::SendFrame()
|
||||
{
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone);
|
||||
}
|
|
@ -5,14 +5,8 @@
|
|||
class NsfPpu : public PPU
|
||||
{
|
||||
protected:
|
||||
void DrawPixel()
|
||||
{
|
||||
}
|
||||
|
||||
void SendFrame()
|
||||
{
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone);
|
||||
}
|
||||
void DrawPixel() override;
|
||||
void SendFrame() override;
|
||||
|
||||
public:
|
||||
using PPU::PPU;
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "ControlManager.h"
|
||||
#include "MemoryManager.h"
|
||||
#include "Console.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
PPU::PPU(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -1051,7 +1052,7 @@ void PPU::SendFrame()
|
|||
{
|
||||
UpdateGrayscaleAndIntensifyBits();
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::PpuFrameDone, _currentOutputBuffer);
|
||||
|
||||
#ifdef LIBRETRO
|
||||
_console->GetVideoDecoder()->UpdateFrameSync(_currentOutputBuffer);
|
||||
|
|
|
@ -285,6 +285,7 @@ struct RomData
|
|||
uint32_t PrgChrCrc32 = 0;
|
||||
|
||||
bool Error = false;
|
||||
bool BiosMissing = false;
|
||||
|
||||
NESHeader NesHeader;
|
||||
NsfHeader NsfInfo;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "MovieManager.h"
|
||||
#include "ControlManager.h"
|
||||
#include "Console.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
ShortcutKeyHandler::ShortcutKeyHandler(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -117,7 +118,7 @@ void ShortcutKeyHandler::CheckMappedKeys()
|
|||
for(uint64_t i = (uint64_t)EmulatorShortcut::SwitchDiskSide; i < (uint64_t)EmulatorShortcut::ShortcutCount; i++) {
|
||||
if(DetectKeyPress((EmulatorShortcut)i)) {
|
||||
void* param = (void*)i;
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, param);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, param);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -169,11 +170,11 @@ void ShortcutKeyHandler::CheckMappedKeys()
|
|||
}
|
||||
|
||||
if(DetectKeyPress(EmulatorShortcut::ToggleCheats) && !isNetplayClient && !isMovieActive) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleCheats);
|
||||
}
|
||||
|
||||
if(DetectKeyPress(EmulatorShortcut::ToggleAudio)) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleAudio);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ExecuteShortcut, (void*)EmulatorShortcut::ToggleAudio);
|
||||
}
|
||||
|
||||
if(DetectKeyPress(EmulatorShortcut::RunSingleFrame)) {
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
#include "HdNesPack.h"
|
||||
#include "RotateFilter.h"
|
||||
#include "DebugHud.h"
|
||||
#include "NotificationManager.h"
|
||||
|
||||
VideoDecoder::VideoDecoder(shared_ptr<Console> console)
|
||||
{
|
||||
|
@ -121,7 +122,7 @@ void VideoDecoder::DecodeFrame(bool synchronous)
|
|||
ScreenSize screenSize;
|
||||
GetScreenSize(screenSize, true);
|
||||
if(_previousScale != EmulationSettings::GetVideoScale() || screenSize.Height != _previousScreenSize.Height || screenSize.Width != _previousScreenSize.Width) {
|
||||
MessageManager::SendNotification(ConsoleNotificationType::ResolutionChanged);
|
||||
_console->GetNotificationManager()->SendNotification(ConsoleNotificationType::ResolutionChanged);
|
||||
}
|
||||
_previousScale = EmulationSettings::GetVideoScale();
|
||||
_previousScreenSize = screenSize;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include "../Core/MessageManager.h"
|
||||
#include "../Core/NotificationManager.h"
|
||||
#include "../Core/Console.h"
|
||||
#include "../Core/GameServer.h"
|
||||
#include "../Core/GameClient.h"
|
||||
|
@ -360,7 +361,7 @@ namespace InteropEmu {
|
|||
auto lock = _externalNotificationListenerLock.AcquireSafe();
|
||||
auto listener = shared_ptr<INotificationListener>(new InteropNotificationListener(callback));
|
||||
_externalNotificationListeners.push_back(listener);
|
||||
MessageManager::RegisterNotificationListener(listener);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(listener);
|
||||
return listener.get();
|
||||
}
|
||||
|
||||
|
@ -413,35 +414,34 @@ namespace InteropEmu {
|
|||
DllExport int32_t __stdcall RunRecordedTest(char* filename)
|
||||
{
|
||||
_recordedRomTest.reset(new RecordedRomTest(_console));
|
||||
MessageManager::RegisterNotificationListener(_recordedRomTest);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
|
||||
return _recordedRomTest->Run(filename);
|
||||
}
|
||||
|
||||
DllExport int32_t __stdcall RunAutomaticTest(char* filename)
|
||||
{
|
||||
shared_ptr<AutomaticRomTest> romTest(new AutomaticRomTest());
|
||||
MessageManager::RegisterNotificationListener(romTest);
|
||||
return romTest->Run(filename);
|
||||
}
|
||||
|
||||
DllExport void __stdcall RomTestRecord(char* filename, bool reset)
|
||||
{
|
||||
_recordedRomTest.reset(new RecordedRomTest(_console));
|
||||
MessageManager::RegisterNotificationListener(_recordedRomTest);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
|
||||
_recordedRomTest->Record(filename, reset);
|
||||
}
|
||||
|
||||
DllExport void __stdcall RomTestRecordFromMovie(char* testFilename, char* movieFilename)
|
||||
{
|
||||
_recordedRomTest.reset(new RecordedRomTest(_console));
|
||||
MessageManager::RegisterNotificationListener(_recordedRomTest);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
|
||||
_recordedRomTest->RecordFromMovie(testFilename, string(movieFilename));
|
||||
}
|
||||
|
||||
DllExport void __stdcall RomTestRecordFromTest(char* newTestFilename, char* existingTestFilename)
|
||||
{
|
||||
_recordedRomTest.reset(new RecordedRomTest(_console));
|
||||
MessageManager::RegisterNotificationListener(_recordedRomTest);
|
||||
_console->GetNotificationManager()->RegisterNotificationListener(_recordedRomTest);
|
||||
_recordedRomTest->RecordFromTest(newTestFilename, existingTestFilename);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue