Skip to content

Instantly share code, notes, and snippets.

@lardratboy
Last active August 29, 2015 14:09
Show Gist options
  • Save lardratboy/415dff091d8342bbe3bb to your computer and use it in GitHub Desktop.
Save lardratboy/415dff091d8342bbe3bb to your computer and use it in GitHub Desktop.
Started looking at upgrading the pixel types used by the LSD engine, using this as an archive/reference.
// BPTLLC_Pixels.h
//
// Copyright (c) 2003, Brad P. Taylor, LLC
//
// All rights reserved, unauthorized reproduction prohibited
//
// -- FILE NOTES --
//
// **Portablilty warning**
//
// Watch the following expression pattern for correctness on your target,
// I haven't seen this generate incorrect answers however the risk is there.
//
// $ = (($ | ($ << #)) & #;
//
// see http://en.cppreference.com/w/cpp/language/eval_order
//
// (thanks for pointing this out, you will know who you are if you ever see the comment :-)
//
//////////////////////////////////////////////////////////////////////
#if !defined(__BPTLLC_PIXELS_H__)
#define __BPTLLC_PIXELS_H__
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
// ----------------------------------------------------------------------------
#include <algorithm>
#define BPTLLC_FORCE_INLINE __forceinline
// ----------------------------------------------------------------------------
#include "BPTLLC_Generic.h"
// ----------------------------------------------------------------------------
namespace BPT {
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned long u32;
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Pixel types
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// ----------------------------------------------------------------------------
#pragma pack( push, PIXEL_packing, 1 )
// ----------------------------------------------------------------------------
#define BPT_MAKE_BASIC_PIXEL_TYPE(NAME,STORAGE) \
struct NAME { \
typedef STORAGE value_type; \
value_type value; \
BPTLLC_FORCE_INLINE NAME() { /* empty */ } \
BPTLLC_FORCE_INLINE NAME( const value_type v ) : value( v ) { } \
BPTLLC_FORCE_INLINE NAME( const int v ) : value( value_type(v) ) { } \
BPTLLC_FORCE_INLINE operator value_type() const { \
return value; \
} \
BPTLLC_FORCE_INLINE NAME& operator=( const value_type set ) { \
value = set; \
return *this; \
} \
BPTLLC_FORCE_INLINE NAME& operator=( const NAME set ) { \
value = set.value; \
return *this; \
} \
};
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_32, u32 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_16, u16 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_8, u8 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_XRGB8888, u32 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_ARGB8888, u32 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_RGB565, u16 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_RGB555, u16 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_ARGB1555, u16 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_ARGB4444, u16 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_RGB332, u8 )
BPT_MAKE_BASIC_PIXEL_TYPE( PIXEL_ARGB2222, u8 )
#undef BPT_MAKE_BASIC_PIXEL_TYPE
// ------------------------------------------------------------------------
// struct to deal with non-integral pixel type (has marshalling code)
// ------------------------------------------------------------------------
//
// PIXEL_RGB888
//
struct PIXEL_RGB888 {
// traits
typedef u8 channel_storage;
typedef PIXEL_RGB888 & reference;
typedef unsigned value_type;
enum {
r_bit_count = 8
,r_shift = 16
,g_bit_count = 8
,g_shift = 8
,b_bit_count = 8
,b_shift = 0
};
// storage
channel_storage b;
channel_storage g;
channel_storage r;
// marshal/unmarshal methods
BPTLLC_FORCE_INLINE PIXEL_RGB888( const value_type set ) {
r = static_cast<channel_storage>((set >> r_shift) & ((1 << r_bit_count) - 1));
g = static_cast<channel_storage>((set >> g_shift) & ((1 << g_bit_count) - 1));
b = static_cast<channel_storage>((set >> b_shift) & ((1 << b_bit_count) - 1));
}
BPTLLC_FORCE_INLINE operator value_type() const {
return static_cast<value_type>( (r << r_shift) | (g << g_shift) | (b << b_shift) );
}
BPTLLC_FORCE_INLINE reference operator=( const value_type set ) {
r = static_cast<channel_storage>((set >> r_shift) & ((1 << r_bit_count) - 1));
g = static_cast<channel_storage>((set >> g_shift) & ((1 << g_bit_count) - 1));
b = static_cast<channel_storage>((set >> b_shift) & ((1 << b_bit_count) - 1));
return *this;
}
};
// ----------------------------------------------------------------------------
#pragma pack( pop, PIXEL_packing )
// ----------------------------------------------------------------------------
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// General pixel trait catch all class
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// TPixelTraits<>
//
template< class T > struct TPixelTraits {
typedef unsigned value_type;
typedef T type;
enum {
channels = 1
,bpp = (sizeof(T) * 8)
,storage_size = sizeof(T)
,r_bit_count = 0
,r_shift = 0
,r_max = 0
,r_isolation_mask = 0
,g_bit_count = 0
,g_shift = 0
,g_max = 0
,g_isolation_mask = 0
,b_bit_count = 0
,b_shift = 0
,b_max = 0
,b_isolation_mask = 0
,a_bit_count = bpp
,a_shift = 0
,a_max = ((1 << a_bit_count) - 1)
,a_isolation_mask = (((1 << a_bit_count) - 1) << a_shift)
,has_alpha = (0 != a_isolation_mask)
,rgb_number = ((r_bit_count * 100) + (g_bit_count * 10) + (b_bit_count))
,argb_number = ((a_bit_count * 1000) + rgb_number)
,rgb_isolation_mask = 0
};
}; /* template TPixelTraits */
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Specialized traits class
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
#define BPT_MAKE_PIXEL_SPECIALIZATION(TT,CHANNELS,BPP,ABITS,RBITS,GBITS,BBITS,ASHIFT,RSHIFT,GSHIFT,BSHIFT) \
template<> struct TPixelTraits<TT> { \
typedef TT::value_type value_type; \
typedef TT type; \
enum { \
channels = (CHANNELS) \
,bpp = (BPP) \
,storage_size = sizeof(TT) \
,r_bit_count = (RBITS) \
,r_shift = (RSHIFT) \
,r_max = ((1 << (RBITS)) - 1) \
,r_isolation_mask = (((1 << (RBITS)) - 1) << (RSHIFT)) \
,g_bit_count = (GBITS) \
,g_shift = (GSHIFT) \
,g_max = ((1 << (GBITS)) - 1) \
,g_isolation_mask = (((1 << (GBITS)) - 1) << (GSHIFT)) \
,b_bit_count = (BBITS) \
,b_shift = (BSHIFT) \
,b_max = ((1 << (BBITS)) - 1) \
,b_isolation_mask = (((1 << (BBITS)) - 1) << (BSHIFT)) \
,a_bit_count = (ABITS) \
,a_shift = (ASHIFT) \
,a_max = ((1 << (ABITS)) - 1) \
,a_isolation_mask = (((1 << (ABITS)) - 1) << (ASHIFT)) \
,has_alpha = (0 != a_isolation_mask) \
,rgb_number = (((RBITS) * 100) + ((GBITS) * 10) + ((BBITS))) \
,argb_number = (((ABITS) * 1000) + rgb_number) \
,rgb_isolation_mask = (r_isolation_mask|g_isolation_mask|b_isolation_mask)\
}; \
};
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_ARGB2222,4,8,2,2,2,2,6,4,2,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_RGB332,3,8,0,3,3,2,0,5,2,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_ARGB4444,4,16,4,4,4,4,12,8,4,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_ARGB1555,4,16,1,5,5,5,15,10,5,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_RGB555,3,16,0,5,5,5,0,10,5,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_RGB565,3,16,0,5,6,5,0,11,5,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_ARGB8888,4,32,8,8,8,8,24,16,8,0)
BPT_MAKE_PIXEL_SPECIALIZATION(PIXEL_XRGB8888,3,32,0,8,8,8,0,16,8,0)
BPT_MAKE_PIXEL_SPECIALIZATION(
PIXEL_RGB888, 3, 24
,0, PIXEL_RGB888::r_bit_count, PIXEL_RGB888::g_bit_count, PIXEL_RGB888::b_bit_count
,0, PIXEL_RGB888::r_shift, PIXEL_RGB888::g_shift, PIXEL_RGB888::b_shift
)
#undef BPT_MAKE_PIXEL_SPECIALIZATION
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
// Channel accessor helper
// -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
//
// TChannel<>
//
template< class T >
struct TChannel {
// Read
// --------------------------------------------------------------------
static typename TPixelTraits<T>::value_type BPTLLC_FORCE_INLINE
R( const typename TPixelTraits<T>::value_type v ) {
return (v & TPixelTraits<T>::r_isolation_mask) >> TPixelTraits<T>::r_shift;
}
static typename TPixelTraits<T>::value_type BPTLLC_FORCE_INLINE
G( const typename TPixelTraits<T>::value_type v ) {
return (v & TPixelTraits<T>::g_isolation_mask) >> TPixelTraits<T>::g_shift;
}
static typename TPixelTraits<T>::value_type BPTLLC_FORCE_INLINE
B( const typename TPixelTraits<T>::value_type v ) {
return (v & TPixelTraits<T>::b_isolation_mask) >> TPixelTraits<T>::b_shift;
}
static typename TPixelTraits<T>::value_type BPTLLC_FORCE_INLINE
A( const typename TPixelTraits<T>::value_type v ) {
return (v & TPixelTraits<T>::a_isolation_mask) >> TPixelTraits<T>::a_shift;
}
// conversion helpers
// --------------------------------------------------------------------
template<const int BITS> static int BPTLLC_FORCE_INLINE
R( const typename TPixelTraits<T>::value_type v ) {
int t = (TChannel<T>::R(v) * ((1 << BITS) - 1))
+ ((1 << TPixelTraits<T>::r_bit_count)>>1);
return (
(t + (t >> TPixelTraits<T>::r_bit_count)) >> TPixelTraits<T>::r_bit_count
);
}
template<const int BITS> static int BPTLLC_FORCE_INLINE
G( const typename TPixelTraits<T>::value_type v ) {
int t = (TChannel<T>::G(v) * ((1 << BITS) - 1))
+ ((1 << TPixelTraits<T>::g_bit_count)>>1);
return (
(t + (t >> TPixelTraits<T>::g_bit_count)) >> TPixelTraits<T>::g_bit_count
);
}
template<const int BITS> static int BPTLLC_FORCE_INLINE
B( const typename TPixelTraits<T>::value_type v ) {
int t = (TChannel<T>::B(v) * ((1 << BITS) - 1))
+ ((1 << TPixelTraits<T>::b_bit_count)>>1);
return (
(t + (t >> TPixelTraits<T>::b_bit_count)) >> TPixelTraits<T>::b_bit_count
);
}
template<const int BITS> static int BPTLLC_FORCE_INLINE
A( const typename TPixelTraits<T>::value_type v ) {
int t = (TChannel<T>::A(v) * ((1 << BITS) - 1))
+ ((1 << TPixelTraits<T>::a_bit_count)>>1);
return (
(t + (t >> TPixelTraits<T>::a_bit_count)) >> TPixelTraits<T>::a_bit_count
);
}
// make
// --------------------------------------------------------------------
static T BPTLLC_FORCE_INLINE Pack_( const int r, const int g, const int b, const int a )
{
return T(
TPixelTraits<T>::value_type(
((r << TPixelTraits<T>::r_shift))
| ((g << TPixelTraits<T>::g_shift))
| ((b << TPixelTraits<T>::b_shift))
| ((a << TPixelTraits<T>::a_shift))
)
);
}
static T BPTLLC_FORCE_INLINE Pack( const int r, const int g, const int b, const int a )
{
return T(
TPixelTraits<T>::value_type(
((r << TPixelTraits<T>::r_shift) & TPixelTraits<T>::r_isolation_mask)
| ((g << TPixelTraits<T>::g_shift) & TPixelTraits<T>::g_isolation_mask)
| ((b << TPixelTraits<T>::b_shift) & TPixelTraits<T>::b_isolation_mask)
| ((a << TPixelTraits<T>::a_shift) & TPixelTraits<T>::a_isolation_mask)
)
);
}
static T BPTLLC_FORCE_INLINE RGBA8888( const int r8, const int g8, const int b8, const int a8 )
{
int rt = (r8 * TPixelTraits<T>::r_max) + 128;
int gt = (g8 * TPixelTraits<T>::g_max) + 128;
int bt = (b8 * TPixelTraits<T>::b_max) + 128;
int at = (a8 * TPixelTraits<T>::a_max) + 128;
return Pack_(
(rt + (rt >> 8)) >> 8
, (gt + (gt >> 8)) >> 8
, (bt + (bt >> 8)) >> 8
, (at + (at >> 8)) >> 8
);
}
// --------------------------------------------------------------------
// TChannel predicates
// --------------------------------------------------------------------
//
// NotZeroAlphaPredicate
//
struct NotZeroAlphaPredicate : public std::unary_function<T,bool> {
bool operator()( const T & i ) const {
return (0 != A( i ));
}
}; // NotZeroAlphaPredicate
//
// ZeroAlphaPredicate
//
struct ZeroAlphaPredicate : public std::unary_function<T,bool> {
bool operator()( const T & i ) const {
return (0 == A( i ));
}
}; // ZeroAlphaPredicate
}; /* struct TChannel */
// ------------------------------------------------------------------------
//
// TConvert<>
//
template< class T >
struct TConvert {
// --------------------------------------------------------------------
template<
const int RBits
, const int GBits
, const int BBits
, const int ABits
>
static T BPTLLC_FORCE_INLINE From(
const int r
, const int g
, const int b
, const int a = ((1 << ABits) - 1)
)
{
int rt = (r * TPixelTraits<T>::r_max) + ((1 << RBits)>>1);
int gt = (g * TPixelTraits<T>::g_max) + ((1 << GBits)>>1);
int bt = (b * TPixelTraits<T>::b_max) + ((1 << BBits)>>1);
int at = (a * TPixelTraits<T>::a_max) + ((1 << ABits)>>1);
return TChannel<T>::Pack_(
(rt + (rt >> RBits)) >> RBits
, (gt + (gt >> GBits)) >> GBits
, (bt + (bt >> BBits)) >> BBits
, (at + (at >> ABits)) >> ABits
);
}
// --------------------------------------------------------------------
private:
template<const bool BLINN>
struct TFrom {
template< typename C >
static T From( const C c ) {
// This uses a generalized version of Jim Blinn's /255 technique to divide by
// other powers of 2^x - 1 values, this allows for correct scaling for
// low bit depth values to be scaled to higher bit depths without division.
int rt = (TChannel<C>::R( c ) * TPixelTraits<T>::r_max)
+ ((1 << TPixelTraits<C>::r_bit_count)>>1);
int gt = (TChannel<C>::G( c ) * TPixelTraits<T>::g_max)
+ ((1 << TPixelTraits<C>::g_bit_count)>>1);
int bt = (TChannel<C>::B( c ) * TPixelTraits<T>::b_max)
+ ((1 << TPixelTraits<C>::b_bit_count)>>1);
int at = (TChannel<C>::A( c ) * TPixelTraits<T>::a_max)
+ ((1 << TPixelTraits<C>::a_bit_count)>>1);
return TChannel<T>::Pack_(
(rt + (rt >> TPixelTraits<C>::r_bit_count)) >> TPixelTraits<C>::r_bit_count
, (gt + (gt >> TPixelTraits<C>::g_bit_count)) >> TPixelTraits<C>::g_bit_count
, (bt + (bt >> TPixelTraits<C>::b_bit_count)) >> TPixelTraits<C>::b_bit_count
, (at + (at >> TPixelTraits<C>::a_bit_count)) >> TPixelTraits<C>::a_bit_count
);
}
}; // TFrom
template<> struct TFrom<false> {
template< typename C >
static T From( const C c ) {
// this could probably be optimized further by managing the channels in a less
// generalized fashion (yet another level of indirection would be needed)
return TChannel<T>::Pack_(
TChannel<C>::R( c ) >> (TPixelTraits<C>::r_bit_count - TPixelTraits<T>::r_bit_count)
, TChannel<C>::G( c ) >> (TPixelTraits<C>::g_bit_count - TPixelTraits<T>::g_bit_count)
, TChannel<C>::B( c ) >> (TPixelTraits<C>::b_bit_count - TPixelTraits<T>::b_bit_count)
, TChannel<C>::A( c ) >> (TPixelTraits<C>::a_bit_count - TPixelTraits<T>::a_bit_count)
);
}
}; // TFrom
public:
// --------------------------------------------------------------------
template< typename C >
static T BPTLLC_FORCE_INLINE From( const C c ) {
return TFrom<
(TPixelTraits<C>::r_bit_count < TPixelTraits<T>::r_bit_count)
&& (TPixelTraits<C>::g_bit_count < TPixelTraits<T>::g_bit_count)
&& (TPixelTraits<C>::b_bit_count < TPixelTraits<T>::b_bit_count)
&& (TPixelTraits<C>::a_bit_count < TPixelTraits<T>::a_bit_count)
>::From( c );
}
static T BPTLLC_FORCE_INLINE From( const T t ) {
return t;
}
template< typename C >
static C BPTLLC_FORCE_INLINE To( const T t ) {
return TConvert<C>::From<T>( t );
}
// --------------------------------------------------------------------
static T BPTLLC_FORCE_INLINE FromCOLORREF( const COLORREF cr ) {
return From<8,8,8,8>(
GetRValue( cr )
, GetGValue( cr )
, GetBValue( cr )
, 255
);
}
static COLORREF BPTLLC_FORCE_INLINE ToCOLORREF(
const typename TPixelTraits<T>::value_type v
) {
return RGB(
TChannel<T>::R<8>( v )
, TChannel<T>::G<8>( v )
, TChannel<T>::B<8>( v )
);
}
}; // TConvert
// ------------------------------------------------------------------------
//
// TConstant
//
template<
const int R
, const int G
, const int B
, const int A
, typename T
, const int Rbits = 8
, const int Gbits = 8
, const int Bbits = 8
, const int Abits = 8
>
struct TConstant {
enum {
rt_ = ((R * TPixelTraits<T>::r_max)
+ ((1 << TPixelTraits<T>::r_bit_count)>>1))
, gt_ = ((G * TPixelTraits<T>::g_max)
+ ((1 << TPixelTraits<T>::g_bit_count)>>1))
, bt_ = ((B * TPixelTraits<T>::b_max)
+ ((1 << TPixelTraits<T>::b_bit_count)>>1))
, at_ = ((A * TPixelTraits<T>::a_max)
+ ((1 << TPixelTraits<T>::a_bit_count)>>1))
};
// const static typename T::value_type value =
const static typename TPixelTraits<T>::value_type value =
(typename TPixelTraits<T>::value_type)(((rt_ + (rt_ >> Rbits)) >> Rbits) << TPixelTraits<T>::r_shift)
| (typename TPixelTraits<T>::value_type)(((gt_ + (gt_ >> Gbits)) >> Gbits) << TPixelTraits<T>::g_shift)
| (typename TPixelTraits<T>::value_type)(((bt_ + (bt_ >> Bbits)) >> Bbits) << TPixelTraits<T>::b_shift)
| (typename TPixelTraits<T>::value_type)(((at_ + (at_ >> Abits)) >> Abits) << TPixelTraits<T>::a_shift)
;
}; // TConstant
// ------------------------------------------------------------------------
//
// TColorTransform<>
//
template< class T >
struct TColorTransform {
template<const int Mul,const int Div>
static T BPTLLC_FORCE_INLINE
TScaleRGB( const typename TPixelTraits<T>::value_type v ) {
return TChannel<T>::Pack(
((TChannel<T>::R(v) * Mul) / Div)
, ((TChannel<T>::G(v) * Mul) / Div)
, ((TChannel<T>::B(v) * Mul) / Div)
, TChannel<T>::A(v)
);
}
static T BPTLLC_FORCE_INLINE
TInvertRGB( const typename TPixelTraits<T>::value_type v ) {
return T( v ^ TPixelTraits<T>::rgb_isolation_mask );
}
static T BPTLLC_FORCE_INLINE
TGrayscaleRGB( const typename TPixelTraits<T>::value_type v ) {
int gray = (
((int)TChannel<T>::R(v) * 307)
+ ((int)TChannel<T>::G(v) * 604)
+ ((int)TChannel<T>::B(v) * 113) ) >> 10;
return TChannel<T>::Pack_( gray, gray, gray, TChannel<T>::A(v) );
}
static T BPTLLC_FORCE_INLINE
TMostlyAveragedRGB( const typename TPixelTraits<T>::value_type v ) {
int avg = (
((int)TChannel<T>::R(v)<<1)
+ ((int)TChannel<T>::G(v)<<2)
+ ((int)TChannel<T>::B(v)<<1) ) >> 3;
return TChannel<T>::Pack( avg, avg, avg, TChannel<T>::A(v) );
}
static T BPTLLC_FORCE_INLINE
TDesaturateRGB( const typename TPixelTraits<T>::value_type v ) {
int r = TChannel<T>::R(v);
int g = TChannel<T>::G(v);
int b = TChannel<T>::B(v);
int gray = (min( r, min( g, b ) ) + max( r, max( g, b ) )) >> 1;
return TChannel<T>::Pack( gray, gray, gray, TChannel<T>::A(v) );
}
// other constant based transforms
}; // TColorTransform
// ------------------------------------------------------------------------
template<typename T> inline T TDesaturateRGB( const T v ) {
return BPT::TColorTransform<T>::TDesaturateRGB( v );
}
template<typename T> inline T TGrayscaleRGB( const T v ) {
return BPT::TColorTransform<T>::TGrayscaleRGB( v );
}
template<typename T> inline T TInvertRGB( const T v ) {
return BPT::TColorTransform<T>::TInvertRGB( v );
}
// ------------------------------------------------------------------------
//
// TBlend_32()
//
template< class T >
struct TBlend_32 {
private:
// --------------------------------------------------------------------
typedef TPixelTraits<T> Traits;
// --------------------------------------------------------------------
typedef TMinMaxMiddle<
Traits::r_isolation_mask
, Traits::g_isolation_mask
, Traits::b_isolation_mask
> sorted_masks;
enum {
split_channels_mask = (sorted_masks::max | sorted_masks::min)
, center_channel_mask = (sorted_masks::middle)
};
// --------------------------------------------------------------------
typedef TMinMaxMiddle<
Traits::r_bit_count
, Traits::g_bit_count
, Traits::b_bit_count
> sorted_counts;
enum {
bit_count = sorted_counts::min
, full_value = (1 << bit_count)
};
// --------------------------------------------------------------------
enum {
all_bits_count = (Traits::a_bit_count + Traits::r_bit_count + Traits::g_bit_count + Traits::b_bit_count)
, alpha_adjust = ((0 == Traits::a_shift) ? ((all_bits_count - Traits::a_shift)) : 0)
};
// ====================================================================
template<const int A> struct TConstantRGB_ {
static T BPTLLC_FORCE_INLINE Op(
const typename Traits::value_type d
, const typename Traits::value_type s
) {
const unsigned dst_1_3 = (d & split_channels_mask) >> alpha_adjust;
const unsigned dst__2_ = (d & center_channel_mask) >> alpha_adjust;
const unsigned src_1_3 = (s & split_channels_mask) >> alpha_adjust;
const unsigned src__2_ = (s & center_channel_mask) >> alpha_adjust;
unsigned d_1_3 = src_1_3 - dst_1_3;
unsigned d__2_ = src__2_ - dst__2_;
d_1_3 *= A;
d__2_ *= A;
d_1_3 >>= bit_count;
d__2_ >>= bit_count;
return T(
/*Traits::a_isolation_mask | */
(typename Traits::value_type)
((((d_1_3 + dst_1_3) & (split_channels_mask >> alpha_adjust))
|((d__2_ + dst__2_) & (center_channel_mask >> alpha_adjust))
) << alpha_adjust)
);
}
}; // TConstantRGB_
template<> struct TConstantRGB_<full_value> {
static T BPTLLC_FORCE_INLINE Op(
const typename Traits::value_type d
, const typename Traits::value_type s
)
{ return T( s ); }
}; // TConstantRGB_<full_value>
template<> struct TConstantRGB_<0> {
static T BPTLLC_FORCE_INLINE Op(
const typename Traits::value_type d
, const typename Traits::value_type s
)
{ return T( d ); }
}; // TConstantRGB_<0>
// ====================================================================
template<const int A> struct TConstantRGBA_ {
static T BPTLLC_FORCE_INLINE Op(
const typename Traits::value_type d
, const typename Traits::value_type s
) {
// ------------------------------------------------------------
// scale the src alpha by the constant alpha
// ------------------------------------------------------------
const unsigned a =
(((((s & Traits::a_isolation_mask) >> Traits::a_shift) * A) + 1) >> Traits::a_bit_count);
// ------------------------------------------------------------
const unsigned dst_1_3 = (d & split_channels_mask) >> alpha_adjust;
const unsigned dst__2_ = (d & center_channel_mask) >> alpha_adjust;
const unsigned src_1_3 = (s & split_channels_mask) >> alpha_adjust;
const unsigned src__2_ = (s & center_channel_mask) >> alpha_adjust;
unsigned d_1_3 = src_1_3 - dst_1_3;
unsigned d__2_ = src__2_ - dst__2_;
// ------------------------------------------------------------
d_1_3 *= a;
d__2_ *= a;
d_1_3 >>= bit_count;
d__2_ >>= bit_count;
return T(
/* Traits::a_isolation_mask | */
(typename Traits::value_type)
((((d_1_3 + dst_1_3) & (split_channels_mask >> alpha_adjust))
|((d__2_ + dst__2_) & (center_channel_mask >> alpha_adjust))
) << alpha_adjust)
);
}
}; // TConstantRGBA_
template<> struct TConstantRGBA_<full_value> {
static T BPTLLC_FORCE_INLINE Op(
const typename Traits::value_type d
, const typename Traits::value_type s
)
{
// ------------------------------------------------------------
unsigned a = (s & Traits::a_isolation_mask);
if ( 0 == a ) return d;
if ( Traits::a_isolation_mask == a ) return s;
a >>= Traits::a_shift;
++a;
// ------------------------------------------------------------
const unsigned dst_1_3 = (d & split_channels_mask) >> alpha_adjust;
const unsigned dst__2_ = (d & center_channel_mask) >> alpha_adjust;
const unsigned src_1_3 = (s & split_channels_mask) >> alpha_adjust;
const unsigned src__2_ = (s & center_channel_mask) >> alpha_adjust;
unsigned d_1_3 = src_1_3 - dst_1_3;
unsigned d__2_ = src__2_ - dst__2_;
// ------------------------------------------------------------
d_1_3 *= a;
d__2_ *= a;
d_1_3 >>= bit_count;
d__2_ >>= bit_count;
return T(
/* Traits::a_isolation_mask | */
(typename Traits::value_type)
((((d_1_3 + dst_1_3) & (split_channels_mask >> alpha_adjust))
|((d__2_ + dst__2_) & (center_channel_mask >> alpha_adjust))
) << alpha_adjust)
);
}
}; // TConstantRGBA_<full_value>
template<> struct TConstantRGBA_<0> {
static T BPTLLC_FORCE_INLINE Op(
const typename Traits::value_type d
, const typename Traits::value_type s
)
{ return T( d ); }
}; // TConstantRGBA_<0>
// --------------------------------------------------------------------
public:
// --------------------------------------------------------------------
template< const int TMul, const int TDiv > struct TConstant {
private:
enum { scaled_value = (TMul * full_value) / TDiv };
public:
typedef TConstantRGB_<scaled_value> rgb;
typedef TConstantRGBA_<scaled_value> rgba;
}; // TConstantBlend
// --------------------------------------------------------------------
}; // TBlend_32
// ------------------------------------------------------------------------
//
// TBlend_16()
//
template< class T >
struct TBlend_16 {
protected:
// --------------------------------------------------------------------
typedef TPixelTraits<T> Traits;
// --------------------------------------------------------------------
typedef TMinMaxMiddle<
Traits::r_isolation_mask
, Traits::g_isolation_mask
, Traits::b_isolation_mask
> sorted_masks;
enum {
split_channels_mask = (sorted_masks::max | sorted_masks::min)
, center_channel_mask = (sorted_masks::middle)
, channels_mask = ((center_channel_mask << 16) | split_channels_mask)
, center_channel_shift =
((center_channel_mask == Traits::r_isolation_mask) ? Traits::r_shift :
((center_channel_mask == Traits::g_isolation_mask) ? Traits::g_shift : Traits::b_shift))
};
// --------------------------------------------------------------------
typedef TMinMaxMiddle<
Traits::r_bit_count
, Traits::g_bit_count
, Traits::b_bit_count
> sorted_counts;
enum {
bit_count = sorted_counts::min
, full_value = (1 << bit_count)
, alpha_mask = (full_value - 1)
};
// ====================================================================
template<const int A> struct TConstantRGB_ {
static T BPTLLC_FORCE_INLINE Op(
unsigned d
, unsigned s
) {
d = (d |= (d << 16)) & channels_mask;
s = (s |= (s << 16)) & channels_mask;
s -= d;
s *= A;
s >>= bit_count;
s += d;
s &= channels_mask;
return T(
(typename Traits::value_type)(s | (s >> 16))
);
}
}; // TConstantRGB_
template<> struct TConstantRGB_<full_value> {
static T BPTLLC_FORCE_INLINE Op(
const unsigned d
, const unsigned s
)
{ return T( (TPixelTraits<T>::value_type)s ); }
}; // TConstantRGB_<full_value>
template<> struct TConstantRGB_<0> {
static T BPTLLC_FORCE_INLINE Op(
const unsigned d
, const unsigned s
)
{ return T( (TPixelTraits<T>::value_type)d ); }
}; // TConstantRGB_<0>
public:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Constant alpha ratio
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template< const int TMul, const int TDiv > struct TConstant {
private:
enum { scaled_value = (TMul * full_value) / TDiv };
public:
typedef TConstantRGB_<scaled_value> rgb;
}; // TConstant
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Alpha
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// AlphaBlendRGB()
//
// -- [0 <= a <= 32]
// -- since a is comming from a source other than the input rgb values
// -- a can represent the full range so that the shift down by the
// -- smaller channel bit count will result in a accurate divide result.
//
static T BPTLLC_FORCE_INLINE AlphaBlendRGB(
unsigned d
, unsigned s
, unsigned a
) {
d = (d |= (d << 16)) & channels_mask;
s = (s |= (s << 16)) & channels_mask;
s -= d;
s *= a;
s >>= bit_count;
s += d;
s &= channels_mask;
return T(
(typename Traits::value_type)(s | (s >> 16))
);
}
protected:
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Additive
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
template<const int> struct TAdditiveRGB_ {
static T BPTLLC_FORCE_INLINE Op(
const unsigned d
, const unsigned s
) {
extern "C" void TAdditiveRGB_unsupported_layout();
TAdditiveRGB_unsupported_layout();
}
};
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
One odd ball channel (i.e. 565)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
00000.000000.00000.rrrrr.gggggg.bbbbb.(s/d)
rrrrr.gggggg.bbbbb.rrrrr.gggggg.bbbbb.(?|(?<<16)
00000.gggggg.xxxxx.rrrrr.xxxxxx.bbbbb.
-------------------------------------------------------
00000.111111.00000.11111.000000.11111.(mask_g_r_b)
00000.011010.00000.11011.000000.11100.(d)
00000.111011.00000.00011.000000.00110.(s)
-------------------------------------------------------
00001.010110.00000.11110.000001.00010.(s+=d)
00000.010110.00000.11110.000000.00010.(d=s&mask_g_r_b)
00001.000000.00000.00000.000001.00000.(s^=d)
00000.000010.00000.00000.000000.00001.(s>>=5)
00000.000000.00000.00000.000000.00001.(t=s>>(g_shift+1))
00000.000001.00000.00000.000000.00000.(t<<=g_shift)
00000.000001.00000.00000.000000.00001.(s|=t)
00001.000000.00000.11111.000001.00000.(s+=maskB)
00000.111111.00000.00000.000001.11111.(s^=maskB)
00000.111111.00000.00000.000000.11111.(s&=mask)
00000.111111.00000.11110.000000.11111.(d|=s)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
enum {
oddball_shift =
((sorted_counts::max == Traits::r_bit_count) ? Traits::r_shift :
((sorted_counts::max == Traits::g_bit_count) ? Traits::g_shift : Traits::b_shift))
, oddball_adjustment_shift =
(oddball_shift + (sorted_counts::max - sorted_counts::min))
, clear_oddball_mask = ~(1 << oddball_adjustment_shift)
};
template<> struct TAdditiveRGB_<1> {
static T BPTLLC_FORCE_INLINE Op(
unsigned d
, unsigned s
) {
d = (d |= (d << 16)) & channels_mask;
s = (s |= (s << 16)) & channels_mask;
s += d;
d = (s & channels_mask);
s ^= d;
s >>= sorted_counts::min;
// (deal with the misplaced bit)
// if it was known for sure that center channel
// and the odd ball were one in the same then the
// clear mask is not needed.
s = (s & clear_oddball_mask) |
((s >> oddball_adjustment_shift) << oddball_shift);
// Okay go back to work, nothing to see here
s += channels_mask;
s ^= channels_mask;
s &= channels_mask;
d |= s;
return T(
(typename Traits::value_type)(d | (d >> 16))
);
}
}; // TAdditiveRGB_
/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
equal channel sizes example (555,444)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
0.00000.00000.00000.0.rrrrr.ggggg.bbbbb.(s/d)
0.rrrrr.ggggg.bbbbb.0.rrrrr.ggggg.bbbbb.(?|(?<<16)
x.00000.ggggg.xxxxx.x.rrrrr.xxxxx.bbbbb.
-----------------------------------------------------------
0.00000.11111.00000.0.11111.00000.11111.(mask)
0.00000.11010.00000.0.11011.00000.11100.(d)
0.00000.11011.00000.0.00011.00000.00110.(s)
-----------------------------------------------------------
0.00001.10101.00000.0.11110.00001.00010.(s+=d)
0.00000.10101.00000.0.11110.00000.00010.(d=s&mask)
0.00001.00000.00000.0.00000.00001.00000.(s^=d)
0.00000.00001.00000.0.00000.00000.00001.(s>>=5)
0.00001.00000.00000.0.11111.00001.00000.(s+=mask)
0.00001.11111.00000.0.00000.00001.11111.(s^=mask)
0.00000.11111.00000.0.00000.00000.11111.(s&=mask)
0.00000.11111.00000.0.11110.00000.11111.(d|=s)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
template<> struct TAdditiveRGB_<0> {
static T BPTLLC_FORCE_INLINE Op(
unsigned d
, unsigned s
)
{
d = (d |= (d << 16)) & channels_mask;
s = (s |= (s << 16)) & channels_mask;
s += d;
d = (s & channels_mask);
s ^= d;
s >>= sorted_counts::min;
s += channels_mask;
s ^= channels_mask;
s &= channels_mask;
d |= s;
return T(
(typename Traits::value_type)(d | (d >> 16))
);
}
}; // TAdditiveRGB_<0>
public:
// --------------------------------------------------------------------
struct TAdditiveRGB {
// Figure out which specialization by figuring out the number
// of different channel sizes 0, 1 or 2 (is there ever a 2 case?)
typedef TAdditiveRGB_<
(TMax<Traits::r_bit_count,Traits::g_bit_count>::value - TMin<Traits::r_bit_count,Traits::g_bit_count>::value)
+ (TMax<Traits::g_bit_count,Traits::b_bit_count>::value - TMin<Traits::g_bit_count,Traits::b_bit_count>::value)
> rgb;
}; // TAdditiveRGB
// --------------------------------------------------------------------
}; // TBlend_16
// ------------------------------------------------------------------------
//
// TBlend<>
//
template< class T > struct TBlend {
private:
template<int> struct Selector {
typedef TBlend_32<T> blender;
};
template<> struct Selector<0> {
typedef TBlend_16<T> blender;
};
public:
template< const int TMul, const int TDiv > struct TConstant {
typedef typename Selector<
((2 == TPixelTraits<T>::storage_size)
&& (0 == TPixelTraits<T>::a_bit_count)) ? 0 : 1
>::blender::template TConstant<TMul,TDiv>::rgb rgb;
}; // TConstant
}; // TBlend<>
// ------------------------------------------------------------------------
//
// ConstantBlendRGB
//
template< const int TMul, const int TDiv, class T >
T BPTLLC_FORCE_INLINE ConstantBlendRGB( const T d, const T s ) {
return typename TBlend<T>::template TConstant<TMul,TDiv>::rgb( d, s );
}
// ------------------------------------------------------------------------
//
// TConvertPixelTypes()
//
/*
NOTE: I didn't make this routine a conversion operator because the process isn't
super cheap, it's 'accurate' without using divides. Of course if division isn't
expensive then this process is a bit overkill.
*/
template< typename DST, typename SRC >
void BPTLLC_FORCE_INLINE TConvertPixelTypes( DST & out, SRC & input )
{
out = TConvert<DST>::template From<SRC>( input );
}
}; /* namespace BPT */
// ----------------------------------------------------------------------------
#endif /* __BPTLLC_PIXELS_H__ */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment