Add text anti-aliasing, disable arcade mode

This commit is contained in:
elasota
2020-01-18 18:20:16 -05:00
parent d8331eaeb7
commit c79ddd0d35
40 changed files with 615 additions and 159 deletions

View File

@@ -0,0 +1,56 @@
#include "AntiAliasTable.h"
#include "RGBAColor.h"
// TODO: This is not gamma correct... do we care?
namespace PortabilityLayer
{
void AntiAliasTable::GenerateForPalette(const RGBAColor &baseColorRef, const RGBAColor *colors, size_t numColors)
{
const RGBAColor baseColor = baseColorRef;
if (numColors > 256)
numColors = 256;
unsigned int baseCh[3] = { baseColor.r, baseColor.g, baseColor.b };
for (size_t i = 0; i < numColors; i++)
{
const RGBAColor existingColor = colors[i];
unsigned int existingCh[3] = { existingColor.r, existingColor.g, existingColor.b };
// 0 alpha is always the same color
m_aaTranslate[i][0] = static_cast<uint8_t>(i);
for (unsigned int b = 1; b < 16; b++)
{
unsigned int newCh[3];
for (unsigned int ch = 0; ch < 3; ch++)
newCh[ch] = (15 - b) * existingCh[ch] + b * baseCh[ch];
uint32_t bestError = 0xffffffffU;
size_t bestColor = 0;
for (size_t cmp = 0; cmp < numColors; cmp++)
{
int16_t existingChScaled[3] = { colors[cmp].r * 15, colors[cmp].g * 15, colors[cmp].b * 15 };
uint32_t error = 0;
for (unsigned int ch = 0; ch < 3; ch++)
{
int16_t delta = static_cast<int16_t>(newCh[ch]) - existingChScaled[ch];
error += static_cast<uint32_t>(delta * delta);
}
if (error < bestError)
{
bestError = error;
bestColor = cmp;
}
}
m_aaTranslate[i][b] = static_cast<uint8_t>(bestColor);
}
}
}
}

View File

@@ -0,0 +1,16 @@
#pragma once
#include <stdint.h>
namespace PortabilityLayer
{
struct RGBAColor;
struct AntiAliasTable
{
// Striped 256x16 because constant background color is more likely than constant sample
uint8_t m_aaTranslate[256][16];
void GenerateForPalette(const RGBAColor &baseColor, const RGBAColor *colors, size_t numColors);
};
}

View File

@@ -24,8 +24,8 @@ namespace PortabilityLayer
FontFamily *GetSystemFont(int textSize, int variationFlags) const override;
FontFamily *GetApplicationFont(int textSize, int variationFlags) const override;
RenderedFont *GetRenderedFont(HostFont *font, int size, FontHacks fontHacks) override;
RenderedFont *GetRenderedFontFromFamily(FontFamily *font, int size, int flags) override;
RenderedFont *GetRenderedFont(HostFont *font, int size, bool aa, FontHacks fontHacks) override;
RenderedFont *GetRenderedFontFromFamily(FontFamily *font, int size, bool aa, int flags) override;
static FontManagerImpl *GetInstance();
@@ -38,6 +38,7 @@ namespace PortabilityLayer
const HostFont *m_font;
int m_size;
uint32_t m_lastUsage;
bool m_aa;
};
FontManagerImpl();
@@ -109,7 +110,7 @@ namespace PortabilityLayer
return m_applicationFont;
}
RenderedFont *FontManagerImpl::GetRenderedFont(HostFont *font, int size, FontHacks fontHacks)
RenderedFont *FontManagerImpl::GetRenderedFont(HostFont *font, int size, bool aa, FontHacks fontHacks)
{
CachedRenderedFont *newCacheSlot = &m_cachedRenderedFonts[0];
@@ -122,7 +123,7 @@ namespace PortabilityLayer
break;
}
if (crf.m_font == font && crf.m_size == size)
if (crf.m_font == font && crf.m_size == size && crf.m_aa == aa)
{
crf.m_lastUsage = m_usageCounter;
RenderedFont *rf = crf.m_rfont;
@@ -138,7 +139,7 @@ namespace PortabilityLayer
newCacheSlot = &crf;
}
RenderedFont *rfont = FontRenderer::GetInstance()->RenderFont(font, size, fontHacks);
RenderedFont *rfont = FontRenderer::GetInstance()->RenderFont(font, size, aa, fontHacks);
if (!rfont)
return nullptr;
@@ -149,6 +150,7 @@ namespace PortabilityLayer
newCacheSlot->m_lastUsage = m_usageCounter;
newCacheSlot->m_size = size;
newCacheSlot->m_rfont = rfont;
newCacheSlot->m_aa = aa;
if (m_usageCounter == UINT32_MAX)
ResetUsageCounter();
@@ -158,7 +160,7 @@ namespace PortabilityLayer
return rfont;
}
RenderedFont *FontManagerImpl::GetRenderedFontFromFamily(FontFamily *fontFamily, int size, int flags)
RenderedFont *FontManagerImpl::GetRenderedFontFromFamily(FontFamily *fontFamily, int size, bool aa, int flags)
{
const int variation = fontFamily->GetVariationForFlags(flags);
@@ -166,7 +168,7 @@ namespace PortabilityLayer
if (!hostFont)
return nullptr;
return PortabilityLayer::FontManager::GetInstance()->GetRenderedFont(hostFont, size, fontFamily->GetHacksForVariation(variation));
return PortabilityLayer::FontManager::GetInstance()->GetRenderedFont(hostFont, size, aa, fontFamily->GetHacksForVariation(variation));
}
FontManagerImpl *FontManagerImpl::GetInstance()

View File

@@ -17,8 +17,8 @@ namespace PortabilityLayer
virtual FontFamily *GetSystemFont(int fontSize, int variationFlags) const = 0;
virtual FontFamily *GetApplicationFont(int fontSize, int variationFlags) const = 0;
virtual RenderedFont *GetRenderedFont(HostFont *font, int size, FontHacks fontHacks) = 0;
virtual RenderedFont *GetRenderedFontFromFamily(FontFamily *fontFamily, int fontSize, int flags) = 0;
virtual RenderedFont *GetRenderedFont(HostFont *font, int size, bool aa, FontHacks fontHacks) = 0;
virtual RenderedFont *GetRenderedFontFromFamily(FontFamily *fontFamily, int fontSize, bool aa, int flags) = 0;
static FontManager *GetInstance();
};

View File

@@ -23,22 +23,24 @@ namespace PortabilityLayer
bool GetGlyph(unsigned int character, const RenderedGlyphMetrics *&outMetricsPtr, const void *&outData) const override;
const RenderedFontMetrics &GetMetrics() const override;
size_t MeasureString(const uint8_t *chars, size_t len) const override;
bool IsAntiAliased() const override;
void Destroy() override;
void SetCharData(unsigned int charID, const void *data, size_t dataOffset, const RenderedGlyphMetrics &metrics);
void SetFontMetrics(const RenderedFontMetrics &metrics);
static RenderedFontImpl *Create(size_t glyphDataSize);
static RenderedFontImpl *Create(size_t glyphDataSize, bool aa);
private:
explicit RenderedFontImpl(void *data);
RenderedFontImpl(void *data, bool aa);
~RenderedFontImpl();
size_t m_dataOffsets[256];
RenderedGlyphMetrics m_glyphMetrics[256];
RenderedFontMetrics m_fontMetrics;
bool m_isAntiAliased;
void *m_data;
};
@@ -46,7 +48,7 @@ namespace PortabilityLayer
class FontRendererImpl final : public FontRenderer
{
public:
RenderedFont *RenderFont(HostFont *font, int size, FontHacks fontHacks) override;
RenderedFont *RenderFont(HostFont *font, int size, bool aa, FontHacks fontHacks) override;
static FontRendererImpl *GetInstance();
@@ -71,7 +73,6 @@ namespace PortabilityLayer
return m_fontMetrics;
}
size_t RenderedFontImpl::MeasureString(const uint8_t *chars, size_t len) const
{
size_t measure = 0;
@@ -85,6 +86,11 @@ namespace PortabilityLayer
return measure;
}
bool RenderedFontImpl::IsAntiAliased() const
{
return m_isAntiAliased;
}
void RenderedFontImpl::Destroy()
{
this->~RenderedFontImpl();
@@ -103,7 +109,7 @@ namespace PortabilityLayer
m_fontMetrics = metrics;
}
RenderedFontImpl *RenderedFontImpl::Create(size_t glyphDataSize)
RenderedFontImpl *RenderedFontImpl::Create(size_t glyphDataSize, bool aa)
{
size_t alignedPrefixSize = sizeof(RenderedFontImpl) + GP_SYSTEM_MEMORY_ALIGNMENT - 1;
alignedPrefixSize -= alignedPrefixSize % GP_SYSTEM_MEMORY_ALIGNMENT;
@@ -119,11 +125,12 @@ namespace PortabilityLayer
memset(storage, 0, allocSize);
return new (storage) RenderedFontImpl(static_cast<uint8_t*>(storage) + alignedPrefixSize);
return new (storage) RenderedFontImpl(static_cast<uint8_t*>(storage) + alignedPrefixSize, aa);
}
RenderedFontImpl::RenderedFontImpl(void *data)
RenderedFontImpl::RenderedFontImpl(void *data, bool aa)
: m_data(data)
, m_isAntiAliased(aa)
{
memset(m_glyphMetrics, 0, sizeof(m_glyphMetrics));
memset(&m_fontMetrics, 0, sizeof(m_fontMetrics));
@@ -134,7 +141,7 @@ namespace PortabilityLayer
{
}
RenderedFont *FontRendererImpl::RenderFont(HostFont *font, int size, FontHacks fontHacks)
RenderedFont *FontRendererImpl::RenderFont(HostFont *font, int size, bool aa, FontHacks fontHacks)
{
const unsigned int numCharacters = 256;
@@ -156,7 +163,7 @@ namespace PortabilityLayer
if (unicodeCodePoint == 0xffff)
continue;
glyphs[i] = font->Render(unicodeCodePoint, size);
glyphs[i] = font->Render(unicodeCodePoint, size, aa);
}
size_t glyphDataSize = GP_SYSTEM_MEMORY_ALIGNMENT; // So we can use 0 to mean no data
@@ -170,7 +177,7 @@ namespace PortabilityLayer
}
}
RenderedFontImpl *rfont = RenderedFontImpl::Create(glyphDataSize);
RenderedFontImpl *rfont = RenderedFontImpl::Create(glyphDataSize, aa);
if (rfont)
{
size_t fillOffset = GP_SYSTEM_MEMORY_ALIGNMENT;
@@ -185,7 +192,7 @@ namespace PortabilityLayer
RenderedGlyphMetrics metrics = glyph->GetMetrics();
const void *data = glyph->GetData();
if (fontHacks == FontHacks_Roboto)
if (fontHacks == FontHacks_Roboto && !aa)
{
if (size < 32)
{

View File

@@ -10,7 +10,7 @@ namespace PortabilityLayer
class FontRenderer
{
public:
virtual RenderedFont *RenderFont(HostFont *font, int size, FontHacks fontHacks) = 0;
virtual RenderedFont *RenderFont(HostFont *font, int size, bool aa, FontHacks fontHacks) = 0;
static FontRenderer *GetInstance();
};

View File

@@ -11,7 +11,7 @@ namespace PortabilityLayer
{
public:
virtual void Destroy() = 0;
virtual HostFontRenderedGlyph *Render(uint32_t unicodeCodePoint, unsigned int size) = 0;
virtual HostFontRenderedGlyph *Render(uint32_t unicodeCodePoint, unsigned int size, bool aa) = 0;
virtual bool GetLineSpacing(unsigned int size, int32_t &outSpacing) = 0;
};
}

View File

@@ -757,7 +757,7 @@ namespace PortabilityLayer
if (menuHdl != selectedMenuHdl)
{
const Point itemPos = Point::Create(static_cast<int16_t>(xCoordinate), kMenuBarTextYOffset);
graf->DrawString(itemPos, PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)));
graf->DrawString(itemPos, PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)), true);
}
}
}
@@ -776,7 +776,7 @@ namespace PortabilityLayer
size_t xCoordinate = menu->cumulativeOffset + (menu->menuIndex * 2) * kMenuBarItemPadding + kMenuBarInitialPadding;
const Point itemPos = Point::Create(static_cast<int16_t>(xCoordinate), kMenuBarTextYOffset);
graf->DrawString(itemPos, PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)));
graf->DrawString(itemPos, PLPasStr(static_cast<const uint8_t*>(menu->stringBlobHandle->m_contents)), true);
}
}
@@ -835,7 +835,7 @@ namespace PortabilityLayer
if (!fontFamily)
return;
PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, kMenuFontSize, kMenuFontFlags);
PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, kMenuFontSize, true, kMenuFontFlags);
if (!rfont)
return;
@@ -879,7 +879,7 @@ namespace PortabilityLayer
if (!fontFamily)
return;
PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, kMenuFontSize, kMenuFontFlags);
PortabilityLayer::RenderedFont *rfont = PortabilityLayer::FontManager::GetInstance()->GetRenderedFontFromFamily(fontFamily, kMenuFontSize, true, kMenuFontFlags);
if (!rfont)
return;
@@ -1132,7 +1132,7 @@ namespace PortabilityLayer
itemPos.v = item.layoutYOffset + kMenuItemTextYOffset;
surface->DrawString(itemPos, PLPasStr(strBlob + item.nameOffsetInStringBlob));
surface->DrawString(itemPos, PLPasStr(strBlob + item.nameOffsetInStringBlob), true);
}
if (m_haveItem)
@@ -1148,7 +1148,7 @@ namespace PortabilityLayer
itemPos.v = item.layoutYOffset + kMenuItemTextYOffset;
surface->DrawString(itemPos, PLPasStr(strBlob + item.nameOffsetInStringBlob));
surface->DrawString(itemPos, PLPasStr(strBlob + item.nameOffsetInStringBlob), true);
}
m_menuGraf->m_port.SetDirty(QDPortDirtyFlag_Contents);

View File

@@ -62,6 +62,6 @@ namespace PortabilityLayer
surface->SetSystemFont(12, PortabilityLayer::FontFamilyFlag_Bold);
int32_t x = (m_rect.left + m_rect.right - static_cast<int32_t>(surface->MeasureString(m_text.ToShortStr()))) / 2;
int32_t y = (m_rect.top + m_rect.bottom + static_cast<int32_t>(surface->MeasureFontAscender())) / 2;
surface->DrawString(Point::Create(x, y), m_text.ToShortStr());
surface->DrawString(Point::Create(x, y), m_text.ToShortStr(), true);
}
}

View File

@@ -27,6 +27,6 @@ namespace PortabilityLayer
const Point topLeftCorner = Point::Create(m_rect.left, m_rect.top);
const Point textStartPoint = topLeftCorner + Point::Create(0, surface->MeasureFontAscender());
surface->DrawStringWrap(textStartPoint, m_rect, m_text.ToShortStr());
surface->DrawStringWrap(textStartPoint, m_rect, m_text.ToShortStr(), true);
}
}

View File

@@ -498,7 +498,8 @@ void GetForeColor(RGBColor *color)
*color = RGBColor(foreColor.r, foreColor.g, foreColor.b);
}
static void DrawGlyph(PortabilityLayer::QDState *qdState, PixMap *pixMap, const Rect &rect, Point &penPos, const PortabilityLayer::RenderedFont *rfont, unsigned int character)
static void DrawGlyph(PortabilityLayer::QDState *qdState, PixMap *pixMap, const Rect &rect, Point &penPos, const PortabilityLayer::RenderedFont *rfont, unsigned int character,
PortabilityLayer::AntiAliasTable *&cachedAATable, PortabilityLayer::RGBAColor &cachedAATableColor)
{
assert(rect.IsValid());
@@ -537,12 +538,41 @@ static void DrawGlyph(PortabilityLayer::QDState *qdState, PixMap *pixMap, const
const size_t outputPitch = pixMap->m_pitch;
const uint8_t *firstInputRowData = static_cast<const uint8_t*>(data) + firstInputRow * inputPitch;
const bool isAA = rfont->IsAntiAliased();
switch (pixMap->m_pixelFormat)
{
case GpPixelFormats::k8BitStandard:
{
uint8_t *firstOutputRowData = static_cast<uint8_t*>(pixMap->m_data) + firstOutputRow * outputPitch;
const PortabilityLayer::AntiAliasTable *aaTable = nullptr;
if (isAA)
{
const PortabilityLayer::RGBAColor foreColor = qdState->GetForeColor();
if (foreColor == PortabilityLayer::RGBAColor::Create(0, 0, 0, 255))
aaTable = &PortabilityLayer::StandardPalette::GetInstance()->GetBlackAATable();
else if (foreColor == PortabilityLayer::RGBAColor::Create(255, 255, 255, 255))
aaTable = &PortabilityLayer::StandardPalette::GetInstance()->GetWhiteAATable();
else if (cachedAATable != nullptr && foreColor == cachedAATableColor)
aaTable = cachedAATable;
else
{
if (!cachedAATable)
{
cachedAATable = static_cast<PortabilityLayer::AntiAliasTable*>(PortabilityLayer::MemoryManager::GetInstance()->Alloc(sizeof(PortabilityLayer::AntiAliasTable)));
if (!cachedAATable)
return;
}
cachedAATableColor = foreColor;
cachedAATable->GenerateForPalette(foreColor, PortabilityLayer::StandardPalette::GetInstance()->GetColors(), 256);
aaTable = cachedAATable;
}
}
const uint8_t color = qdState->ResolveForeColor8(nullptr, 0);
for (uint32_t row = 0; row < numRows; row++)
{
@@ -550,11 +580,26 @@ static void DrawGlyph(PortabilityLayer::QDState *qdState, PixMap *pixMap, const
uint8_t *outputRowData = firstOutputRowData + row * outputPitch;
// It should be possible to speed this up, if needed. The input is guaranteed to be well-aligned and not mutable within this loop.
for (uint32_t col = 0; col < numCols; col++)
if (isAA)
{
const size_t inputOffset = firstInputCol + col;
if (inputRowData[inputOffset / 8] & (1 << (inputOffset & 0x7)))
outputRowData[firstOutputCol + col] = color;
for (uint32_t col = 0; col < numCols; col++)
{
const size_t inputOffset = firstInputCol + col;
const unsigned int grayLevel = (inputRowData[inputOffset / 2] >> ((inputOffset & 1) * 4)) & 0xf;
uint8_t &targetPixel = outputRowData[firstOutputCol + col];
targetPixel = aaTable->m_aaTranslate[targetPixel][grayLevel];
}
}
else
{
for (uint32_t col = 0; col < numCols; col++)
{
const size_t inputOffset = firstInputCol + col;
if (inputRowData[inputOffset / 8] & (1 << (inputOffset & 0x7)))
outputRowData[firstOutputCol + col] = color;
}
}
}
}
@@ -564,7 +609,7 @@ static void DrawGlyph(PortabilityLayer::QDState *qdState, PixMap *pixMap, const
}
}
void DrawSurface::DrawString(const Point &point, const PLPasStr &str)
void DrawSurface::DrawString(const Point &point, const PLPasStr &str, bool aa)
{
PortabilityLayer::QDPort *port = &m_port;
@@ -576,7 +621,7 @@ void DrawSurface::DrawString(const Point &point, const PLPasStr &str)
const int fontVariationFlags = qdState->m_fontVariationFlags;
PortabilityLayer::FontFamily *fontFamily = qdState->m_fontFamily;
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, fontVariationFlags);
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, aa, fontVariationFlags);
Point penPos = point;
const size_t len = str.Length();
@@ -599,13 +644,13 @@ void DrawSurface::DrawString(const Point &point, const PLPasStr &str)
penPos = paraStartPos;
}
else
DrawGlyph(qdState, pixMap, rect, penPos, rfont, chars[i]);
DrawGlyph(qdState, pixMap, rect, penPos, rfont, chars[i], m_cachedAATable, m_cachedAAColor);
}
m_port.SetDirty(PortabilityLayer::QDPortDirtyFlag_Contents);
}
void DrawSurface::DrawStringWrap(const Point &point, const Rect &constrainRect, const PLPasStr &str)
void DrawSurface::DrawStringWrap(const Point &point, const Rect &constrainRect, const PLPasStr &str, bool aa)
{
PortabilityLayer::QDPort *port = &m_port;
@@ -617,7 +662,7 @@ void DrawSurface::DrawStringWrap(const Point &point, const Rect &constrainRect,
const int fontVariationFlags = qdState->m_fontVariationFlags;
PortabilityLayer::FontFamily *fontFamily = qdState->m_fontFamily;
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, fontVariationFlags);
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, aa, fontVariationFlags);
Point penPos = point;
const size_t len = str.Length();
@@ -703,7 +748,7 @@ void DrawSurface::DrawStringWrap(const Point &point, const Rect &constrainRect,
{
const uint8_t character = chars[currentStartChar + ci];
DrawGlyph(qdState, pixMap, pixMap->m_rect, penPos, rfont, character);
DrawGlyph(qdState, pixMap, pixMap->m_rect, penPos, rfont, character, m_cachedAATable, m_cachedAAColor);
}
currentStartChar += committedLength;
@@ -728,7 +773,7 @@ size_t DrawSurface::MeasureString(const PLPasStr &str)
const int variationFlags = qdState->m_fontVariationFlags;
const int fontSize = qdState->m_fontSize;
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, variationFlags);
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, false, variationFlags);
if (!rfont)
return 0;
@@ -748,7 +793,7 @@ int32_t DrawSurface::MeasureFontAscender()
const int variationFlags = qdState->m_fontVariationFlags;
const int fontSize = qdState->m_fontSize;
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, variationFlags);
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, false, variationFlags);
if (!rfont)
return 0;
@@ -768,7 +813,7 @@ int32_t DrawSurface::MeasureFontLineGap()
const int variationFlags = qdState->m_fontVariationFlags;
const int fontSize = qdState->m_fontSize;
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, variationFlags);
PortabilityLayer::RenderedFont *rfont = fontManager->GetRenderedFontFromFamily(fontFamily, fontSize, false, variationFlags);
if (!rfont)
return 0;

View File

@@ -43,7 +43,7 @@ namespace PortabilityLayer
surface->SetForeColor(StdColors::Black());
surface->SetSystemFont(12, FontFamilyFlag_Bold);
int32_t textV = (m_rect.top + m_rect.bottom + surface->MeasureFontAscender()) / 2;
surface->DrawString(Point::Create(m_rect.left + radioFrameSize + 2, textV), m_text.ToShortStr());
surface->DrawString(Point::Create(m_rect.left + radioFrameSize + 2, textV), m_text.ToShortStr(), true);
}
void RadioButtonWidget::SetString(const PLPasStr &str)

View File

@@ -1,5 +1,6 @@
#include "ResourceManager.h"
#include "VirtualDirectory.h"
#include "BMPFormat.h"
#include "FileManager.h"
#include "GPArchive.h"
#include "HostFileSystem.h"
@@ -14,10 +15,67 @@
#include "ResourceFile.h"
#include "PLPasStr.h"
#include "PLErrorCodes.h"
#include "VirtualDirectory.h"
#include "WaveFormat.h"
#include "ZipFileProxy.h"
#include <vector>
namespace ResourceValidationRules
{
enum ResourceValidationRule
{
kNone,
kWAV,
kBMP,
};
}
typedef ResourceValidationRules::ResourceValidationRule ResourceValidationRule_t;
namespace
{
// Validation is only intended to validate enough of the file structure that constrained validation can be performed
// without needing to pass the file size
static bool ValidateResource(const void *res, size_t size, ResourceValidationRule_t validationRule)
{
switch (validationRule)
{
case ResourceValidationRules::kWAV:
{
if (size < sizeof(PortabilityLayer::RIFFTag))
return false;
PortabilityLayer::RIFFTag mainTag;
memcpy(&mainTag, res, sizeof(mainTag));
if (mainTag.m_chunkSize > size - sizeof(sizeof(PortabilityLayer::RIFFTag)))
return false;
return true;
}
break;
case ResourceValidationRules::kBMP:
{
if (size < sizeof(PortabilityLayer::BitmapFileHeader))
return false;
PortabilityLayer::BitmapFileHeader mainHeader;
memcpy(&mainHeader, res, sizeof(mainHeader));
if (mainHeader.m_fileSize > size)
return false;
return true;
}
break;
default:
break;
};
}
}
namespace PortabilityLayer
{
struct MMHandleBlock;
@@ -315,6 +373,14 @@ namespace PortabilityLayer
THandle<void> ResourceArchive::GetResource(const ResTypeID &resTypeID, int id, bool load)
{
const char *extension = ".bin";
ResourceValidationRule_t validationRule = ResourceValidationRules::kNone;
if (resTypeID == ResTypeID('snd '))
{
extension = ".wav";
validationRule = ResourceValidationRules::kWAV;
}
char resourceFile[64];
GpArcResourceTypeTag resTag = GpArcResourceTypeTag::Encode(resTypeID);
@@ -350,11 +416,13 @@ namespace PortabilityLayer
handle->m_contents = contents;
handle->m_size = ref->m_size;
if (!m_zipFileProxy->LoadFile(index, contents))
if (!m_zipFileProxy->LoadFile(index, contents) || (validationRule != ResourceValidationRules::kNone && !ValidateResource(contents, ref->m_size, validationRule)))
{
MemoryManager::GetInstance()->Release(contents);
handle->m_contents = nullptr;
handle->m_size = 0;
return THandle<void>();
}
}
}

View File

@@ -7,6 +7,7 @@
#include "HostMutex.h"
#include "HostSystemServices.h"
#include "HostThreadEvent.h"
#include "WaveFormat.h"
#include <assert.h>
@@ -42,7 +43,7 @@ namespace PortabilityLayer
~AudioChannelImpl();
void Destroy(bool wait) override;
bool AddBuffer(const void *smBuffer, bool blocking) override;
bool AddBuffer(const void *lengthTaggedBuffer, bool blocking) override;
bool AddCallback(AudioChannelCallback_t callback, bool blocking) override;
void ClearAllCommands() override;
void Stop() override;
@@ -67,7 +68,6 @@ namespace PortabilityLayer
void DigestBufferCommand(const void *dataPointer);
PortabilityLayer::HostAudioChannel *m_audioChannel;
;
HostMutex *m_mutex;
HostThreadEvent *m_threadEvent;
@@ -145,11 +145,11 @@ namespace PortabilityLayer
PortabilityLayer::MemoryManager::GetInstance()->Release(this);
}
bool AudioChannelImpl::AddBuffer(const void *smBuffer, bool blocking)
bool AudioChannelImpl::AddBuffer(const void *lengthTaggedBuffer, bool blocking)
{
AudioCommand cmd;
cmd.m_commandType = AudioCommandTypes::kBuffer;
cmd.m_param.m_ptr = smBuffer;
cmd.m_param.m_ptr = lengthTaggedBuffer;
return this->PushCommand(cmd, blocking);
}
@@ -195,26 +195,11 @@ namespace PortabilityLayer
void AudioChannelImpl::DigestBufferCommand(const void *dataPointer)
{
struct BufferHeader
{
BEUInt32_t m_samplePtr;
BEUInt32_t m_length;
BEFixed32_t m_sampleRate;
BEUInt32_t m_loopStart;
BEUInt32_t m_loopEnd;
uint8_t m_encoding;
uint8_t m_baseFrequency;
};
// At this point, the buffer should already be validated and converted, and the data pointer should point at the data tag
uint32_t length;
memcpy(&length, dataPointer, 4);
BufferHeader bufferHeader;
GP_STATIC_ASSERT(sizeof(BufferHeader) >= 22);
memcpy(&bufferHeader, dataPointer, 22);
const uint32_t length = bufferHeader.m_length;
m_audioChannel->PostBuffer(static_cast<const uint8_t*>(dataPointer) + 22, length);
m_audioChannel->PostBuffer(static_cast<const uint8_t*>(dataPointer) + 4, length);
m_state = State_PlayingAsync;
}

View File

@@ -11,7 +11,7 @@ namespace PortabilityLayer
struct AudioChannel
{
virtual void Destroy(bool wait) = 0;
virtual bool AddBuffer(const void *smBuffer, bool blocking) = 0;
virtual bool AddBuffer(const void *lengthTaggedBuffer, bool blocking) = 0;
virtual bool AddCallback(AudioChannelCallback_t callback, bool blocking) = 0;
virtual void ClearAllCommands() = 0;
virtual void Stop() = 0;

View File

@@ -138,6 +138,7 @@
<ClInclude Include="..\GpCommon\GpBitfield.h" />
<ClInclude Include="AEHandlerDesc.h" />
<ClInclude Include="AEManager.h" />
<ClInclude Include="AntiAliasTable.h" />
<ClInclude Include="BinarySearch.h" />
<ClInclude Include="BinHex4.h" />
<ClInclude Include="BMPFormat.h" />
@@ -289,6 +290,7 @@
<ItemGroup>
<ClCompile Include="..\stb\stb_image_write.c" />
<ClCompile Include="AEManager.cpp" />
<ClCompile Include="AntiAliasTable.cpp" />
<ClCompile Include="BinHex4.cpp" />
<ClCompile Include="ByteSwap.cpp" />
<ClCompile Include="CFileStream.cpp" />

View File

@@ -465,6 +465,9 @@
<ClInclude Include="DeflateCodec.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="AntiAliasTable.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="CFileStream.cpp">
@@ -725,5 +728,8 @@
<ClCompile Include="DeflateCodec.cpp">
<Filter>Source Files</Filter>
</ClCompile>
<ClCompile Include="AntiAliasTable.cpp">
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
</Project>

View File

@@ -1,4 +1,6 @@
#include "QDGraf.h"
#include "MemoryManager.h"
#include "QDPixMap.h"
#include "QDPort.h"
#include "IGpDisplayDriver.h"
@@ -6,6 +8,8 @@
DrawSurface::~DrawSurface()
{
if (m_cachedAATable)
PortabilityLayer::MemoryManager::GetInstance()->Release(m_cachedAATable);
}
void DrawSurface::PushToDDSurface(IGpDisplayDriver *displayDriver)

View File

@@ -9,6 +9,7 @@
namespace PortabilityLayer
{
struct AntiAliasTable;
class FontFamily;
struct RGBAColor;
class ScanlineMask;
@@ -27,12 +28,16 @@ struct DrawSurface final
DrawSurface()
: m_port(PortabilityLayer::QDPortType_DrawSurface)
, m_ddSurface(nullptr)
, m_cachedAAColor(PortabilityLayer::RGBAColor::Create(0, 0, 0, 255))
, m_cachedAATable(nullptr)
{
}
explicit DrawSurface(PortabilityLayer::QDPortType overridePortType)
: m_port(overridePortType)
, m_ddSurface(nullptr)
, m_cachedAAColor(PortabilityLayer::RGBAColor::Create(0, 0, 0, 255))
, m_cachedAATable(nullptr)
{
}
@@ -76,8 +81,8 @@ struct DrawSurface final
void SetApplicationFont(int size, int variationFlags);
void SetSystemFont(int size, int variationFlags);
void DrawString(const Point &point, const PLPasStr &str);
void DrawStringWrap(const Point &point, const Rect &constrainRect, const PLPasStr &str);
void DrawString(const Point &point, const PLPasStr &str, bool aa);
void DrawStringWrap(const Point &point, const Rect &constrainRect, const PLPasStr &str, bool aa);
size_t MeasureString(const PLPasStr &str);
int32_t MeasureFontAscender();
@@ -93,8 +98,13 @@ struct DrawSurface final
Rect GetClipRect() const;
void SetClipRect(const Rect &rect);
void RegenerateAATable(const PortabilityLayer::RGBAColor &color, const PortabilityLayer::RGBAColor *paletteColors, size_t numColors);
// Must be the first item
PortabilityLayer::QDPort m_port;
IGpDisplayDriverSurface *m_ddSurface;
PortabilityLayer::AntiAliasTable *m_cachedAATable;
PortabilityLayer::RGBAColor m_cachedAAColor;
};

View File

@@ -81,7 +81,35 @@ namespace PortabilityLayer
for (unsigned int rs = 0; rs < 16; rs++)
for (unsigned int gs = 0; gs < 16; gs++)
for (unsigned int bs = 0; bs < 16; bs++)
m_lut[rs + (gs << 4) + (bs << 8)] = MapColorAnalyticTruncated(rs, gs, bs);
m_lut[rs + (gs << 4) + (bs << 8)] = MapColorAnalyticTruncated(rs, gs, bs);
for (unsigned int i = 0; i < 256; i++)
{
unsigned int shortChannels[3] =
{
m_colors[i].r / 17,
m_colors[i].g / 17,
m_colors[i].b / 17
};
for (unsigned int b = 0; b < 16; b++)
{
unsigned int whiteScale[3];
unsigned int blackScale[3];
for (unsigned int ch = 0; ch < 3; ch++)
{
unsigned int scaledBackground = (15 - b) * shortChannels[ch];
unsigned int scaledWhiteForeground = 15 * b;
blackScale[ch] = scaledBackground / 15;
whiteScale[ch] = (scaledBackground + scaledWhiteForeground) / 15;
}
m_blackAATable.m_aaTranslate[i][b] = MapColorAnalyticTruncated(blackScale[0], blackScale[1], blackScale[2]);
m_whiteAATable.m_aaTranslate[i][b] = MapColorAnalyticTruncated(whiteScale[0], whiteScale[1], whiteScale[2]);
}
}
}
const RGBAColor *StandardPalette::GetColors() const
@@ -228,6 +256,16 @@ namespace PortabilityLayer
const StandardPalette *StandardPalette::GetInstance()
{
return &ms_instance;
}
const AntiAliasTable &StandardPalette::GetWhiteAATable() const
{
return m_whiteAATable;
}
const AntiAliasTable &StandardPalette::GetBlackAATable() const
{
return m_blackAATable;
}
StandardPalette StandardPalette::ms_instance;

View File

@@ -1,9 +1,12 @@
#pragma once
#include "AntiAliasTable.h"
#include "RGBAColor.h"
namespace PortabilityLayer
{
{
struct AntiAliasTable;
class StandardPalette
{
public:
@@ -16,14 +19,18 @@ namespace PortabilityLayer
static uint8_t MapColorAnalytic(uint8_t r, uint8_t g, uint8_t b);
static uint8_t MapColorAnalytic(const RGBAColor &color);
uint8_t MapColorLUT(uint8_t r, uint8_t g, uint8_t b) const;
uint8_t MapColorLUT(const RGBAColor &color) const;
uint8_t MapColorLUT(const RGBAColor &color) const;
const AntiAliasTable &GetWhiteAATable() const;
const AntiAliasTable &GetBlackAATable() const;
static const StandardPalette *GetInstance();
private:
static StandardPalette ms_instance;
RGBAColor m_colors[kSize];
RGBAColor m_colors[kSize];
AntiAliasTable m_whiteAATable;
AntiAliasTable m_blackAATable;
uint8_t m_lut[16 * 16 * 16];
};
}

View File

@@ -8,6 +8,8 @@ namespace PortabilityLayer
{
uint8_t r, g, b, a;
bool operator==(const RGBAColor &other) const;
bool operator!=(const RGBAColor &other) const;
static RGBAColor Create(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
};
@@ -20,5 +22,15 @@ namespace PortabilityLayer
color.a = a;
return color;
}
inline bool RGBAColor::operator==(const RGBAColor &other) const
{
return this->r == other.r && this->g == other.g && this->b == other.b && this->a == other.a;
}
inline bool RGBAColor::operator!=(const RGBAColor &other) const
{
return !((*this) == other);
}
}

View File

@@ -14,6 +14,7 @@ namespace PortabilityLayer
virtual bool GetGlyph(unsigned int character, const RenderedGlyphMetrics *&outMetricsPtr, const void *&outData) const = 0;
virtual const RenderedFontMetrics &GetMetrics() const = 0;
virtual size_t MeasureString(const uint8_t *chars, size_t len) const = 0;
virtual bool IsAntiAliased() const = 0;
virtual void Destroy() = 0;
};

View File

@@ -1,6 +1,6 @@
#pragma once
#include "PLLittleEndian.h"
#include "PLLittleEndian.h"
namespace PortabilityLayer
{
@@ -10,9 +10,9 @@ namespace PortabilityLayer
static const uint32_t kRiffChunkID = 0x46464952;
static const uint32_t kWaveChunkID = 0x45564157;
static const uint32_t kFormatChunkID = 0x20746d66;
static const uint32_t kDataChunkID = 0x61746164;
static const uint32_t kDataChunkID = 0x61746164;
}
struct RIFFTag
{
LEUInt32_t m_tag;