3 Concepts, same Result

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

3 Concepts, same Result

Post by MrSwiss »

While it sometimes appears, that there is a *established*, *best* solution to a particular
problem, there may be other *more favorable* solutions, in a differing context.

In below code snippets, the Union solution appears to be somewhat clumsy, on its own.
However, in the context of a library (where the Union is external to procedures) it may
be the best solution.
Similar, to the pointer method, in cases where only one channel is needed (but could
also be done, by a simple #Define ... depending on context).
Last but not least, the Macro method which may look familiar to those, having roots in
assembly programming (shifting & masking), which is probably fastest, on its own.

All 3 of them are capable of being made reversible, however some might need additio-
nal temp. variables (namely the pointer method). The first code (with demo) shows
the Getter's, while the second (without demo), shows the Setter's (inverted process).

[edit] new title, to better reflect the main purpose [/edit]

first:

Code: Select all

' 3-Methods_sameResult.bas -- 2018-07-20, by MrSwiss
'
' compile: -s console
'

Sub Get_ChanU( _                        ' get individual channels from color32 (ULong) 
    ByVal clr   As ULong, _             ' color to be split into channels (input)
    ByRef a     As UByte = 0, _         ' alpha-channel (return)
    ByRef r     As UByte = 0, _         ' red-channel (return)
    ByRef g     As UByte = 0, _         ' green-channel (return)
    ByRef b     As UByte = 0 _          ' blue-channel (return)
    )
    Union cl_                           ' define the union itself
        As ULong    c
        Type
            As UByte b, g, r, a         ' LSB to MSB (little endian)
        End Type
    End Union
    ' below: use of the union
    Dim As cl_  ret                     ' define one instance of union
    ret.c = clr                         ' load it with input color
    a = ret.a                           ' get & assign results ...
    r = ret.r
    g = ret.g
    b = ret.b
End Sub

Sub Get_ChanP( _                        ' get individual channels from color32 (ULong) 
    ByVal clr   As ULong, _             ' color to be split into channels (input)
    ByRef a     As UByte = 0, _         ' alpha-channel (return)
    ByRef r     As UByte = 0, _         ' red-channel (return)
    ByRef g     As UByte = 0, _         ' green-channel (return)
    ByRef b     As UByte = 0 _          ' blue-channel (return)
    )
    a = CPtr(UByte Ptr, @clr)[3]        ' MSB
    r = CPtr(UByte Ptr, @clr)[2]
    g = CPtr(UByte Ptr, @clr)[1]
    b = CPtr(UByte Ptr, @clr)[0]        ' LSB
End Sub

Sub Get_ChanM( _                        ' get individual channels from color32 (ULong) 
    ByVal clr   As ULong, _             ' color to be split into channels (input)
    ByRef a     As UByte = 0, _         ' alpha-channel (return)
    ByRef r     As UByte = 0, _         ' red-channel (return)
    ByRef g     As UByte = 0, _         ' green-channel (return)
    ByRef b     As UByte = 0 _          ' blue-channel (return)
    )
    a = clr Shr 24 And 255              ' MSB   (255 = &hFF = &b11111111)
    r = clr Shr 16 And 255
    g = clr Shr  8 And 255
    b = clr And 255                     ' LSB
End Sub


Const As ULong  red = &hFFFF0000, green = &h7F00FF00, blue = &h3F0000FF
' variables used ...
Dim As UByte    ac = 0, rc = 0, gc = 0, bc = 0
Dim As String   sa(1 To 6) => { "color in HEX:  ", "alpha-channel: ", _
                                "red-channel:   ", "green-channel: ", _
                                "blue-channel:  ", "  aarrggbb" }

'Get_ChanM(red, ac, rc, gc, bc)          ' macro method (ASM like: shift & mask)
'Get_ChanP(red, ac, rc, gc, bc)          ' pointer casting method
Get_ChanU(red, ac, rc, gc, bc)          ' union method
Print sa(1); Hex(red, 8); sa(6)
Print sa(2); ac; ", "; Hex(ac, 2)
Print sa(3); rc; ", "; Hex(rc, 2)
Print sa(4); gc; ", "; Hex(gc, 2)
Print sa(5); bc; ", "; Hex(bc, 2)
Print
ac = 0 : rc = 0 : gc = 0 : bc = 0       ' reset channel-UByte's

'Get_ChanM(green, ac, rc, gc, bc)
Get_ChanP(green, ac, rc, gc, bc)
'Get_ChanU(green, ac, rc, gc, bc)
Print sa(1); Hex(green, 8); sa(6)
Print sa(2); ac; ", "; Hex(ac, 2)
Print sa(3); rc; ", "; Hex(rc, 2)
Print sa(4); gc; ", "; Hex(gc, 2)
Print sa(5); bc; ", "; Hex(bc, 2)
Print
ac = 0 : rc = 0 : gc = 0 : bc = 0

Get_ChanM(blue, ac, rc, gc, bc)
'Get_ChanP(blue, ac, rc, gc, bc)
'Get_ChanU(blue, ac, rc, gc, bc)
Print sa(1); Hex(blue, 8); sa(6)
Print sa(2); ac; ", "; Hex(ac, 2)
Print sa(3); rc; ", "; Hex(rc, 2)
Print sa(4); gc; ", "; Hex(gc, 2)
Print sa(5); bc; ", "; Hex(bc, 2)
Print

Erase(sa)                               ' destroy string array

Sleep
second:

Code: Select all

' 3-Methods_sameResult_2.bas -- 2018-07-21, by MrSwiss
'
' compile: -s console
'

Function Set_ChanU( _                   ' set individual channels to color32 (ULong)
    ByVal a     As UByte = 255, _       ' alpha-channel (input), default = opaque
    ByVal r     As UByte = 0, _         ' red-channel (input)
    ByVal g     As UByte = 0, _         ' green-channel (input)
    ByVal b     As UByte = 0 _          ' blue-channel (input)
    ) As ULong                          ' assembled 32bit color
    Union cl_                           ' define the union itself
        As ULong    c
        Type
            As UByte b, g, r, a         ' LSB to MSB (little endian)
        End Type
    End Union
    ' below: use of the union
    Dim As cl_  ret                     ' define one instance of union
    ret.a = a
    ret.r = r
    ret.g = g
    ret.b = b
    Return ret.c
End Function

Function Set_ChanP( _                   ' set individual channels to color32 (ULong)
    ByVal a     As UByte = 255, _       ' alpha-channel (input), default = opaque
    ByVal r     As UByte = 0, _         ' red-channel (input)
    ByVal g     As UByte = 0, _         ' green-channel (input)
    ByVal b     As UByte = 0 _          ' blue-channel (input)
    ) As ULong                          ' assembled 32bit color
    Dim As ULong    clr                 ' temp. variable needed!
    CPtr(UByte Ptr, @clr)[3] = a        ' MSB
    CPtr(UByte Ptr, @clr)[2] = r
    CPtr(UByte Ptr, @clr)[1] = g
    CPtr(UByte Ptr, @clr)[0] = b        ' LSB
    Return clr
End Function

Function Set_ChanM( _                   ' set individual channels to color32 (ULong)
    ByVal a     As UByte = 255, _       ' alpha-channel (input), default = opaque
    ByVal r     As UByte = 0, _         ' red-channel (input)
    ByVal g     As UByte = 0, _         ' green-channel (input)
    ByVal b     As UByte = 0 _          ' blue-channel (input)
    ) As ULong                          ' assembled 32bit color
    Return (a Shl 24) + (r Shl 16) + (g Shl 8) + b
End Function
Last edited by MrSwiss on Jul 23, 2018 16:31, edited 1 time in total.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: 3 Methods, same Result

Post by dodicat »

The Fourth Kind.
Looks like, but essentially a path to The Third Kind.

Code: Select all

 

sub getcolour(c as ulong,byref r as ubyte,byref g as ubyte,byref b as ubyte,byref a as ubyte)
    g=hibyte(c)
    b=lobyte(c)
    r=lobyte(hiword(c))
    a=hibyte(hiword(c))
end sub




dim as ubyte r,g,b,a

getcolour(rgba(1,2,3,4),r,g,b,a)
print r,g,b,a

getcolour(rgba(255,2,255,255),r,g,b,a)
print r,g,b,a

getcolour(rgba(255,255,255,55),r,g,b,a)
print r,g,b,a

getcolour(rgba(55,5,255,155),r,g,b,a)
print r,g,b,a

'loop tester
dim as ubyte r1,g1,b1,a1
for n as long=1 to 1000000
    r1=rnd*255
    g1=rnd*255
    b1=rnd*255
    a1=rnd*255
 getcolour(rgba(r1,g1,b1,a1),r,g,b,a) 
 if r1<>r or g1<>g or b1<>b or a1<>a then print "Error"
next 

 print "done"
sleep
 
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: 3 Methods, same Result

Post by dodicat »

A Fifth Kind

Code: Select all

 #include "crt.bi"
function getcolour(c as ulong) as ubyte ptr
    static as ubyte u(3)
    memcpy(@u(0),@c,4)
    swap u(0),u(2)
    return @u(0)   'u[0]=r u[1]=g u[2]=b u[4]=alpha
    end function

Function map(a As Single,b As Single,x As Single,c As Single,d As Single) As Single
    Return ((d)-(c))*((x)-(a))/((b)-(a))+(c)
End Function


Screen 19,32
Dim As Any Ptr i=Imagecreate(800,600)
Dim As Long start =0,fin=160,flag=1
Dim As Long r,g,b
lbl:
'brief colour chart
For y As Long=0 To 600
    For x As Long=start To fin
        Select Case  flag
        Case 1
            r=255
            g=map(0,600,y,0,255)
            b=map(0,600,y,0,255)
        Case 2
            r=map(0,600,y,0,255)
            g=255
            b=map(0,600,y,0,255)
        Case 3
            r=map(0,600,y,0,255)
            g=map(0,600,y,0,255)
            b=255
        Case 4
            r=map(0,600,y,0,255)
            g=map(0,600,y,0,255)
            b=map(0,600,y,0,255)
        End Select
         Pset i,(x,y),Rgb(r,g,b)
    Next
Next
flag+=1
start+=160:fin+=160
If flag<=4 Then Goto lbl

Dim As Long mx,my
Dim As Ubyte Ptr u
Do
    Getmouse mx,my
    Screenlock
    Cls
    Put(0,0),i
    If mx<640 Then u=getcolour(Point(mx,my)) Else u=getcolour(Rgb(0,0,0))
    
    Line(640,0)-(800,200),   Rgb(u[0],0,0),bf
    Line(640,200)-(800,400), Rgb(0,u[1],0),bf
    Line(640,400)-(800,600), Rgb(0,0,u[2]),bf
    windowtitle "rgb("+right("000"+ str(u[0]),3)+","+right("000"+str(u[1]),3)+","+right("000"+str(u[2]),3)+")"
    Screenunlock
    Sleep 1,1
Loop Until Len(Inkey)


   
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: 3 Concepts, same Result

Post by MrSwiss »

@dodicat,

you seem to misunderstand something here:
your methods may be different but, the conceps however, are traceable to one of the
methods outlined in the original post (the fifth is sort of Union, first method, again),
as you've also indicated, that the fourth by consequence, leads to the third ...

It was never intended to become a:
  • implementation contest
  • speed trial thread
As we both know: there are many ways, to skin a cat ...
Re-titled the thread, to better explain its purpose ...

Just to proof the point your last one recoded, to equal type/signature:

Code: Select all

#include "crt.bi"
 
Sub getcolour( _
    ByVal clr   As ULong, _
    ByRef a     As UByte, _
    ByRef r     As UByte, _
    ByRef g     As UByte, _
    ByRef b     As UByte _
    )
    Static As UByte u(0 To 3)
    memcpy(@u(0), @clr, 4)
    a = u(3)
    r = u(2)
    g = u(1)
    b = u(0)
End Sub
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: 3 Concepts, same Result

Post by dodicat »

Another kind.

Code: Select all




function getcolours(u as string) as ubyte ptr
    static as ubyte c(1 to 4)
    c(4)=vallng("&h"+mid(u,1,2))
    c(1)=vallng("&h"+mid(u,3,2))
    c(2)=vallng("&h"+mid(u,5,2))
    c(3)=vallng("&h"+mid(u,7,2))
    return @c(1)
    end function




dim as ubyte u()


var z=getcolours(hex(rgba(173,28,100,200)))
print z[0],z[1],z[2],z[3]


dim as ulong clr=rgb(12,13,14)
z= getcolours(hex(clr))
print z[0],z[1],z[2],z[3]


sleep
  
Stonemonkey
Posts: 649
Joined: Jun 09, 2005 0:08

Re: 3 Concepts, same Result

Post by Stonemonkey »

Code: Select all

Sub Get_ChanM( _                        ' get individual channels from color32 (ULong) 
    ByVal clr   As ULong, _             ' color to be split into channels (input)
    ByRef a     As UByte = 0, _         ' alpha-channel (return)
    ByRef r     As UByte = 0, _         ' red-channel (return)
    ByRef g     As UByte = 0, _         ' green-channel (return)
    ByRef b     As UByte = 0 _          ' blue-channel (return)
    )
    a = clr Shr 24 And 255              ' MSB   (255 = &hFF = &b11111111)
    r = clr Shr 16 And 255
    g = clr Shr  8 And 255
    b = clr And 255                     ' LSB
End Sub
I know from a readability point of view it makes sense to include the And 255 in the 4 lines of code but they're not required, just the shifts would do.
And if I was doing it in assembly I'd do it like dodicats fourth kind example. Didn't know you could do that in FB, handy to know.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: 3 Concepts, same Result

Post by D.J.Peters »

What you can define a type or a union inside of sub and function !
Unbelievable that is absolute new for me and I use FB since 2005

Joshy

Code: Select all

Sub Get_ChanU ...
    Union cl_                           ' define the union itself
        As ULong    c
        Type
            As UByte b, g, r, a         ' LSB to MSB (little endian)
        End Type
    End Union
    ...
End Sub
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: 3 Concepts, same Result

Post by fxm »

More generally, you can define local Types / Unions in a local scope block (For..Next, While..Wend, Do..Loop, If..Then, Select..End Select, With..End With, Scope..End Scope, Sub, Function), but without any member procedures, including any constructor / destructor (even implicit).
A var-len string field is therefore forbidden.
Stonemonkey
Posts: 649
Joined: Jun 09, 2005 0:08

Re: 3 Concepts, same Result

Post by Stonemonkey »

Is it possible to create a variable of a different data type that the compiler knows points to the same instance without the use of pointers, kind of like an unspecified union?

Code: Select all

Sub anything(byval a as ulong)
  Dim b as single
  ....
Where a and b share the same space.
D.J.Peters
Posts: 8586
Joined: May 28, 2005 3:28
Contact:

Re: 3 Concepts, same Result

Post by D.J.Peters »

@Stonemonkey no you have to cast the pointer but only once :-)

BYREF is the key from this point different vars points to the same memory location.

Joshy

Code: Select all

type color32
  as ubyte b
  as ubyte g
  as ubyte r
  as ubyte a
end type   
Dim As ulong a = RGBA(1,2,3,4)
Dim ByRef As color32 b = *cptr(color32 ptr,@a)
print a
print b.r,b.g,b.b,b.a
print
b.r = 255
print a
print b.r,b.g,b.b,b.a
sleep
badidea
Posts: 2591
Joined: May 24, 2007 22:10
Location: The Netherlands

Re: 3 Concepts, same Result

Post by badidea »

Stonemonkey wrote:Is it possible to create a variable of a different data type that the compiler knows points to the same instance without the use of pointers, kind of like an unspecified union?

Code: Select all

Sub anything(byval a as ulong)
  Dim b as single
  ....
Where a and b share the same space.
I had a similar question here: https://freebasic.net/forum/viewtopic.php?f=3&t=27085
The answers was roughly 'yes, but complicated, whats wrong with pointers?'
Something like 'Dim b as single at @a' would be needed I think.
fxm
Moderator
Posts: 12110
Joined: Apr 22, 2009 12:46
Location: Paris suburbs, FRANCE

Re: 3 Concepts, same Result

Post by fxm »

Indeed, I do not see a simpler solution than using a reference.

A similar solution using a macro:
#Define b (*Cptr(Single Ptr, @a))
Stonemonkey
Posts: 649
Joined: Jun 09, 2005 0:08

Re: 3 Concepts, same Result

Post by Stonemonkey »

whats wrong with pointers?'
Pointers are indirectly addressed, I was just wondering if there was a way around that in some situations.

Thanks fxm.

Code: Select all

sub Get_ChanU(byval clr as ulong,byref a as ubyte=0,byref r as ubyte,byref g as ubyte,byref b as ubyte)
#define clr_component (*cptr(component ptr,@clr))
    type component
        b as ubyte
        g as ubyte
        r as ubyte
        a as ubyte
    end type
    b=clr_component.b
    g=clr_component.g
    r=clr_component.r
    a=clr_component.a
end sub
Ive not looked at the asm output to see what that does yet.

EDIT:

or as a macro

Code: Select all

#macro Get_ChanM(clr,a,r,g,b)
    scope
        type component
            b as ubyte
            g as ubyte
            r as ubyte
            a as ubyte
        end type
        b=(*cptr(component ptr,@clr)).b
        g=(*cptr(component ptr,@clr)).g
        r=(*cptr(component ptr,@clr)).r
        a=(*cptr(component ptr,@clr)).a
    end scope
#endmacro
Last edited by Stonemonkey on Oct 25, 2018 21:18, edited 3 times in total.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: 3 Concepts, same Result

Post by dodicat »

long and ulong for instance can share the same memory location and have apparently different values.
These two different values could be used .

Code: Select all

 
 

#include "crt.bi"

function map(a as double,b as double,x as double,c as double,d as double) as double
    return ((d)-(c))*((x)-(a))/((b)-(a))+(c)
    end function
screen 19,32

'======   same memory address =====
dim a as ulong 
dim byref b as long = a
'==================================

printf(!"@a       @b        a          b\n")
for n as longint= -1 to -3000000 step -1
b=n
var xpos=map(-1,-3000000,b,0,800)
if n mod 150000 =0 then printf(!"%d %d %u %d\n",@a,@b,a,b)
circle (10+xpos,300+50*sin(n/1000000)),20-n/100000,a/10,,,,f
next


sleep

 
Stonemonkey
Posts: 649
Joined: Jun 09, 2005 0:08

Re: 3 Concepts, same Result

Post by Stonemonkey »

That makes no sense dodicats, I'm going to look into that and see if I can find what's going on.

Edit:

They don't have different values, they have the same binary value, just when viewed as signed or unsigned they are different.
Post Reply