Acknowledged

Creating Full White Color Results in Transparent

We might expect this code to draw a filled white circle:

var testWhite = Graphics.createColor(0xFF, 0xFF, 0xFF, 0xFF);
dc.setFill(testWhite);
dc.fillCircle(halfScreenWidth, halfScreenHeight, 10);

However, what actually happens is nothing is drawn. This is because Graphics.createColor translates the color to 0xFFFFFFFF, which is -1 in twos complement, and which is the same as Graphics.COLOR_TRANSPARENT. Changing e.g. the alpha value to 0xFE instead of 0xFF will cause the circle to draw as expected.

  • > Changing e.g. the alpha value to 0xFE instead of 0xFF will cause the circle to draw as expected.

    Instead of changing the alpha value to 0xFE [which is is theoretically slightly less than "full white"], I think it would be more "correct" to use 0xFFFFFF / COLOR_WHITE instead [see below]

    > I do wish that Monkey C had an 32-bit unsigned int type for this to avoid these quirks...

    That wouldn't help as -1 [COLOR_TRANSPARENT] can't be directly represented as a 32-bit unsigned value, so I can think of a couple of ways Monkey C could handle trying to convert -1 to an unsigned 32-bit value:

    - Trying to convert -1 to an unsigned 32-bit value results in some sort of out of range exception/error [this would be bad of course]

    - Trying to convert -1 to an unsigned 32-bit value works just like a C-style cast from int32_t to uint32_t: the compiler takes the signed 32-bit representation of -1 [0xFFFFFFFF] and reinterprets the same bit pattern as an unsigned 32-bit value, which gives us...0xFFFFFFFF [so we're exactly back where we started]

    What would kind of work would be my suggestion to use Long [signed 64-bit int] except that alone wouldn't solve the other problem where setting an alpha channel of 0 would actually give you a solid colour. [Except they'd never change anything about ColorType now - it's too late]

    I'm also not sure if the checkColor[] function that's provided is a good idea as written, because because if you pass in colour constants such as Graphics.COLOR_WHITE, Graphics.COLOR_BLUE, etc, they're all changed to black [they're all in RGB format with the most significant byte set to 0]. For example COLOR_WHITE is 0xFFFFFF and COLOR_ORANGE is 0xFF5500. All of the colour constants [and user-specified colours with no alpha channel] will be less than 0x01000000, which will be changed to 0 [black] by that function.

    Again the problem is that Monkey C uses *either* ARGB or RGB format, which means a colour with an alpha channel of 0, which should be completely transparent, is indistinguishable from an opaque colour with no alpha channel.

    Instead I would create a wrapper function for dc.createColor() which unambiguously requires the alpha channel to be specified [just as dc.createColor itself]:

  • I stumbled upon this today. It's not great, but I "solved" it by adding a few if statements whenever I set a color that check if it's pure white an return a color that's barely not pure white or if it' actually a transparent color and return 0. I encapsulated it in a utility function:

    function checkColor(color as ColorType) as ColorType {
        if (color == 0xFFFFFFFF) {
            return 0xFFFFFFFE;
        }
        if (color < 0x01000000) {
            return 0x00000000;
        }
        return color;
    }

    I just wrap all my calls to setFill and setStroke with this:

    dc.setFill(Util.checkColor(fillColor))
    dc.setStroke(Util.checkColor(strokeColor))

    Not ideal, but seems to work as desired. I do wish that Monkey C had an 32-bit unsigned int type for this to avoid these quirks...

  • Probably the easiest comprehensive solution that doesn't require changing any types would be:

    - Graphics.createColor(0xFF, 0xFF, 0xFF, 0xFF) should return 0xFFFFFF. This gets around the bug where createColor() returns COLOR_TRANSPARENT for solid white (alpha = 0xff)

    - Graphics.createColor(0, ...) should return -1 / COLOR_TRANSPARENT. This gets around the bug where createColor() returns an opaque color when the alpha channel is 0.

  • Or if we could change ColorType to Long (which still probably wouldn't happen), one of the extra bits could be used to indicate the color format (RGB or ARGB). One problem with this approach is that it would be confusing for developers when reading and writing raw numerical / hex values for colors.

  • (I guess the perfect solution would be for Garmin to go back in time and retroactively use RGBA or ARGB internally for all colors. If only.)