Skip to content
This repository has been archived by the owner on Oct 4, 2020. It is now read-only.

Commit

Permalink
HD Packs: Added ability to have multiple backgrounds on different lay…
Browse files Browse the repository at this point in the history
…ers (up to 40)
  • Loading branch information
SourMesen committed May 9, 2020
1 parent 193235b commit c1f841b
Show file tree
Hide file tree
Showing 6 changed files with 132 additions and 107 deletions.
4 changes: 2 additions & 2 deletions Core/HdData.h
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,8 @@ struct HdBackgroundInfo
vector<HdPackCondition*> Conditions;
float HorizontalScrollRatio;
float VerticalScrollRatio;
bool BehindBgPrioritySprites;
uint8_t Priority;

uint32_t Left;
uint32_t Top;

Expand Down Expand Up @@ -377,7 +378,6 @@ enum class HdPackOptions
None = 0,
NoSpriteLimit = 1,
AlternateRegisterRange = 2,
NoContours = 4,
DisableCache = 8,
DontRenderOriginalTiles = 16
};
157 changes: 75 additions & 82 deletions Core/HdNesPack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ void HdNesPack::DrawColor(uint32_t color, uint32_t *outputBuffer, uint32_t scale
}
}

void HdNesPack::DrawCustomBackground(uint32_t *outputBuffer, uint32_t x, uint32_t y, uint32_t scale, uint32_t screenWidth)
void HdNesPack::DrawCustomBackground(HdBackgroundInfo& bgInfo, uint32_t *outputBuffer, uint32_t x, uint32_t y, uint32_t scale, uint32_t screenWidth)
{
int brightness = _hdData->Backgrounds[_backgroundIndex].Brightness;
uint32_t left = _hdData->Backgrounds[_backgroundIndex].Left;
uint32_t top = _hdData->Backgrounds[_backgroundIndex].Top;
uint32_t width = _hdData->Backgrounds[_backgroundIndex].Data->Width;
uint32_t *pngData = _hdData->Backgrounds[_backgroundIndex].data() + ((top + y) * _hdData->Scale * width) + ((left + x) * _hdData->Scale);
int brightness = bgInfo.Brightness;
uint32_t left = bgInfo.Left;
uint32_t top = bgInfo.Top;
uint32_t width = bgInfo.Data->Width;
uint32_t *pngData = bgInfo.data() + ((top + y) * _hdData->Scale * width) + ((left + x) * _hdData->Scale);
uint32_t pixelColor;

for(uint32_t i = 0; i < scale; i++) {
Expand Down Expand Up @@ -145,32 +145,37 @@ uint32_t HdNesPack::GetScale()
return _hdData->Scale;
}

void HdNesPack::OnLineStart(HdPpuPixelInfo &lineFirstPixel)
void HdNesPack::OnLineStart(HdPpuPixelInfo &lineFirstPixel, uint8_t y)
{
_scrollX = ((lineFirstPixel.TmpVideoRamAddr & 0x1F) << 3) | lineFirstPixel.XScroll | ((lineFirstPixel.TmpVideoRamAddr & 0x400) ? 0x100 : 0);
_useCachedTile = false;

if(_backgroundIndex >= 0) {
int32_t scrollY = (((lineFirstPixel.TmpVideoRamAddr & 0x3E0) >> 2) | ((lineFirstPixel.TmpVideoRamAddr & 0x7000) >> 12)) + ((lineFirstPixel.TmpVideoRamAddr & 0x800) ? 240 : 0);
HdBackgroundInfo &bgInfo = _hdData->Backgrounds[_backgroundIndex];

_bgScrollX = (int32_t)(_scrollX * bgInfo.HorizontalScrollRatio);
_bgScrollY = (int32_t)(scrollY * bgInfo.VerticalScrollRatio);
int32_t scrollY = (((lineFirstPixel.TmpVideoRamAddr & 0x3E0) >> 2) | ((lineFirstPixel.TmpVideoRamAddr & 0x7000) >> 12)) + ((lineFirstPixel.TmpVideoRamAddr & 0x800) ? 240 : 0);

for(int layer = 0; layer < 4; layer++) {
for(int i = 0; i < _activeBgCount[layer]; i++) {
HdBgConfig& cfg = _bgConfig[layer * HdNesPack::PriorityLevelsPerLayer + i];
HdBackgroundInfo& bgInfo = _hdData->Backgrounds[cfg.BackgroundIndex];
cfg.BgScrollX = (int32_t)(_scrollX * bgInfo.HorizontalScrollRatio);
cfg.BgScrollY = (int32_t)(scrollY * bgInfo.VerticalScrollRatio);
if(y >= -cfg.BgScrollY && (y + bgInfo.Top + cfg.BgScrollY + 1) * _hdData->Scale <= bgInfo.Data->Height) {
cfg.BgMinX = -cfg.BgScrollX;
cfg.BgMaxX = bgInfo.Data->Width / _hdData->Scale - bgInfo.Left - cfg.BgScrollX - 1;
} else {
cfg.BgMinX = -1;
cfg.BgMaxX = -1;
}
}
}
}

void HdNesPack::OnBeforeApplyFilter()
int32_t HdNesPack::GetLayerIndex(uint8_t priority)
{
_palette = _hdData->Palette.size() == 0x40 ? _hdData->Palette.data() : _settings->GetRgbPalette();
_contoursEnabled = (_hdData->OptionFlags & (int)HdPackOptions::NoContours) == 0;
_cacheEnabled = (_hdData->OptionFlags & (int)HdPackOptions::DisableCache) == 0;

if(_hdData->OptionFlags & (int)HdPackOptions::NoSpriteLimit) {
_settings->SetFlags(EmulationFlags::RemoveSpriteLimit | EmulationFlags::AdaptiveSpriteLimit);
}

_backgroundIndex = -1;
for(size_t i = 0; i < _hdData->Backgrounds.size(); i++) {
if(_hdData->Backgrounds[i].Priority != priority) {
continue;
}

bool isMatch = true;
for(HdPackCondition* condition : _hdData->Backgrounds[i].Conditions) {
if(!condition->CheckCondition(_hdScreenInfo, 0, 0, nullptr)) {
Expand All @@ -180,10 +185,32 @@ void HdNesPack::OnBeforeApplyFilter()
}

if(isMatch) {
_backgroundIndex = (int32_t)i;
break;
return (int32_t)i;
}
}
return -1;
}

void HdNesPack::OnBeforeApplyFilter()
{
_palette = _hdData->Palette.size() == 0x40 ? _hdData->Palette.data() : _settings->GetRgbPalette();
_cacheEnabled = (_hdData->OptionFlags & (int)HdPackOptions::DisableCache) == 0;

if(_hdData->OptionFlags & (int)HdPackOptions::NoSpriteLimit) {
_settings->SetFlags(EmulationFlags::RemoveSpriteLimit | EmulationFlags::AdaptiveSpriteLimit);
}

for(int layer = 0; layer < 4; layer++) {
uint32_t activeCount = 0;
for(int i = 0; i < HdNesPack::PriorityLevelsPerLayer; i++) {
int32_t index = GetLayerIndex(layer * HdNesPack::PriorityLevelsPerLayer + i);
if(index >= 0) {
_bgConfig[layer*10+activeCount].BackgroundIndex = index;
activeCount++;
}
}
_activeBgCount[layer] = activeCount;
}

for(unique_ptr<HdPackCondition> &condition : _hdData->Conditions) {
condition->ClearCache();
Expand Down Expand Up @@ -235,39 +262,15 @@ HdPackTileInfo* HdNesPack::GetMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo
return nullptr;
}

bool HdNesPack::IsNextToSprite(uint32_t x, uint32_t y)
bool HdNesPack::DrawBackgroundLayer(uint8_t priority, uint32_t x, uint32_t y, uint32_t* outputBuffer, uint32_t screenWidth)
{
bool hasNonBackgroundSurrounding = false;
auto processAdjacentTile = [&hasNonBackgroundSurrounding](HdPpuPixelInfo& pixelInfo) {
if(pixelInfo.Tile.BgColorIndex != 0) {
hasNonBackgroundSurrounding = true;
} else {
for(int i = 0; i < pixelInfo.SpriteCount; i++) {
if(pixelInfo.Sprite[i].SpriteColorIndex == 0 || pixelInfo.Sprite[i].SpriteColor != pixelInfo.Sprite[i].BgColor) {
hasNonBackgroundSurrounding |= pixelInfo.Sprite[i].TileIndex != HdPpuTileInfo::NoTile && pixelInfo.Sprite[i].SpriteColorIndex != 0;
}
if(hasNonBackgroundSurrounding) {
break;
}
}
}
};
for(int i = -1; i <= 1; i++) {
if((int)y + i < 0 || y + i >= PPU::ScreenHeight) {
continue;
}

for(int j = -1; j <= 1; j++) {
if((int)x + j < 0 || x + j >= PPU::ScreenWidth) {
continue;
}

if(!hasNonBackgroundSurrounding) {
processAdjacentTile(_hdScreenInfo->ScreenTiles[(i + y) * 256 + j + x]);
}
}
HdBgConfig bgConfig = _bgConfig[(int)priority];
if((int32_t)x >= bgConfig.BgMinX && (int32_t)x <= bgConfig.BgMaxX) {
HdBackgroundInfo& bgInfo = _hdData->Backgrounds[bgConfig.BackgroundIndex];
DrawCustomBackground(bgInfo, outputBuffer, x + bgConfig.BgScrollX, y + bgConfig.BgScrollY, _hdData->Scale, screenWidth);
return true;
}
return hasNonBackgroundSurrounding;
return false;
}

void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uint32_t *outputBuffer, uint32_t screenWidth)
Expand All @@ -285,26 +288,9 @@ void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uin

DrawColor(_palette[pixelInfo.Tile.PpuBackgroundColor], outputBuffer, _hdData->Scale, screenWidth);

bool hasCustomBackground = false;
bool hasNonBackgroundSurrounding = false;
bool backgroundBehindBgSprites = false;
if(_backgroundIndex >= 0) {
HdBackgroundInfo &bgInfo = _hdData->Backgrounds[_backgroundIndex];

//Enable custom background if the current pixel fits within the background's boundaries
hasCustomBackground =
(int32_t)x >= -_bgScrollX &&
(int32_t)y >= -_bgScrollY &&
(y + bgInfo.Top + _bgScrollY + 1) * _hdData->Scale <= bgInfo.Data->Height &&
(x + bgInfo.Left + _bgScrollX + 1) * _hdData->Scale <= bgInfo.Data->Width;

if(hasCustomBackground) {
hasNonBackgroundSurrounding = _contoursEnabled && IsNextToSprite(x, y);
if(bgInfo.BehindBgPrioritySprites) {
DrawCustomBackground(outputBuffer, x + _bgScrollX, y + _bgScrollY, _hdData->Scale, screenWidth);
backgroundBehindBgSprites = true;
}
}
bool hasBackground = false;
for(int i = 0; i < _activeBgCount[0]; i++) {
hasBackground |= DrawBackgroundLayer(HdNesPack::BehindBgSpritesPriority+i, x, y, outputBuffer, screenWidth);
}

if(hasSprite) {
Expand All @@ -324,20 +310,23 @@ void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uin
}
}

if (hasCustomBackground && !backgroundBehindBgSprites) {
DrawCustomBackground(outputBuffer, x + _bgScrollX, y + _bgScrollY, _hdData->Scale, screenWidth);
for(int i = 0; i < _activeBgCount[1]; i++) {
hasBackground |= DrawBackgroundLayer(HdNesPack::BehindBgPriority+i, x, y, outputBuffer, screenWidth);
}

if(hdPackTileInfo) {
DrawTile(pixelInfo.Tile, *hdPackTileInfo, outputBuffer, screenWidth);
} else if(renderOriginalTiles) {
//Draw regular SD background tile
bool useCustomBackground = !hasNonBackgroundSurrounding && hasCustomBackground && pixelInfo.Tile.BgColorIndex == 0;
if(!useCustomBackground && (pixelInfo.Tile.BgColorIndex != 0 || hasNonBackgroundSurrounding)) {
if(!hasBackground || pixelInfo.Tile.BgColorIndex != 0) {
DrawColor(_palette[pixelInfo.Tile.BgColor], outputBuffer, _hdData->Scale, screenWidth);
}
}

for(int i = 0; i < _activeBgCount[2]; i++) {
DrawBackgroundLayer(HdNesPack::BehindFgSpritesPriority+i, x, y, outputBuffer, screenWidth);
}

if(hasSprite) {
for(int k = pixelInfo.SpriteCount - 1; k >= 0; k--) {
if(!pixelInfo.Sprite[k].BackgroundPriority && lowestBgSprite > k) {
Expand All @@ -350,6 +339,10 @@ void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uin
}
}
}

for(int i = 0; i < _activeBgCount[3]; i++) {
DrawBackgroundLayer(HdNesPack::ForegroundPriority+i, x, y, outputBuffer, screenWidth);
}
}

void HdNesPack::Process(HdScreenInfo *hdScreenInfo, uint32_t* outputBuffer, OverscanDimensions &overscan)
Expand All @@ -360,7 +353,7 @@ void HdNesPack::Process(HdScreenInfo *hdScreenInfo, uint32_t* outputBuffer, Over

OnBeforeApplyFilter();
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
OnLineStart(hdScreenInfo->ScreenTiles[i << 8]);
OnLineStart(hdScreenInfo->ScreenTiles[i << 8], i);
uint32_t bufferIndex = (i - overscan.Top) * screenWidth * hdScale;
uint32_t lineStartIndex = bufferIndex;
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
Expand Down
31 changes: 23 additions & 8 deletions Core/HdNesPack.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,33 @@ class EmulationSettings;
class HdNesPack
{
private:
struct HdBgConfig
{
int32_t BackgroundIndex = -1;
int32_t BgScrollX = 0;
int32_t BgScrollY = 0;
int16_t BgMinX = -1;
int16_t BgMaxX = -1;
};

shared_ptr<HdPackData> _hdData;
EmulationSettings *_settings;

int32_t _backgroundIndex = -1;
static constexpr uint8_t PriorityLevelsPerLayer = 10;
static constexpr uint8_t BehindBgSpritesPriority = 0 * PriorityLevelsPerLayer;
static constexpr uint8_t BehindBgPriority = 1 * PriorityLevelsPerLayer;
static constexpr uint8_t BehindFgSpritesPriority = 2 * PriorityLevelsPerLayer;
static constexpr uint8_t ForegroundPriority = 3 * PriorityLevelsPerLayer;

uint8_t _activeBgCount[4] = {};
HdBgConfig _bgConfig[40] = {};

HdScreenInfo *_hdScreenInfo = nullptr;
uint32_t* _palette = nullptr;
bool _contoursEnabled = false;
HdPackTileInfo* _cachedTile = nullptr;
bool _cacheEnabled = false;
bool _useCachedTile = false;
int32_t _scrollX = 0;
int32_t _bgScrollX = 0;
int32_t _bgScrollY = 0;

__forceinline void BlendColors(uint8_t output[4], uint8_t input[4]);
__forceinline uint32_t AdjustBrightness(uint8_t input[4], int brightness);
Expand All @@ -29,16 +43,17 @@ class HdNesPack
__forceinline HdPackTileInfo* GetCachedMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo* tile);
__forceinline HdPackTileInfo* GetMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo* tile, bool* disableCache = nullptr);

__forceinline bool IsNextToSprite(uint32_t x, uint32_t y);
__forceinline void DrawCustomBackground(uint32_t *outputBuffer, uint32_t x, uint32_t y, uint32_t scale, uint32_t screenWidth);
__forceinline bool DrawBackgroundLayer(uint8_t priority, uint32_t x, uint32_t y, uint32_t* outputBuffer, uint32_t screenWidth);
__forceinline void DrawCustomBackground(HdBackgroundInfo& bgInfo, uint32_t *outputBuffer, uint32_t x, uint32_t y, uint32_t scale, uint32_t screenWidth);

void OnLineStart(HdPpuPixelInfo &lineFirstPixel);
void OnLineStart(HdPpuPixelInfo &lineFirstPixel, uint8_t y);
int32_t GetLayerIndex(uint8_t priority);
void OnBeforeApplyFilter();
__forceinline void GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uint32_t *outputBuffer, uint32_t screenWidth);
__forceinline void ProcessGrayscaleAndEmphasis(HdPpuPixelInfo &pixelInfo, uint32_t* outputBuffer, uint32_t hdScreenWidth);

public:
static constexpr uint32_t CurrentVersion = 105;
static constexpr uint32_t CurrentVersion = 106;

HdNesPack(shared_ptr<HdPackData> hdData, EmulationSettings* settings);
~HdNesPack();
Expand Down
3 changes: 0 additions & 3 deletions Core/HdPackBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -371,9 +371,6 @@ void HdPackBuilder::SaveHdPack()
if(_hdData.OptionFlags & (int)HdPackOptions::AlternateRegisterRange) {
ss << "alternateRegisterRange,";
}
if(_hdData.OptionFlags & (int)HdPackOptions::NoContours) {
ss << "disableContours,";
}
if(_hdData.OptionFlags & (int)HdPackOptions::DisableCache) {
ss << "disableCache,";
}
Expand Down
11 changes: 7 additions & 4 deletions Core/HdPackLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -392,8 +392,6 @@ void HdPackLoader::ProcessOptionTag(vector<string> &tokens)
_data->OptionFlags |= (int)HdPackOptions::NoSpriteLimit;
} else if(token == "alternateRegisterRange") {
_data->OptionFlags |= (int)HdPackOptions::AlternateRegisterRange;
} else if(token == "disableContours") {
_data->OptionFlags |= (int)HdPackOptions::NoContours;
} else if(token == "disableCache") {
_data->OptionFlags |= (int)HdPackOptions::DisableCache;
} else if(token == "disableOriginalTiles") {
Expand Down Expand Up @@ -577,7 +575,7 @@ void HdPackLoader::ProcessBackgroundTag(vector<string> &tokens, vector<HdPackCon
}
backgroundInfo.HorizontalScrollRatio = 0;
backgroundInfo.VerticalScrollRatio = 0;
backgroundInfo.BehindBgPrioritySprites = false;
backgroundInfo.Priority = 10;
backgroundInfo.Left = 0;
backgroundInfo.Top = 0;

Expand Down Expand Up @@ -605,7 +603,12 @@ void HdPackLoader::ProcessBackgroundTag(vector<string> &tokens, vector<HdPackCon
}
if(tokens.size() > 4) {
checkConstraint(_data->Version >= 102, "[HDPack] This feature requires version 102+ of HD Packs");
backgroundInfo.BehindBgPrioritySprites = tokens[4] == "Y";
if(_data->Version >= 106) {
backgroundInfo.Priority = std::stoi(tokens[4]);
checkConstraint(backgroundInfo.Priority >= 0 && backgroundInfo.Priority < 40, "[HDPack] Invalid background priority value");
} else {
backgroundInfo.Priority = tokens[4] == "Y" ? 0 : 10;
}
}
if(tokens.size() > 6) {
checkConstraint(_data->Version >= 105, "[HDPack] This feature requires version 105+ of HD Packs");
Expand Down
Loading

0 comments on commit c1f841b

Please sign in to comment.