2017-06-28 19:00:08 -04:00
|
|
|
#include "stdafx.h"
|
|
|
|
#include <algorithm>
|
|
|
|
#include <unordered_map>
|
|
|
|
#include "HdNesPack.h"
|
|
|
|
#include "Console.h"
|
|
|
|
#include "MessageManager.h"
|
|
|
|
#include "EmulationSettings.h"
|
|
|
|
#include "HdPackLoader.h"
|
|
|
|
#include "../Utilities/FolderUtilities.h"
|
|
|
|
#include "../Utilities/PNGHelper.h"
|
|
|
|
|
2018-07-13 22:19:26 -04:00
|
|
|
HdNesPack::HdNesPack(shared_ptr<HdPackData> hdData, EmulationSettings* settings)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
_hdData = hdData;
|
2018-07-13 22:19:26 -04:00
|
|
|
_settings = settings;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
HdNesPack::~HdNesPack()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdNesPack::BlendColors(uint8_t output[4], uint8_t input[4])
|
|
|
|
{
|
|
|
|
uint8_t invertedAlpha = 256 - input[3];
|
2020-02-01 09:52:49 -05:00
|
|
|
output[0] = input[0] + (uint8_t)((invertedAlpha * output[0]) >> 8);
|
|
|
|
output[1] = input[1] + (uint8_t)((invertedAlpha * output[1]) >> 8);
|
|
|
|
output[2] = input[2] + (uint8_t)((invertedAlpha * output[2]) >> 8);
|
2017-06-28 19:00:08 -04:00
|
|
|
output[3] = 0xFF;
|
|
|
|
}
|
|
|
|
|
2019-12-20 13:53:13 -05:00
|
|
|
uint32_t HdNesPack::AdjustBrightness(uint8_t input[4], int brightness)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2018-03-24 11:22:43 -04:00
|
|
|
return (
|
2019-12-20 13:53:13 -05:00
|
|
|
std::min(255, (brightness * ((int)input[0] + 1)) >> 8) |
|
|
|
|
(std::min(255, (brightness * ((int)input[1] + 1)) >> 8) << 8) |
|
|
|
|
(std::min(255, (brightness * ((int)input[2] + 1)) >> 8) << 16) |
|
2018-03-24 11:22:43 -04:00
|
|
|
(input[3] << 24)
|
|
|
|
);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2017-07-25 19:46:25 -04:00
|
|
|
void HdNesPack::DrawColor(uint32_t color, uint32_t *outputBuffer, uint32_t scale, uint32_t screenWidth)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2017-07-25 19:46:25 -04:00
|
|
|
if(scale == 1) {
|
|
|
|
*outputBuffer = color;
|
|
|
|
} else {
|
|
|
|
for(uint32_t i = 0; i < scale; i++) {
|
|
|
|
std::fill(outputBuffer, outputBuffer + scale, color);
|
|
|
|
outputBuffer += screenWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdNesPack::DrawCustomBackground(uint32_t *outputBuffer, uint32_t x, uint32_t y, uint32_t scale, uint32_t screenWidth)
|
|
|
|
{
|
2019-12-20 13:53:13 -05:00
|
|
|
int brightness = _hdData->Backgrounds[_backgroundIndex].Brightness;
|
|
|
|
uint32_t left = _hdData->Backgrounds[_backgroundIndex].Left;
|
|
|
|
uint32_t top = _hdData->Backgrounds[_backgroundIndex].Top;
|
2018-07-01 15:21:05 -04:00
|
|
|
uint32_t width = _hdData->Backgrounds[_backgroundIndex].Data->Width;
|
2019-12-20 13:53:13 -05:00
|
|
|
uint32_t *pngData = _hdData->Backgrounds[_backgroundIndex].data() + ((top + y) * _hdData->Scale * width) + ((left + x) * _hdData->Scale);
|
2020-02-01 09:52:49 -05:00
|
|
|
uint32_t pixelColor;
|
2018-02-17 23:44:25 -05:00
|
|
|
|
2020-02-01 09:52:49 -05:00
|
|
|
for(uint32_t i = 0; i < scale; i++) {
|
|
|
|
for(uint32_t j = 0; j < scale; j++) {
|
|
|
|
if(brightness == 255) {
|
|
|
|
pixelColor = *pngData;
|
|
|
|
} else {
|
|
|
|
pixelColor = AdjustBrightness((uint8_t*)pngData, brightness);
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
|
2020-02-01 09:52:49 -05:00
|
|
|
if(((uint8_t*)pngData)[3] == 0xFF) {
|
|
|
|
*outputBuffer = pixelColor;
|
|
|
|
} else if(((uint8_t*)pngData)[3]) {
|
|
|
|
BlendColors((uint8_t*)outputBuffer, (uint8_t*)(&pixelColor));
|
2017-07-25 19:46:25 -04:00
|
|
|
}
|
2020-02-01 09:52:49 -05:00
|
|
|
|
|
|
|
outputBuffer++;
|
|
|
|
pngData++;
|
2017-07-25 19:46:25 -04:00
|
|
|
}
|
2020-02-01 09:52:49 -05:00
|
|
|
outputBuffer += screenWidth - scale;
|
|
|
|
pngData += width - scale;
|
2017-07-25 19:46:25 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-08-15 19:18:00 -04:00
|
|
|
void HdNesPack::DrawTile(HdPpuTileInfo &tileInfo, HdPackTileInfo &hdPackTileInfo, uint32_t *outputBuffer, uint32_t screenWidth)
|
2017-07-25 19:46:25 -04:00
|
|
|
{
|
2017-08-15 19:18:00 -04:00
|
|
|
if(hdPackTileInfo.IsFullyTransparent) {
|
|
|
|
return;
|
2017-07-25 19:46:25 -04:00
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
uint32_t scale = GetScale();
|
|
|
|
uint32_t *bitmapData = hdPackTileInfo.HdTileData.data();
|
|
|
|
uint32_t tileWidth = 8 * scale;
|
|
|
|
uint8_t tileOffsetX = tileInfo.HorizontalMirroring ? 7 - tileInfo.OffsetX : tileInfo.OffsetX;
|
|
|
|
uint32_t bitmapOffset = (tileInfo.OffsetY * scale) * tileWidth + tileOffsetX * scale;
|
|
|
|
int32_t bitmapSmallInc = 1;
|
|
|
|
int32_t bitmapLargeInc = tileWidth - scale;
|
|
|
|
if(tileInfo.HorizontalMirroring) {
|
|
|
|
bitmapOffset += scale - 1;
|
|
|
|
bitmapSmallInc = -1;
|
|
|
|
bitmapLargeInc = tileWidth + scale;
|
|
|
|
}
|
|
|
|
if(tileInfo.VerticalMirroring) {
|
|
|
|
bitmapOffset += tileWidth * (scale - 1);
|
|
|
|
bitmapLargeInc = (tileInfo.HorizontalMirroring ? (int32_t)scale : -(int32_t)scale) - (int32_t)tileWidth;
|
|
|
|
}
|
2017-07-25 19:46:25 -04:00
|
|
|
|
|
|
|
uint32_t rgbValue;
|
2019-12-20 13:53:13 -05:00
|
|
|
if(hdPackTileInfo.HasTransparentPixels || hdPackTileInfo.Brightness != 255) {
|
2017-07-25 19:46:25 -04:00
|
|
|
for(uint32_t y = 0; y < scale; y++) {
|
|
|
|
for(uint32_t x = 0; x < scale; x++) {
|
|
|
|
if(hdPackTileInfo.Brightness == 255) {
|
|
|
|
rgbValue = *(bitmapData + bitmapOffset);
|
|
|
|
} else {
|
|
|
|
rgbValue = AdjustBrightness((uint8_t*)(bitmapData + bitmapOffset), hdPackTileInfo.Brightness);
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!hdPackTileInfo.HasTransparentPixels || (bitmapData[bitmapOffset] & 0xFF000000) == 0xFF000000) {
|
2017-06-28 19:00:08 -04:00
|
|
|
*outputBuffer = rgbValue;
|
2017-07-25 19:46:25 -04:00
|
|
|
} else {
|
|
|
|
if(bitmapData[bitmapOffset] & 0xFF000000) {
|
|
|
|
BlendColors((uint8_t*)outputBuffer, (uint8_t*)&rgbValue);
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2017-07-25 19:46:25 -04:00
|
|
|
outputBuffer++;
|
|
|
|
bitmapOffset += bitmapSmallInc;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2017-07-25 19:46:25 -04:00
|
|
|
bitmapOffset += bitmapLargeInc;
|
|
|
|
outputBuffer += screenWidth - scale;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2017-07-25 19:46:25 -04:00
|
|
|
} else {
|
|
|
|
for(uint32_t y = 0; y < scale; y++) {
|
|
|
|
for(uint32_t x = 0; x < scale; x++) {
|
|
|
|
*outputBuffer = *(bitmapData + bitmapOffset);
|
|
|
|
outputBuffer++;
|
|
|
|
bitmapOffset += bitmapSmallInc;
|
|
|
|
}
|
|
|
|
bitmapOffset += bitmapLargeInc;
|
|
|
|
outputBuffer += screenWidth - scale;
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t HdNesPack::GetScale()
|
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
return _hdData->Scale;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
void HdNesPack::OnLineStart(HdPpuPixelInfo &lineFirstPixel)
|
|
|
|
{
|
|
|
|
_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);
|
2018-07-01 15:21:05 -04:00
|
|
|
HdBackgroundInfo &bgInfo = _hdData->Backgrounds[_backgroundIndex];
|
2018-02-17 23:44:25 -05:00
|
|
|
|
|
|
|
_bgScrollX = (int32_t)(_scrollX * bgInfo.HorizontalScrollRatio);
|
|
|
|
_bgScrollY = (int32_t)(scrollY * bgInfo.VerticalScrollRatio);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdNesPack::OnBeforeApplyFilter()
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2018-07-13 22:19:26 -04:00
|
|
|
_palette = _hdData->Palette.size() == 0x40 ? _hdData->Palette.data() : _settings->GetRgbPalette();
|
2018-07-01 15:21:05 -04:00
|
|
|
_contoursEnabled = (_hdData->OptionFlags & (int)HdPackOptions::NoContours) == 0;
|
|
|
|
_cacheEnabled = (_hdData->OptionFlags & (int)HdPackOptions::DisableCache) == 0;
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
if(_hdData->OptionFlags & (int)HdPackOptions::NoSpriteLimit) {
|
2018-07-13 22:19:26 -04:00
|
|
|
_settings->SetFlags(EmulationFlags::RemoveSpriteLimit | EmulationFlags::AdaptiveSpriteLimit);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
_backgroundIndex = -1;
|
2018-07-01 15:21:05 -04:00
|
|
|
for(size_t i = 0; i < _hdData->Backgrounds.size(); i++) {
|
2017-06-28 19:00:08 -04:00
|
|
|
bool isMatch = true;
|
2018-07-01 15:21:05 -04:00
|
|
|
for(HdPackCondition* condition : _hdData->Backgrounds[i].Conditions) {
|
2018-02-17 23:44:25 -05:00
|
|
|
if(!condition->CheckCondition(_hdScreenInfo, 0, 0, nullptr)) {
|
2017-06-28 19:00:08 -04:00
|
|
|
isMatch = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(isMatch) {
|
2017-07-25 19:46:25 -04:00
|
|
|
_backgroundIndex = (int32_t)i;
|
2017-06-28 19:00:08 -04:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
for(unique_ptr<HdPackCondition> &condition : _hdData->Conditions) {
|
2018-02-17 23:44:25 -05:00
|
|
|
condition->ClearCache();
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
HdPackTileInfo* HdNesPack::GetCachedMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo* tile)
|
|
|
|
{
|
|
|
|
if(((_scrollX + x) & 0x07) == 0) {
|
|
|
|
_useCachedTile = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool disableCache = false;
|
|
|
|
HdPackTileInfo* hdPackTileInfo;
|
|
|
|
if(_useCachedTile) {
|
|
|
|
hdPackTileInfo = _cachedTile;
|
|
|
|
} else {
|
|
|
|
hdPackTileInfo = GetMatchingTile(x, y, tile, &disableCache);
|
|
|
|
|
|
|
|
if(!disableCache && _cacheEnabled) {
|
|
|
|
//Use this tile for the next 8 horizontal pixels
|
|
|
|
//Disable cache if a sprite condition is used, because sprites are not on a 8x8 grid
|
|
|
|
_cachedTile = hdPackTileInfo;
|
|
|
|
_useCachedTile = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hdPackTileInfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
HdPackTileInfo* HdNesPack::GetMatchingTile(uint32_t x, uint32_t y, HdPpuTileInfo* tile, bool* disableCache)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
2018-07-01 15:21:05 -04:00
|
|
|
auto hdTile = _hdData->TileByKey.find(*tile);
|
|
|
|
if(hdTile == _hdData->TileByKey.end()) {
|
|
|
|
hdTile = _hdData->TileByKey.find(tile->GetKey(true));
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
if(hdTile != _hdData->TileByKey.end()) {
|
2017-08-30 19:36:20 -04:00
|
|
|
for(HdPackTileInfo* hdPackTile : hdTile->second) {
|
2018-02-17 23:44:25 -05:00
|
|
|
if(disableCache != nullptr && hdPackTile->ForceDisableCache) {
|
|
|
|
*disableCache = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(hdPackTile->MatchesCondition(_hdScreenInfo, x, y, tile)) {
|
2017-08-30 19:36:20 -04:00
|
|
|
return hdPackTile;
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
bool HdNesPack::IsNextToSprite(uint32_t x, uint32_t y)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
|
|
|
bool hasNonBackgroundSurrounding = false;
|
|
|
|
auto processAdjacentTile = [&hasNonBackgroundSurrounding](HdPpuPixelInfo& pixelInfo) {
|
2017-07-25 19:46:25 -04:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
for(int i = -1; i <= 1; i++) {
|
2017-08-30 19:36:20 -04:00
|
|
|
if((int)y + i < 0 || y + i >= PPU::ScreenHeight) {
|
2017-08-15 19:18:00 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
for(int j = -1; j <= 1; j++) {
|
2017-08-30 19:36:20 -04:00
|
|
|
if((int)x + j < 0 || x + j >= PPU::ScreenWidth) {
|
2017-08-15 19:18:00 -04:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
if(!hasNonBackgroundSurrounding) {
|
2018-02-17 23:44:25 -05:00
|
|
|
processAdjacentTile(_hdScreenInfo->ScreenTiles[(i + y) * 256 + j + x]);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return hasNonBackgroundSurrounding;
|
|
|
|
}
|
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
void HdNesPack::GetPixels(uint32_t x, uint32_t y, HdPpuPixelInfo &pixelInfo, uint32_t *outputBuffer, uint32_t screenWidth)
|
2017-06-28 19:00:08 -04:00
|
|
|
{
|
|
|
|
HdPackTileInfo *hdPackTileInfo = nullptr;
|
|
|
|
HdPackTileInfo *hdPackSpriteInfo = nullptr;
|
|
|
|
|
2017-07-25 19:46:25 -04:00
|
|
|
bool hasSprite = pixelInfo.SpriteCount > 0;
|
2019-12-20 13:53:13 -05:00
|
|
|
bool renderOriginalTiles = ((_hdData->OptionFlags & (int)HdPackOptions::DontRenderOriginalTiles) == 0);
|
2017-07-25 19:46:25 -04:00
|
|
|
if(pixelInfo.Tile.TileIndex != HdPpuTileInfo::NoTile) {
|
2018-02-17 23:44:25 -05:00
|
|
|
hdPackTileInfo = GetCachedMatchingTile(x, y, &pixelInfo.Tile);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2017-07-25 19:46:25 -04:00
|
|
|
int lowestBgSprite = 999;
|
2017-08-15 19:18:00 -04:00
|
|
|
|
2018-07-01 15:21:05 -04:00
|
|
|
DrawColor(_palette[pixelInfo.Tile.PpuBackgroundColor], outputBuffer, _hdData->Scale, screenWidth);
|
2017-08-15 19:18:00 -04:00
|
|
|
|
2018-06-19 22:17:00 -04:00
|
|
|
bool hasCustomBackground = false;
|
|
|
|
bool hasNonBackgroundSurrounding = false;
|
|
|
|
bool backgroundBehindBgSprites = false;
|
|
|
|
if(_backgroundIndex >= 0) {
|
2018-07-01 15:21:05 -04:00
|
|
|
HdBackgroundInfo &bgInfo = _hdData->Backgrounds[_backgroundIndex];
|
2018-06-19 22:17:00 -04:00
|
|
|
|
|
|
|
//Enable custom background if the current pixel fits within the background's boundaries
|
|
|
|
hasCustomBackground =
|
|
|
|
(int32_t)x >= -_bgScrollX &&
|
|
|
|
(int32_t)y >= -_bgScrollY &&
|
2019-12-20 13:53:13 -05:00
|
|
|
(y + bgInfo.Top + _bgScrollY + 1) * _hdData->Scale <= bgInfo.Data->Height &&
|
|
|
|
(x + bgInfo.Left + _bgScrollX + 1) * _hdData->Scale <= bgInfo.Data->Width;
|
2018-06-19 22:17:00 -04:00
|
|
|
|
|
|
|
if(hasCustomBackground) {
|
|
|
|
hasNonBackgroundSurrounding = _contoursEnabled && IsNextToSprite(x, y);
|
|
|
|
if(bgInfo.BehindBgPrioritySprites) {
|
2018-07-01 15:21:05 -04:00
|
|
|
DrawCustomBackground(outputBuffer, x + _bgScrollX, y + _bgScrollY, _hdData->Scale, screenWidth);
|
2018-06-19 22:17:00 -04:00
|
|
|
backgroundBehindBgSprites = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-06-28 19:00:08 -04:00
|
|
|
if(hasSprite) {
|
2017-07-25 19:46:25 -04:00
|
|
|
for(int k = pixelInfo.SpriteCount - 1; k >= 0; k--) {
|
2018-02-25 16:21:01 -05:00
|
|
|
if(pixelInfo.Sprite[k].BackgroundPriority) {
|
2018-02-26 18:42:49 -05:00
|
|
|
if(pixelInfo.Sprite[k].SpriteColorIndex != 0) {
|
|
|
|
lowestBgSprite = k;
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2018-02-17 23:44:25 -05:00
|
|
|
hdPackSpriteInfo = GetMatchingTile(x, y, &pixelInfo.Sprite[k]);
|
2017-08-15 19:18:00 -04:00
|
|
|
if(hdPackSpriteInfo) {
|
|
|
|
DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth);
|
|
|
|
} else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) {
|
2018-07-01 15:21:05 -04:00
|
|
|
DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, _hdData->Scale, screenWidth);
|
2017-07-25 19:46:25 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2017-07-25 19:46:25 -04:00
|
|
|
|
2018-06-19 22:17:00 -04:00
|
|
|
if (hasCustomBackground && !backgroundBehindBgSprites) {
|
2018-07-01 15:21:05 -04:00
|
|
|
DrawCustomBackground(outputBuffer, x + _bgScrollX, y + _bgScrollY, _hdData->Scale, screenWidth);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
|
2017-08-15 19:18:00 -04:00
|
|
|
if(hdPackTileInfo) {
|
|
|
|
DrawTile(pixelInfo.Tile, *hdPackTileInfo, outputBuffer, screenWidth);
|
2019-12-20 13:53:13 -05:00
|
|
|
} else if(renderOriginalTiles) {
|
2017-08-15 19:18:00 -04:00
|
|
|
//Draw regular SD background tile
|
|
|
|
bool useCustomBackground = !hasNonBackgroundSurrounding && hasCustomBackground && pixelInfo.Tile.BgColorIndex == 0;
|
2018-02-17 23:44:25 -05:00
|
|
|
if(!useCustomBackground && (pixelInfo.Tile.BgColorIndex != 0 || hasNonBackgroundSurrounding)) {
|
2018-07-01 15:21:05 -04:00
|
|
|
DrawColor(_palette[pixelInfo.Tile.BgColor], outputBuffer, _hdData->Scale, screenWidth);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
2017-07-25 19:46:25 -04:00
|
|
|
}
|
2017-06-28 19:00:08 -04:00
|
|
|
|
2017-07-25 19:46:25 -04:00
|
|
|
if(hasSprite) {
|
|
|
|
for(int k = pixelInfo.SpriteCount - 1; k >= 0; k--) {
|
|
|
|
if(!pixelInfo.Sprite[k].BackgroundPriority && lowestBgSprite > k) {
|
2018-02-17 23:44:25 -05:00
|
|
|
hdPackSpriteInfo = GetMatchingTile(x, y, &pixelInfo.Sprite[k]);
|
2017-07-25 19:46:25 -04:00
|
|
|
if(hdPackSpriteInfo) {
|
2017-08-15 19:18:00 -04:00
|
|
|
DrawTile(pixelInfo.Sprite[k], *hdPackSpriteInfo, outputBuffer, screenWidth);
|
2017-07-25 19:46:25 -04:00
|
|
|
} else if(pixelInfo.Sprite[k].SpriteColorIndex != 0) {
|
2018-07-01 15:21:05 -04:00
|
|
|
DrawColor(_palette[pixelInfo.Sprite[k].SpriteColor], outputBuffer, _hdData->Scale, screenWidth);
|
2017-06-28 19:00:08 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
|
|
|
|
void HdNesPack::Process(HdScreenInfo *hdScreenInfo, uint32_t* outputBuffer, OverscanDimensions &overscan)
|
|
|
|
{
|
|
|
|
_hdScreenInfo = hdScreenInfo;
|
|
|
|
uint32_t hdScale = GetScale();
|
|
|
|
uint32_t screenWidth = overscan.GetScreenWidth() * hdScale;
|
|
|
|
|
|
|
|
OnBeforeApplyFilter();
|
|
|
|
for(uint32_t i = overscan.Top, iMax = 240 - overscan.Bottom; i < iMax; i++) {
|
|
|
|
OnLineStart(hdScreenInfo->ScreenTiles[i << 8]);
|
|
|
|
uint32_t bufferIndex = (i - overscan.Top) * screenWidth * hdScale;
|
2018-03-11 22:42:32 -04:00
|
|
|
uint32_t lineStartIndex = bufferIndex;
|
2018-02-17 23:44:25 -05:00
|
|
|
for(uint32_t j = overscan.Left, jMax = 256 - overscan.Right; j < jMax; j++) {
|
|
|
|
GetPixels(j, i, hdScreenInfo->ScreenTiles[i * 256 + j], outputBuffer + bufferIndex, screenWidth);
|
|
|
|
bufferIndex += hdScale;
|
|
|
|
}
|
2018-03-11 22:42:32 -04:00
|
|
|
|
|
|
|
ProcessGrayscaleAndEmphasis(hdScreenInfo->ScreenTiles[i * 256], outputBuffer + lineStartIndex, screenWidth);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void HdNesPack::ProcessGrayscaleAndEmphasis(HdPpuPixelInfo &pixelInfo, uint32_t* outputBuffer, uint32_t hdScreenWidth)
|
|
|
|
{
|
|
|
|
//Apply grayscale/emphasis bits on a scanline level (less accurate, but shouldn't cause issues and simpler to implement)
|
|
|
|
uint32_t scale = GetScale();
|
|
|
|
if(pixelInfo.Grayscale) {
|
|
|
|
uint32_t* out = outputBuffer;
|
|
|
|
for(uint32_t y = 0; y < scale; y++) {
|
|
|
|
for(uint32_t x = 0; x < hdScreenWidth; x++) {
|
|
|
|
uint32_t &rgbValue = out[x];
|
|
|
|
uint8_t average = (((rgbValue >> 16) & 0xFF) + ((rgbValue >> 8) & 0xFF) + (rgbValue & 0xFF)) / 3;
|
|
|
|
rgbValue = (rgbValue & 0xFF000000) | (average << 16) | (average << 8) | average;
|
|
|
|
}
|
|
|
|
out += hdScreenWidth;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if(pixelInfo.EmphasisBits) {
|
|
|
|
uint8_t emphasisBits = pixelInfo.EmphasisBits;
|
|
|
|
double red = 1.0, green = 1.0, blue = 1.0;
|
|
|
|
if(emphasisBits & 0x01) {
|
|
|
|
//Intensify red
|
|
|
|
red *= 1.1;
|
|
|
|
green *= 0.9;
|
|
|
|
blue *= 0.9;
|
|
|
|
}
|
|
|
|
if(emphasisBits & 0x02) {
|
|
|
|
//Intensify green
|
|
|
|
green *= 1.1;
|
|
|
|
red *= 0.9;
|
|
|
|
blue *= 0.9;
|
|
|
|
}
|
|
|
|
if(emphasisBits & 0x04) {
|
|
|
|
//Intensify blue
|
|
|
|
blue *= 1.1;
|
|
|
|
red *= 0.9;
|
|
|
|
green *= 0.9;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t* out = outputBuffer;
|
|
|
|
for(uint32_t y = 0; y < scale; y++) {
|
|
|
|
for(uint32_t x = 0; x < hdScreenWidth; x++) {
|
|
|
|
uint32_t &rgbValue = out[x];
|
|
|
|
|
|
|
|
rgbValue = 0xFF000000 |
|
|
|
|
(std::min<uint16_t>((uint16_t)(((rgbValue >> 16) & 0xFF) * red), 255) << 16) |
|
|
|
|
(std::min<uint16_t>((uint16_t)(((rgbValue >> 8) & 0xFF) * green), 255) << 8) |
|
|
|
|
std::min<uint16_t>((uint16_t)((rgbValue & 0xFF) * blue), 255);
|
|
|
|
}
|
|
|
|
out += hdScreenWidth;
|
|
|
|
}
|
2018-02-17 23:44:25 -05:00
|
|
|
}
|
|
|
|
}
|