mirror of
https://github.com/elasota/Aerofoil.git
synced 2025-12-14 03:59:36 +00:00
Add some initial widget functionality (prefs partly working)
This commit is contained in:
258
PortabilityLayer/IconLoader.cpp
Normal file
258
PortabilityLayer/IconLoader.cpp
Normal file
@@ -0,0 +1,258 @@
|
||||
#include "IconLoader.h"
|
||||
#include "PLCore.h"
|
||||
#include "PLCTabReducer.h"
|
||||
#include "ResourceManager.h"
|
||||
#include "QDStandardPalette.h"
|
||||
#include "QDPixMap.h"
|
||||
|
||||
#include "SharedTypes.h"
|
||||
|
||||
// Color icons (cicn) format:
|
||||
// ColorIconSerializedData (82 bytes)
|
||||
// Mask bits
|
||||
// B&W bits
|
||||
// BEColorTableHeader (8 bytes)
|
||||
// BEColorTableItem (8 bytes)
|
||||
// Color bits
|
||||
|
||||
// ICON format is just a 32x32 bitfield
|
||||
|
||||
struct IconImagePrefix
|
||||
{
|
||||
BEUInt32_t m_unknown; // Seems to always be zero
|
||||
BEUInt16_t m_pitch; // +0x8000 for color
|
||||
};
|
||||
|
||||
struct ColorIconSerializedData
|
||||
{
|
||||
IconImagePrefix m_colorPrefix;
|
||||
BEPixMap m_colorPixMap;
|
||||
IconImagePrefix m_maskPrefix;
|
||||
BEBitMap m_maskBitMap;
|
||||
IconImagePrefix m_bwPrefix;
|
||||
BEBitMap m_bwBitMap;
|
||||
|
||||
uint8_t m_unused[4];
|
||||
};
|
||||
|
||||
namespace PortabilityLayer
|
||||
{
|
||||
class IconLoaderImpl final : public IconLoader
|
||||
{
|
||||
public:
|
||||
bool LoadColorIcon(const int16_t id, THandle<PixMapImpl> &outColorImage, THandle<PixMapImpl> &outBWImage, THandle<PixMapImpl> &outMaskImage) override;
|
||||
THandle<PixMapImpl> LoadBWIcon(const int16_t id) override;
|
||||
|
||||
static IconLoaderImpl *GetInstance();
|
||||
|
||||
private:
|
||||
static bool ParseColorImage(const IconImagePrefix &prefix, const BEPixMap &pixMapHeader, THandle<PixMapImpl> &outHandle, const uint8_t *&dataPtr);
|
||||
static bool ParseBWImage(const IconImagePrefix &prefix, const BEBitMap &bitMapHeader, THandle<PixMapImpl> &outHandle, const uint8_t *&dataPtr);
|
||||
|
||||
static IconLoaderImpl ms_instance;
|
||||
};
|
||||
|
||||
|
||||
bool IconLoaderImpl::LoadColorIcon(const int16_t id, THandle<PixMapImpl> &outColorImage, THandle<PixMapImpl> &outBWImage, THandle<PixMapImpl> &outMaskImage)
|
||||
{
|
||||
THandle<const uint8_t> data = PortabilityLayer::ResourceManager::GetInstance()->GetResource('cicn', id).StaticCast<const uint8_t>();
|
||||
|
||||
if (!data)
|
||||
return false;
|
||||
|
||||
GP_STATIC_ASSERT(sizeof(ColorIconSerializedData) == 82);
|
||||
|
||||
ColorIconSerializedData header;
|
||||
memcpy(&header, *data, sizeof(header));
|
||||
|
||||
const uint8_t *dataPtr = (*data) + sizeof(header);
|
||||
|
||||
THandle<PixMapImpl> maskImage;
|
||||
if (!ParseBWImage(header.m_maskPrefix, header.m_maskBitMap, maskImage, dataPtr))
|
||||
{
|
||||
data.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
THandle<PixMapImpl> bwImage;
|
||||
if (!ParseBWImage(header.m_bwPrefix, header.m_bwBitMap, bwImage, dataPtr))
|
||||
{
|
||||
PixMapImpl::Destroy(maskImage);
|
||||
data.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
THandle<PixMapImpl> colorImage;
|
||||
if (!ParseColorImage(header.m_colorPrefix, header.m_colorPixMap, colorImage, dataPtr))
|
||||
{
|
||||
PixMapImpl::Destroy(bwImage);
|
||||
PixMapImpl::Destroy(maskImage);
|
||||
data.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
outColorImage = colorImage;
|
||||
outBWImage = bwImage;
|
||||
outMaskImage = maskImage;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IconLoaderImpl::ParseColorImage(const IconImagePrefix &prefix, const BEPixMap &pixMapHeader, THandle<PixMapImpl> &outHandle, const uint8_t *&dataPtr)
|
||||
{
|
||||
if (pixMapHeader.m_componentCount != 1 || pixMapHeader.m_packType != 0)
|
||||
{
|
||||
PL_NotYetImplemented();
|
||||
return false;
|
||||
}
|
||||
|
||||
const uint8_t *inData = dataPtr;
|
||||
|
||||
BEColorTableHeader colorTableHeader;
|
||||
memcpy(&colorTableHeader, inData, sizeof(BEColorTableHeader));
|
||||
|
||||
inData += sizeof(BEColorTableHeader);
|
||||
|
||||
const size_t numItems = static_cast<uint16_t>(colorTableHeader.m_numItemsMinusOne) + 1;
|
||||
if (numItems > 256)
|
||||
return false;
|
||||
|
||||
uint8_t remapping[256];
|
||||
for (int i = 0; i < 256; i++)
|
||||
remapping[i] = 0;
|
||||
|
||||
for (size_t i = 0; i < numItems; i++)
|
||||
{
|
||||
BEColorTableItem ctabItem;
|
||||
memcpy(&ctabItem, inData, sizeof(BEColorTableItem));
|
||||
inData += sizeof(BEColorTableItem);
|
||||
|
||||
const uint16_t index = ctabItem.m_index;
|
||||
if (index >= 256)
|
||||
return false;
|
||||
|
||||
const PortabilityLayer::RGBAColor remappedColor = CTabReducer::DecodeClutItem(ctabItem);
|
||||
|
||||
remapping[index] = StandardPalette::GetInstance()->MapColorLUT(remappedColor);
|
||||
}
|
||||
|
||||
const Rect rect = pixMapHeader.m_bounds.ToRect();
|
||||
if (!rect.IsValid())
|
||||
return false;
|
||||
|
||||
THandle<PixMapImpl> pixMap = PixMapImpl::Create(rect, GpPixelFormats::k8BitStandard);
|
||||
if (!pixMap)
|
||||
return false;
|
||||
|
||||
const size_t width = rect.Width();
|
||||
const size_t height = rect.Height();
|
||||
const size_t inPitch = (prefix.m_pitch & 0x7fff);
|
||||
|
||||
uint8_t *outData = static_cast<uint8_t*>((*pixMap)->GetPixelData());
|
||||
const size_t outPitch = (*pixMap)->GetPitch();
|
||||
|
||||
for (size_t row = 0; row < height; row++)
|
||||
{
|
||||
if (numItems > 16)
|
||||
{
|
||||
// 8bpp
|
||||
for (size_t col = 0; col < width; col++)
|
||||
{
|
||||
const unsigned int index = inData[col];
|
||||
outData[col] = remapping[index];
|
||||
}
|
||||
}
|
||||
else if (numItems > 4)
|
||||
{
|
||||
// 4bpp
|
||||
for (size_t col = 0; col < width; col++)
|
||||
{
|
||||
const unsigned int index = (inData[col / 2] >> (4 - ((col & 1) * 4))) & 0x0f;
|
||||
outData[col] = remapping[index];
|
||||
}
|
||||
}
|
||||
else if (numItems > 2)
|
||||
{
|
||||
// 2bpp
|
||||
for (size_t col = 0; col < width; col++)
|
||||
{
|
||||
const unsigned int index = (inData[col / 4] >> (6 - ((col & 3) * 2))) & 0x03;
|
||||
outData[col] = remapping[index];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 1bpp
|
||||
for (size_t col = 0; col < width; col++)
|
||||
{
|
||||
const unsigned int index = (inData[col / 4] >> (7 - (col & 7))) & 0x01;
|
||||
outData[col] = remapping[index];
|
||||
}
|
||||
}
|
||||
|
||||
inData += inPitch;
|
||||
outData += outPitch;
|
||||
}
|
||||
|
||||
outHandle = pixMap;
|
||||
dataPtr = inData;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool IconLoaderImpl::ParseBWImage(const IconImagePrefix &prefix, const BEBitMap &bitMapHeader, THandle<PixMapImpl> &outHandle, const uint8_t *&dataPtr)
|
||||
{
|
||||
const Rect rect = bitMapHeader.m_bounds.ToRect();
|
||||
if (!rect.IsValid())
|
||||
return false;
|
||||
|
||||
THandle<PixMapImpl> pixMap = PixMapImpl::Create(rect, GpPixelFormats::kBW1);
|
||||
if (!pixMap)
|
||||
return THandle<PixMapImpl>();
|
||||
|
||||
const size_t inPitch = prefix.m_pitch;
|
||||
const size_t height = rect.Height();
|
||||
const size_t width = rect.Width();
|
||||
|
||||
const uint8_t *inData = dataPtr;
|
||||
uint8_t *outData = static_cast<uint8_t*>((*pixMap)->GetPixelData());
|
||||
const size_t outPitch = (*pixMap)->GetPitch();
|
||||
|
||||
for (size_t row = 0; row < height; row++)
|
||||
{
|
||||
for (size_t col = 0; col < width; col++)
|
||||
{
|
||||
if (inData[col / 8] & (0x80 >> (col & 7)))
|
||||
outData[col] = 0xff;
|
||||
else
|
||||
outData[col] = 0x00;
|
||||
}
|
||||
|
||||
inData += inPitch;
|
||||
outData += outPitch;
|
||||
}
|
||||
|
||||
dataPtr = inData;
|
||||
outHandle = pixMap;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
THandle<PixMapImpl> IconLoaderImpl::LoadBWIcon(const int16_t id)
|
||||
{
|
||||
PL_NotYetImplemented();
|
||||
return THandle<PixMapImpl>();
|
||||
}
|
||||
|
||||
IconLoaderImpl *IconLoaderImpl::GetInstance()
|
||||
{
|
||||
return &ms_instance;
|
||||
}
|
||||
|
||||
IconLoaderImpl IconLoaderImpl::ms_instance;
|
||||
|
||||
IconLoader *IconLoader::GetInstance()
|
||||
{
|
||||
return IconLoaderImpl::GetInstance();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user