#pragma once #include "stdafx.h" #include #include "PPU.h" #include "../Utilities/HexUtilities.h" struct HdTileKey { static constexpr int32_t NoTile = -1; uint32_t PaletteColors; uint8_t TileData[16]; int32_t TileIndex; bool IsChrRamTile = false; HdTileKey GetKey(bool defaultKey) { if(defaultKey) { HdTileKey copy = *this; copy.PaletteColors = 0xFFFFFFFF; return copy; } else { return *this; } } uint32_t GetHashCode() const { if(IsChrRamTile) { return CalculateHash((uint8_t*)&PaletteColors, 20); } else { uint64_t key = TileIndex | ((uint64_t)PaletteColors << 32); return CalculateHash((uint8_t*)&key, sizeof(key)); } } size_t operator() (const HdTileKey &tile) const { return tile.GetHashCode(); } bool operator==(const HdTileKey &other) const { if(IsChrRamTile) { return memcmp((uint8_t*)&PaletteColors, (uint8_t*)&other.PaletteColors, 20) == 0; } else { return TileIndex == other.TileIndex && PaletteColors == other.PaletteColors; } } uint32_t CalculateHash(const uint8_t* key, size_t len) const { uint32_t result = 0; for(size_t i = 0; i < len; i += 4) { uint32_t chunk; memcpy(&chunk, key, sizeof(uint32_t)); result += chunk; result = (result << 2) | (result >> 30); key += 4; } return result; } bool IsSpriteTile() { return (PaletteColors & 0xFF000000) == 0xFF000000; } }; namespace std { template <> struct hash { size_t operator()(const HdTileKey& x) const { return x.GetHashCode(); } }; } struct HdPpuTileInfo : public HdTileKey { uint8_t OffsetX; uint8_t OffsetY; bool HorizontalMirroring; bool VerticalMirroring; bool BackgroundPriority; uint8_t BgColorIndex; uint8_t SpriteColorIndex; uint8_t BgColor; uint8_t SpriteColor; uint8_t PpuBackgroundColor; }; struct HdPpuPixelInfo { HdPpuTileInfo Tile; vector Sprite; int SpriteCount; uint16_t TmpVideoRamAddr; uint8_t XScroll; uint8_t EmphasisBits; bool Grayscale; HdPpuPixelInfo() { for(int i = 0; i < 4; i++) { Sprite.push_back(HdPpuTileInfo()); } } }; struct HdScreenInfo { HdPpuPixelInfo* ScreenTiles; std::unordered_map WatchedAddressValues; uint32_t FrameNumber; HdScreenInfo(const HdScreenInfo& that) = delete; HdScreenInfo(bool isChrRamGame) { ScreenTiles = new HdPpuPixelInfo[PPU::PixelCount]; for(int i = 0; i < PPU::PixelCount; i++) { ScreenTiles[i].Tile.BackgroundPriority = false; ScreenTiles[i].Tile.IsChrRamTile = isChrRamGame; ScreenTiles[i].Tile.HorizontalMirroring = false; ScreenTiles[i].Tile.VerticalMirroring = false; for(int j = 0; j < 4; j++) { ScreenTiles[i].Sprite[j].IsChrRamTile = isChrRamGame; } } } ~HdScreenInfo() { delete[] ScreenTiles; } }; struct HdPackCondition { string Name; virtual string GetConditionName() = 0; virtual bool IsExcludedFromFile() { return false; } virtual string ToString() = 0; virtual ~HdPackCondition() { } void ClearCache() { _resultCache = -1; } bool CheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) { if(_resultCache == -1) { bool result = InternalCheckCondition(screenInfo, x, y, tile); if(Name[0] == '!') { result = !result; } if(_useCache) { _resultCache = result ? 1 : 0; } return result; } else { return (bool)_resultCache; } } protected: int8_t _resultCache = -1; bool _useCache = false; virtual bool InternalCheckCondition(HdScreenInfo *screenInfo, int x, int y, HdPpuTileInfo* tile) = 0; }; struct HdPackTileInfo : public HdTileKey { uint32_t X; uint32_t Y; uint32_t BitmapIndex; uint8_t Brightness; bool DefaultTile; bool Blank; bool HasTransparentPixels; bool TransparencyRequired; bool IsFullyTransparent; vector HdTileData; uint32_t ChrBankId; vector Conditions; bool ForceDisableCache; bool MatchesCondition(HdScreenInfo *hdScreenInfo, int x, int y, HdPpuTileInfo* tile) { for(HdPackCondition* condition : Conditions) { if(!condition->CheckCondition(hdScreenInfo, x, y, tile)) { return false; } } return true; } vector ToRgb(uint32_t* palette) { vector rgbBuffer; for(uint8_t i = 0; i < 8; i++) { uint8_t lowByte = TileData[i]; uint8_t highByte = TileData[i + 8]; for(uint8_t j = 0; j < 8; j++) { uint8_t color = ((lowByte >> (7 - j)) & 0x01) | (((highByte >> (7 - j)) & 0x01) << 1); uint32_t rgbColor; if(IsSpriteTile() || TransparencyRequired) { rgbColor = color == 0 ? 0x00FFFFFF : palette[(PaletteColors >> ((3 - color) * 8)) & 0x3F]; } else { rgbColor = palette[(PaletteColors >> ((3 - color) * 8)) & 0x3F]; } rgbBuffer.push_back(rgbColor); } } return rgbBuffer; } void UpdateFlags() { Blank = true; HasTransparentPixels = false; IsFullyTransparent = true; for(size_t i = 0; i < HdTileData.size(); i++) { if(HdTileData[i] != HdTileData[0]) { Blank = false; } if((HdTileData[i] & 0xFF000000) != 0xFF000000) { HasTransparentPixels = true; } if(HdTileData[i] & 0xFF000000) { IsFullyTransparent = false; } } } string ToString(int pngIndex) { stringstream out; if(Conditions.size() > 0) { out << "["; for(size_t i = 0; i < Conditions.size(); i++) { if(i > 0) { out << "&"; } out << Conditions[i]->Name; } out << "]"; } if(IsChrRamTile) { out << "" << pngIndex << ","; for(int i = 0; i < 16; i++) { out << HexUtilities::ToHex(TileData[i]); } out << "," << HexUtilities::ToHex(PaletteColors, true) << "," << X << "," << Y << "," << (double)Brightness / 255 << "," << (DefaultTile ? "Y" : "N") << "," << ChrBankId << "," << TileIndex; } else { out << "" << pngIndex << "," << TileIndex << "," << HexUtilities::ToHex(PaletteColors, true) << "," << X << "," << Y << "," << (double)Brightness / 255 << "," << (DefaultTile ? "Y" : "N"); } return out.str(); } }; struct HdPackBitmapInfo { vector PixelData; uint32_t Width; uint32_t Height; }; struct HdBackgroundFileData { string PngName; uint32_t Width; uint32_t Height; vector PixelData; }; struct HdBackgroundInfo { HdBackgroundFileData* Data; uint8_t Brightness; vector Conditions; float HorizontalScrollRatio; float VerticalScrollRatio; bool BehindBgPrioritySprites; uint32_t* data() { return Data->PixelData.data(); } string ToString() { stringstream out; if(Conditions.size() > 0) { out << "["; for(size_t i = 0; i < Conditions.size(); i++) { if(i > 0) { out << "&"; } out << Conditions[i]->Name; } out << "]"; } out << Data->PngName << ","; out << (Brightness / 255.0); return out.str(); } }; struct HdPackData { vector Backgrounds; vector> BackgroundFileData; vector> Tiles; vector> Conditions; std::unordered_set WatchedMemoryAddresses; std::unordered_map> TileByKey; std::unordered_map PatchesByHash; std::unordered_map BgmFilesById; std::unordered_map SfxFilesById; vector Palette; bool HasOverscanConfig = false; OverscanDimensions Overscan; uint32_t Scale = 1; uint32_t Version = 0; uint32_t OptionFlags = 0; HdPackData() { } ~HdPackData() { } HdPackData(const HdPackData&) = delete; HdPackData& operator=(const HdPackData&) = delete; }; enum class HdPackOptions { None = 0, NoSpriteLimit = 1, AlternateRegisterRange = 2, NoContours = 4, DisableCache = 8, };