#include "QDPixMap.h" #include "CoreDefs.h" #include "MemoryManager.h" #include "QDStandardPalette.h" #include static const PortabilityLayer::RGBAColor *gs_staticPalette = PortabilityLayer::StandardPalette::GetInstance()->GetColors(); class PixMapSampler_8BitStandard { public: inline static uint8_t ReadAs8BitStandard(const void *rowData, size_t index) { return static_cast(rowData)[index]; } inline static uint32_t ReadAsRGBA(const void *rowData, size_t index) { return gs_staticPalette[static_cast(rowData)[index]].AsUInt32(); } }; class PixMapSampler_32Bit { public: inline static uint8_t ReadAs8BitStandard(const void *rowData, size_t index) { const uint8_t *pixelData = static_cast(rowData) + index * 4; return PortabilityLayer::StandardPalette::GetInstance()->MapColorLUT(PortabilityLayer::RGBAColor::Create(pixelData[0], pixelData[1], pixelData[2], 255)); } inline static uint32_t ReadAsRGBA(const void *rowData, size_t index) { return static_cast(rowData)[index]; } }; template class PixMapCopier_8BitStandard { public: inline static void Copy(const void *inData, size_t inIndex, void *outData, size_t outIndex) { static_cast(outData)[outIndex] = TSampler::ReadAs8BitStandard(inData, inIndex); } }; template class PixMapCopier_32Bit { public: inline static void Copy(const void *inData, size_t inIndex, void *outData, size_t outIndex) { static_cast(outData)[outIndex] = TSampler::ReadAsRGBA(inData, inIndex); } }; template class PixMapColBlitter { public: static void BlitRow(const void *inData, size_t inSize, void *outData, size_t outSize) { if (inSize == outSize) { for (size_t i = 0; i < inSize; i++) TCopier::Copy(inData, i, outData, i); } else if (inSize < outSize) { size_t remainder = 0; size_t inIndex = 0; for (size_t i = 0; i < outSize; i++) { TCopier::Copy(inData, inIndex, outData, i); remainder += inSize; if (remainder >= outSize) { remainder -= outSize; inIndex++; } } } else //if (outSize < inSize) { size_t remainder = 0; size_t outIndex = 0; for (size_t i = 0; i < inSize; i++) { remainder += outSize; if (remainder >= inSize) { TCopier::Copy(inData, i, outData, outIndex); remainder -= inSize; outIndex++; } } } } }; template class PixMapRowBlitter { public: static void Blit(const void *inData, size_t inPitch, size_t inColCount, size_t inRowCount, void *outData, size_t outPitch, size_t outColCount, size_t outRowCount) { if (inRowCount == outRowCount) { for (size_t i = 0; i < inRowCount; i++) { PixMapColBlitter::BlitRow(inData, inColCount, outData, outColCount); inData = static_cast(inData) + inPitch; outData = static_cast(outData) + outPitch; } } else if (inRowCount < outRowCount) { size_t remainder = 0; size_t inIndex = 0; for (size_t i = 0; i < outRowCount; i++) { PixMapColBlitter::BlitRow(inData, inColCount, outData, outColCount); remainder += inRowCount; if (remainder >= outRowCount) { remainder -= outRowCount; inData = static_cast(inData) + inPitch; } outData = static_cast(outData) + outPitch; } } else //if(outRowCount < inRowCount) { size_t remainder = 0; size_t outIndex = 0; for (size_t i = 0; i < inRowCount; i++) { remainder += outRowCount; if (remainder >= inRowCount) { PixMapColBlitter::BlitRow(inData, inColCount, outData, outColCount); remainder -= inRowCount; outData = static_cast(outData) + outPitch; } inData = static_cast(inData) + inPitch; } } } }; template class PixMapBlitTargetDisambiguator { public: static void Blit(const void *inData, size_t inPitch, size_t inColCount, size_t inRowCount, void *outData, size_t outPitch, size_t outColCount, size_t outRowCount, GpPixelFormat_t destFormat) { void(*blitFunc)(const void *inData, size_t inPitch, size_t inColCount, size_t inRowCount, void *outData, size_t outPitch, size_t outColCount, size_t outRowCount); blitFunc = nullptr; switch (destFormat) { case GpPixelFormats::k8BitStandard: blitFunc = PixMapRowBlitter >::Blit; break; case GpPixelFormats::kRGB32: blitFunc = PixMapRowBlitter >::Blit; break; default: PL_NotYetImplemented(); break; } if (blitFunc != nullptr) blitFunc(inData, inPitch, inColCount, inRowCount, outData, outPitch, outColCount, outRowCount); } }; class PixMapBlitSourceDisambiguator { public: static void Blit(const void *inData, size_t inPitch, size_t inColCount, size_t inRowCount, GpPixelFormat_t srcFormat, void *outData, size_t outPitch, size_t outColCount, size_t outRowCount, GpPixelFormat_t destFormat) { void(*blitFunc)(const void *inData, size_t inPitch, size_t inColCount, size_t inRowCount, void *outData, size_t outPitch, size_t outColCount, size_t outRowCount, GpPixelFormat_t srcFormat); blitFunc = nullptr; switch (srcFormat) { case GpPixelFormats::k8BitStandard: blitFunc = PixMapBlitTargetDisambiguator::Blit; break; case GpPixelFormats::kRGB32: blitFunc = PixMapBlitTargetDisambiguator::Blit; break; default: PL_NotYetImplemented(); break; } if (blitFunc != nullptr) blitFunc(inData, inPitch, inColCount, inRowCount, outData, outPitch, outColCount, outRowCount, srcFormat); } }; namespace PortabilityLayer { void PixMapImpl::Destroy(THandle &hdl) { if (hdl) { (*hdl)->~PixMapImpl(); } hdl.Dispose(); } PixMapImpl::PixMapImpl(int16_t left, int16_t top, uint16_t width, uint16_t height, GpPixelFormat_t pixelFormat) : m_left(left) , m_top(top) , m_width(width) , m_height(height) , m_dataCapacity(0) { const Rect rect = Rect::Create(top, left, static_cast(top + height), static_cast(left + width)); const size_t pitch = PitchForWidth(width, pixelFormat); void *dataPtr = reinterpret_cast(this) + AlignedSize(); m_dataCapacity = PitchForWidth(width, pixelFormat) * height; static_cast(this)->Init(rect, pixelFormat, PitchForWidth(width, pixelFormat), dataPtr); } PixMapImpl::~PixMapImpl() { } size_t PixMapImpl::SizeForDimensions(uint16_t width, uint16_t height, GpPixelFormat_t pixelFormat) { return AlignedSize() + PitchForWidth(width, pixelFormat) * height; } size_t PixMapImpl::AlignedSize() { const size_t szBase = sizeof(PixMapImpl) + GP_SYSTEM_MEMORY_ALIGNMENT - 1; const size_t szAdjusted = szBase - szBase % GP_SYSTEM_MEMORY_ALIGNMENT; return szAdjusted; } size_t PixMapImpl::PitchForWidth(uint16_t width, GpPixelFormat_t pixelFormat) { size_t rowByteCount = 0; switch (pixelFormat) { case GpPixelFormats::k8BitCustom: case GpPixelFormats::k8BitStandard: case GpPixelFormats::kBW1: rowByteCount = width; break; case GpPixelFormats::kRGB555: rowByteCount = width * 2; break; case GpPixelFormats::kRGB24: rowByteCount = width * 3; break; case GpPixelFormats::kRGB32: rowByteCount = width * 4; break; default: assert(false); return 0; } const size_t szBase = rowByteCount + GP_SYSTEM_MEMORY_ALIGNMENT - 1; const size_t szAdjusted = szBase - szBase % GP_SYSTEM_MEMORY_ALIGNMENT; return szAdjusted; } THandle PixMapImpl::Create(const Rect &rect, GpPixelFormat_t pixelFormat) { if (!rect.IsValid()) return THandle(); const uint16_t width = static_cast(rect.right - rect.left); const uint16_t height = static_cast(rect.bottom - rect.top); const size_t pixMapSize = PixMapImpl::SizeForDimensions(width, height, pixelFormat); if (pixMapSize == 0) return THandle(); MMHandleBlock *pmBlock = PortabilityLayer::MemoryManager::GetInstance()->AllocHandle(pixMapSize); if (!pmBlock) return THandle(); memset(pmBlock->m_contents, 0, pixMapSize); new (pmBlock->m_contents) PixMapImpl(rect.left, rect.top, width, height, pixelFormat); return THandle(pmBlock); } THandle PixMapImpl::ScaleTo(uint16_t width, uint16_t height) { // Stupid stuff to cover the entire numeric range Rect scaledRect; scaledRect.right = static_cast(width / 2); scaledRect.bottom = static_cast(height / 2); scaledRect.top = static_cast(scaledRect.bottom - height); scaledRect.left = static_cast(scaledRect.right - width); THandle scaled = PixMapImpl::Create(scaledRect, m_pixelFormat); if (!scaled) return THandle(); PixMapImpl *destPixMap = *scaled; const uint16_t oldWidth = m_rect.Width(); const uint16_t oldHeight = m_rect.Height(); PixMapBlitSourceDisambiguator::Blit(GetPixelData(), m_pitch, m_rect.Width(), m_rect.Height(), m_pixelFormat, destPixMap->GetPixelData(), destPixMap->GetPitch(), width, height, m_pixelFormat); return scaled; } } void PixMap::Init(const Rect &rect, GpPixelFormat_t pixelFormat, size_t pitch, void *dataPtr) { BitMap::Init(rect, pixelFormat, pitch, dataPtr); }