あなたが提供したコード スニペットを調べてみると、対処すべきいくつかの注意事項に気付くことができました。
まず第一に、red
厳密に 7 より小さい整数red = ((red/7) * 31)
の結果は常に 0 になります。これは、このように記述すると、整数除算の後に整数乗算を実行するようにコンパイラに指示しているためです。つまり、小数は無視されます。
あなたが提供した例に関して、68行目で、私color = (0xFFFF & (((red << 11) & RED_5_6_5) & ((green << 5) & GRN_5_6_5) & (blue & BLU_5_6_5)));
はまた常に0になると信じRED_5_6_5 & GRN_5_6_5 & BLU_5_6_5 = 0 = 0
ています。私はあなたがcolor = (0xFFFF & (((red << 11) & RED_5_6_5) | ((green << 5) & GRN_5_6_5) | (blue & BLU_5_6_5)));
ここを意味したと信じています。
さらにunsigned short
、「std::uint16_t」の同義語として使用し、同様に「std::uint32_t」の同義語として使用しますunsigned int
。これは、すべてのプラットフォームで保持する必要はなく、同じプラットフォームの異なるコンパイラ バージョン間でも保持する必要がないため、強くにある前述の固定サイズの整数を使用することをお勧めします。
コード全体で定数を多用していることと、かなりの量のコードが重複していることから、ほぼ確実に、コードを保守したり、コードを機能させたりするのに多くの困難に直面することになるでしょう。そうは言っても、それが私の傲慢に聞こえないことを願っていますが、あなたがアドバイスを求めてここに来た特定の問題を修正することは別として、これらのピクセル抽象化を処理するまったく新しい方法を提案する自由を取りました.
以下のコード スニペットでは、RGB ピクセルを処理するための API を書き直し、メタプログラミングを使用してコードの重複を最小限に抑えています。たとえば、ピクセル形式と深さの可能なすべての組み合わせを処理するためにクラスを特殊化する必要がないことに気付くでしょう。特定のピクセル形式の可能な深さで機能template<...> struct Pixel
するヘルパー クラスに残忍な詳細を残したからです。template<...> struct pixel_tools
したがって、コードの複製が減少します。
私のソリューションがこのコンテキストに最適であるとは思いません。実際、そうではないことは間違いありませんが、コードのメンテナンスに関しては、あなたのソリューションよりも改善されていると信じています。この時点から、私の提案のいずれかを採用することに決めた場合、あなたが取り組んでいる他のピクセル抽象化のアイデアを拡張するのは簡単だと思います.
注意:このコード スニペットにはバグが含まれている可能性が非常に高く、申し訳ありませんが、完全に確認する時間がありませんでした。
#include <cstddef>
#include <cstdint>
#include <iostream>
template <std::size_t bit_depth>
struct underlying_type;
template <>
struct underlying_type<8U>
{
typedef std::uint8_t type;
};
template <>
struct underlying_type<16U>
{
typedef std::uint16_t type;
};
template <>
struct underlying_type<32U>
{
typedef std::uint32_t type;
};
enum class COLOR
{
RED = 0,
GREEN = 1,
BLUE = 2,
ALPHA = 3
};
enum class PIXEL_FORMAT : char
{
PALETTE,
RGB,
RGBA
};
template<PIXEL_FORMAT fmt>
struct pixel_tools;
template<>
struct pixel_tools<PIXEL_FORMAT::RGB>
{
//this metafunction avoids the use of #defines, which do get nasty quickly and should be avoided at all costs
//luckly c++ has strong metaprogramming idioms and boost is your best friend
//the third argument is necessary because total template specialization is not allowed inside templated structures
template <COLOR color, std::size_t bit_depth, typename _ = void>
struct color_mask;
template <typename _>
struct color_mask<COLOR::RED, 8U, _>
{
static typename underlying_type<8U>::type const value = 0xE0;
};
template <typename _>
struct color_mask<COLOR::GREEN, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x1C;
};
template <typename _>
struct color_mask<COLOR::BLUE, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x03;
};
template <typename _>
struct color_mask<COLOR::RED, 16U, _>
{
static typename underlying_type<16U>::type const value = 0xF800;
};
template <typename _>
struct color_mask<COLOR::GREEN, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x07E0;
};
template <typename _>
struct color_mask<COLOR::BLUE, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x001F;
};
template <typename _>
struct color_mask<COLOR::RED, 32U, _>
{
static typename underlying_type<32U>::type const value = 0xFFC00000;
};
template <typename _>
struct color_mask<COLOR::GREEN, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x003FF000;
};
template <typename _>
struct color_mask<COLOR::BLUE, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x00000FFC;
};
//the third argument is necessary because total template specialization is not allowed inside templated structures
template <COLOR color, std::size_t bit_depth, typename _ = void>
struct color_offset_mask;
template <typename _>
struct color_offset_mask<COLOR::RED, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x05;
};
template <typename _>
struct color_offset_mask<COLOR::GREEN, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x02;
};
template <typename _>
struct color_offset_mask<COLOR::BLUE, 8U, _>
{
static typename underlying_type<8U>::type const value = 0x00;
};
template <typename _>
struct color_offset_mask<COLOR::RED, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x000B;
};
template <typename _>
struct color_offset_mask<COLOR::GREEN, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x0005;
};
template <typename _>
struct color_offset_mask<COLOR::BLUE, 16U, _>
{
static typename underlying_type<16U>::type const value = 0x0000;
};
template <typename _>
struct color_offset_mask<COLOR::RED, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x00000016;
};
template <typename _>
struct color_offset_mask<COLOR::GREEN, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x0000000C;
};
template <typename _>
struct color_offset_mask<COLOR::BLUE, 32U, _>
{
static typename underlying_type<32U>::type const value = 0x00000002;
};
template <COLOR color, std::size_t from, std::size_t to>
struct depth_conversion_factor
{
static constexpr double const value =
double(color_mask<color, to>::value >> color_offset_mask<color, to>::value)/
double(color_mask<color, from>::value >> color_offset_mask<color, from>::value);
};
template <COLOR color, std::size_t bit_depth>
static typename underlying_type<bit_depth>::type get_color(typename underlying_type<bit_depth>::type pixel)
{
return (color_mask<color, bit_depth>::value & pixel) >> color_offset_mask<color, bit_depth>::value;
}
template <COLOR color, std::size_t bit_depth>
static void set_color(typename underlying_type<bit_depth>::type& pixel, typename underlying_type<bit_depth>::type clr)
{
//erase current color
pixel &= ~color_mask<color, bit_depth>::value;
//set new value
pixel |= (clr << color_offset_mask<color, bit_depth>::value) & color_mask<color, bit_depth>::value;
}
template <std::size_t from, std::size_t to>
static typename underlying_type<to>::type convert_depth(typename underlying_type<from>::type pixel)
{
typename underlying_type<to>::type const converted_red = double(get_color<COLOR::RED, from>(pixel))*depth_conversion_factor<COLOR::RED, from, to>::value;
typename underlying_type<to>::type const converted_green = double(get_color<COLOR::GREEN, from>(pixel))*depth_conversion_factor<COLOR::GREEN, from, to>::value;
typename underlying_type<to>::type const converted_blue = double(get_color<COLOR::BLUE, from>(pixel))*depth_conversion_factor<COLOR::BLUE, from, to>::value;
typename underlying_type<to>::type converted_pixel(0);
set_color<COLOR::RED, to>(converted_pixel, converted_red);
set_color<COLOR::GREEN, to>(converted_pixel, converted_green);
set_color<COLOR::BLUE, to>(converted_pixel, converted_blue);
return converted_pixel;
}
template <std::size_t bit_depth>
static typename underlying_type<bit_depth>::type convert_depth(typename underlying_type<bit_depth>::type pixel)
{
return pixel;
}
};
template<std::size_t bit_depth, PIXEL_FORMAT fmt>
struct Pixel
{
typename underlying_type<bit_depth>::type color;
Pixel(typename underlying_type<bit_depth>::type red, typename underlying_type<bit_depth>::type green, typename underlying_type<bit_depth>::type blue)
: color(0)
{
pixel_tools<fmt>::template set_color<COLOR::RED, bit_depth>(this->color, red);
pixel_tools<fmt>::template set_color<COLOR::BLUE, bit_depth>(this->color, blue);
pixel_tools<fmt>::template set_color<COLOR::GREEN, bit_depth>(this->color, green);
}
Pixel(typename underlying_type<bit_depth>::type clr)
{
//always a good idea to guarantee a valid value
pixel_tools<fmt>::template set_color<COLOR::RED, bit_depth>(this->color, pixel_tools<fmt>::template get_color<COLOR::RED, bit_depth>(clr));
pixel_tools<fmt>::template set_color<COLOR::BLUE, bit_depth>(this->color, pixel_tools<fmt>::template get_color<COLOR::BLUE, bit_depth>(clr));
pixel_tools<fmt>::template set_color<COLOR::GREEN, bit_depth>(this->color, pixel_tools<fmt>::template get_color<COLOR::GREEN, bit_depth>(clr));
}
template<std::size_t new_bit_depth>
Pixel<new_bit_depth, fmt> convert_depth() const
{
return Pixel<new_bit_depth, fmt>(pixel_tools<fmt>::template convert_depth<bit_depth, new_bit_depth>(this->color));
}
};
template<typename char_t, typename char_traits, std::size_t bit_depth, PIXEL_FORMAT fmt>
std::basic_ostream<char_t, char_traits>& operator << (std::basic_ostream<char_t, char_traits>& o, Pixel<bit_depth, fmt> const& pixel)
{
o << '<'
<< std::uint32_t(pixel_tools<fmt>::template get_color<COLOR::RED, bit_depth>(pixel.color)) << ", "
<< std::uint32_t(pixel_tools<fmt>::template get_color<COLOR::GREEN, bit_depth>(pixel.color)) << ", "
<< std::uint32_t(pixel_tools<fmt>::template get_color<COLOR::BLUE, bit_depth>(pixel.color))
<< '>';
}
int main()
{
Pixel<16U, PIXEL_FORMAT::RGB> p16(2U, 5U, 4U);
Pixel<32U, PIXEL_FORMAT::RGB> p32 = p16.convert_depth<32U>();
//should output <2, 5, 4> <66, 81, 132> <2, 4, 4> <0, 0, 0>
std::cout << std::endl << p16 << ' ' << p32 << ' ' << p32.convert_depth<16>() << ' ' << p16.convert_depth<8>() << std::endl;
return 0;
}
注: Archlinux x64 ボックスで gcc GCC 4.8.1 20130725 (プレリリース) を使用してコンパイルおよびテストされています。