Color-Union evolved (over last 4 years)

Post your FreeBASIC source, examples, tips and tricks here. Please don’t post code without including an explanation.
Post Reply
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Color-Union evolved (over last 4 years)

Post by MrSwiss »

Hi all,

to start off, let me introduce you to a real monstrosity encountered 4 years ago:
from a old forum discussion in Documentation (April, 2016), a real 'monstrosity'

Code: Select all

Type ColorType                          ' don't like it (see next evolution step)
    Union
        As Ulong value                  ' clr is preferred over value (of what?)
        Type
            blue As uByte               ' if we are using long names then: _
            green As uByte
            red As ubyte
            a As Ubyte                  ' I'd call it: alpha, instead of a
        End Type                        ' (that is, if not short-cutting all)
    End Union
End Type
Reasons (to call it monstrous):
1) enclosing Type is totally pointless, because the Union itself can be 'named'
2) switching declaration mode to data-type before name shows improvement potential

Both issues and above remarks (in the code) attended to, resulted in:

Code: Select all

Union Color_u                           ' preferred naming (for Union's, append _u)
    As ULong        clr                 ' indicates: 32 bit color
    Type
        As UByte    b                   ' since I prefer short (over long)
        As UByte    g
        As UByte    r
        As UByte    a
    End Type
End Union
Addressing the above mentioned improvement potential:

Code: Select all

Union Color_u
    As ULong        clr                 ' 32 bit color
    Type
        As UByte    b, g, r, a          ' color-channel's (UByte access)
    End Type
End Union
Is this the best, that can be done?
Well, depends on whether we rely on the named UBytes or not ...

Without names for the UBytes we simply use a fixed-size UByte array and, at the
same time, getting rid of the Union's internal (unnamed) type:

Code: Select all

Union Color_u                           
    As ULong    clr
    As UByte    cc(0 to 3)              ' cc() = short for color-channel
End Union
' cc(0) = blue; cc(1) = green; cc(2) = red; cc(3) = alpha (little-endian)
That now is the most compact Union possible (methinks), without loosing functionality,
that is ...

Below a proof of concept demo (short and sweet):

Code: Select all

' a union is global in FB, like a Type (can be used in procedures, too)
Union c_u                               ' c_u = color union (24/32 bit)
    As ULong    clr                     ' 32 bit color; little-endian = _
    As UByte    cc(0 To 3)              ' BGRA = LSB to MSB memory-layout _
End Union                               ' color-channels (UByte access)

' use of Union inside procedure (Function here)
Private Function Swap_RB( _             ' WIN to FB or FB to WIN (both ways)
    ByVal valu  As ULong  _             ' original color value (32 bit)
    ) As ULong                          ' swapped R and B channels
    Dim As c_u  u                       ' one instance of Union (scope: local)
    u.clr = valu                        ' assign input value to Union
    Swap u.cc(0), u.cc(2)               ' swap blue-cc(0) / red-cc(2) UByte's
    Return u.clr                        ' return with swapped B/R channels
End Function                            ' (alpha and green unmodified)


Const As ULong  red = &hFFFF0000        ' unmodifiable (just used as source)
' use of Union in MAIN-code
Dim As c_u  u                           ' one instance of Union (scope: global)

For i As UInteger = 0 To 255
    Var inc = CUByte(i)                 ' conversion: UInteger to UByte
    u.cc(3) = inc                       ' alpha-channel assign
    'u.cc(2) = inc                       ' red-channel assign
    u.cc(1) = inc                       ' green-channel assign
    'u.cc(0) = inc                       ' blue-channel assign
    Print inc, "&h"; Hex(u.clr, 8), _   ' show UByte's state in the ULong
          , u.clr                       ' ULong in decimal is: useless! for _
Next                                    ' this demo's purpose ...

Print : Print "red: "; Hex(red, 8)      ' Hex() shows AARRGGBB, inverted memory _
Print                                   ' layout (string is big-endian, always) 
Print "red: "; Hex(Swap_RB(red), 8); " -- swapped red/blue channels"
Print : Print                           ' above: call Function (RB swapper)
Print "press a key to EXIT program ... ";

Sleep
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Color-Union evolved (over last 4 years)

Post by Imortis »

Interesting. A data driven approach. I can see how some would prefer a more verbose version, but I like what you have here.
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: Color-Union evolved (over last 4 years)

Post by MrSwiss »

Imortis wrote: I can see how some would prefer a more verbose version, ...
@Imortis, thanks.
Where would you want "more verbose"? The UBytes names (instead of: b, g, r, a)?
IMO, those are generally pretty commonly used by many here.
For that, the 3rd version can be used (instead of the last one).
The simplest looking one (last one) is regarded as: 'advanced coders' use.
Imortis
Moderator
Posts: 1923
Joined: Jun 02, 2005 15:10
Location: USA
Contact:

Re: Color-Union evolved (over last 4 years)

Post by Imortis »

I was specifically talking about the last example. I think it makes a lot of sense to use the array, but yes, the third code listing is what I could see as more general use.
Post Reply