123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- // Jolt Physics Library (https://github.com/jrouwe/JoltPhysics)
- // SPDX-FileCopyrightText: 2021 Jorrit Rouwe
- // SPDX-License-Identifier: MIT
- #include <TestFramework.h>
- #include <Image/Surface.h>
- //////////////////////////////////////////////////////////////////////////////////////////
- // FormatDescription
- //
- // Description of a surface format
- //////////////////////////////////////////////////////////////////////////////////////////
- // Format descriptions
- static FormatDescription sFormats[] =
- {
- // Decription BPP #CMP Closest 8 Bit Closest Alpha Red Mask Green Mask Blue Mask Alpha Mask
- FormatDescription("A4L4", 8, 2, ESurfaceFormat::A8L8, ESurfaceFormat::A4L4, 0x0000000f, 0x0000000f, 0x0000000f, 0x000000f0),
- FormatDescription("L8", 8, 1, ESurfaceFormat::L8, ESurfaceFormat::A8L8, 0x000000ff, 0x000000ff, 0x000000ff, 0x00000000),
- FormatDescription("A8", 8, 1, ESurfaceFormat::A8, ESurfaceFormat::A8, 0x00000000, 0x00000000, 0x00000000, 0x000000ff),
- FormatDescription("A8L8", 16, 2, ESurfaceFormat::A8L8, ESurfaceFormat::A8L8, 0x000000ff, 0x000000ff, 0x000000ff, 0x0000ff00),
- FormatDescription("R5G6B5", 16, 3, ESurfaceFormat::R8G8B8, ESurfaceFormat::A1R5G5B5, 0x0000f800, 0x000007e0, 0x0000001f, 0x00000000),
- FormatDescription("X1R5G5B5", 16, 3, ESurfaceFormat::R8G8B8, ESurfaceFormat::A1R5G5B5, 0x00007c00, 0x000003e0, 0x0000001f, 0x00000000),
- FormatDescription("X4R4G4B4", 16, 3, ESurfaceFormat::R8G8B8, ESurfaceFormat::A4R4G4B4, 0x00000f00, 0x000000f0, 0x0000000f, 0x00000000),
- FormatDescription("A1R5G5B5", 16, 4, ESurfaceFormat::A8R8G8B8, ESurfaceFormat::A1R5G5B5, 0x00007c00, 0x000003e0, 0x0000001f, 0x00008000),
- FormatDescription("A4R4G4B4", 16, 4, ESurfaceFormat::A8R8G8B8, ESurfaceFormat::A4R4G4B4, 0x00000f00, 0x000000f0, 0x0000000f, 0x0000f000),
- FormatDescription("R8G8B8", 24, 3, ESurfaceFormat::R8G8B8, ESurfaceFormat::A8R8G8B8, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
- FormatDescription("B8G8R8", 24, 3, ESurfaceFormat::B8G8R8, ESurfaceFormat::A8B8G8R8, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000),
- FormatDescription("X8R8G8B8", 32, 3, ESurfaceFormat::X8R8G8B8, ESurfaceFormat::A8R8G8B8, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000),
- FormatDescription("X8B8G8R8", 32, 3, ESurfaceFormat::X8B8G8R8, ESurfaceFormat::A8B8G8R8, 0x000000ff, 0x0000ff00, 0x00ff0000, 0x00000000),
- FormatDescription("A8R8G8B8", 32, 4, ESurfaceFormat::A8R8G8B8, ESurfaceFormat::A8R8G8B8, 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000),
- FormatDescription("A8B8G8R8", 32, 4, ESurfaceFormat::A8B8G8R8, ESurfaceFormat::A8B8G8R8, 0x000000ff, 0x0000ff00, 0x00ff0000, 0xff000000),
- FormatDescription("Invalid", 0, 0, ESurfaceFormat::Invalid, ESurfaceFormat::Invalid, 0x00000000, 0x00000000, 0x00000000, 0x00000000),
- };
- FormatDescription::FormatDescription(const char *inFormatName, int inBitsPerPixel, int inNumberOfComponents, ESurfaceFormat inClosest8BitFormat, ESurfaceFormat inClosestAlphaFormat, uint32 inRedMask, uint32 inGreenMask, uint32 inBlueMask, uint32 inAlphaMask) :
- mFormatName(inFormatName),
- mBitsPerPixel(inBitsPerPixel),
- mNumberOfComponents(inNumberOfComponents),
- mClosest8BitFormat(inClosest8BitFormat),
- mClosestAlphaFormat(inClosestAlphaFormat),
- mRedMask(inRedMask),
- mGreenMask(inGreenMask),
- mBlueMask(inBlueMask),
- mAlphaMask(inAlphaMask)
- {
- }
- uint32 FormatDescription::Encode(ColorArg inColor) const
- {
- uint32 col = 0;
- uint32 written_mask = 0;
- // Loop through all components
- for (int c = 0; c < 4; ++c)
- {
- // Check that we have not yet written this part of the color yet
- uint32 mask = GetComponentMask(c);
- if ((written_mask & mask) != 0) continue;
- written_mask |= mask;
- // Or in this component
- col |= int(round((1.0f / 255.0f) * mask * inColor(c))) & mask;
- }
- return col;
- }
- const Color FormatDescription::Decode(uint32 inColor) const
- {
- Color col(0, 0, 0, 0);
- // Loop through all components
- for (int c = 0; c < 4; ++c)
- {
- uint32 mask = GetComponentMask(c);
- if (mask != 0)
- {
- uint32 shift = CountTrailingZeros(mask);
- uint32 shifted_color = (inColor & mask) >> shift;
- uint32 shifted_mask = mask >> shift;
- col(c) = uint8((255 * shifted_color + 127) / shifted_mask);
- }
- else
- col(c) = 255;
- }
- return col;
- }
- const FormatDescription &GetFormatDescription(ESurfaceFormat inFormat)
- {
- if (inFormat <= ESurfaceFormat::Invalid)
- return sFormats[uint(inFormat)];
- return sFormats[uint(ESurfaceFormat::Invalid)];
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // Surface
- //
- // Class that contains an image in arbitrary format
- //////////////////////////////////////////////////////////////////////////////////////////
- Surface::Surface(int inWidth, int inHeight, ESurfaceFormat inFormat) :
- mFormat(inFormat),
- mWidth(inWidth),
- mHeight(inHeight),
- mLength(0),
- mLockMode(ESurfaceLockMode::None),
- mStride(0),
- mData(nullptr)
- {
- }
- Surface::~Surface()
- {
- JPH_ASSERT(!IsLocked());
- JPH_ASSERT(mData == nullptr);
- JPH_ASSERT(mStride == 0);
- JPH_ASSERT(mLength == 0);
- }
- void Surface::Lock(ESurfaceLockMode inMode) const
- {
- // Check if this resource can be locked
- JPH_ASSERT(!IsLocked());
- JPH_ASSERT((uint(inMode) & uint(ESurfaceLockMode::ReadWrite)) != 0);
- // Store mode
- mLockMode = inMode;
- // Lock the buffer
- HardwareLock();
- // Check that data and stride were filled in
- JPH_ASSERT(mData != nullptr);
- JPH_ASSERT(mStride > 0);
- JPH_ASSERT(mLength > 0);
- }
- void Surface::UnLock() const
- {
- // Check if this resource was locked
- JPH_ASSERT(IsLocked());
- // Unlock the hardware resource
- HardwareUnLock();
- // Reset members, so we are sure they will be set next time
- mLockMode = ESurfaceLockMode::None;
- mStride = 0;
- mLength = 0;
- mData = nullptr;
- }
- void Surface::Clear(ColorArg inColor)
- {
- Lock(ESurfaceLockMode::Write);
- // Get image properties
- int bpp = GetBytesPerPixel();
- int width = GetWidth();
- int height = GetHeight();
- // Determine clear color
- uint32 col = GetFormatDescription().Encode(inColor);
- // Clear the image
- for (int y = 0; y < height; ++y)
- {
- uint8 *d = GetScanLine(y);
- uint8 *d_end = GetScanLine(y) + width * bpp;
- while (d < d_end)
- {
- memcpy(d, &col, bpp);
- d += bpp;
- }
- }
- UnLock();
- }
- //////////////////////////////////////////////////////////////////////////////////////////
- // SoftwareSurface
- //
- // Class that contains an image in arbitrary format
- //////////////////////////////////////////////////////////////////////////////////////////
- SoftwareSurface::SoftwareSurface(int inWidth, int inHeight, ESurfaceFormat inFormat, int inStride) :
- Surface(inWidth, inHeight, inFormat)
- {
- // Determine stride and length
- mPixelStride = inStride == 0? ((mWidth * GetBytesPerPixel() + 3) & ~3) : inStride;
- mPixelLength = mPixelStride * inHeight;
- // Allocate pixel data
- JPH_ASSERT(mPixelLength > 0);
- mPixelData = new uint8 [mPixelLength];
- }
- SoftwareSurface::~SoftwareSurface()
- {
- delete mPixelData;
- }
- void SoftwareSurface::HardwareLock() const
- {
- // Get pointer to data
- mData = mPixelData;
- mStride = mPixelStride;
- mLength = mPixelLength;
- }
- void SoftwareSurface::HardwareUnLock() const
- {
- }
|