Author Topic: Is there a reason why a color statement must be defined AFTER a screen statement  (Read 2875 times)

0 Members and 1 Guest are viewing this topic.

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
The following code has the color statement BEFORE the Screen statement and the boxes will not display. I would have thought if the color (or any variable) is declared and defined before hand, it should be readily available for application into any screen or subroutine. Why would the placement of the definition of the color be affected by the Screen statement? Any ideas?



DIM SHARED LightBrown&
DIM SHARED White&
DIM SHARED LightGreen&
DIM SHARED Red&


'SCREEN _NEWIMAGE(1800, 1000, 32)
'_FULLSCREEN
'CLS


White& = _RGB(255, 255, 255)
LightGreen& = _RGB(0, 255, 0)
LightBrown& = _RGB(172, 100, 61)
Red& = _RGB(255, 0, 0)

SCREEN _NEWIMAGE(1800, 1000, 32)
_FULLSCREEN
CLS


LINE (1, 1)-(1750, 975), White&, B
SLEEP
LINE (5, 5)-(1745, 970), LightGreen&, B
SLEEP
LINE (10, 10)-(1740, 965), LightBrown&, B
SLEEP
LINE (50, 15)-(1600, 800), Red&, B
SLEEP


FellippeHeitor

  • Guest
Use _RGB32 instead of _RGB and it will work as you expect it. The wiki shows the difference in behavior (click the keywords to jump there):

Code: QB64: [Select]

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Seems like I've repeated this a couple of dozen times over the last month, but I suppose I'll have to repeat it again here:

_RGB returns the closest possible color match to the values specified, for the current screen.

In a text screen (such as screen 0), we only have a palette of 16 colors to choose from and use.  When we specify _RGB(255, 0, 0), we get the closest possible match to pure red -- which is COLOR 4.

In fact, if you run the following, you'll see that *EVERY* value in the next loop will return the value of 4 -- the closest possible match to the red we specify, for a text screen:

FOR i = 86 to 255
    PRINT _RGB(i, 0, 0),
NEXT

There's only one red available, so it's the closest match possible -- COLOR 4.  If we specify a value less than 86, then _RGB will return a value of 0, as at that point it believes black is a closer match to your chosen color than red is.

************************

Now, when we do something like the following, what do we expect the value of red to be?

Red = _RGB(255, 0, 0)
SCREEN _NEWIMAGE(600, 400, 32)

Well, since the screen mode when Red was created wasn't set, it's the default text screen -- SCREEN 0.  Since screen 0 only has a single red value for it, when we call _RGB(255, 0, 0), it returns a match *FOR THAT SCREEN MODE* -- which is COLOR 4.

And what is the color 4 on a 32-bit screen?   It's 0 alpha, 0 red, 0 green, 4 blue.   It's certainly nothing like 255 alpha, 255 red, 0 green, 0 blue....   It's almost a completely transparent black.

Try the following:

SCREEN 0
SCREEN 13
Red = _RGB(255, 0, 0)
SCREEN 12
SCREEN 7
SCREEN _NEWIMAGE(640,480,32)

Now, what value do we expect Red to have?  Should it be the color value for a SCREEN 0 screen?  Screen 13?  Screen 7 or 12?  Or should it change to be a value fitting to work for the last screen called, the 32-bit screen??

It's the value of the closest match, for the current screen mode, when the function is called.  Since we were in screen 13 when we called RGB(255, 0, 0), the return value of the above is going to be 40 -- the closest possible match for the 256 color palette which screen 13 has.

If you *always* want 32-bit color values, *use* _RGB32 instead of _RGB.  _RGB returns the closest possible match, for the currently available color palette -- which depends on whatever the current screen specified is.
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
Thanks for going over this again - The part that doesn't seem to register with me, and catches me out a lot, is "returns a match for that screen mode". I can write Red&=_RBG(255,0,0) and the color Red is understood BEFORE the Screen Statement (meaning no error on the line detected) even though its the default Screen 0 (which should have only accepted the code as Color 4). Couple that with declaring and defining the color for all future use in subroutines so I do not have to write that same code again, I just always expect the color to be red.

Thanks Again for going over this Steve, I have read your other explanation on color (actually have a binder with a lot of the info you and the other members have provided) and yet I sometimes still don't fathom the depth of the info until I experience the issue in my own coding.

FillippeHector I will forever more use _RGB32

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
There is another way to set colors:
Code: QB64: [Select]
  1. _TITLE "Press any key for new color until end"  
  2. CONST xmax = 800, ymax = 600
  3.  
  4. ' CONST are automatically SHARED
  5. CONST White = &HFFFFFFFF '_RGB(255, 255, 255)
  6. CONST LightGreen = &HFF00FF00 '_RGB(0, 255, 0)
  7. CONST LightBrown = &HFFAC643D '_RGB(172, 100, 61)
  8. CONST Red = &HFFFF0000 '_RGB(255, 0, 0)
  9.  
  10. SCREEN _NEWIMAGE(xmax, ymax, 32)
  11. '_FULLSCREEN
  12. 'CLS
  13.  
  14.  
  15. LINE (1, 1)-(xmax - 5, ymax - 5), White, BF
  16. LINE (5, 5)-(xmax - 15, ymax - 15), LightGreen, BF
  17. LINE (10, 10)-(xmax - 25, ymax - 25), LightBrown, BF
  18. LINE (50, 50)-(xmax - 105, ymax - 105), Red, BF
  19. reuseColor
  20.  
  21. SUB reuseColor
  22.     CLS
  23.     LINE (1, 1)-(xmax - 5, ymax - 5), Red, BF
  24.     SLEEP
  25.     LINE (5, 5)-(xmax - 15, ymax - 15), LightBrown, BF
  26.     SLEEP
  27.     LINE (10, 10)-(xmax - 25, ymax - 25), LightGreen, BF
  28.     SLEEP
  29.     LINE (50, 50)-(xmax - 105, ymax - 105), White, BF
  30.  
  31.  
  32.  

EDIT: Sorry! I meant to use CONST not SHARED variables, because CONST's are SHARED and don't have to be Typed.
« Last Edit: May 19, 2019, 09:42:38 am by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Thanks for going over this again - The part that doesn't seem to register with me, and catches me out a lot, is "returns a match for that screen mode". I can write Red&=_RBG(255,0,0) and the color Red is understood BEFORE the Screen Statement (meaning no error on the line detected) even though its the default Screen 0 (which should have only accepted the code as Color 4). Couple that with declaring and defining the color for all future use in subroutines so I do not have to write that same code again, I just always expect the color to be red.

Thanks Again for going over this Steve, I have read your other explanation on color (actually have a binder with a lot of the info you and the other members have provided) and yet I sometimes still don't fathom the depth of the info until I experience the issue in my own coding.

FillippeHector I will forever more use _RGB32

There’s two main things to remember here:

1) Red& is a LONG variable.
2) _RGB is a function which returns a simple numeric value.

Let’s look at a very simple program:

DIM SHARED x
x = 3
SCREEN _NEWIMAGE(640, 480, 32)

What value is x before the SCREEN statement?   What value is x *after* that SCREEN statement?  Why would changing the screen mode affect the value of that variable at all?

Now, apply that same logic to _RGB:

DIM SHARED Red AS LONG
Red = _RGB(255, 0, 0)
SCREEN _NEWIMAGE(800, 600, 32)

Now, what value is Red *before the SCREEN statement*??

Since _RGB is dependent on a return value based on the current SCREEN mode, we first have to ask, “What *is* the screen mode when Red is called?”

Add a SLEEP statement to that little program and you can easily see the default screen mode:

DIM SHARED Red AS LONG
Red = _RGB(255, 0, 0)
SLEEP
SCREEN _NEWIMAGE(800, 600, 32)

Run the above and you’ll initially create a SCREEN 0 text screen — what QB64 defaults to, until you change it with a SCREEN statement...

So, when _RGB is called in the above snippet, it returns a value for the closest match for Red, for a SCREEN 0 text screen — COLOR 4. 

Red is 4 *before* the SCREEN statement.  It’s also 4 *after* that SCREEN statement.

The difference, and issue, is the number of colors one has to draw with. 

SCREEN 0 has 1 color for BLACK — COLOR 0.  A 32-bit screen has 256 transparent colors of black alone...  0 Red, 0 Blue, 0 Green is black — but we have 256 alpha colors for various shades of 0 Red, Green, Blue colors.

Think of it as having a set of crayons to color with.  In one box of 16 colors, we have 1 black crayon; in a larger box, we have 256 shades of black crayons.

If I tell you to color with the 4th crayon in each box, what color would you be using?  What’s the chance that both of those colors are the same?  Wouldn’t you naturally expect them to be different?

The same principle applies to our screen modes.

Red’s value is 4, as it’s set while still in the default SCREEN 0 text screen. 

For a text screen, COLOR 4 is used to represent red.
For a 32-bit color screen, COLOR 4 is one of those multiple transparent shades of black.

**********************

_RGB returns a numeric value based on the palette available for the screen mode when the function is called.  If you assign that value to a variable, and then change screen modes, that value doesn’t magically change on us — though what it represents now might be a completely different color.

If you want to use _RGB, you need to make certain that you’re in the desired screen mode when you use it, or else the numbers you use aren’t going to be the same.

If you need 32-bit color values, simply make a habit to always use RGB32 — it’s faster and always returns a 32-bit color value.

**And that’s why the program behaves different, depending on where the SCREEN statement is placed, in relation to the _RGB function calls.**
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
1) Red& is a LONG variable.


Correct me if I'm wrong, but the variable Red must always be an UNSIGNED LONG (~&), otherwise you'll get the wrong value: _RGB32(r,g,b) will give values in the range 0 - 4,294,967,295.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Correct me if I'm wrong, but the variable Red must always be an UNSIGNED LONG (~&), otherwise you'll get the wrong value: _RGB32(r,g,b) will give values in the range 0 - 4,294,967,295.

QB64 tends to overflow values instead of tossing errors for us, so in *most* cases, you can use either signed or unsigned variables and still operate properly with FUNCTIONS/SUBS.

Try this:

DIM x AS _BYTE
DIM ux AS _UNSIGNED _BYTE
ux = 255
x = ux
PRINT x

In this case, ux is 255, so what is x? 

It’s -128.

WHY?

Because in hex, *both* values are represented as FF.

**************

So how does this allow us to pass both signed and unsigned values to a FUNCTION and have it behave as intended?

SUB whatever (x AS _UNSIGNED _BYTE)

Let’s say the above is a SUB in my program, and I call it via the following line:

whatever -1

What value will x have inside the sub Whatever?  We passed it a value of -1, but x is defined as an unsigned byte, so what value does it become?

255.  (As we saw above, in reverse.)

***********************

So WHY can we use signed LONG values for *most* color functions?

Because of this overflow property.

White& = _RGB32(255, 255, 255)

What value does White become, in the above??

-1

But what happens when we use that -1 value to set COLOR??  Try it:

SCREEN _NEWIMAGE(640, 480, 32)
COLOR -1
PRINT “Hello World 2”

Run the above and you’ll see that the -1 overflowed to become bright white, since COLOR expects unsigned long values to be passed to it.

************************

In *most* cases, the difference in signed and unsigned doesn’t matter, when passing values to subs and functions.

“So when *does* it matter,” you ask?

When doing direct comparisons.

SCREEN _NEWIMAGE(640, 480, 32)
White& = -1
PSET (0, 0), White&
IF POINT(0, 0) = White& THEN
    PRINT “You’ll never see this.  It doesn’t.”
ELSE
    PRINT “I told you so.”
END IF

With the above, White is a LONG variable, so its value is -1 (as we assigned it).  The issue is POINT returns unsigned values to us, and -1 is *NOT* equal to 4325467898712 (Whatever the unsigned value actually is).

The only way to make the above work is to do one of two things:

1) Make White an unsigned long value, so it compares properly with our return function values.

OR

2) Never do direct comparisons, without assigning return function values to signed variables first, so they overflow properly as well.
P& = POINT(0, 0)
IF P& = White& THEN....

(The above would be true, since IF is comparing -1 to -1, for both variables.)

************************

So what do *I* recommend to do??

Always use unsigned variable types for color values.

So, why did I use a signed Long in my previous post??

Just because that’s what the original poster used in defining his variables.

Personally, I think all color variable types should be unsigned, to prevent issues like with the POINT comparisons, but one can work around those limitations if they choose to.  Since I was responding to someone’s question, I tried to answer using the same style as their original post — even if it’s not my preferred method.  😉
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline Qwerkey

  • Forum Resident
  • Posts: 755
    • View Profile
Steve, I agree with everything you've said.  I should have said "you should always use UNSIGNED" rather than "must".

Offline Dimster

  • Forum Resident
  • Posts: 500
    • View Profile
"Run the above and you’ll initially create a SCREEN 0 text screen — what QB64 defaults to, until you change it with a SCREEN statement...
So, when _RGB is called in the above snippet, it returns a value for the closest match for Red, for a SCREEN 0 text screen — COLOR 4. 
Red is 4 *before* the SCREEN statement.  It’s also 4 *after* that SCREEN statement."


Steve - you must have the patience of Jobe - so I do understand that Red& is a Long Variable and _RGB is a function. From your above quote, in SCREEN O text screen, if the statement Red& = _RGB(255,0,0) is used BEFORE the Screen statement, then the QB64 should recognize the assignment statement as meaning COLOR 4. (that being the closest match for screen 0). In fact, it does appear QB64 has no problem with that assignment statement as you get "OK" after moving off that line of code.
  But it appears that statement is not OK. That the assignment statement Red&=_RGB(255,0,0) is not interpreted as COLOR 4 in SCREEN 0

So,
"_RGB returns a numeric value based on the palette available for the screen mode when the function is called.  If you assign that value to a variable, and then change screen modes, that value doesn’t magically change on us — though what it represents now might be a completely different color.
If you want to use _RGB, you need to make certain that you’re in the desired screen mode when you use it, or else the numbers you use aren’t going to be the same."


are the words to live by. God I hope I got it.