Mesen/Core/HdData.h

383 lines
7.7 KiB
C++

#pragma once
#include "stdafx.h"
#include <unordered_set>
#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<HdTileKey>
{
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<HdPpuTileInfo> 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<uint32_t, uint8_t> 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 Name.size() > 0 && Name[0] == '!'; }
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;
int Brightness;
bool DefaultTile;
bool Blank;
bool HasTransparentPixels;
bool TransparencyRequired;
bool IsFullyTransparent;
vector<uint32_t> HdTileData;
uint32_t ChrBankId;
vector<HdPackCondition*> 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<uint32_t> ToRgb(uint32_t* palette)
{
vector<uint32_t> 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 << "<tile>" << 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 << "<tile>" <<
pngIndex << "," <<
HexUtilities::ToHex(TileIndex) << "," <<
HexUtilities::ToHex(PaletteColors, true) << "," <<
X << "," <<
Y << "," <<
(double)Brightness / 255 << "," <<
(DefaultTile ? "Y" : "N");
}
return out.str();
}
};
struct HdPackBitmapInfo
{
vector<uint32_t> PixelData;
uint32_t Width;
uint32_t Height;
};
struct HdBackgroundFileData
{
string PngName;
uint32_t Width;
uint32_t Height;
vector<uint32_t> PixelData;
};
struct HdBackgroundInfo
{
HdBackgroundFileData* Data;
int Brightness;
vector<HdPackCondition*> Conditions;
float HorizontalScrollRatio;
float VerticalScrollRatio;
uint8_t Priority;
uint32_t Left;
uint32_t Top;
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 << "<background>";
out << Data->PngName << ",";
out << (Brightness / 255.0);
return out.str();
}
};
struct HdPackData
{
vector<HdBackgroundInfo> Backgrounds;
vector<unique_ptr<HdBackgroundFileData>> BackgroundFileData;
vector<unique_ptr<HdPackTileInfo>> Tiles;
vector<unique_ptr<HdPackCondition>> Conditions;
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, string> SfxFilesById;
vector<uint32_t> 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,
DisableCache = 8,
DontRenderOriginalTiles = 16
};