diff --git a/librtt/Display/Rtt_BufferBitmap.cpp b/librtt/Display/Rtt_BufferBitmap.cpp index 6771631ce..7a6a3c1e9 100644 --- a/librtt/Display/Rtt_BufferBitmap.cpp +++ b/librtt/Display/Rtt_BufferBitmap.cpp @@ -25,7 +25,7 @@ BufferBitmap::BufferBitmap( Rtt_Allocator* allocator, size_t w, size_t h, Platfo fWidth( (U32) w ), fHeight( (U32) h ), fProperties( 0 ), - fFormat( format ), + fFormat( format.GetValue() ), fOrientation( orientation ) { Rtt_ASSERT( fData ); @@ -89,7 +89,7 @@ BufferBitmap::UprightHeight() const PlatformBitmap::Format BufferBitmap::GetFormat() const { - return (PlatformBitmap::Format)fFormat; + return (PlatformBitmap::FormatValue)fFormat; } bool diff --git a/librtt/Display/Rtt_PlatformBitmap.cpp b/librtt/Display/Rtt_PlatformBitmap.cpp index acb552ecf..11e3be8cc 100644 --- a/librtt/Display/Rtt_PlatformBitmap.cpp +++ b/librtt/Display/Rtt_PlatformBitmap.cpp @@ -16,6 +16,25 @@ namespace Rtt { +// ---------------------------------------------------------------------------- + + PlatformBitmap::Format::Format( FormatValue value ) +: fValue( value ) +{ +} + +PlatformBitmap::FormatValue +PlatformBitmap::Format::GetValue() const +{ + return (FormatValue)GetStockFormatAndFlag( fValue ); +} + +bool +PlatformBitmap::Format::IsNonCore() const +{ + return HasFormatFlag( fValue ); +} + // ---------------------------------------------------------------------------- PlatformBitmap::PlatformBitmap() @@ -50,7 +69,7 @@ PlatformBitmap::HitTest( Rtt_Allocator *context, int i, int j, U8 threshold ) co int index = (int) bytesPerPixel * ( i + j*Width() ); - switch ( format ) + switch ( format.GetValue() ) { case kMask: { @@ -134,7 +153,7 @@ PlatformBitmap::HasAlphaChannel() const Format format = GetFormat(); - switch ( format ) + switch ( format.GetValue() ) { case kRGBA: case kBGRA: @@ -143,6 +162,12 @@ PlatformBitmap::HasAlphaChannel() const result = true; break; default: + if ( format.IsNonCore() ) + { + FormatDetails details = FormatDetails::UnpackFromValue( format.GetBackingValue() ); + + result = -1 != details.fAlphaIndex; + } break; } @@ -189,7 +214,7 @@ PlatformBitmap::IsLandscape() const size_t PlatformBitmap::BytesPerPixel( Format format ) { - switch( format ) + switch( format.GetValue() ) { case kMask: return 1; @@ -203,6 +228,12 @@ PlatformBitmap::BytesPerPixel( Format format ) case kABGR: return 4; default: + if ( format.IsNonCore() ) + { + FormatDetails details = FormatDetails::UnpackFromValue( format.GetBackingValue() ); + + return details.fBytesPerComponent * details.fNumComponents; + } break; } @@ -259,7 +290,7 @@ PlatformBitmap::GetColorByteIndexesFor( int blueIndexOut = -1; // Fetch the color byte index by format and endianness. - switch (format) + switch ( format.GetValue() ) { case PlatformBitmap::kRGB: #ifdef Rtt_LITTLE_ENDIAN @@ -325,8 +356,20 @@ PlatformBitmap::GetColorByteIndexesFor( #endif break; default: - // New formats need to have a case above - Rtt_ASSERT_NOT_IMPLEMENTED(); + if ( format.IsNonCore() ) + { + FormatDetails details = FormatDetails::UnpackFromValue( format.GetBackingValue() ); + + redIndexOut = details.fRedIndex; + greenIndexOut = details.fGreenIndex; + blueIndexOut = details.fBlueIndex; + alphaIndexOut = details.fAlphaIndex; + } + else + { + // New formats need to have a case above + Rtt_ASSERT_NOT_IMPLEMENTED(); + } break; } @@ -371,7 +414,7 @@ PlatformBitmap::Unlock() void PlatformBitmap::SwapRGB() { - if ( GetFormat() != kRGBA ) + if ( GetFormat().GetValue() != kRGBA ) return; char * pixels = const_cast( (const char *) GetBits( NULL ) ); @@ -402,6 +445,15 @@ PlatformBitmap::SwapBitmapRGB( char * pixels, int w, int h ) // ---------------------------------------------------------------------------- +using FV1 = Texture::FormatValue; +using FV2 = PlatformBitmap::FormatValue; + +// These details are basically frozen, but enforce them. +Rtt_STATIC_ASSERT( (U32)FV1::kNumFormats == (U32)FV2::kNumFormats ); +Rtt_STATIC_ASSERT( (U32)( 1U << kStockFormatBits ) >= (U32)FV1::kNumFormats ); + +// ---------------------------------------------------------------------------- + } // namespace Rtt // ---------------------------------------------------------------------------- diff --git a/librtt/Display/Rtt_PlatformBitmap.h b/librtt/Display/Rtt_PlatformBitmap.h index b01dc3ebb..33ca71f47 100644 --- a/librtt/Display/Rtt_PlatformBitmap.h +++ b/librtt/Display/Rtt_PlatformBitmap.h @@ -26,7 +26,7 @@ namespace Rtt class PlatformBitmap { public: - typedef enum Format + typedef enum FormatValue { kUndefined = 0, kMask, @@ -38,7 +38,22 @@ class PlatformBitmap kLUMINANCE_ALPHA, kNumFormats } - Format; + FormatValue; + + class Format { + public: + Format( FormatValue value = kUndefined ); + + FormatValue GetValue() const; + U32 GetBackingValue() const { return fValue; } + void SetBackingValue( U32 value ) { fValue = value; } + + public: + bool IsNonCore() const; + + private: + U32 fValue; + }; public: typedef enum _Orientation @@ -162,7 +177,7 @@ class PlatformBitmap bool IsLandscape() const; // TODO: Remove as this is subsumed by GetFormat(); - Rtt_INLINE bool IsMask() const { return GetFormat() == kMask; } + Rtt_INLINE bool IsMask() const { return GetFormat().GetValue() == kMask; } public: RenderTypes::TextureFilter GetMagFilter() const { return (RenderTypes::TextureFilter)fMagFilter; } diff --git a/librtt/Display/Rtt_PlatformBitmapTexture.cpp b/librtt/Display/Rtt_PlatformBitmapTexture.cpp index 35df89755..f0beef574 100755 --- a/librtt/Display/Rtt_PlatformBitmapTexture.cpp +++ b/librtt/Display/Rtt_PlatformBitmapTexture.cpp @@ -53,7 +53,7 @@ PlatformBitmapTexture::ConvertFormat( PlatformBitmap::Format format ) { Texture::Format result = Texture::kRGBA; - switch ( format ) + switch ( format.GetValue() ) { case PlatformBitmap::kRGB: result = Texture::kRGB; @@ -88,7 +88,14 @@ PlatformBitmapTexture::ConvertFormat( PlatformBitmap::Format format ) result = Texture::kLuminanceAlpha; break; default: - Rtt_ASSERT_NOT_IMPLEMENTED(); + if ( format.IsNonCore() ) + { + result.SetBackingValue( format.GetBackingValue() ); + } + else + { + Rtt_ASSERT_NOT_IMPLEMENTED(); + } break; } diff --git a/librtt/Display/Rtt_TextureResource.cpp b/librtt/Display/Rtt_TextureResource.cpp index 63b7057df..36c6ca26f 100644 --- a/librtt/Display/Rtt_TextureResource.cpp +++ b/librtt/Display/Rtt_TextureResource.cpp @@ -57,7 +57,7 @@ TextureResource::ConvertFormat( Texture::Format format ) { PlatformBitmap::Format result = PlatformBitmap::kRGBA; - switch ( format ) + switch ( format.GetValue() ) { case Texture::kRGB: result = PlatformBitmap::kRGB; @@ -79,7 +79,14 @@ TextureResource::ConvertFormat( Texture::Format format ) case Texture::kLuminance: case Texture::kAlpha: default: - Rtt_ASSERT_NOT_IMPLEMENTED(); + if ( format.IsNonCore() ) + { + result.SetBackingValue( format.GetBackingValue() ); + } + else + { + Rtt_ASSERT_NOT_IMPLEMENTED(); + } break; } diff --git a/librtt/Display/Rtt_TextureResourceBitmap.cpp b/librtt/Display/Rtt_TextureResourceBitmap.cpp index e48fbede3..7f68115e9 100644 --- a/librtt/Display/Rtt_TextureResourceBitmap.cpp +++ b/librtt/Display/Rtt_TextureResourceBitmap.cpp @@ -46,6 +46,7 @@ TextureResourceBitmap::Create( if( save_to_file ) { + // TODO? check if this can occur with non-built-in-formats (BufferBitmap currently just uses a U8) bitmap = Rtt_NEW( allocator, BufferBitmap( display.GetAllocator(), w, diff --git a/librtt/Display/Rtt_TextureResourceCanvas.cpp b/librtt/Display/Rtt_TextureResourceCanvas.cpp index 84f752a30..476a112ff 100644 --- a/librtt/Display/Rtt_TextureResourceCanvas.cpp +++ b/librtt/Display/Rtt_TextureResourceCanvas.cpp @@ -57,7 +57,7 @@ TextureResourceCanvas* TextureResourceCanvas::Create(Rtt::TextureFactory &factor Texture::Filter filter = RenderTypes::Convert( display.GetDefaults().GetMagTextureFilter() ); Texture::Wrap wrap = RenderTypes::Convert( display.GetDefaults().GetTextureWrapX() ); - if (Texture::kLuminance == format) + if ( Texture::kLuminance == format.GetValue() ) { format = Texture::kRGBA; } diff --git a/librtt/Renderer/Rtt_FrameBufferObject.h b/librtt/Renderer/Rtt_FrameBufferObject.h index 9b00fd2bc..fcd5a5b87 100644 --- a/librtt/Renderer/Rtt_FrameBufferObject.h +++ b/librtt/Renderer/Rtt_FrameBufferObject.h @@ -18,6 +18,7 @@ namespace Rtt { +class BufferBitmap; class Texture; // ---------------------------------------------------------------------------- @@ -42,6 +43,8 @@ class FrameBufferObject : public CPUResource U8 GetDepthBits() const { return fDepthBits; } U8 GetStencilBits() const { return fStencilBits; } bool GetMustClear() const { return fMustClear; } + + static void Capture( BufferBitmap& bitmap, S32 x_in_pixels, S32 y_in_pixels, S32 w_in_pixels, S32 h_in_pixels ); private: Texture* fTexture; diff --git a/librtt/Renderer/Rtt_GLFrameBufferObject.cpp b/librtt/Renderer/Rtt_GLFrameBufferObject.cpp index ae5e73b75..4750f52c2 100644 --- a/librtt/Renderer/Rtt_GLFrameBufferObject.cpp +++ b/librtt/Renderer/Rtt_GLFrameBufferObject.cpp @@ -21,6 +21,8 @@ #include #include "Rtt_Profiling.h" +#include "Display/Rtt_BufferBitmap.h" + // ---------------------------------------------------------------------------- #define ENABLE_DEBUG_PRINT 0 @@ -272,8 +274,117 @@ GLFrameBufferObject::Blit( int srcX0, int srcY0, int srcX1, int srcY1, int dstX0 sBlitFramebuffer( srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter ); } +static GLenum +GPU_GetPixelFormat( PlatformBitmap::Format format ) +{ +# ifdef Rtt_OPENGLES + + switch ( format ) + { + case PlatformBitmap::kRGBA: + return GL_RGBA; + case PlatformBitmap::kMask: + return GL_ALPHA; + case PlatformBitmap::kRGB: + case PlatformBitmap::kBGRA: + case PlatformBitmap::kARGB: + default: + Rtt_ASSERT_NOT_IMPLEMENTED(); + return GL_ALPHA; + } + +# else // Not Rtt_OPENGLES. + + switch ( format.GetValue() ) + { + case PlatformBitmap::kBGRA: + case PlatformBitmap::kARGB: + return GL_BGRA; + case PlatformBitmap::kRGBA: + return GL_RGBA; + case PlatformBitmap::kRGB: + return GL_BGR; + case PlatformBitmap::kMask: + return GL_ALPHA; + default: + Rtt_ASSERT_NOT_IMPLEMENTED(); + return GL_ALPHA; + } + +# endif // Rtt_OPENGLES +} + +static GLenum +GPU_GetPixelType( PlatformBitmap::Format format ) +{ +# ifdef Rtt_OPENGLES + + switch( format ) + { + case PlatformBitmap::kMask: + return GL_UNSIGNED_BYTE; + case PlatformBitmap::kBGRA: + case PlatformBitmap::kARGB: + case PlatformBitmap::kRGBA: + default: + Rtt_ASSERT_NOT_IMPLEMENTED(); + return GL_UNSIGNED_BYTE; + } + +# else // Not Rtt_OPENGLES. + + switch( format.GetValue() ) + { + case PlatformBitmap::kBGRA: + #ifdef Rtt_BIG_ENDIAN + return GL_UNSIGNED_INT_8_8_8_8_REV; + #else + return GL_UNSIGNED_INT_8_8_8_8; + #endif + case PlatformBitmap::kARGB: + #ifdef Rtt_BIG_ENDIAN + return GL_UNSIGNED_INT_8_8_8_8; + #else + return GL_UNSIGNED_INT_8_8_8_8_REV; + #endif + case PlatformBitmap::kRGBA: + #ifdef Rtt_BIG_ENDIAN + return GL_UNSIGNED_INT_8_8_8_8_REV; + #else + return GL_UNSIGNED_INT_8_8_8_8; + #endif + case PlatformBitmap::kMask: + return GL_UNSIGNED_BYTE; + default: + Rtt_ASSERT_NOT_IMPLEMENTED(); + return GL_UNSIGNED_BYTE; + } + +# endif // Rtt_OPENGLES +} + +void FrameBufferObject::Capture( BufferBitmap& bitmap, S32 x_in_pixels, S32 y_in_pixels, S32 w_in_pixels, S32 h_in_pixels ) +{ +#ifdef Rtt_OPENGLES + const GLenum kFormat = GL_RGBA; + const GLenum kType = GL_UNSIGNED_BYTE; +#else + PlatformBitmap::Format format = bitmap.GetFormat(); + const GLenum kFormat = GPU_GetPixelFormat( format ); + GLenum kType = GPU_GetPixelType( format ); +#endif + + glReadPixels( x_in_pixels, + y_in_pixels, + w_in_pixels, + h_in_pixels, + kFormat, + kType, + bitmap.WriteAccess() ); +} + // ---------------------------------------------------------------------------- } // namespace Rtt -// ---------------------------------------------------------------------------- \ No newline at end of file +// ---------------------------------------------------------------------------- diff --git a/librtt/Renderer/Rtt_GLTexture.cpp b/librtt/Renderer/Rtt_GLTexture.cpp index e046b2b72..cc9256fa4 100644 --- a/librtt/Renderer/Rtt_GLTexture.cpp +++ b/librtt/Renderer/Rtt_GLTexture.cpp @@ -39,7 +39,7 @@ namespace /*anonymous*/ void getFormatTokens( Texture::Format format, GLint& internalFormat, GLenum& sourceFormat, GLenum& sourceType ) { - switch( format ) + switch( format.GetValue() ) { case Texture::kAlpha: internalFormat = GL_ALPHA; sourceFormat = GL_ALPHA; sourceType = GL_UNSIGNED_BYTE; break; #if defined( Rtt_MetalANGLE) diff --git a/librtt/Renderer/Rtt_RenderTypes.cpp b/librtt/Renderer/Rtt_RenderTypes.cpp index f63963688..350a01ae1 100644 --- a/librtt/Renderer/Rtt_RenderTypes.cpp +++ b/librtt/Renderer/Rtt_RenderTypes.cpp @@ -1170,6 +1170,349 @@ BlendMode::operator==( const BlendMode& rhs ) const // ---------------------------------------------------------------------------- +// These details are used to lug around some information for non-built-in or non-2D-target +// texture and / or bitmap resources. Although this can be looked up, there are several +// usual situations where doing so is inconvenient. + +enum { + // These bits describe whether a texture and sampler can pair up, so that paints + // know whether they can plug into a given shader input. Some bitmap operations + // can also take this into consideration, e.g. only considering vanilla 2D. + kFamilyBits = 2, + kTargetBits = 3, + kTargetSubtypeBits = 2, + + // If this flag is set, we have a "non-core" format and the remaining bits come + // into play; the stock bits themselves lose their meaning and may be repurposed. + // N.B. this flag could be anywhere, but together with the stock bits we follow + // the reasonable assumption and put them in the lowest few bits. + kFormatFlagBit = 1 << kStockFormatBits, + + // Allow 512 possible texture formats and aliases. + // This value is fairly arbitrary: some research suggests a Vulkan backend, which + // seemed to be the most prolific case, might allow 300-some options. In practice + // this is probably overly generous, with the majority of these being irrelevant. + kFormatIndexBits = 9, + + // These are some details used to interpret the format as a bitmap, e.g. to find + // the size or component layout. The format may be "normal", packed, or compressed, + // with the information interpreted accordingly. + kShiftBits = 2, + kComponentBits = 3, + kDataBits = 4, + + // Sums of some related bits... + kTargetPartBits = kFamilyBits + kTargetBits + kTargetSubtypeBits, + kDetailBits = kShiftBits + kComponentBits + kDataBits, + + // ...and # of bits maximally alloted, i.e. when the format flag bit is set and + // the stock format bits have been fully repurposed. + kAllBits = 1 + kFormatIndexBits + kTargetPartBits + kDetailBits + + // Some validation of these is done in corresponding C++ files. +}; + +Rtt_STATIC_ASSERT( kAllBits <= 32 ); + +// ---------------------------------------------------------------------------- + +struct MaskInfo { + int fFirstBit; + int fNumBits; + U32 fIncludeMask; + U32 fExcludeMask; +}; + +#define INCLUDE_MASK( numBits ) ( ( 1U << ( numBits ) ) - 1 ) +#define MAKE_MASK_INFO( first, numBits, next ) { \ + first, numBits, INCLUDE_MASK( numBits ), ~( INCLUDE_MASK( numBits ) << ( first ) ) \ +}; const int next = first + numBits + +static const MaskInfo FormatMask = MAKE_MASK_INFO( 0, kStockFormatBits, kFormatFlagOffset ); +static const U32 FormatFlag = 1U << kFormatFlagOffset; +static const MaskInfo FormatAndFlagMask = MAKE_MASK_INFO( 0, kStockFormatBits + 1, kFormatIndexOffset ); + +static const MaskInfo FormatIndexMask = MAKE_MASK_INFO( kFormatIndexOffset, kFormatIndexBits, kFamilyOffset ); + +static const MaskInfo FamilyMask = MAKE_MASK_INFO( kFamilyOffset, kFamilyBits, kTargetOffset ); +static const MaskInfo TargetMask = MAKE_MASK_INFO( kTargetOffset, kTargetBits, kTargetSubtypeOffset ); +static const MaskInfo TargetSubtypeMask = MAKE_MASK_INFO( kTargetSubtypeOffset, kTargetSubtypeBits, kShiftOffset ); + +// n.b. repurposes stock format bits when using non-core format +Rtt_STATIC_ASSERT(kStockFormatBits == kComponentBits); +static const MaskInfo ComponentMask = FormatMask; + +static const MaskInfo ShiftMask = MAKE_MASK_INFO( kShiftOffset, kShiftBits, kDataOffset ); +static const MaskInfo DataMask = MAKE_MASK_INFO( kDataOffset, kDataBits, kDoneOffset ); + +Rtt_STATIC_ASSERT( kDoneOffset == kAllBits ); + +#undef INCLUDE_MASK +#undef MAKE_MASK_INFO + +static U32 +GetBits( U32 v, const MaskInfo& info ) +{ + return ( v >> info.fFirstBit ) & info.fIncludeMask; +} + +static void +SetBits( U32* v, U32 bits, const MaskInfo& info ) +{ + Rtt_ASSERT( ( bits & info.fIncludeMask ) == bits ); + + *v &= info.fExcludeMask; + *v |= bits << info.fFirstBit; +} + +// ---------------------------------------------------------------------------- + +bool +HasFormatFlag( U32 v ) +{ + return 0 != ( v & kFormatFlagBit ); +} + +U32 +GetStockFormatAndFlag( U32 v ) +{ + return GetBits( v, FormatAndFlagMask ); +} + +U32 +GetFormatIndex( U32 v ) +{ + return GetBits( v, FormatIndexMask ); +} + +void +SetFormatIndex( U32* v, U32 index ) +{ + SetBits( v, index, FormatIndexMask ); +} + +U32 +GetFamily( U32 v ) +{ + return GetBits( v, FamilyMask ); +} + +void +SetFamily( U32* v, U32 family ) +{ + SetBits( v, family, FamilyMask ); +} + +U32 +GetTarget( U32 v ) +{ + return GetBits( v, TargetMask ); +} + +void +SetTarget( U32* v, U32 target ) +{ + SetBits( v, target, TargetMask ); +} + +U32 +GetTargetSubtype( U32 v ) +{ + return GetBits( v, TargetSubtypeMask ); +} + +void +SetTargetSubtype( U32* v, U32 targetSubtype ) +{ + SetBits( v, targetSubtype, TargetSubtypeMask ); +} + +U32 +GetComponents( U32 v ) +{ + return GetBits( v, ComponentMask ); +} + +void +SetComponents( U32* v, U32 components ) +{ + SetBits( v, components, ComponentMask ); +} + +U32 +GetShift( U32 v ) +{ + return GetBits( v, ShiftMask ); +} + +void +SetShift( U32* v, U32 shift ) +{ + SetBits( v, shift, ShiftMask ); +} + +U32 +GetData( U32 v ) +{ + return GetBits( v, DataMask ); +} + +void +SetData( U32* v, U32 data ) +{ + SetBits( v, data, DataMask ); +} + +// Grouped: + +// TODO? + // format-and-flag sort of abuses that #formats == 1 << StockFormatBits (and then uses those bits + flag) + // maybe should just make the enum have U32 class? + +// TODO? + // could save DetailMask::kNextBitIndex to use the remaining 6 or so bits + +// ---------------------------------------------------------------------------- + +const U32 kASTCMask = 1U << ( kComponentBits - 1 ); // high bit, when compressed = has ASTC-style block + +bool +FormatDetails::PackToValue( U32* v ) +{ + // ensure power-of-2 in (1, 2, 4, 8) + Rtt_ASSERT( fBytesPerComponent > 0 ); + Rtt_ASSERT( fBytesPerComponent < 16 ); + Rtt_ASSERT( 0 == ( fBytesPerComponent & ( fBytesPerComponent - 1 ) ) ); + + // ensure power-of-2 in (1, 2, 4) + bool isCompressed = 0 != fBlockSize; + + Rtt_ASSERT( !isCompressed || ( 0 != fBlockWidth && 0 != fBlockHeight ) ); + Rtt_ASSERT( isCompressed || fBytesPerComponent > 0 ); + Rtt_ASSERT( isCompressed || fBytesPerComponent < 8 ); + Rtt_ASSERT( isCompressed || 0 == ( fBytesPerComponent & ( fBytesPerComponent - 1 ) ) ); + + // TODO: so far we only have simple schemes; fix up + // if and when more sophisticated cases arise + + int componentCount = 1; + int indices[] = { fRedIndex, fGreenIndex, fBlueIndex, fAlphaIndex }; + const char * names[] = { "red", "green", "blue", "index" }; + + for (int i = 0; i < 4; i++) + { + if (indices[i] != i) + { + if (-1 == indices[i] && i > 0) + { + break; + } + else + { + // CORONA_LOG_ERROR( "Formats with non-%i %s index not yet supported", i, names[i] ); + + return false; + } + } + else if (i > 0) + { + componentCount++; + } + } + + U32 shift = 0, components = componentCount - 1, data = 0; + + if ( !isCompressed ) + { + for ( ; shift < 3; shift++ ) + { + if ( fBytesPerComponent == ( 1 << shift ) ) + { + break; + } + } + + Rtt_ASSERT( shift < 3 ); + } + else + { + // TODO: any reason to worry about non-Texture case? + shift = 3; // cf. UnpackDetails() + + if ( 16 == fBlockSize ) // ASTC or BC7? + { + Rtt_ASSERT( 0 == ( components & kASTCMask ) ); + + components |= kASTCMask; + data = Texture::Format::BlockDimsID( fBlockWidth, fBlockHeight ); + + Rtt_ASSERT( data >= 0 && data < ( 1 << kDataBits ) ); + } + } + + SetShift( v, shift ); + SetComponents( v, components ); + SetData( v, data ); + + return true; +} + +FormatDetails +FormatDetails::UnpackFromValue( U32 v ) +{ + FormatDetails details; + + details.fBytesPerComponent = 1U << GetShift( v ); + + U32 components = GetComponents( v ); + if ( 8 == details.fBytesPerComponent ) // 8 not a valid bpc, encodes "compressed" + { + details.fBytesPerComponent = 1; + + bool isASTCish = 0 != ( components & kASTCMask ); + if ( isASTCish ) + { + components &= ~kASTCMask; + + Texture::Format::GetBlockDims( GetData( v ), details.fBlockWidth, details.fBlockHeight ); + } + else + { + details.fBlockWidth = 4; + details.fBlockHeight = 4; + } + + details.fBlockSize = isASTCish ? 16 : 8; + } + + if ( components < 4 ) // 0-3: "normal" case, value = #components - 1 + { + details.fNumComponents = components + 1; + switch ( details.fNumComponents ) + { + case 1: + details.fAlphaIndex = -1; + // ...and fall through + case 2: + details.fBlueIndex = -1; + // ...and fall through + case 3: + details.fGreenIndex = -1; + // ...and fall through + default: + break; + } + } + else + { + // CORONA_LOG_ERROR( "NYI: unpacking non-count component formats" ); + } + + return details; +} + +// ---------------------------------------------------------------------------- + } // namespace Rtt // ---------------------------------------------------------------------------- diff --git a/librtt/Renderer/Rtt_RenderTypes.h b/librtt/Renderer/Rtt_RenderTypes.h index 59c34b854..8c204ed77 100644 --- a/librtt/Renderer/Rtt_RenderTypes.h +++ b/librtt/Renderer/Rtt_RenderTypes.h @@ -211,6 +211,64 @@ struct BlendMode // ---------------------------------------------------------------------------- +enum { + kStockFormatBits = 3 // bits alloted to built-in formats, for Texture::FormatValue and bitmap counterpart +}; + +bool HasFormatFlag( U32 v ); +U32 GetStockFormatAndFlag( U32 v ); +U32 GetFormatIndex( U32 v ); +void SetFormatIndex( U32* v, U32 index ); +U32 GetFamily( U32 v ); +void SetFamily( U32* v, U32 family ); +U32 GetTarget( U32 v ); +void SetTarget( U32* v, U32 target ); +U32 GetTargetSubtype( U32 v ); +void SetTargetSubtype( U32* v, U32 targetSubtype ); +U32 GetComponents( U32 v ); +void SetComponents( U32* v, U32 components ); +U32 GetShift( U32 v ); +void SetShift( U32* v, U32 shift ); +U32 GetData( U32 v ); +void SetData( U32* v, U32 data ); + +// ---------------------------------------------------------------------------- + +struct FormatDetails { + // TODO +/* + typedef enum _InputType + { + kByte, + kUint16, + kUint32, + kFloat16, + kFloat32, + kNumTypes + } + InputType; + + InputType fInputType = kByte +*/ + int fBytesPerComponent = 1; + int fNumComponents = 4; + int fRedIndex = 0; + int fGreenIndex = 1; + int fBlueIndex = 2; + int fAlphaIndex = 3; + U8 fBlockWidth = 0; + U8 fBlockHeight = 0; + U8 fBlockSize = 0; // if > 0, compressed + bool fIsFloat = false; + bool fIsPacked = false; + // TODO? bool fIssRGB = false; + + bool PackToValue( U32* v ); + static FormatDetails UnpackFromValue( U32 v ); +}; + +// ---------------------------------------------------------------------------- + } // namespace Rtt // ---------------------------------------------------------------------------- diff --git a/librtt/Renderer/Rtt_Renderer.cpp b/librtt/Renderer/Rtt_Renderer.cpp index 2812ffbce..cd9fb6dc5 100644 --- a/librtt/Renderer/Rtt_Renderer.cpp +++ b/librtt/Renderer/Rtt_Renderer.cpp @@ -300,11 +300,14 @@ Renderer::BeginDrawing() void Renderer::CaptureFrameBuffer( RenderingStream & stream, BufferBitmap & bitmap, S32 x_in_pixels, S32 y_in_pixels, S32 w_in_pixels, S32 h_in_pixels ) { +/* stream.CaptureFrameBuffer( bitmap, x_in_pixels, y_in_pixels, w_in_pixels, h_in_pixels ); +*/ + FrameBufferObject::Capture(bitmap, x_in_pixels, y_in_pixels, w_in_pixels, h_in_pixels); } void diff --git a/librtt/Renderer/Rtt_Texture.cpp b/librtt/Renderer/Rtt_Texture.cpp index 0e1856b4a..12ae27e2d 100644 --- a/librtt/Renderer/Rtt_Texture.cpp +++ b/librtt/Renderer/Rtt_Texture.cpp @@ -10,12 +10,128 @@ #include "Renderer/Rtt_Texture.h" #include "Core/Rtt_Assert.h" +#include "Rtt_RenderTypes.h" // ---------------------------------------------------------------------------- namespace Rtt { +// ---------------------------------------------------------------------------- + + Texture::Format::Format( FormatValue value ) +: fValue( value ) +{ +} + +// ---------------------------------------------------------------------------- + +Texture::FormatValue +Texture::Format::GetValue() const +{ + return (FormatValue)GetStockFormatAndFlag( fValue ); +} + +bool +Texture::Format::IsNonCore() const +{ + return HasFormatFlag( fValue ); +} + +#define PACK_ASTC( WIDTH, HEIGHT ) ( ( WIDTH << 4 ) | ( HEIGHT ) ) + +static const U16 kASTCDims[] = { + PACK_ASTC( 4, 4 ), + PACK_ASTC( 5, 4 ), + PACK_ASTC( 5, 5 ), + PACK_ASTC( 6, 5 ), + PACK_ASTC( 6, 6 ), + PACK_ASTC( 8, 5 ), + PACK_ASTC( 8, 6 ), + PACK_ASTC( 8, 8 ), + PACK_ASTC( 10, 5 ), + PACK_ASTC( 10, 6 ), + PACK_ASTC( 10, 8 ), + PACK_ASTC( 10, 10 ), + PACK_ASTC( 12, 10 ), + PACK_ASTC( 12, 12 ) +}; + +int +Texture::Format::BlockDimsID( U8 width, U8 height ) +{ + Rtt_ASSERT( width < 16 ); + Rtt_ASSERT( height < 16 ); + + U8 packed = PACK_ASTC( width, height ); + for ( int i = 0; i < sizeof( kASTCDims ) / sizeof( *kASTCDims ); i++ ) + { + if ( kASTCDims[i] == packed ) + { + return i; + } + } + + Rtt_ASSERT_NOT_REACHED(); + + return -1; +} + +void +Texture::Format::GetBlockDims( int blockDimsID, U8& width, U8& height ) +{ + Rtt_ASSERT( blockDimsID >= 0 ); + Rtt_ASSERT( blockDimsID < sizeof( kASTCDims ) / sizeof( *kASTCDims ) ); + + U8 packed = kASTCDims[blockDimsID]; + + width = packed >> 4; + height = packed & 0xF; +} + +#undef PACK_ASTC + +template inline int +RoundUp( U16 dim ) +{ + return ( dim + N - 1 ) / N; +} + +static int +RoundUpToMultiple( U16 dim, U8 size ) +{ + switch (size) + { + case 4: // most cases + return RoundUp<4>( dim ); + case 8: // ASTC... + return RoundUp<8>( dim ); + case 3: // ...and ditto the rest, albeit not powers of 2 + return RoundUp<3>( dim ); + case 5: + return RoundUp<5>( dim ); + case 6: + return RoundUp<6>( dim ); + case 10: + return RoundUp<10>( dim ); + case 12: + return RoundUp<12>( dim ); + default: + Rtt_ASSERT_NOT_REACHED(); + + return 0; + } +} + +int +Texture::Format::GetCompressedSize( U16 w, U16 h, U8 blockWidth, U8 blockHeight, U8 blockSize ) +{ + int blocksW = RoundUpToMultiple( w, blockWidth ); + int blocksH = RoundUpToMultiple( h, blockHeight ); + + return blocksW * blocksH * blockSize; +} + // ---------------------------------------------------------------------------- Texture::Texture( Rtt_Allocator* allocator ) @@ -64,7 +180,7 @@ Texture::GetSizeInBytes() const U32 w = GetWidth(); U32 h = GetHeight(); - switch(format) + switch( format.GetValue() ) { case kLuminance: return w * h * 1; case kRGB: return w * h * 3; @@ -72,7 +188,23 @@ Texture::GetSizeInBytes() const case kBGRA: return w * h * 4; case kABGR: return w * h * 4; case kARGB: return w * h * 4; - default: return 0; + default: + if ( format.IsNonCore() ) + { + FormatDetails details = FormatDetails::UnpackFromValue( format.GetBackingValue() ); + if ( 0 == details.fBlockSize ) // not compressed? + { + return w * h * details.fBytesPerComponent * details.fNumComponents; + } + else + { + return Format::GetCompressedSize( w, h, details.fBlockWidth, details.fBlockHeight, details.fBlockSize ); + } + } + else + { + return 0; + } } } diff --git a/librtt/Renderer/Rtt_Texture.h b/librtt/Renderer/Rtt_Texture.h index cf0207742..7cc23b867 100644 --- a/librtt/Renderer/Rtt_Texture.h +++ b/librtt/Renderer/Rtt_Texture.h @@ -27,7 +27,7 @@ class Texture : public CPUResource typedef CPUResource Super; typedef Texture Self; - typedef enum _Format + typedef enum _FormatValue { kAlpha, kLuminance, @@ -39,7 +39,26 @@ class Texture : public CPUResource kLuminanceAlpha, kNumFormats } - Format; + FormatValue; + + class Format { + public: + Format( FormatValue value = kRGBA ); + + FormatValue GetValue() const; + U32 GetBackingValue() const { return fValue; } + void SetBackingValue( U32 value ) { fValue = value; } + + public: + bool IsNonCore() const; + + static int BlockDimsID( U8 width, U8 height ); + static void GetBlockDims( int blockDimsID, U8& width, U8& height ); + static int GetCompressedSize( U16 w, U16 h, U8 blockWidth, U8 blockHeight, U8 blockSize ); + + private: + U32 fValue; + }; typedef enum _Filter { @@ -70,6 +89,39 @@ class Texture : public CPUResource } Unit; + typedef enum _Target + { + k2D, // default + k1D, + k3D, + kCube, + kBuffer, + kRectangle, + kMultisample, + kNumTargets + } + Target; + + typedef enum _TargetSubtype + { + kNormal, // default + kArray, + kImage, + kImageArray, + kNumTargetSubtypes + } + TargetSubtype; + + typedef enum _Family + { + kFloatingPoint, // default + kSignedInteger, + kUnsignedInteger, + kOtherFamily, // shadow formats, atomic_uint + kNumFamilies + } + Family; + public: Texture( Rtt_Allocator* allocator ); @@ -97,7 +149,7 @@ class Texture : public CPUResource public: void SetRetina( bool newValue ){ fIsRetina = newValue; } - bool IsRetina(){ return fIsRetina; } + bool IsRetina() const { return fIsRetina; } void SetTarget( bool newValue ){ fIsTarget = newValue; } bool IsTarget() const { return fIsTarget; } diff --git a/librtt/Renderer/Rtt_VulkanTexture.cpp b/librtt/Renderer/Rtt_VulkanTexture.cpp index f749d3b4e..3abfe3a91 100644 --- a/librtt/Renderer/Rtt_VulkanTexture.cpp +++ b/librtt/Renderer/Rtt_VulkanTexture.cpp @@ -518,7 +518,7 @@ VulkanTexture::GetVulkanFormat( Texture::Format format, VkComponentMapping & map { VkFormat vulkanFormat = VK_FORMAT_R8G8B8A8_UNORM; // TODO: allow sR* forms, floats, etc. - switch( format ) + switch( format.GetValue() ) { case Texture::kAlpha: mapping.g = mapping.b = mapping.a = VK_COMPONENT_SWIZZLE_R; @@ -558,4 +558,4 @@ VulkanTexture::GetVulkanFormat( Texture::Format format, VkComponentMapping & map } // namespace Rtt -// ---------------------------------------------------------------------------- \ No newline at end of file +// ---------------------------------------------------------------------------- diff --git a/librtt/Rtt_GPU.h b/librtt/Rtt_GPU.h index e17c010ee..858c419df 100644 --- a/librtt/Rtt_GPU.h +++ b/librtt/Rtt_GPU.h @@ -162,6 +162,10 @@ class GPU #define GPUError() do {} while(0) #endif +#ifdef OLD_GRAPHICS + #error Details now moved to non-librtt code (tachyon) +#endif + // ---------------------------------------------------------------------------- } // namespace Rtt diff --git a/librtt/Rtt_GPUStream.cpp b/librtt/Rtt_GPUStream.cpp index 2c6dc9cd4..d577b1972 100644 --- a/librtt/Rtt_GPUStream.cpp +++ b/librtt/Rtt_GPUStream.cpp @@ -21,7 +21,7 @@ #include "Display/Rtt_VertexCache.h" #include "Renderer/Rtt_RenderTypes.h" -#if defined( Rtt_WIN_DESKTOP_ENV ) && !defined( Rtt_POWERVR_ENV ) +#if defined( OLD_GRAPHICS ) && defined( Rtt_WIN_DESKTOP_ENV ) && !defined( Rtt_POWERVR_ENV ) #if defined(Rtt_EMSCRIPTEN_ENV) #include #elif defined(Rtt_LINUX_ENV) @@ -140,6 +140,8 @@ GLModeForMode( RenderTypes::Mode mode ) #endif // ---------------------------------------------------------------------------- +#ifdef OLD_GRAPHICS + int GPUStream::GetMaxTextureUnits() { @@ -161,16 +163,22 @@ GPUStream::GetMaxTextureUnits() static const GLenum kDataType = GL_FLOAT; #endif +#endif + #ifdef Rtt_DEBUG static int sTextureStackSize = -1; #endif +#ifdef OLD_GRAPHICS + GLenum GPUStream::GetDataType() { return kDataType; } +#endif + GPUStream::GPUStream( Rtt_Allocator* pAllocator ) : Super(), fCurrentPaint( NULL ), @@ -200,7 +208,7 @@ GPUStream::GPUStream( Rtt_Allocator* pAllocator ) { memset( & fColor, 0xFF, sizeof( fColor ) ); -#if defined( Rtt_WIN_DESKTOP_ENV ) && !defined( Rtt_POWERVR_ENV ) +#if defined( OLD_GRAPHICS ) && defined( Rtt_WIN_DESKTOP_ENV ) && !defined( Rtt_POWERVR_ENV ) if ( glActiveTexture == NULL ) { glActiveTexture = (PFNGLACTIVETEXTUREPROC) wglGetProcAddress("glActiveTexture"); glClientActiveTexture = (PFNGLCLIENTACTIVETEXTUREPROC) wglGetProcAddress("glClientActiveTexture"); @@ -1373,6 +1381,8 @@ GPUStream::SetAlpha( U8 newValue, bool accumuluate ) return result; } +#ifdef OLD_GRAPHICS + GLenum GPU_GetPixelFormat( PlatformBitmap::Format format ) { @@ -1462,10 +1472,14 @@ GPU_GetPixelType( PlatformBitmap::Format format ) # endif // Rtt_OPENGLES } +#endif + // Performs a screen capture and outputs the image to the given "outBuffer" bitmap. void GPUStream::CaptureFrameBuffer( BufferBitmap& outBuffer, S32 xScreen, S32 yScreen, S32 wScreen, S32 hScreen ) { +#ifdef OLD_GRAPHICS /* details moved to Rtt_FrameBufferObject / Rtt_GLFrameBufferObject */ + // GLint x = Rtt_RealToInt( bounds.xMin ); // GLint y = Rtt_RealToInt( bounds.yMin ); // GLint w = Rtt_RealToInt( bounds.xMax ) - x; @@ -1486,6 +1500,7 @@ GPUStream::CaptureFrameBuffer( BufferBitmap& outBuffer, S32 xScreen, S32 yScreen kFormat, kType, outBuffer.WriteAccess() ); +#endif } void diff --git a/librtt/Rtt_GPUStream.h b/librtt/Rtt_GPUStream.h index a595ef724..4311e8578 100644 --- a/librtt/Rtt_GPUStream.h +++ b/librtt/Rtt_GPUStream.h @@ -15,7 +15,7 @@ #include "Rtt_RenderingStream.h" #include "Display/Rtt_Paint.h" -#include "Rtt_GPU.h" +/* #include "Rtt_GPU.h" */ // TODO: created annoying dependencies, and seemed to be mostly dead code (probably safe to remove) #if defined( Rtt_AUTHORING_SIMULATOR ) || defined( Rtt_ANDROID_ENV ) #define RTT_SURFACE_ROTATION @@ -48,12 +48,16 @@ class GPUStream : public RenderingStream kMaxTextureStackDepth = 32 }; +#ifdef OLD_GRAPHICS + public: static int GetMaxTextureUnits(); public: static GLenum GetDataType(); +#endif + public: GPUStream( Rtt_Allocator* ); virtual ~GPUStream(); @@ -176,8 +180,16 @@ class GPUStream : public RenderingStream TextureStackFrame fTextureStack[kMaxTextureStackDepth]; private: - GLint fWindowWidth; - GLint fWindowHeight; + #ifdef OLD_GRAPHICS /* window dimensions and clear components; the old versions drag in GL dependencies */ + typedef GLint wdInt; + typedef GLclampf ccFloat; + #else + typedef int wdInt; + typedef float ccFloat; + #endif + + wdInt fWindowWidth; + wdInt fWindowHeight; S32 fRenderedContentWidth; // width of rect in which content is rendered (not necessarily same as content width) S32 fRenderedContentHeight; // height of rect in which content is rendered (not necessarily same as content height) @@ -196,10 +208,10 @@ class GPUStream : public RenderingStream TextureFunction fTextureFunction; // Clear color - GLclampf fClearR; - GLclampf fClearG; - GLclampf fClearB; - GLclampf fClearA; + ccFloat fClearR; + ccFloat fClearG; + ccFloat fClearB; + ccFloat fClearA; protected: Rtt_Allocator* fAllocator; diff --git a/librtt/Rtt_LuaLibSystem.cpp b/librtt/Rtt_LuaLibSystem.cpp index 6ae2e081b..2016b41f3 100644 --- a/librtt/Rtt_LuaLibSystem.cpp +++ b/librtt/Rtt_LuaLibSystem.cpp @@ -20,7 +20,7 @@ #include "Rtt_MPlatformDevice.h" #include "Rtt_Runtime.h" -#include "Rtt_GPU.h" +/* #include "Rtt_GPU.h" */ // TODO: created annoying dependencies, and seemed to be mostly dead code (probably safe to remove) #include "Rtt_GPUStream.h" #include "Rtt_PhysicsWorld.h" #include "Rtt_PlatformInAppStore.h" diff --git a/librtt/Rtt_PlatformSurface.cpp b/librtt/Rtt_PlatformSurface.cpp index 693909bde..bfd6f6e94 100644 --- a/librtt/Rtt_PlatformSurface.cpp +++ b/librtt/Rtt_PlatformSurface.cpp @@ -114,7 +114,9 @@ PlatformSurface::SetDelegate( PlatformSurfaceDelegate* delegate ) // ---------------------------------------------------------------------------- // TODO: Replace platform ifdef's with a feature ifdef: Rtt_OFFSCREEN_SURFACE in Rtt_Config.h -#if ! defined( Rtt_ANDROID_ENV ) && !defined( Rtt_WIN_ENV ) && !defined( Rtt_EMSCRIPTEN_ENV ) && !defined( Rtt_NXS_ENV ) +// TODO (follow-up): seems to be dead code; probably can be removed altogether +#if defined( OLD_GRAPHICS ) && \ + ! defined( Rtt_ANDROID_ENV ) && !defined( Rtt_WIN_ENV ) && !defined( Rtt_EMSCRIPTEN_ENV ) && !defined( Rtt_NXS_ENV ) OffscreenGPUSurface::OffscreenGPUSurface( const PlatformSurface& parent ) : fWidth( parent.Width() ), diff --git a/librtt/Rtt_PlatformSurface.h b/librtt/Rtt_PlatformSurface.h index ddefb6d54..6012d5aeb 100644 --- a/librtt/Rtt_PlatformSurface.h +++ b/librtt/Rtt_PlatformSurface.h @@ -92,16 +92,19 @@ class PlatformSurface // ---------------------------------------------------------------------------- // TODO: Remove this when OffscreenGPUSurface is moved to a separate file -#include "Rtt_GPU.h" +// TODO (follow-up): was dead code anyway? +/* #include "Rtt_GPU.h" */ namespace Rtt { // ---------------------------------------------------------------------------- -#if ! defined( Rtt_ANDROID_ENV ) && ! defined( Rtt_EMSCRIPTEN_ENV ) +#if defined( OLD_GRAPHICS) && \ + ! defined( Rtt_ANDROID_ENV ) && ! defined( Rtt_EMSCRIPTEN_ENV ) // TODO: Move to a separate file +// TODO (follow-up): seems to be dead code; probably can be removed altogether // GPU-specific class OffscreenGPUSurface : public PlatformSurface { diff --git a/platform/apple/Rtt_ApplePlatform.mm b/platform/apple/Rtt_ApplePlatform.mm index 4fda6c5bf..aa87cbac6 100644 --- a/platform/apple/Rtt_ApplePlatform.mm +++ b/platform/apple/Rtt_ApplePlatform.mm @@ -621,7 +621,7 @@ - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)err PlatformSurface* ApplePlatform::CreateOffscreenSurface( const PlatformSurface& parent ) const { -#ifdef Rtt_NO_GUI +#if defined( Rtt_NO_GUI ) || !defined( OLD_GRAPHICS ) // n.b. seems to be dead code return NULL; #else OffscreenGPUSurface *result = Rtt_NEW( Allocator(), OffscreenGPUSurface( parent ) ); diff --git a/platform/emscripten/Rtt_EmscriptenPlatform.cpp b/platform/emscripten/Rtt_EmscriptenPlatform.cpp index cfbcdc54a..99ea370d0 100644 --- a/platform/emscripten/Rtt_EmscriptenPlatform.cpp +++ b/platform/emscripten/Rtt_EmscriptenPlatform.cpp @@ -294,7 +294,7 @@ namespace Rtt } } - if (result && result->GetFormat() == PlatformBitmap::kUndefined) + if (result && result->GetFormat().GetValue() == PlatformBitmap::kUndefined) { // failed to load bitmap Rtt_DELETE(result); diff --git a/platform/linux/src/Rtt_LinuxPlatform.cpp b/platform/linux/src/Rtt_LinuxPlatform.cpp index caa793a44..1ef81a700 100644 --- a/platform/linux/src/Rtt_LinuxPlatform.cpp +++ b/platform/linux/src/Rtt_LinuxPlatform.cpp @@ -201,7 +201,7 @@ namespace Rtt } } - if (result && result->GetFormat() == PlatformBitmap::kUndefined) + if (result && result->GetFormat().GetValue() == PlatformBitmap::kUndefined) { // failed to load bitmap Rtt_DELETE(result); diff --git a/platform/mac/Rtt_MacPlatform.mm b/platform/mac/Rtt_MacPlatform.mm index cfc099a01..7bf7f8b97 100644 --- a/platform/mac/Rtt_MacPlatform.mm +++ b/platform/mac/Rtt_MacPlatform.mm @@ -574,7 +574,7 @@ -(void)alertDidEnd:(NSAlert *)alertView returnCode:(NSInteger)returnCode context // const size_t kBitsPerComponent = 8; // TODO: Should this depend on bitmap->GetFormat() - Rtt_ASSERT( bitmap->GetFormat() == PlatformBitmap::kBGRA ); + Rtt_ASSERT( bitmap->GetFormat().GetValue() == PlatformBitmap::kBGRA ); // Bug 4921: I don't understand this, but changing kCGImageAlphaPremultipliedFirst to kCGImageAlphaNoneSkipFirst fixes the white box issue. //Preserve previous jpeg save functionality (black background) diff --git a/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinPlatform.cpp b/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinPlatform.cpp index 1b7c8e472..852e42b61 100644 --- a/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinPlatform.cpp +++ b/platform/windows/Corona.Native.Library.Win32/Rtt/Rtt_WinPlatform.cpp @@ -908,7 +908,7 @@ namespace Rtt // Given image has a 4 channel color format. Fetch its color channel values. color = Gdiplus::Color(bits[alphaIndex], bits[redIndex], bits[greenIndex], bits[blueIndex]); } - else if (bitmap->GetFormat() == PlatformBitmap::kMask) + else if (bitmap->GetFormat().GetValue() == PlatformBitmap::kMask) { // Given image is a 1 channel grayscale bitmap. Convert it to a 3 channel RGB color value. color = Gdiplus::Color((BYTE)(*bits / 0.30), (BYTE)(*bits / 0.59), (BYTE)(*bits / 0.11));