Last active
August 29, 2015 14:09
-
-
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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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