Click here to Skip to main content
16,004,647 members

Welcome to the Lounge

   

For discussing anything related to a software developer's life but is not for programming questions. Got a programming question?

The Lounge is rated Safe For Work. If you're about to post something inappropriate for a shared office environment, then don't post it. No ads, no abuse, and no programming questions. Trolling, (political, climate, religious or whatever) will result in your account being removed.

 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
Amarnath S20-Jun-24 1:26
professionalAmarnath S20-Jun-24 1:26 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
Alister Morton20-Jun-24 3:41
Alister Morton20-Jun-24 3:41 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
Member 1486058521-Jun-24 4:43
Member 1486058521-Jun-24 4:43 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
Jonas Hammarberg21-Jun-24 0:45
professionalJonas Hammarberg21-Jun-24 0:45 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
Matt Bond21-Jun-24 2:15
Matt Bond21-Jun-24 2:15 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
honey the codewitch21-Jun-24 4:01
mvahoney the codewitch21-Jun-24 4:01 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
Dweeberly21-Jun-24 7:51
Dweeberly21-Jun-24 7:51 
GeneralRe: Thinking ahead. Just reflecting on some perhaps "overengineered" code Pin
honey the codewitch21-Jun-24 8:00
mvahoney the codewitch21-Jun-24 8:00 
Thanks. I mean in hindsight, I agree because I used the stuff I engineered for. Smile | :)

Edit: As far as directx, that's true, except for the format used for the last mile native draw surface. the alpha channel is not used in that situation.

I actually do use variadic templates to do my template definitions.

(background docs if you're interested: https://honeythecodewitch.com/gfx/wiki/pixels.md[^])

Each pixel has one or more channel_traits that are fed into it using variadic templates.

Like so:

C++
// creates an RGB pixel by making each channel 
// one third of the whole. Any remainder bits
// are added to the green channel
template<size_t BitDepth>
using rgb_pixel = pixel<
    channel_traits<channel_name::R,(BitDepth/3)>,
    channel_traits<channel_name::G,((BitDepth/3)+(BitDepth%3))>,
    channel_traits<channel_name::B,(BitDepth/3)>
>;
// creates an RGBA pixel by making each channel 
// one quarter of the whole. Any remainder bits
// are added to the green channel
template<size_t BitDepth>
using rgba_pixel = pixel<
    channel_traits<channel_name::R,(BitDepth/4)>,
    channel_traits<channel_name::G,((BitDepth/4)+(BitDepth%4))>,
    channel_traits<channel_name::B,(BitDepth/4)>,
    channel_traits<channel_name::A,(BitDepth/4),0,(1<<(BitDepth/4))-1,(1<<(BitDepth/4))-1>
>;
// creates a grayscale or monochome pixel
template<size_t BitDepth>
using gsc_pixel = pixel<
    channel_traits<channel_name::L,BitDepth>
>;
// creates a Y'UV pixel by making each channel 
// one third of the whole. Any remainder bits
// are added to the Y' channel
template<size_t BitDepth>
using yuv_pixel = pixel<
    channel_traits<channel_name::Y,((BitDepth/3)+(BitDepth%3))>,
    channel_traits<channel_name::U,(BitDepth/3)>,
    channel_traits<channel_name::V,(BitDepth/3)>
>;
// creates a Y'UV/A pixel by making each 
// channel 1/4 of the whole. Remaining bits
// are added to Y'
template<size_t BitDepth>
using yuva_pixel = pixel<
    channel_traits<channel_name::Y,((BitDepth/4)+(BitDepth%4))>,
    channel_traits<channel_name::U,(BitDepth/4)>,
    channel_traits<channel_name::V,(BitDepth/4)>,
    channel_traits<channel_name::A,(BitDepth/4),0,(1<<(BitDepth/4))-1,(1<<(BitDepth/4))-1>
>;


And here's the actual pixel class.

C++
// represents the pixel base class
template<typename... ChannelTraits> 
struct pixel {
    // this type
    using type = pixel<ChannelTraits...>;
    // the type used for doing intermediary conversions to different formats when no explicit conversion is implemented
    using rgb_conversion_type = pixel<channel_traits<channel_name::R,16>,channel_traits<channel_name::G,16>,channel_traits<channel_name::B,16>,channel_traits<channel_name::A,16>>;
    // the integer type of the pixel
    using int_type = bits::uintx<bits::get_word_size(helpers::bit_depth<ChannelTraits...>::value)>;
    // the number of channels
    constexpr static const size_t channels = sizeof...(ChannelTraits);
    // the number of color channels
    constexpr static const size_t color_channels = helpers::color_channels_size<ChannelTraits...>::value;
    // the total bit depth of the pixel
    constexpr static const size_t bit_depth = helpers::bit_depth<ChannelTraits...>::value;
    // the minimum number of bytes needed to store the pixel
    constexpr static const size_t packed_size = (bit_depth+7) / 8;
    // true if the pixel is a whole number of bytes
    constexpr static const bool byte_aligned = 0==bit_depth/8.0 - (size_t)(bit_depth/8);
    // the total size in bits, including padding
    constexpr static const size_t total_size_bits = sizeof(int_type)*8;
    // the packed size, in bits
    constexpr static const size_t packed_size_bits = packed_size*8;
    // the count of bits to the right that are unused
    constexpr static const size_t pad_right_bits = total_size_bits-bit_depth;
    // the mask of the pixel's value
    constexpr static const int_type mask = int_type(int_type(~int_type(0))<<(pad_right_bits));
    
    // the pixel value, in platform native format
    int_type native_value;
    
    // initializes the pixel
    constexpr inline pixel() : native_value(0) {
        helpers::pixel_init_impl<type,0,ChannelTraits...>::init(*this);
    }
    constexpr inline pixel(int_type native_value,bool dummy) : native_value(native_value) {
    }
    // initializes the pixel with a set of channel values
    constexpr inline pixel(typename ChannelTraits::int_type... values) : native_value(0) {
        helpers::pixel_init_impl<type,0,ChannelTraits...>::init(*this,values...);
    }
    // initializes the pixel with a set of floating point values between 0 and 1.0
    constexpr inline pixel(bool dummy,typename ChannelTraits::real_type... values) : native_value(0) {
        helpers::pixel_init_impl<type,0,ChannelTraits...>::initf(*this,values...);
    }
    // gets the pixel value in big endian form
    constexpr inline int_type value() const {
        return helpers::order_guard(native_value);
    }
    // sets the pixel value in big endian form
    constexpr inline void value(int_type value) {
        native_value=helpers::order_guard(value);
    }
    constexpr inline bool operator==(pixel rhs) {
        return rhs.native_value==native_value;
    }
    constexpr inline bool operator!=(pixel rhs) {
        return rhs.native_value!=native_value;
    }
    // retrieves a channel's metadata by index
    template<int Index> using channel_by_index = typename helpers::channel_by_index_impl<type,Index,channels,0,ChannelTraits...>::type;
    // retrieves a channel's metadata by index in cases where the checked version will cause an error
    template<int Index> using channel_by_index_unchecked = typename helpers::channel_by_index_unchecked_impl<type,Index,channels,0,ChannelTraits...>::type;
    // gets the index of the channel by the channel name
    template<typename Name> using channel_index_by_name = typename helpers::channel_index_by_name_impl<0,Name,ChannelTraits...>;
    // gets the channel by name
    template<typename Name> using channel_by_name = channel_by_index<helpers::channel_index_by_name_impl<0,Name,ChannelTraits...>::value>;
    // retrieves a channel's metadata by name in cases where the checked version will cause an error
    template<typename Name> using channel_by_name_unchecked = channel_by_index_unchecked<channel_index_by_name<Name>::value>;
    // returns true if the pixel contains channels with each name
    template<typename... ChannelNames> using has_channel_names = typename helpers::has_channel_names_impl<type,ChannelNames...>;
    // returns true if the pixel has the given color model (discounting non color channels like alpha, and nop)
    template<typename... ChannelNames> using is_color_model = typename helpers::is_color_model_impl<type,ChannelNames...>;
    // returns true if this channel is a subset of the other
    template<typename PixelRhs> using is_subset_of = typename helpers::is_subset_pixel_impl<PixelRhs,ChannelTraits...>;
    // returns true if this channel is a superset of the other
    template<typename PixelRhs> using is_superset_of = typename PixelRhs::template is_subset_of<type>;
    // returns true if the two pixels have channels with the same names, regardless of order
    template<typename PixelRhs> using unordered_equals = typename helpers::unordered_equals_pixel_impl<type,PixelRhs>;
    // returns true if the two pixels have channels with the same names, in the same order
    template<typename PixelRhs> using equals = typename helpers::equals_pixel_impl<PixelRhs,ChannelTraits...>;
    // returns true if the two pixels are exactly the same
    template<typename PixelRhs> using equals_exact = typename helpers::is_same<type,PixelRhs>;
    
    // retrieves the integer channel value without performing compile time checking on Index
    template<int Index>
    constexpr inline typename channel_by_index_unchecked<Index>::int_type channel_unchecked() const {
        return helpers::get_channel_direct_unchecked<type,Index>(native_value);
    }
    // sets the integer channel value without performing compile time checking on Index
    template<int Index>
    constexpr inline void channel_unchecked(typename channel_by_index_unchecked<Index>::int_type value) {
        helpers::set_channel_direct_unchecked<type,Index>(native_value,value);
    }
    // retrieves the integer channel value by index
    template<int Index>
    constexpr inline typename channel_by_index<Index>::int_type channel() const {
        using ch = channel_by_index<Index>;
        return typename ch::int_type(typename ch::pixel_type::int_type(native_value & ch::channel_mask)>>ch::total_bits_to_right);
        
    }
    // sets the integer channel value by index
    template<int Index>
    constexpr inline void channel(typename channel_by_index<Index>::int_type value) {
        using ch = channel_by_index<Index>;
        const typename ch::pixel_type::int_type shval = typename ch::pixel_type::int_type(typename ch::pixel_type::int_type(helpers::clamp(value,ch::min,ch::max))<<ch::total_bits_to_right);
        native_value=typename ch::pixel_type::int_type((native_value&typename ch::pixel_type::int_type(~ch::channel_mask))|shval);
    }
    // retrieves the floating point channel value by index
    template<int Index>
    constexpr inline typename channel_by_index_unchecked<Index>::real_type channelr() const {
        using ch = channel_by_index<Index>;
        return channel<Index>()*ch::scaler;
    }
    // sets the floating point channel value by index
    template<int Index>
    constexpr inline void channelr(typename channel_by_index<Index>::real_type value) {
        using ch = channel_by_index<Index>;
        channel<Index>(value*ch::scale+.5);
    }
    // retrieves the floating point channel value by index
    template<int Index>
    constexpr inline typename channel_by_index_unchecked<Index>::real_type channelr_unchecked() const {
        using ch = channel_by_index_unchecked<Index>;
        return (typename ch::real_type)channel_unchecked<Index>()*ch::scaler;
    }
    // sets the floating point channel value by index
    template<int Index>
    constexpr inline void channelr_unchecked(typename channel_by_index<Index>::real_type value) {
        using ch = channel_by_index_unchecked<Index>;
        channel_unchecked<Index>(value*ch::scale+.5);
    }
    // retrieves the integer channel value by name
    template<typename Name>
    constexpr inline auto channel() const {
        const int index = channel_index_by_name<Name>::value;
        return channel<index>();
    }
    // sets the integer channel value by name
    template<typename Name>
    constexpr inline void channel(typename channel_by_index<channel_index_by_name<Name>::value>::int_type value) {
        const int index = channel_index_by_name<Name>::value;
        channel<index>(value);
    }
    // gets the floating point channel value by name
    template<typename Name>
    constexpr inline auto channelr() const {
        const int index = channel_index_by_name<Name>::value;
        return channelr<index>();
    }
    // sets the floating point channel value by name
    template<typename Name>
    constexpr inline void channelr(typename channel_by_name<Name>::real_type value) {
        const int index = channel_index_by_name<Name>::value;
        channelr<index>(value);
    }
    // returns the difference between two pixels
    constexpr double difference(type rhs) const {
        return sqrt(helpers::pixel_diff_impl<type,0,ChannelTraits...>::diff_sum(*this,rhs));
    }
    // blends two pixels. ratio is between zero and one. larger ratio numbers favor this pixel
    constexpr gfx_result blend(const type rhs,double ratio,type* out_pixel) const {
        if(out_pixel==nullptr) {
            return gfx_result::invalid_argument;
        }
        static_assert(!has_channel_names<channel_name::index>::value,"pixel must not be indexed");
        if(ratio==1.0) {
            out_pixel->native_value = native_value;
            return gfx_result::success;
        } else if(ratio==0.0) {
            out_pixel->native_value = rhs.native_value;
            return gfx_result::success;
        }
        if(type::template has_channel_names<channel_name::A>::value) {
            
            constexpr const int ai = type::channel_index_by_name<channel_name::A>::value;

            float a1 = this->template channelr_unchecked<ai>();
            float a2 = rhs.template channelr_unchecked<ai>();
            float r2 = a1/a2;
            ratio = ratio * r2;
            if(ratio>1.0)
                ratio = 1.0;               
        }
        
        helpers::pixel_blend_impl<type,0,ChannelTraits...>::blend_val(*this,rhs,ratio,out_pixel);
        return gfx_result::success;
    }
    // blends two pixels. ratio is between zero and one. larger ratio numbers favor this pixel
    constexpr type blend(const type rhs,double ratio) const {
        type result;
        blend(rhs,ratio,&result);
        return result;
    }
    
    static_assert(sizeof...(ChannelTraits)>0,"A pixel must have at least one channel trait");
    static_assert(bit_depth<=HTCW_MAX_WORD,"Bit depth must be less than or equal to the maximum machine word size");
};

Check out my IoT graphics library here:
https://honeythecodewitch.com/gfx
And my IoT UI/User Experience library here:
https://honeythecodewitch.com/uix

GeneralI was sent this, and... Pin
OriginalGriff19-Jun-24 20:09
mveOriginalGriff19-Jun-24 20:09 
GeneralRe: I was sent this, and... Pin
Kornfeld Eliyahu Peter19-Jun-24 20:41
professionalKornfeld Eliyahu Peter19-Jun-24 20:41 
GeneralRe: I was sent this, and... Pin
obermd20-Jun-24 3:19
obermd20-Jun-24 3:19 
GeneralRe: I was sent this, and... Pin
PJ Arends20-Jun-24 11:01
professionalPJ Arends20-Jun-24 11:01 
GeneralI think we can resolve the Fermi Paradox. PinPopular
OriginalGriff19-Jun-24 19:50
mveOriginalGriff19-Jun-24 19:50 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
Kornfeld Eliyahu Peter19-Jun-24 20:37
professionalKornfeld Eliyahu Peter19-Jun-24 20:37 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
GKP199219-Jun-24 21:13
professionalGKP199219-Jun-24 21:13 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
Jörgen Andersson19-Jun-24 23:12
professionalJörgen Andersson19-Jun-24 23:12 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
OriginalGriff20-Jun-24 0:59
mveOriginalGriff20-Jun-24 0:59 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
honey the codewitch20-Jun-24 1:01
mvahoney the codewitch20-Jun-24 1:01 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
OriginalGriff20-Jun-24 1:59
mveOriginalGriff20-Jun-24 1:59 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
maze320-Jun-24 2:48
professionalmaze320-Jun-24 2:48 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
jochance20-Jun-24 4:40
jochance20-Jun-24 4:40 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
Maximilien20-Jun-24 3:42
Maximilien20-Jun-24 3:42 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
OriginalGriff20-Jun-24 4:16
mveOriginalGriff20-Jun-24 4:16 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
rob tillaart20-Jun-24 22:37
rob tillaart20-Jun-24 22:37 
GeneralRe: I think we can resolve the Fermi Paradox. Pin
Bruce Patin21-Jun-24 4:23
Bruce Patin21-Jun-24 4:23 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.