#pragma region CPL License /* Nuclex Native Framework Copyright (C) 2002-2021 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #pragma endregion // CPL License #ifndef NUCLEX_PIXELS_PIXELFORMATS_CONVERTPIXEL_H #error This file is intended to be included through ConvertPixel.h #endif namespace Nuclex { namespace Pixels { namespace PixelFormats { // ------------------------------------------------------------------------------------------- // /// Converts a pixel in a floating point format into an integer format /// Pixel format used by the input pixel /// Pixel format used by the output pixel /// Pixel that will be converted to the output pixel format /// A pixel in the output pixel format that's equivalent to the input pixel template< PixelFormat TSourcePixelFormat, PixelFormat TTargetPixelFormat, typename std::enable_if_t< (TSourcePixelFormat != TTargetPixelFormat) && (IsFloatFormat) && (!IsFloatFormat) > * = nullptr > NUCLEX_PIXELS_ALWAYS_INLINE void ConvertPixel( const PixelTypeFromFormat *sourcePixel, PixelTypeFromFormat *targetPixel ) { (void)sourcePixel; // MSVC fantasizes a constellation where no channels exist (void)targetPixel; // then warns that these two parameters aren't used... // TODO: Float->Int converter currently does not support signed integer formats static_assert( !IsSignedFormat && u8"Signed pixel formats not implemented yet" ); if constexpr(NeedConvertChannel1) { static_assert( ((PixelFormatDescription::Channel1::LowestBitIndex % 8) == 0) && u8"Source floating point channel bits start at a byte boundary" ); typedef ChannelFloatType< PixelFormatDescription::Channel1::BitCount > SourceFloatType; const SourceFloatType *source = reinterpret_cast( reinterpret_cast(sourcePixel) + (PixelFormatDescription::Channel1::LowestBitIndex / 8) ); const constexpr PixelTypeFromFormat channelBitMask = BitMask< PixelTypeFromFormat, 0, //PixelFormatDescription::Channel1::LowestBitIndex, PixelFormatDescription::Channel1::BitCount >; const constexpr int ShiftOffset = ( -static_cast(PixelFormatDescription::Channel1::LowestBitIndex) ); // Since we perform the conversion in the lowest bits, and since garbage // bits above the number can't happen, we don't need to bit mask the result! *targetPixel = BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } if constexpr(NeedConvertChannel2) { static_assert( ((PixelFormatDescription::Channel2::LowestBitIndex % 8) == 0) && u8"Source floating point channel bits start at a byte boundary" ); typedef ChannelFloatType< PixelFormatDescription::Channel2::BitCount > SourceFloatType; const SourceFloatType *source = reinterpret_cast( reinterpret_cast(sourcePixel) + (PixelFormatDescription::Channel2::LowestBitIndex / 8) ); const constexpr PixelTypeFromFormat channelBitMask = BitMask< PixelTypeFromFormat, 0, //PixelFormatDescription::Channel2::LowestBitIndex, PixelFormatDescription::Channel2::BitCount >; const constexpr int ShiftOffset = ( -static_cast(PixelFormatDescription::Channel2::LowestBitIndex) ); // Since we perform the conversion in the lowest bits, and since garbage // bits above the number can't happen, we don't need to bit mask the result! if constexpr(NeedConvertChannel1) { *targetPixel |= BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } else { *targetPixel = BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } } if constexpr(NeedConvertChannel3) { static_assert( ((PixelFormatDescription::Channel3::LowestBitIndex % 8) == 0) && u8"Source floating point channel bits start at a byte boundary" ); typedef ChannelFloatType< PixelFormatDescription::Channel3::BitCount > SourceFloatType; const SourceFloatType *source = reinterpret_cast( reinterpret_cast(sourcePixel) + (PixelFormatDescription::Channel3::LowestBitIndex / 8) ); const constexpr PixelTypeFromFormat channelBitMask = BitMask< PixelTypeFromFormat, 0, //PixelFormatDescription::Channel3::LowestBitIndex, PixelFormatDescription::Channel3::BitCount >; const constexpr int ShiftOffset = ( -static_cast(PixelFormatDescription::Channel3::LowestBitIndex) ); // Since we perform the conversion in the lowest bits, and since garbage // bits above the number can't happen, we don't need to bit mask the result! if constexpr( NeedConvertChannel1 || NeedConvertChannel2 ) { *targetPixel |= BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } else { *targetPixel = BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } } if constexpr(NeedConvertChannel4) { static_assert( ((PixelFormatDescription::Channel4::LowestBitIndex % 8) == 0) && u8"Source floating point channel bits start at a byte boundary" ); typedef ChannelFloatType< PixelFormatDescription::Channel4::BitCount > SourceFloatType; const SourceFloatType *source = reinterpret_cast( reinterpret_cast(sourcePixel) + (PixelFormatDescription::Channel4::LowestBitIndex / 8) ); const constexpr PixelTypeFromFormat channelBitMask = BitMask< PixelTypeFromFormat, 0, //PixelFormatDescription::Channel4::LowestBitIndex, PixelFormatDescription::Channel4::BitCount >; const constexpr int ShiftOffset = ( -static_cast(PixelFormatDescription::Channel4::LowestBitIndex) ); // Since we perform the conversion in the lowest bits, and since garbage // bits above the number can't happen, we don't need to bit mask the result! if constexpr( NeedConvertChannel1 || NeedConvertChannel2 || NeedConvertChannel3 ) { *targetPixel |= BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } else { *targetPixel = BitShift( static_cast>( (*source) * static_cast(channelBitMask) ) ); } } else if constexpr(HasAlphaChannel) { if constexpr( NeedConvertChannel1 || NeedConvertChannel2 || NeedConvertChannel3 ) { *targetPixel |= BitMask< PixelTypeFromFormat, PixelFormats::PixelFormatDescription::Channel4::LowestBitIndex, PixelFormats::PixelFormatDescription::Channel4::BitCount >; } else { *targetPixel = BitMask< PixelTypeFromFormat, PixelFormats::PixelFormatDescription::Channel4::LowestBitIndex, PixelFormats::PixelFormatDescription::Channel4::BitCount >; } } } // ------------------------------------------------------------------------------------------- // }}} // namespace Nuclex::Pixels::PixelFormats