Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

AGS 4: color properties have alpha component #2648

Merged

Conversation

ivan-mogilko
Copy link
Contributor

@ivan-mogilko ivan-mogilko commented Jan 10, 2025

The first step for #2525. The priority is to have alpha component stored in color properties, both in Editor and runtime, and fix a problem with some GUI parameters that were not able to get assigned a black color after #1980.

This does not yet guarantee that alpha will actually work (probably it won't). The idea is to make opaque colors work while having alpha component, and be able to assign transparent color (0).

Editor treats color numbers as ARGB, but forces opaque properties for now.

  1. Color properties formally support alpha component.
  2. When upgrading older projects, all 32-bit colors are ensured to be opaque (as alpha was not supported before).
  3. Property Grid technically allows ARGB property values, but forces them to opaque for now, until we actually make use of alpha value in the engine. Please note that Color picker cannot select "transparent" color yet, you have to type it manually.
  4. The one important exception is transparent color: it can be set and is displayed as "0" for simplicity.
  5. ColorUIEditor draws "transparent" color as a classic checkered rectangle.
  6. Color properties are now serialized as a hex number, for easier reading.

Engine:

  1. Color properties and parameters formally support alpha component, but I suspect that either won't work or produce strange effects if you try to use it now.
  2. Game.GetColorFromRGB() ensures that returned color is opaque.
    3. Had to refactor the dreadful asspch parameter in display_main, which combined text color with extra meaning, which is impossible to do when color value occupies all 32-bits. Introduced DisplayTextFlags for passing extra options. This part should be backported to 3.6 branch, I think. this is done by Engine: refactor passing text_color into display_main() #2649 and ported among active branches.

In Script:

  1. COLOR_TRANSPARENT constant is redefined as 0, because -1 translates to "opaque white" ARGB.

I raised format version numbers, but only ensured that project upgrade works at the moment. If it's necessary, a backwards compatible fixes could be done in the engine too, the raised versions leave such backup opportunity in case someone finds that necessary.

@ivan-mogilko ivan-mogilko added this to the 4.0.0 (preliminary) milestone Jan 10, 2025
@ivan-mogilko ivan-mogilko force-pushed the ags4--argbcolorparameters branch from bbe3790 to a71a1d0 Compare January 11, 2025 22:07
1. Color properties formally support alpha component.
2. When upgrading older projects, all 32-bit colors are ensured to be opaque (as alpha was not supported before).
3. Property Grid technically allows ARGB property values, but forces them to opaque for now, until we actually make use of alpha value in the engine.
4. The one important exception is transparent color: it can be set and is displayed as "0" for simplicity.
5. ColorUIEditor draws "transparent" color as a classic checkered rectangle.
Necessary, because -1 would translate as a valid color with alpha.
1. Color properties and parameters formally support alpha component.
2. GUI::GetStandardColor() ensures that returned color is opaque.
3. Game.GetColorFromRGB() ensures that returned color is opaque.
@ivan-mogilko ivan-mogilko force-pushed the ags4--argbcolorparameters branch from a71a1d0 to 603aef4 Compare January 11, 2025 22:19
@ivan-mogilko
Copy link
Contributor Author

Rebased after #2649 and porting changes to ags4.

Also, made ColorUIEditor display transparent color selection with checkered rectangle.

@ivan-mogilko
Copy link
Contributor Author

The GH actions will fail, because of the test game failing (would need to correct color constants again).

@ericoporto
Copy link
Member

Hey, how do I get transparent GUI background color now?

image

The upgrade didn't got any of my GUIs - in case it was supposed to.

@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Jan 12, 2025

Hey, how do I get transparent GUI background color now?

The only way is to set 0 directly into the property. Standard color picker does not have such option.

The upgrade didn't got any of my GUIs - in case it was supposed to.

I'm conflicted about how to upgrade from the previous 4.0, because the previous 32-bit implementation did not let distinguish 0 as transparent and 0x000000 as black. If I make it transparent, then all the controls with black text color will have transparent text color, for example. That's why I thought that it will be less annoying to port it as black, and let users changes to transparent background where they need to.

EDIT: maybe I could treat 0 only in background colors as transparent when upgrading.

@ericoporto
Copy link
Member

ericoporto commented Jan 12, 2025

that would make sense, since they are transparent in background colors. I don't know how hard that would be, but I use the background transparent a lot,.

Edit: actually border color 0 used to be transparent too.

I also think that the color number thing in the Editor colour finder could have a way to copy it as hex (since ags now accepts 0x notation too).

I made this script stealing from the color mapper in the editor code

// new module script

int RGBScale5[32];
int RGBScale6[64];
        
void game_start()
{
  RGBScale5[0] = 0;
  RGBScale5[1] = 8;
  RGBScale5[2] = 16;
  RGBScale5[3] = 24;
  RGBScale5[4] = 33;
  RGBScale5[5] = 41;
  RGBScale5[6] = 49;
  RGBScale5[7] = 57;
  RGBScale5[8] = 66;
  RGBScale5[9] = 74;
  RGBScale5[10] = 82;
  RGBScale5[11] = 90;
  RGBScale5[12] = 99;
  RGBScale5[13] = 107;
  RGBScale5[14] = 115;
  RGBScale5[15] = 123;
  RGBScale5[16] = 132;
  RGBScale5[17] = 140;
  RGBScale5[18] = 148;
  RGBScale5[19] = 156;
  RGBScale5[20] = 165;
  RGBScale5[21] = 173;
  RGBScale5[22] = 181;
  RGBScale5[23] = 189;
  RGBScale5[24] = 198;
  RGBScale5[25] = 206;
  RGBScale5[26] = 214;
  RGBScale5[27] = 222;
  RGBScale5[28] = 231;
  RGBScale5[29] = 239;
  RGBScale5[30] = 247;
  RGBScale5[31] = 255;

  for (int i = 0; i < 64; i++) {
    if (i < 16) {
      RGBScale6[i] = i * 4;
    } else {
      RGBScale6[i] = i * 3;
    }
  }
}

int RemapFromLegacyColourNumber(int legacyColourNumber)
{
  // Special color number 0 is treated as fully transparent
  if (legacyColourNumber == 0)
      return 0;
  // Special color numbers 1-31 were always interpreted as palette indexes;
  // for them we compose a 32-bit ARGB from the palette entry
  if ((legacyColourNumber > 0) && (legacyColourNumber < 32))
  {
    int r = palette[legacyColourNumber].r;
    int g = palette[legacyColourNumber].g;
    int b = palette[legacyColourNumber].b;
    return b | (g << 8) | (r << 16) | (0xFF000000); // always opaque
  }

  // The rest is a R5G6B5 color; we convert it to a proper 32-bit ARGB;
  // color is always opaque when ported from legacy projects
  int red = RGBScale5[(legacyColourNumber >> 11) & 0x1f];
  int green = RGBScale6[(legacyColourNumber >> 5) & 0x3f];
  int blue = RGBScale5[(legacyColourNumber) & 0x1f];
  return blue | (green << 8) | (red << 16) | (0xFF000000);
}

I didn't remade the colors in script and just called this function everywhere and then I got it all working the same as before!

I still had to manually fix ever ysingle gui background and bordercolor.

This is required because color 0 had different purpose in 32-bit games: it meant transparent in background color properties, and opaque black in foreground color properties.
This is not perfect, but close to what users might want when upgrading a game.
@ivan-mogilko ivan-mogilko force-pushed the ags4--argbcolorparameters branch from 6850309 to e7696e1 Compare January 12, 2025 16:10
@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Jan 12, 2025

Adjusted the upgrade process. Now it treats color 0 in background and foreground colors separately: back color 0 becomes transparent, fore color 0 becomes opaque black.
GUI.BorderColor is treated as "background" for normal GUI and "foreground" for TextWindow gui, because it means "text color" there (i'm not 100% certain about it, but this may be fixed easily if found wrong).

When upgrading games made before 4.0 Alpha 13 (3.6.* and early 4.0) all the colors seem to upgrade properly.
In games made after Alpha 13 the only problem is that GUI with fully black background will turn transparent. But there's no real way to work around that.

@ericoporto
Copy link
Member

ericoporto commented Jan 12, 2025

I tested this, and the upgrade process works fine!

Now, the only thing I found that is weird, is in my game using surface.Clear() causes the surface to be orange. I fixed this by remaking all of these with surface.Clear(0), and now they properly clear the surfaces. Edit: I think the issue is simply the default value of clear is not COLOR_TRANSPARENT but is instead SCR_NO_VALUE for whatever reason (maybe something 8-bit related? Don't know)

I can't find anything else so far that is not working as I expected.

@ivan-mogilko
Copy link
Contributor Author

Now, the only thing I found that is weird, is in my game using surface.Clear() causes the surface to be orange.

Ugh. This is because it has a uncommon default value:
import void Clear(int colour=-SCR_NO_VALUE);

where SCR_NO_VALUE is an arbitrary number
#define SCR_NO_VALUE 31998

@ericoporto
Copy link
Member

Well, that is great, all looks fine now. I think we could use color transparent in the API even in master branch, or at least I don't see any reason right away why that wouldn't work - although we still need to keep the check for no value macro there in the actual clear implementation for backwards compatibility in that case.

@ivan-mogilko ivan-mogilko force-pushed the ags4--argbcolorparameters branch from 0381643 to d8b1d77 Compare January 12, 2025 17:55
@ivan-mogilko
Copy link
Contributor Author

ivan-mogilko commented Jan 12, 2025

Added [SerializeAsHex] attribute to Color properties, for easier reading colors inside Game.agf (easier for a human at least).

Reading back is done in two steps (first try hex, if failed then try decimal), for backwards compatibility.

@ericoporto

This comment was marked as off-topic.

@ericoporto
Copy link
Member

ericoporto commented Jan 12, 2025

@ivan-mogilko can you test if the SpeechColor from a character in an ags4 game of your upgrades correctly?

In the Sierra Template - I opened it from ags-templates-source - the player speech color was 12 (a reddish color) and now is 83; 102; 96 (a dark green-gray color).

The diff of colors looks like a previous int is now interpreted as hex

image

I think we need to manually add a prefix to the hex colors and later manually identify the prefix and then use the appropriate TryParse depending if it has an hex prefix or no prefix at all, otherwise previously int values are now interpreted as hex.

Like

if (prop.GetCustomAttribute(typeof(SerializeAsHex), true) != null)
    writer.WriteElementString(prop.Name, "0x" + ((int)prop.GetValue(obj, null)).ToString("X8"));

and

if (prop.GetCustomAttribute(typeof(SerializeAsHex), true) != null)
{
    int value;
    bool isHex = elementValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase);
    if (isHex && int.TryParse(elementValue.Substring(2), NumberStyles.HexNumber, null, out value))
    {
        prop.SetValue(obj, value, null);
        continue;
    }
}

@ivan-mogilko ivan-mogilko force-pushed the ags4--argbcolorparameters branch from d8b1d77 to 3cc809b Compare January 12, 2025 19:32
@ivan-mogilko
Copy link
Contributor Author

Right, I did not realize that.

Apparently Convert.ToInt32 also handles 0x prefix, so I use that instead of TryParse.

This is purely for easier reading of the Game.agf.
@ivan-mogilko ivan-mogilko force-pushed the ags4--argbcolorparameters branch from 3cc809b to 031c4f4 Compare January 12, 2025 19:34
@ericoporto
Copy link
Member

ok, I tested this again, and now it is correctly loading both upgrading previous ags4 projects and loading the ones that are already upgraded by this, properly picking up the hex value of colors and pretty much all that I could think of!

@ivan-mogilko
Copy link
Contributor Author

Alright, I will merge this then.

@ivan-mogilko ivan-mogilko merged commit fc5359d into adventuregamestudio:ags4 Jan 13, 2025
17 of 21 checks passed
@ivan-mogilko ivan-mogilko deleted the ags4--argbcolorparameters branch January 13, 2025 19:45
@ericoporto
Copy link
Member

@AlanDrake just in case the bit shifts you are playing with are color related, I put a code hidden by details tag in the comment #2648 (comment) that may be useful to you.

@ivan-mogilko
Copy link
Contributor Author

@AlanDrake could you tell, were you able to upgrade your game after this update?

I'm asking because I have not seen any user feedback on this yet on forums.

@AlanDrake
Copy link
Contributor

@ivan-mogilko Yes. I only had to update the scripts, while GUIs were good to go.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants