How to retrieve background color in 32 bits?

General FreeBASIC programming questions.
Post Reply
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

How to retrieve background color in 32 bits?

Post by Tourist Trap »

Hi,

The documentation is quite clear, the hi/lo-Word(color()) command would only return foreground color in 32 bits color mode (in this case loWord only can be useful). This is normal as far as I understand the deal, since a word is 32 bits and splitting it in high and low wouldn't help to retrieve twice full 32 bits data.Edit: Even worse if a WORD in fb is only 16 bits as it seems to be.

Whatever, what is the workaround then? Or is it in the oven some extension of the color() function such that it would deal with QWord, and then hiQWord would be implemented? In one final 'word', what's going on here, and is there anything to do?

I need this in the context of setting automatically and at any time a contrasted foreground color according to the current background one.

Thanks by advance.
Last edited by Tourist Trap on Nov 19, 2015 14:24, edited 1 time in total.
MichaelW
Posts: 3500
Joined: May 16, 2006 22:34
Location: USA

Re: How to retrieve background color in 32 bits?

Post by MichaelW »

Looking at the 1.04.0 source, in fb_gfx_private.h, the FB_GFXCTX (fb_gfx context) structure stores the foreground and background colors as separate 32-bit unsigned integers:

Code: Select all

typedef struct FB_GFXCTX {
	int id;
	int work_page;
	unsigned char **line;
	int max_h;
	int target_bpp;
	int target_pitch;
	void *last_target;
	float last_x, last_y;
	union {
		struct {
			int view_x, view_y, view_w, view_h;
		};
		int view[4];
	};
	union {
		struct {
			int old_view_x, old_view_y, old_view_w, old_view_h;
		};
		int old_view[4];
	};
	float win_x, win_y, win_w, win_h;
	unsigned int fg_color, bg_color;
	void (*put_pixel)(struct FB_GFXCTX *ctx, int x, int y, unsigned int color);
	unsigned int (*get_pixel)(struct FB_GFXCTX *ctx, int x, int y);
	void *(*pixel_set)(void *dest, int color, size_t size);
	PUTTER **putter[PUT_MODES];
	int flags;
} FB_GFXCTX;
So the data appears to be there, but the problem is in accessing it.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to retrieve background color in 32 bits?

Post by dodicat »

screencontrol 13 yields the foreground and background colours.

They are passed as uinteger.
You can extract the colour components via a pointer, or use the macros (from the help file):
#define RGBA_R( c ) ( CUInt( c ) Shr 16 And 255 )
#define RGBA_G( c ) ( CUInt( c ) Shr 8 And 255 )
#define RGBA_B( c ) ( CUInt( c ) And 255 )
#define RGBA_A( c ) ( CUInt( c ) Shr 24 )

Example:

Code: Select all


dim as uinteger fore,back
screenres 500,300,32
color rgb(255,200,12),rgb(50,90,245)
screencontrol 13,fore,back
var forepointer=cptr(ubyte ptr,@fore),backpointer=cptr(ubyte ptr,@back)
print fore,back
do
    screenlock
    cls
    locate 5,1
    print fore,back
    print
    print
    '         red          green            blue
    print forepointer[2],forepointer[1],forepointer[0],"foreground"
    print
     print backpointer[2],backpointer[1],backpointer[0],"background"
    screenunlock
    sleep 1,1
    loop until len(inkey)
 
Maybe I am missing something here, do you want something else.
What's with hiword/loword ??
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: How to retrieve background color in 32 bits?

Post by MrSwiss »

@Tourist Trap,

your description of word is wrong, a word = short = 16bits = 2x Byte ...

@dodicat,
dodicat wrote:They are passed as uinteger. -- NO as ULong (in FB)
Maybe I am missing something here ... What's with hiword/loword ??
Your code is only in 32bit correct, it is far better to use ULong for Color
and I'm positive that is, what CUInt means. A 32bit unsigned INT.

UInteger becomes 64bit unsigned INT in 64bit code, which is wrong!
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: How to retrieve background color in 32 bits?

Post by Tourist Trap »

dodicat wrote:screencontrol 13 yields the foreground and background colours.
Thanks dodicat!

What I wanted to do is simply something like:

Code: Select all

#define _R(c) ( cUint(c) shr 16 and 255 )
#define _G(c) ( cUint(c) shr 08 and 255 )
#define _B(c) ( cUint(c) shr 00 and 255 )

dim as ulong bckgcolor = hiWord(color())
dim as ulong fgndcolor

fgndcolor = rgb( iif(_R(bckgcolor )<128, 255, 0), _ 
		 iif(_G(bckgcolor )<128, 255, 0), _ 
		 iif(_B(bckgcolor )<128, 255, 0) )

print "Hello in a contrasted way!"

sleep
It is not possible since in 32 bits color mode, hiWord wouldn't return the background when applied to color() return value. It's a pitty since color() is the perfect function for dealing with colors; at least it has the perfect name!

I'll try what you've posted in few hours. But if screenControl is abble to return colors why color() built-in funct doesn't simply wrap it? What exactly does color() in particular compared to this?
MrSwiss wrote:@Tourist Trap,
your description of word is wrong, a word = short = 16bits = 2x Byte ...
Yes in fb you are right, seems that DWORD is the type holding 32 bits. But in general, what a WORD means exactly varies very much, and most often corresponds to the system integers.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: How to retrieve background color in 32 bits?

Post by dodicat »

Interesting to find a foreground and background colour guaranteed to be noticeablly different.
I cannot think of anything remotely clever, just a brute force way.
Here 100 bytes at least are between reds,greens,and blues.
(Left mouse click to change colours)

Code: Select all

 
Dim As Ulong fore,back
Screenres 500,300,32
Color Rgb(255,200,12),Rgb(50,90,245)
Screencontrol 13,fore,back
Var forepointer=Cptr(Ubyte Ptr,@fore),backpointer=Cptr(Ubyte Ptr,@back)

Dim As Long m,button,flag,counter
Do
    Getmouse m,m,,button
    If button=1 And flag=0 Then
        flag=1
        counter=0
        Do
            counter+=1
            'Get new foreground colour from new background colour:
            back=Rgb(Rnd*255,Rnd*255,Rnd*255)
            fore=Rgb(Rnd*255,Rnd*255,Rnd*255)
        Loop Until Abs(forepointer[2]-backpointer[2])>100 And _
                   Abs(forepointer[1]-backpointer[1])>100 And _
                   Abs(forepointer[0]-backpointer[0])>100
        Color fore,back
    End If
    Screenlock
    Cls
    Locate 5,1
    Print "foreground",fore
    Print
    Print "background",back
    Print
    Print "iterations",counter
    Print
    Print
    '         red          green            blue
    Print forepointer[2],forepointer[1],forepointer[0],"foreground"
    Print
    Print backpointer[2],backpointer[1],backpointer[0],"background"
    Circle(250,200),50,,,,,f
    Screenunlock
    Sleep 1,1
    flag=button
Loop Until Len(Inkey)

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

Re: How to retrieve background color in 32 bits?

Post by MrSwiss »

@Tourist Trap,
Tourist Trap wrote:
MrSwiss wrote:@Tourist Trap,
your description of word is wrong, a word = short = 16bits = 2x Byte ...
Yes in fb you are right, seems that DWORD is the type holding 32 bits. But in general, what a WORD means exactly varies very much, and most often corresponds to the system integers.
I'm NOT talking about any HLL (high level language) here, but ASSEMBLY
in particular Intel ASM, where there are:
  • Byte = 8bits (Byte/UByte - FB)
    Word = 16bits (Short/UShort - FB)
    DWord = 32bits (Long/ULong - FB ++ Integer/UInteger, in 32bit FBC only)
    QWord = 64bits (LongInt/ULongInt - FB ++ Integer/UInteger, in 64bit FBC only)
This has, so far, never changed and probably never will.
This is not to be confused with all the HLL definitions, which can be very misleading!

As MichaelW already pointed out:
Color(FG, BG) ' where FG = ULong and BG = ULong
Tourist Trap
Posts: 2958
Joined: Jun 02, 2015 16:24

Re: How to retrieve background color in 32 bits?

Post by Tourist Trap »

MrSwiss wrote:I'm NOT talking about any HLL (high level language) here, but ASSEMBLY
in particular Intel ASM, where there are:
  • Byte = 8bits (Byte/UByte - FB)
    Word = 16bits (Short/UShort - FB)
    DWord = 32bits (Long/ULong - FB ++ Integer/UInteger, in 32bit FBC only)
    QWord = 64bits (LongInt/ULongInt - FB ++ Integer/UInteger, in 64bit FBC only)
This has, so far, never changed and probably never will.
Ok, I see now.

But for the color function things are melted a little. Arguments are ulong as you've recalled, but we need lo/hi-word to decypher the return. And finally we still need two 32 bits placeholders to get both foreground and background color in 32 bits mode, which placeholders, color function doesn't seem to provide (at present day at least).
dodicat wrote:Interesting to find a foreground and background colour guaranteed to be noticeablly different.
I cannot think of anything remotely clever, just a brute force way.
Hey dodicat. I agree perfectly and I have been searching the web for a formula that encloses a given color in rgb boundaries. Unfortunately that seems not to be something that has been done. Rather there are some enumerations like pantone variations for a huge example.

I've done this below to give an example of something I would find doable to seek by hand such boundaries for a color. In the code below (not the most general for this version) I say that I'm searching all variations around the red color. For instance of course rgb(r,0,0) will always be ok, but we dont leave the red scope immediatly when adding the 2 other components. It is still quite reddish if we set rgb(150, 60, 80).

This question of course can get generalized. Given any color as rgb(rc,gc,bc) what are the boundaries so that rgb(rc+r0,gc-g0,bc+b0) is still the same color (yet a variant)....

Code: Select all

'tool to study the full range of a color 
'without overlapping when r, g, b vary

screenRes 600, 450, 32
color , rgb(60,60,90)

dim as uInteger r, g, b

dim as uInteger rCursorBox_xMin, rCursorBox_xMax 
dim as uInteger rCursorBox_yMin, rCursorBox_yMax 
dim as uInteger rCursorValue

dim as uInteger gCursorBox_xMin, gCursorBox_xMax 
dim as uInteger gCursorBox_yMin, gCursorBox_yMax 
dim as uInteger gCursorValue

dim as uInteger bCursorBox_xMin, bCursorBox_xMax 
dim as uInteger bCursorBox_yMin, bCursorBox_yMax 
dim as uInteger bCursorValue

rCursorBox_xMin => 60 - 2
rCursorBox_xMax => 60 + 2
rCursorBox_yMin => 42
rCursorBox_yMax => 46

gCursorBox_xMin => 82
gCursorBox_xMax => 86
gCursorBox_yMin => 60 - 2
gCursorBox_yMax => 60 + 2

bCursorBox_xMin => 222
bCursorBox_xMax => 226
bCursorBox_yMin => 60 - 2
bCursorBox_yMax => 60 + 2

dim as integer  gmX, gmY, gmBtn1
dim as boolean  rCursorDragStarted 
dim as boolean  gCursorDragStarted 
dim as boolean  bCursorDragStarted 
dim as integer  dsGmX, dsGmY  
do
    '_____________display______________________________________________
    screenLock
    cls
    '*rBox*************************************************************
    line (59,19)-(60 + 256,41), rgb(255,255,255), bf
    draw string (60 + 256 + 20, 15), " main color is RED"
    draw string (60 + 256 + 20, 28), " <- RED full variation"
    draw string (60 + 256 + 20, 40), " <- rCursorValue = "& _ 
                                     (rCursorValue mod 255)
    for r = 0 to 255
        line (60 + r,20)-(60 + r,40), rgb(r,0,0)
    next r
    '*rCursor
    line (rCursorBox_xMin - 1, rCursorBox_yMin - 1)- _ 
         (rCursorBox_xMax + 1, rCursorBox_yMax + 1), _ 
         , _ 
         bf
    line (rCursorBox_xMin, rCursorBox_yMin)-(rCursorBox_xMax, rCursorBox_yMax), _ 
         rgb(rCursorValue,0,0), _ 
         bf
    '*gBox*************************************************************
    line (59,59)-(81,60 + 256), rgb(255,255,255), bf
    for g = 0 to 255
        line (60,60 + g)-(80,60 + g), rgb(0,g,0)
    next g
    '*gCursor
    draw string (88, 58 + gCursorValue), str(gCursorValue mod 255)
    line (gCursorBox_xMin - 1, gCursorBox_yMin - 1)- _ 
         (gCursorBox_xMax + 1, gCursorBox_yMax + 1), _ 
         , _ 
         bf
    line (gCursorBox_xMin, gCursorBox_yMin)-(gCursorBox_xMax, gCursorBox_yMax), _ 
         rgb(0,gCursorValue,0), _ 
         bf
    '*bBox*************************************************************
    line (199,59)-(221,60 + 256), rgb(255,255,255), bf
    for b = 0 to 255
        line (200,60 + b)-(220,60 + b), rgb(0,0,b)
    next b
    '*bCursor
    draw string (228, 58 + bCursorValue), str(bCursorValue mod 255)
    line (bCursorBox_xMin - 1, bCursorBox_yMin - 1)- _ 
         (bCursorBox_xMax + 1, bCursorBox_yMax + 1), _ 
         , _ 
         bf
    line (bCursorBox_xMin, bCursorBox_yMin)-(bCursorBox_xMax, bCursorBox_yMax), _ 
         rgb(0,0,bCursorValue), _ 
         bf
    '**(r,g,b) resultant**********************************************
    draw string (340,240), _ 
                str("("& cUbyte(rCursorValue) & _ 
                    ","& cUbyte(gCursorValue) & _ 
                    ","& cUbyte(bCursorValue) &")")
    line (339,259)-(441,361), ,b
    line (340,260)-(440,360), _ 
         rgb(rCursorValue,gCursorValue,bCursorValue), _ 
         bf
    
    screenUnlock


    '___mouse interaction______________________________________________
    '*rCursor
    if rCursorDragStarted then
        getMouse dsGmX, gmY, , gmBtn1
        if dsGmX<rCursorBox_xMin then dsGmX = rCursorBox_xMin + 2
        if dsGmX>rCursorBox_xMax then dsGmX = rCursorBox_xMax - 2
        if gmY<rCursorBox_yMin then gmY = rCursorBox_yMin + 2
        if gmY>rCursorBox_yMax then gmY = rCursorBox_yMax - 2
    else
        if not gCursorDragStarted and _ 
           not bCursorDragStarted then 
            getMouse gmX, gmY, , gmBtn1
        end if
    end if
    if gmX>=rCursorBox_xMin and _ 
       gmX<=rCursorBox_xMax and _ 
       gmY>=rCursorBox_yMin and _ 
       gmY<=rCursorBox_yMax then
        if gmBtn1=+1 then
            if rCursorDragStarted then
                getMouse dsGmX, dsGmY
                rCursorBox_xMin += dsGmX - gmX
                rCursorBox_xMax += dsGmX - gmX
                gmX              = rCursorBox_xMin + 2
            else
                rCursorDragStarted = TRUE
            end if
        else
            rCursorDragStarted = FALSE
        end if
    end if
    rCursorValue    => rCursorBox_xMin - 58
    
    '*gCursor
    if gCursorDragStarted then
        getMouse gmX, dsGmY, , gmBtn1
        if gmX<gCursorBox_xMin then gmX = gCursorBox_xMin + 2
        if gmX>gCursorBox_xMax then gmX = gCursorBox_xMax - 2
        if dsGmY<gCursorBox_yMin then dsGmY = gCursorBox_yMin + 2
        if dsGmY>gCursorBox_yMax then dsGmY = gCursorBox_yMax - 2
    else
        if not rCursorDragStarted and _ 
           not bCursorDragStarted then 
            getMouse gmX, gmY, , gmBtn1
        end if
    end if
    if gmX>=gCursorBox_xMin and _ 
       gmX<=gCursorBox_xMax and _ 
       gmY>=gCursorBox_yMin and _ 
       gmY<=gCursorBox_yMax then
        if gmBtn1=+1 then
            if gCursorDragStarted then
                getMouse dsGmX, dsGmY
                gCursorBox_yMin += dsGmy - gmY
                gCursorBox_yMax += dsGmY - gmY
                gmY              = gCursorBox_yMin + 2
            else
                gCursorDragStarted = TRUE
            end if
        else
            gCursorDragStarted = FALSE
        end if
    end if
    gCursorValue    => gCursorBox_yMin - 58
    
    '*bCursor
    if bCursorDragStarted then
        getMouse gmX, dsGmY, , gmBtn1
        if gmX<bCursorBox_xMin then gmX = bCursorBox_xMin + 2
        if gmX>bCursorBox_xMax then gmX = bCursorBox_xMax - 2
        if dsGmY<bCursorBox_yMin then dsGmY = bCursorBox_yMin + 2
        if dsGmY>bCursorBox_yMax then dsGmY = bCursorBox_yMax - 2
    else
        getMouse gmX, gmY, , gmBtn1
    end if
    if gmX>=bCursorBox_xMin and _ 
       gmX<=bCursorBox_xMax and _ 
       gmY>=bCursorBox_yMin and _ 
       gmY<=bCursorBox_yMax then
        if gmBtn1=+1 then
            if bCursorDragStarted then
                getMouse dsGmX, dsGmY
                bCursorBox_yMin += dsGmy - gmY
                bCursorBox_yMax += dsGmY - gmY
                gmY              = bCursorBox_yMin + 2
            else
                bCursorDragStarted = TRUE
            end if
        else
            bCursorDragStarted = FALSE
        end if
    end if
    bCursorValue    => bCursorBox_yMin - 58
    
    
    ''''''''
    sleep 15
loop until inkey=chr(27)

sleep
'[eof]
Once we know what color we have in hand by reading rgb components, we can easily find a complementary that is well contrasted (this is a thing that has been done for what is called accessibility for "blind users" and so on). Red and yellow for instance are well contrasted. Not red and blue in any case!

An other interesting approach is to get the dark side of a given bright color, and the inverse. And many other nice things allowing to ensure good color display.
dkr
Posts: 40
Joined: Nov 20, 2015 15:17
Location: Alabama, USA

Re: How to retrieve background color in 32 bits?

Post by dkr »

Please forgive my ignorance - just an old quickbasic coder - and not very good...

This code posted from dodicat:

dim as ulong fore,back
screenres 500,300,32
color rgb(255,200,12),rgb(50,90,245)
screencontrol 13,fore,back
var forepointer=cptr(ubyte ptr,@fore),backpointer=cptr(ubyte ptr,@back)
print fore,back
<more code not included>

The compiler does not like using ulong(s) with screencontrol ?? Is there more code or libraries I should use to make this work? Sometimes I will grab code on the forum just to see how things are done.

Thanks,
Darren
I'm using Windows 7 64bit


C:\Program Files\FreeBASIC-1.02.0-win64>fbc -version
FreeBASIC Compiler - Version 1.02.0 (04-05-2015), built for win64 (64bit)
Copyright (C) 2004-2015 The FreeBASIC development team.
standalone

C:\Program Files\FreeBASIC-1.02.0-win64>fbc -lang fb d:\FB_code\fore_back_colors.bas
d:\FB_code\fore_back_colors.bas(5) error 57: Type mismatch, at parameter 2 of SCREENCONTROL() in 'screencontrol 13,fore,
back'
MrSwiss
Posts: 3910
Joined: Jun 02, 2013 9:27
Location: Switzerland

Re: How to retrieve background color in 32 bits?

Post by MrSwiss »

A little example:

Code: Select all

#Ifdef __FB_64BIT__
	Dim As ULongInt	FG, BG
#Else
	Dim As ULong FG, BG
#EndIf	' UInteger behaviour: emulated ... idiotically needed

ScreenRes	400, 200, 32
Color(&hFFFFFFFF, &hFF000000)	' setter is clearly an ULong

ScreenControl 13, FG, BG		' getter has to be UInteger (vomiting!)
' were is the much beloved, discussed etc. consistency of FreeBASIC ???

Draw String (10, 10), "Retrieving COLORS (without FBGFX includes)", &hFF0080FF
Draw String (10, 26), "2015 by MrSwiss", &hFF0040FF
Draw String (10, 60), "Foreground Color: " & Hex(FG, 16)	' 4-8 Bytes ???
Draw String (10, 76), "Background Color: " & Hex(BG, 16)
Draw String (10,120), "Clear to see: half the used MEMORY is wasted!", &hFFFF0000
Draw String (10,136), "Reason: it will never be used anyway!", &hFFFFC000
Draw String (10,180), "Any user action QUIT's prog. ...", &hFFC0C0C0 

Sleep : End
Post Reply