汎用高速アルファブレンド
id:melpon:20060920 で書いたコードの 256 段階バージョンを作る必要が出てきたんだけど、さすがに手で書くのはきついので、テンプレートを使ってちょこちょこ書いてみた。
//int GetDepth(int value) //{ // int count = 0; // while ((value & 1) == 0) // { // count++; // value >>= 1; // } // return count; //} //unsigned long AlphaBlendHelper(unsigned long dst, unsigned long src, // int alpha, int maxBits, int nowAlpha) //{ // if (alpha == nowAlpha) // { // return detail::blend_half(dst, src); // } // else if (alpha < nowAlpha) // { // return AlphaBlendHelper(dst, detail::blend_half(dst, src), // alpha, maxBits, nowAlpha - (1 << (GetDepth(nowAlpha) - 1))); // } // else // if (alpha > nowAlpha) // { // return AlphaBlendHelper(detail::blend_half(dst, src), src, // alpha, maxBits, nowAlpha + (1 << (GetDepth(nowAlpha) - 1))); // } //} // //unsigned long AlphaBlend(unsigned long dst, unsigned long src, // int alpha, int maxBits) //{ // if (alpha <= 0) // { // return dst; // } // if (alpha >= 255) // { // return src; // } // return AlphaBlendHelper(dst, src, alpha, maxBits, 1 << (maxBits - 1)); //} // 下記の内容は、上記の内容を template 化したもの。 namespace detail { unsigned long blend_half(unsigned long dst, unsigned long src) { return (dst & src) + (((dst ^ src) & 0xfefefefe) >> 1); } template<int TValue> struct power2 { static const int value = 1 << TValue; }; template<int TValue, bool = (TValue & 1) == 0> struct depth { static const int value = 1 + depth<(TValue >> 1)>::value; }; template<int TValue> struct depth<TValue, false> { static const int value = 0; }; // TLeft < TRight の場合は -1 // TLeft == TRight の場合は 0 // TLeft > TRight の場合は 1 template<int TLeft, int TRight> struct pred { static const int value = (TLeft == TRight) ? 0 : ((TLeft < TRight) ? -1 : 1); }; template<int TAlpha, int TMaxAlphaBits, int TNowAlpha, int = pred<TAlpha, TNowAlpha>::value> struct alpha_blend_helper_internal { static unsigned long blend(unsigned long dst, unsigned long src) { return blend_half(dst, src); } }; template<int TAlpha, int TMaxAlphaBits, int TNowAlpha> struct alpha_blend_helper_internal<TAlpha, TMaxAlphaBits, TNowAlpha, -1> { static unsigned long blend(unsigned long dst, unsigned long src) { return alpha_blend_helper_internal<TAlpha, TMaxAlphaBits, TNowAlpha - power2<depth<TNowAlpha>::value - 1>::value>::blend( dst, blend_half(dst, src)); } }; template<int TAlpha, int TMaxAlphaBits, int TNowAlpha> struct alpha_blend_helper_internal<TAlpha, TMaxAlphaBits, TNowAlpha, 1> { static unsigned long blend(unsigned long dst, unsigned long src) { return alpha_blend_helper_internal<TAlpha, TMaxAlphaBits, TNowAlpha + power2<depth<TNowAlpha>::value - 1>::value>::blend( blend_half(dst, src), src); } }; // TLeft < TCenter < TRight の場合は 0 // TLeft >= TCenter の場合は -1 // TRight <= TCenter の場合は 1 template<int TLeft, int TCenter, int TRight> struct pred2 { static const int value = (TCenter <= TLeft) ? -1 : ((TCenter >= TRight) ? 1 : 0); }; template<int TAlpha, int TMaxAlphaBits, int = pred2<0, TAlpha, power2<TMaxAlphaBits>::value>::value> struct alpha_blend_helper { static unsigned long blend(unsigned long dst, unsigned long src) { return alpha_blend_helper_internal<TAlpha, TMaxAlphaBits, power2<TMaxAlphaBits - 1>::value>::blend(dst, src); } }; template<int TAlpha, int TMaxAlphaBits> struct alpha_blend_helper<TAlpha, TMaxAlphaBits, -1> { static unsigned long blend(unsigned long dst, unsigned long src) { return dst; } }; template<int TAlpha, int TMaxAlphaBits> struct alpha_blend_helper<TAlpha, TMaxAlphaBits, 1> { static unsigned long blend(unsigned long dst, unsigned long src) { return src; } }; } template<int TAlpha, int TMaxAlphaBits> unsigned long AlphaBlend(unsigned long dst, unsigned long src) { return detail::alpha_blend_helper<TAlpha, TMaxAlphaBits>::blend(dst, src); }
で、ブレンドする際に必要なだけ実体化させる。
template<int TAlpha> void BltInternal(Pixel32 dst, Pixel32 src, ...) { for (int y = 0; y < ...) { for (int x = 0; x < ...) { dst[x] = AlphaBlend<TAlpha, 8>(dst[x], src[x]); } dst = dst.NextLine(); src = src.NextLine(); } } void Blt(Pixel32 dst, Pixel32, src, int alpha, ...) { switch (alpha) { case 0: BltInternal< 0>(dst, src, ...); break; case 1: BltInternal< 1>(dst, src, ...); break; ... case 255: BltInternal<255>(dst, src, ...); break; case 256: BltInternal<256>(dst, src, ...); break; } }
これでいけるはず。