Merge pull request #14 from mkwong98/master

HD Pack Builder and BGM tag improvement
This commit is contained in:
NovaSquirrel 2020-12-27 22:14:15 -05:00 committed by GitHub
commit 790eb237fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 815 additions and 558 deletions

View file

@ -41,10 +41,15 @@ bool HdAudioDevice::PlayBgmTrack(uint8_t track, uint32_t startOffset)
{
int trackId = _album * 256 + track;
auto result = _hdData->BgmFilesById.find(trackId);
auto result2 = _hdData->BgmLoopPointsById.find(trackId);
if(result != _hdData->BgmFilesById.end()) {
if(_oggMixer->Play(result->second, false, startOffset, result2->second)) {
if(_oggMixer->Play(result->second.File, false, startOffset, result->second.LoopPoint)) {
_lastBgmTrack = trackId;
if (result->second.PlaybackOptions != -1) {
_oggMixer->SetPlaybackOptions(result->second.PlaybackOptions);
}
if (result->second.Volume != -1) {
_oggMixer->SetBgmVolume(result->second.Volume);
}
return true;
}
} else {

View file

@ -65,6 +65,16 @@ protected:
sprite.TileIndex = (isChrRam ? (_lastSprite->TileAddr & _chrRamIndexMask) : _lastSprite->AbsoluteTileAddr) / 16;
sprite.PaletteColors = ReadPaletteRAM(_lastSprite->PaletteOffset + 3) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 2) << 8) | (ReadPaletteRAM(_lastSprite->PaletteOffset + 1) << 16) | 0xFF000000;
sprite.IsChrRamTile = isChrRam;
sprite.BackgroundPriority = _lastSprite->BackgroundPriority;
sprite.HorizontalMirroring = _lastSprite->HorizontalMirror;
sprite.VerticalMirroring = _lastSprite->VerticalMirror;
sprite.OffsetX = (int32_t)_cycle - _lastSprite->SpriteX - 1;
if (_lastSprite->OffsetY >= 8) {
sprite.OffsetY = _lastSprite->OffsetY - 8;
}
else {
sprite.OffsetY = _lastSprite->OffsetY;
}
_console->GetMapper()->CopyChrTile(_lastSprite->AbsoluteTileAddr & 0xFFFFFFF0, sprite.TileData);
_hdPackBuilder->ProcessTile(_cycle - 1, _scanline, _lastSprite->AbsoluteTileAddr, sprite, mapper, false, _bankHashes[_lastSprite->TileAddr / _chrRamBankSize], false);
@ -77,6 +87,8 @@ protected:
tile.TileIndex = (isChrRam ? (lastTile->TileAddr & _chrRamIndexMask) : lastTile->AbsoluteTileAddr) / 16;
tile.PaletteColors = ReadPaletteRAM(lastTile->PaletteOffset + 3) | (ReadPaletteRAM(lastTile->PaletteOffset + 2) << 8) | (ReadPaletteRAM(lastTile->PaletteOffset + 1) << 16) | (ReadPaletteRAM(0) << 24);
tile.IsChrRamTile = isChrRam;
tile.OffsetX = (_state.XScroll + ((_cycle - 1) & 0x07)) & 0x07;
tile.OffsetY = lastTile->OffsetY;
_console->GetMapper()->CopyChrTile(lastTile->AbsoluteTileAddr & 0xFFFFFFF0, tile.TileData);
_hdPackBuilder->ProcessTile(_cycle - 1, _scanline, lastTile->AbsoluteTileAddr, tile, mapper, false, _bankHashes[lastTile->TileAddr / _chrRamBankSize], hasBgSprite);
@ -121,10 +133,12 @@ public:
void SendFrame()
{
if(_hdData) {
HdPpu::SendFrame();
} else {
PPU::SendFrame();
}
_hdPackBuilder->endFrame();
}
};

View file

@ -346,6 +346,14 @@ struct HdBackgroundInfo
}
};
struct HdBGMInfo {
string File;
uint32_t LoopPoint;
int16_t Volume;
int16_t PlaybackOptions;
};
struct HdPackData
{
vector<HdBackgroundInfo> Backgrounds;
@ -355,8 +363,7 @@ struct HdPackData
std::unordered_set<uint32_t> WatchedMemoryAddresses;
std::unordered_map<HdTileKey, vector<HdPackTileInfo*>> TileByKey;
std::unordered_map<string, string> PatchesByHash;
std::unordered_map<int, string> BgmFilesById;
std::unordered_map<int, uint32_t> BgmLoopPointsById;
std::unordered_map<int, HdBGMInfo> BgmFilesById;
std::unordered_map<int, string> SfxFilesById;
vector<uint32_t> Palette;
@ -381,4 +388,14 @@ enum class HdPackOptions
AlternateRegisterRange = 2,
DisableCache = 8,
DontRenderOriginalTiles = 16
};
};
struct HdScreenTileInfo : public HdTileKey
{
int16_t ScreenX;
int16_t ScreenY;
bool HorizontalMirroring;
bool VerticalMirroring;
bool BackgroundPriority;
bool IsNew;
};

View file

@ -5,6 +5,7 @@
#include "HdNesPack.h"
#include "Console.h"
#include "ConsolePauseHelper.h"
#include "VideoDecoder.h"
HdPackBuilder* HdPackBuilder::_instance = nullptr;
@ -15,6 +16,7 @@ enum HdPackRecordFlags
SortByUsageFrequency = 2,
GroupBlankTiles = 4,
IgnoreOverscan = 8,
SaveFrame = 16,
};
HdPackBuilder::HdPackBuilder(shared_ptr<Console> console, string saveFolder, ScaleFilterType filterType, uint32_t scale, uint32_t flags, uint32_t chrRamBankSize, bool isChrRam)
@ -25,7 +27,8 @@ HdPackBuilder::HdPackBuilder(shared_ptr<Console> console, string saveFolder, Sca
_chrRamBankSize = chrRamBankSize;
_flags = flags;
_isChrRam = isChrRam;
_hasNewTile = false;
_frameID = 0;
string existingPackDefinition = FolderUtilities::CombinePath(saveFolder, "hires.txt");
if(ifstream(existingPackDefinition)) {
HdPackLoader::LoadHdNesPack(existingPackDefinition, _hdData);
@ -41,18 +44,130 @@ HdPackBuilder::HdPackBuilder(shared_ptr<Console> console, string saveFolder, Sca
_hdData.Scale = scale;
}
if (_flags & (HdPackRecordFlags::SaveFrame)) {
uint32_t foundID;
vector<string> screenFiles = FolderUtilities::GetFilesInFolder(saveFolder, { ".png", ".csv" }, false);
string filePrefix = FolderUtilities::CombinePath(_saveFolder, "");
for (string path : screenFiles) {
if (path.compare(filePrefix.length(), 7, "screen_") == 0) {
foundID = std::stoi(path.substr(filePrefix.length() + 7, path.length() - filePrefix.length() - 11));
if (foundID >= _frameID) {
_frameID = foundID + 1;
}
}
}
FolderUtilities::CreateFolder(_saveFolder);
}
_romName = FolderUtilities::GetFilename(_console->GetRomInfo().RomName, false);
_instance = this;
}
HdPackBuilder::~HdPackBuilder()
{
SaveHdPack();
if(_instance == this) {
_instance = nullptr;
}
}
void HdPackBuilder::endFrame() {
if (_hasNewTile && (spritesOnScreen.size() > 0 || bgTilesOnScreen.size() > 0) && _flags & (HdPackRecordFlags::SaveFrame)) {
//generate file name suffix
string counterStr = std::to_string(_frameID);
while (counterStr.length() < 3) {
counterStr = "0" + counterStr;
}
//save screen
_console->GetVideoDecoder()->TakeScreenshot(FolderUtilities::CombinePath(_saveFolder, "screen_" + counterStr + ".png"));
//save screen info
stringstream ss;
ss << "Type,X,Y,Tile,Palette,Background Priority,Horizontal Mirroring,Vertical Mirroring,Is New," << std::endl;
stringstream ssidx;
if (_frameID == 0) {
ssidx << "Type,Tile,Palette,Screen ID," << std::endl;
}
for (HdScreenTileInfo t:spritesOnScreen) {
ss << "Sprite," << t.ScreenX << "," << t.ScreenY << ",";
if (t.IsChrRamTile) {
for (int i = 0; i < 16; i++) {
ss << HexUtilities::ToHex(t.TileData[i]);
}
}
else {
ss << HexUtilities::ToHex(t.TileIndex);
}
ss << "," << HexUtilities::ToHex(t.PaletteColors, true) << "," <<
(t.BackgroundPriority ? "Y" : "N") << "," <<
(t.HorizontalMirroring ? "Y" : "N") << "," <<
(t.VerticalMirroring ? "Y" : "N") << "," <<
(t.IsNew ? "Y" : "N") << "," << std::endl;
if (t.IsNew) {
ssidx << "Sprite,";
if (t.IsChrRamTile) {
for (int i = 0; i < 16; i++) {
ssidx << HexUtilities::ToHex(t.TileData[i]);
}
}
else {
ssidx << HexUtilities::ToHex(t.TileIndex);
}
ssidx << "," << HexUtilities::ToHex(t.PaletteColors, true) << "," << counterStr << "," << std::endl;
}
}
for (HdScreenTileInfo t : bgTilesOnScreen) {
ss << "Background," << t.ScreenX << "," << t.ScreenY << ",";
if (t.IsChrRamTile) {
for (int i = 0; i < 16; i++) {
ss << HexUtilities::ToHex(t.TileData[i]);
}
}
else {
ss << HexUtilities::ToHex(t.TileIndex);
}
ss << "," << HexUtilities::ToHex(t.PaletteColors, true) << ",,,," << (t.IsNew ? "Y" : "N") << "," << std::endl;
if (t.IsNew) {
ssidx << "Background,";
if (t.IsChrRamTile) {
for (int i = 0; i < 16; i++) {
ssidx << HexUtilities::ToHex(t.TileData[i]);
}
}
else {
ssidx << HexUtilities::ToHex(t.TileIndex);
}
ssidx << "," << HexUtilities::ToHex(t.PaletteColors, true) << "," << counterStr << "," << std::endl;
}
}
ofstream screenInfoFile(FolderUtilities::CombinePath(_saveFolder, "screen_" + counterStr + ".csv"), ios::out);
screenInfoFile << ss.str();
screenInfoFile.close();
ofstream tileIndexFile(FolderUtilities::CombinePath(_saveFolder, "tileIndex.csv"), ios::app);
tileIndexFile << ssidx.str();
tileIndexFile.close();
_frameID++;
}
//reset for next frame
_hasNewTile = false;
spritesOnScreen.clear();
bgTilesOnScreen.clear();
}
void HdPackBuilder::AddTile(HdPackTileInfo *tile, uint32_t usageCount)
{
bool isTileBlank = (_flags & HdPackRecordFlags::GroupBlankTiles) ? tile->Blank : false;
@ -93,6 +208,7 @@ void HdPackBuilder::AddTile(HdPackTileInfo *tile, uint32_t usageCount)
_tilesByKey[tile->GetKey(false)] = tile;
_tileUsageCount[tile->GetKey(false)] = usageCount;
_hasNewTile = true;
}
void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpuTileInfo &tile, BaseMapper *mapper, bool isSprite, uint32_t chrBankHash, bool transparencyRequired)
@ -110,7 +226,7 @@ void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpu
//Check to see if a default tile matches
result = _tileUsageCount.find(tile.GetKey(true));
}
bool isNew = false;
if(result == _tileUsageCount.end()) {
//First time seeing this tile/palette combination, store it
HdPackTileInfo* hdTile = new HdPackTileInfo();
@ -126,6 +242,7 @@ void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpu
_hdData.Tiles.push_back(unique_ptr<HdPackTileInfo>(hdTile));
AddTile(hdTile, 1);
isNew = true;
} else {
if(transparencyRequired) {
auto existingTile = _tilesByKey.find(tile.GetKey(false));
@ -139,6 +256,26 @@ void HdPackBuilder::ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpu
result->second++;
}
}
if ((x == 0 || ((tile.OffsetX & 0x07) == 0)) && (y == 0 || ((tile.OffsetY & 0x07) == 0))) {
HdScreenTileInfo t;
t.IsChrRamTile = tile.IsChrRamTile;
t.PaletteColors = tile.PaletteColors;
t.ScreenX = x - tile.OffsetX;
t.ScreenY = y - tile.OffsetY - (tile.IsSpriteTile() ? 1 : 0);
memcpy(t.TileData, tile.TileData, 16);
t.TileIndex = tile.TileIndex;
t.IsNew = isNew;
if (tile.IsSpriteTile()) {
t.BackgroundPriority = tile.BackgroundPriority;
t.HorizontalMirroring = tile.HorizontalMirroring;
t.VerticalMirroring = tile.VerticalMirroring;
spritesOnScreen.push_back(t);
}
else {
bgTilesOnScreen.push_back(t);
}
}
}
void HdPackBuilder::GenerateHdTile(HdPackTileInfo *tile)
@ -352,7 +489,7 @@ void HdPackBuilder::SaveHdPack()
}
for(auto &bgmInfo : _hdData.BgmFilesById) {
ss << "<bgm>" << std::to_string(bgmInfo.first >> 8) << "," << std::to_string(bgmInfo.first & 0xFF) << "," << VirtualFile(bgmInfo.second).GetFileName() << std::endl;
ss << "<bgm>" << std::to_string(bgmInfo.first >> 8) << "," << std::to_string(bgmInfo.first & 0xFF) << "," << VirtualFile(bgmInfo.second.File).GetFileName() << "," << bgmInfo.second.LoopPoint << "," << bgmInfo.second.PlaybackOptions << "," << bgmInfo.second.Volume << std::endl;
}
for(auto &sfxInfo : _hdData.SfxFilesById) {

View file

@ -31,6 +31,11 @@ private:
string _saveFolder;
string _romName;
uint32_t _flags;
bool _hasNewTile;
uint32_t _frameID;
vector<HdScreenTileInfo> spritesOnScreen;
vector<HdScreenTileInfo> bgTilesOnScreen;
//Used to group blank tiles together
uint32_t _blankTileIndex = 0;
@ -44,6 +49,7 @@ public:
HdPackBuilder(shared_ptr<Console> console, string saveFolder, ScaleFilterType filterType, uint32_t scale, uint32_t flags, uint32_t chrRamBankSize, bool isChrRam);
~HdPackBuilder();
void endFrame();
void ProcessTile(uint32_t x, uint32_t y, uint16_t tileAddr, HdPpuTileInfo& tile, BaseMapper* mapper, bool isSprite, uint32_t chrBankHash, bool transparencyRequired);
void SaveHdPack();

View file

@ -651,18 +651,30 @@ void HdPackLoader::ProcessBgmTag(vector<string> &tokens)
if(trackId >= 0) {
if(_loadFromZip) {
VirtualFile file(_hdPackFolder, tokens[2]);
_data->BgmFilesById[trackId] = file;
_data->BgmFilesById[trackId].File = file;
} else {
_data->BgmFilesById[trackId] = FolderUtilities::CombinePath(_hdPackFolder, tokens[2]);
_data->BgmFilesById[trackId].File = FolderUtilities::CombinePath(_hdPackFolder, tokens[2]);
}
_data->BgmFilesById[trackId].LoopPoint = 0;
_data->BgmFilesById[trackId].PlaybackOptions = -1;
_data->BgmFilesById[trackId].Volume = -1;
if (tokens.size() >= 4) {
stringstream pt(tokens[3]);
uint32_t loopPoint;
pt >> loopPoint;
_data->BgmLoopPointsById[trackId] = loopPoint;
}
else {
_data->BgmLoopPointsById[trackId] = 0;
_data->BgmFilesById[trackId].LoopPoint = loopPoint;
if (tokens.size() >= 5) {
stringstream pt(tokens[4]);
int16_t pbo;
pt >> pbo;
_data->BgmFilesById[trackId].PlaybackOptions = pbo;
if (tokens.size() >= 6) {
stringstream pt(tokens[5]);
int16_t vol;
pt >> vol;
_data->BgmFilesById[trackId].Volume = vol;
}
}
}
}
}

View file

@ -253,6 +253,13 @@ void VideoDecoder::TakeScreenshot()
}
}
void VideoDecoder::TakeScreenshot(string filePath)
{
if (_videoFilter) {
_videoFilter->TakeScreenshot(_videoFilterType, filePath);
}
}
void VideoDecoder::TakeScreenshot(std::stringstream &stream, bool rawScreenshot)
{
if(!_ppuOutputBuffer) {

View file

@ -61,6 +61,7 @@ public:
void DecodeFrame(bool synchronous = false);
void TakeScreenshot();
void TakeScreenshot(string filePath);
void TakeScreenshot(std::stringstream &stream, bool rawScreenshot = false);
uint32_t GetFrameCount();

View file

@ -624,6 +624,7 @@
<Control ID="chkLargeSprites">Use 8x16 sprite display mode</Control>
<Control ID="chkGroupBlankTiles">Group blank tiles</Control>
<Control ID="chkIgnoreOverscan">Ignore tiles at the edges of the screen (overscan)</Control>
<Control ID="chkSaveFrame">Save frames which the tiles are first shown</Control>
<Control ID="lblFolder">Save Folder:</Control>
<Control ID="btnSelectFolder">Browse...</Control>
<Control ID="btnStartRecording">Start Recording</Control>
@ -869,6 +870,7 @@
<Message ID="HdPackBuilderGroupBlankHelp">This option groups all the blank tiles sequentially into the same PNG&#xA;files - this helps reduce the number of PNG files produced by removing &#xA;almost-empty PNG files containing only blank tiles.</Message>
<Message ID="HdPackBuilderLargeSpritesHelp">When enabled, this option will alter the display order of CHR banks&#xA;that contain only sprites to make the sprites easier to edit in the PNG file.</Message>
<Message ID="HdPackBuilderIgnoreOverscanHelp">When enabled, this will make the builder ignore any pixels in the overscan area.&#xA;This is useful in games that contain glitches on the outer edge of the screen.&#xA;Incorrect palette combinations due to these glitches will be ignored and won't be shown in the PNG files.</Message>
<Message ID="HdPackBuilderSaveFrameHelp">When enabled, the builder will save a screenshot and the composition of the screen in the pack folder when it encounters new tile in a frame.&#xA;This is useful for checking where that tile is used.&#xA;These files are not needed in the pack and should be deleted when sharing the pack.</Message>
<Message ID="InstallHdPackWrongRom">The selected HD Pack is not compatible with the currently running game and cannot be installed.</Message>
<Message ID="InstallHdPackError">An error occurred while trying to install the HD Pack: &#xA;&#xA;{0}</Message>

File diff suppressed because it is too large Load diff

View file

@ -43,8 +43,9 @@ namespace Mesen.GUI.Forms.HdPackEditor
toolTip.SetToolTip(picGroupBlankHelp, ResourceHelper.GetMessage("HdPackBuilderGroupBlankHelp"));
toolTip.SetToolTip(picLargeSpritesHelp, ResourceHelper.GetMessage("HdPackBuilderLargeSpritesHelp"));
toolTip.SetToolTip(picIgnoreOverscanHelp, ResourceHelper.GetMessage("HdPackBuilderIgnoreOverscanHelp"));
toolTip.SetToolTip(picSaveFrameHelp, ResourceHelper.GetMessage("HdPackBuilderSaveFrameHelp"));
UpdateUI(false);
UpdateUI(false);
}
protected override void OnFormClosing(FormClosingEventArgs e)
@ -123,6 +124,8 @@ namespace Mesen.GUI.Forms.HdPackEditor
chkLargeSprites.Enabled = !isRecording;
chkSortByFrequency.Enabled = !isRecording;
chkGroupBlankTiles.Enabled = !isRecording;
chkIgnoreOverscan.Enabled = !isRecording;
chkSaveFrame.Enabled = !isRecording;
cboChrBankSize.Enabled = !isRecording;
cboScale.Enabled = !isRecording;
@ -156,7 +159,10 @@ namespace Mesen.GUI.Forms.HdPackEditor
if(chkIgnoreOverscan.Checked) {
flags |= HdPackRecordFlags.IgnoreOverscan;
}
InteropEmu.HdBuilderStartRecording(txtSaveFolder.Text, ((FilterInfo)cboScale.SelectedItem).FilterType, ((FilterInfo)cboScale.SelectedItem).Scale, flags, (UInt32)Math.Pow(2, cboChrBankSize.SelectedIndex) * 0x400);
if(chkSaveFrame.Checked) {
flags |= HdPackRecordFlags.SaveFrame;
}
InteropEmu.HdBuilderStartRecording(txtSaveFolder.Text, ((FilterInfo)cboScale.SelectedItem).FilterType, ((FilterInfo)cboScale.SelectedItem).Scale, flags, (UInt32)Math.Pow(2, cboChrBankSize.SelectedIndex) * 0x400);
tmrRefresh.Start();
UpdateUI(true);

View file

@ -121,6 +121,9 @@
<value>17, 17</value>
</metadata>
<metadata name="tmrRefresh.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
<value>107, 17</value>
<value>110, 17</value>
</metadata>
<metadata name="$this.TrayHeight" type="System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
<value>194</value>
</metadata>
</root>

View file

@ -2548,9 +2548,10 @@ namespace Mesen.GUI
SortByUsageFrequency = 2,
GroupBlankTiles = 4,
IgnoreOverscan = 8,
}
SaveFrame = 16,
}
[StructLayout(LayoutKind.Sequential)]
[StructLayout(LayoutKind.Sequential)]
public class AddressTypeInfo
{
public Int32 Address;