#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