From ca829d8e39817a824e1246f8ca61a94365271c3a Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 10 Jan 2025 19:33:38 +0300 Subject: [PATCH 1/9] Editor: treat AGSColor numbers as ARGB, but force opaque props 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. 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. --- Editor/AGS.Editor/AGSEditor.cs | 3 +- Editor/AGS.Editor/Tasks.cs | 10 ++++ Editor/AGS.Editor/Utils/ColorMapper.cs | 55 +++++++++++++------ Editor/AGS.Types/GUIListBox.cs | 5 +- .../PropertyGridExtras/ColorUIEditor.cs | 21 ++++++- .../CustomColorConverter.cs | 17 ++++-- 6 files changed, 82 insertions(+), 29 deletions(-) diff --git a/Editor/AGS.Editor/AGSEditor.cs b/Editor/AGS.Editor/AGSEditor.cs index 2293d148c30..f0a84932d1f 100644 --- a/Editor/AGS.Editor/AGSEditor.cs +++ b/Editor/AGS.Editor/AGSEditor.cs @@ -128,9 +128,10 @@ public class AGSEditor : IAGSEditorDirectories * Settings.ScriptCompiler as a selection of script compiler IDs, * ExtendedCompiler is deprecated. * 4.00.00.12 - ViewFrame.Flip has full flip selection. + * 4.00.00.14 - Obligatory alpha component in 32-bit color. * */ - public const int LATEST_XML_VERSION_INDEX = 4000012; + public const int LATEST_XML_VERSION_INDEX = 4000014; /// /// XML version index on the release of AGS 4.0.0, this constant be used to determine /// if upgrade of Rooms/Sprites/etc. to new format have been performed. diff --git a/Editor/AGS.Editor/Tasks.cs b/Editor/AGS.Editor/Tasks.cs index 29a6cd8017c..2b98c27ff43 100644 --- a/Editor/AGS.Editor/Tasks.cs +++ b/Editor/AGS.Editor/Tasks.cs @@ -553,6 +553,10 @@ private void SetDefaultValuesForNewFeatures(Game game) { RemapLegacyColourProperties(game); } + else if (xmlVersionIndex < 4000014) + { + RemapOpaqueColourProperties(game); + } // Update ScriptCompiler selection if (xmlVersionIndex < 3999900) @@ -666,6 +670,12 @@ private static void RemapLegacyColourProperties(Game game) RemapColourProperties(game, remapColor); } + private static void RemapOpaqueColourProperties(Game game) + { + Func remapColor = (color) => { return ColorMapper.MakeOpaque(color, game.Settings.ColorDepth); }; + RemapColourProperties(game, remapColor); + } + /// /// Remaps all color properties in game using provided delegate. /// diff --git a/Editor/AGS.Editor/Utils/ColorMapper.cs b/Editor/AGS.Editor/Utils/ColorMapper.cs index d0f04908641..da38cb618c5 100644 --- a/Editor/AGS.Editor/Utils/ColorMapper.cs +++ b/Editor/AGS.Editor/Utils/ColorMapper.cs @@ -22,9 +22,9 @@ public int MapRgbColorToAgsColourNumber(Color rgbColor) // For 8-bit games find the nearest matching palette index if (_editor.CurrentGame.Settings.ColorDepth == GameColorDepth.Palette) { - return FindNearestColourInGamePalette(rgbColor); + return FindNearestColourInGamePalette(rgbColor, _editor.CurrentGame.Palette); } - // Otherwise compose a 32-bit xRGB + // Otherwise compose a 32-bit ARGB return ColorToAgsColourNumberDirect(rgbColor); } @@ -36,11 +36,11 @@ public Color MapAgsColourNumberToRgbColor(int agsColorNumber) if (agsColorNumber >= _editor.CurrentGame.Palette.Length) { // don't attempt to map invalid 8-bit colour numbers >255 - return Color.Black; + return Color.FromArgb(0); } return _editor.CurrentGame.Palette[agsColorNumber].Colour; } - // Otherwise treat number as a 32-bit xRGB + // Otherwise treat number as a 32-bit ARGB return AgsColourNumberToColorDirect(agsColorNumber); } @@ -51,7 +51,7 @@ public Color MapAgsColourNumberToRgbColor(int agsColorNumber) /// public static int ColorToAgsColourNumberDirect(Color color) { - return color.B | (color.G << 8) | (color.R << 16); + return color.B | (color.G << 8) | (color.R << 16) | (color.A << 24); } /// @@ -60,18 +60,23 @@ public static int ColorToAgsColourNumberDirect(Color color) public static Color AgsColourNumberToColorDirect(int agsColorNumber) { return Color.FromArgb( + (agsColorNumber >> 24) & 0xff, (agsColorNumber >> 16) & 0xff, (agsColorNumber >> 8) & 0xff, agsColorNumber & 0xff); } - private int FindNearestColourInGamePalette(Color rgbColor) - { - return FindNearestColourInGamePalette(rgbColor, _editor.CurrentGame.Palette); - } - + /// + /// Finds a palette index which color is closest to the given RGB. + /// Any non-zero alpha value is ignored; any color with zero alpha is treated as the + /// same "transparent color" palette entry + /// public static int FindNearestColourInGamePalette(Color rgbColor, PaletteEntry[] palette) { + // Special case: ARGB colors with zero alpha are converted to transparent entry 0 + if (rgbColor.A == 0) + return 0; + int nearestDistance = int.MaxValue; int nearestIndex = 0; @@ -162,19 +167,37 @@ public static int RemapFromLegacyColourNumber(int legacyColourNumber, PaletteEnt return legacyColourNumber; } - // Special 0-31 color numbers were always interpreted as palette indexes; - // for them we compose a 32-bit xRGB from the palette entry - if ((legacyColourNumber >= 0) && (legacyColourNumber < 32)) + // 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)) { var rgbColor = palette[legacyColourNumber].Colour; - return rgbColor.B | (rgbColor.G << 8) | (rgbColor.R << 16); + return rgbColor.B | (rgbColor.G << 8) | (rgbColor.R << 16) | (0xFF << 24); // always opaque } - // The rest is a R5G6B5 color; we convert it to a proper 32-bit xRGB + // The rest is a R5G6B5 color; we convert it to a proper 32-bit ARGB; + // color is always opaque when ported from legacy projects byte red = RGBScale5[(legacyColourNumber >> 11) & 0x1f]; byte green = RGBScale6[(legacyColourNumber >> 5) & 0x3f]; byte blue = RGBScale5[(legacyColourNumber) & 0x1f]; - return blue | (green << 8) | (red << 16); + return blue | (green << 8) | (red << 16) | (0xFF << 24); + } + + /// + /// Makes a opaque colour number value from a number which presumably may not have an alpha component. + /// + public static int MakeOpaque(int colorNumber, GameColorDepth gameColorDepth) + { + // For 8-bit games simply treat the color number as a palette index + if (gameColorDepth == GameColorDepth.Palette) + { + return colorNumber; + } + + return colorNumber | (0xFF << 24); } } } diff --git a/Editor/AGS.Types/GUIListBox.cs b/Editor/AGS.Types/GUIListBox.cs index 21fb38679ff..2a6d271e1a6 100644 --- a/Editor/AGS.Types/GUIListBox.cs +++ b/Editor/AGS.Types/GUIListBox.cs @@ -22,10 +22,7 @@ public GUIListBox(int x, int y, int width, int height) _showScrollArrows = true; _textColor = 0; _selectedTextColor = 7; - // FIXME: selected bg color was 16, but had to change to 17 as a temp hotfix, - // because 16 is pure black (ags color property = 0), and ListBox refuses to - // paint selection if property eq 0. - _selectedBackgroundColor = 17; + _selectedBackgroundColor = 16; _textAlignment = HorizontalAlignment.Left; } diff --git a/Editor/AGS.Types/PropertyGridExtras/ColorUIEditor.cs b/Editor/AGS.Types/PropertyGridExtras/ColorUIEditor.cs index 6f133adc361..2f5f534d4c6 100644 --- a/Editor/AGS.Types/PropertyGridExtras/ColorUIEditor.cs +++ b/Editor/AGS.Types/PropertyGridExtras/ColorUIEditor.cs @@ -59,9 +59,26 @@ public override bool GetPaintValueSupported(ITypeDescriptorContext context) public override void PaintValue(PaintValueEventArgs e) { Color color = ColorFromPropertyValue(e.Context, e.Value); - using (SolidBrush brush = new SolidBrush(color)) + if (color.A > 0) { - e.Graphics.FillRectangle(brush, e.Bounds); + // Fixup alpha value for display + // TODO: possibly paint using alpha component when we actually support it here + color = Color.FromArgb(0xFF, color.R, color.G, color.B); + using (SolidBrush brush = new SolidBrush(color)) + { + e.Graphics.FillRectangle(brush, e.Bounds); + } + } + else + { + using (SolidBrush brush1 = new SolidBrush(Color.White)) + using (SolidBrush brush2 = new SolidBrush(Color.DarkGray)) + { + e.Graphics.FillRectangle(brush1, e.Bounds.Left, e.Bounds.Top, e.Bounds.Width / 2, e.Bounds.Height / 2); + e.Graphics.FillRectangle(brush1, e.Bounds.Left + e.Bounds.Width / 2, e.Bounds.Top + e.Bounds.Height / 2, e.Bounds.Width / 2, e.Bounds.Height / 2); + e.Graphics.FillRectangle(brush2, e.Bounds.Left + e.Bounds.Width / 2, e.Bounds.Top, e.Bounds.Width / 2, e.Bounds.Height / 2); + e.Graphics.FillRectangle(brush2, e.Bounds.Left, e.Bounds.Top + e.Bounds.Height / 2, e.Bounds.Width / 2, e.Bounds.Height / 2); + } } } } diff --git a/Editor/AGS.Types/PropertyGridExtras/CustomColorConverter.cs b/Editor/AGS.Types/PropertyGridExtras/CustomColorConverter.cs index d503d36205d..825cad0a328 100644 --- a/Editor/AGS.Types/PropertyGridExtras/CustomColorConverter.cs +++ b/Editor/AGS.Types/PropertyGridExtras/CustomColorConverter.cs @@ -70,16 +70,21 @@ public override object ConvertFrom(ITypeDescriptorContext context, System.Global private Color ColorFromString(string value) { var rgb = value.Split(';'); - if (rgb.Length == 3) - return Color.FromArgb(int.Parse(rgb[0]), int.Parse(rgb[1]), int.Parse(rgb[2])); - else if (rgb.Length == 4) - return Color.FromArgb(int.Parse(rgb[0]), int.Parse(rgb[1]), int.Parse(rgb[2]), int.Parse(rgb[3])); - return Color.Black; // or throw? + switch (rgb.Length) + { + case 3: return Color.FromArgb(int.Parse(rgb[0]), int.Parse(rgb[1]), int.Parse(rgb[2])); + // TODO: parse rgb[0] as alpha when we actually support alpha here + case 4: return Color.FromArgb(0xFF, int.Parse(rgb[1]), int.Parse(rgb[2]), int.Parse(rgb[3])); + default: return Color.FromArgb(0); // return transparent color on failure + } } private string ColorToString(Color color) { - return string.Format($"{color.R}; {color.G}; {color.B}"); + // We make transparent color a special case, for user's convenience + return color.A == 0 ? "0" : + // TODO: add alpha component when we actually support alpha here + string.Format($"{color.R}; {color.G}; {color.B}"); } private int AgsColorNumberFromString(string value) From d52f4e27c4f531227c42bfb4509cdee05d548857 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 10 Jan 2025 20:27:52 +0300 Subject: [PATCH 2/9] Script API: redefine COLOR_TRANSPARENT as 0 Necessary, because -1 would translate as a valid color with alpha. --- Common/ac/gamesetupstructbase.cpp | 1 + Common/ac/gamestructdefines.h | 3 ++- Editor/AGS.Editor/Resources/agsdefns.sh | 8 ++++---- Editor/AGS.Types/Enums/ScriptAPIVersion.cs | 2 ++ Engine/ac/runtime_defines.h | 2 +- 5 files changed, 10 insertions(+), 6 deletions(-) diff --git a/Common/ac/gamesetupstructbase.cpp b/Common/ac/gamesetupstructbase.cpp index 9aa5313ad55..b4bf54b947c 100644 --- a/Common/ac/gamesetupstructbase.cpp +++ b/Common/ac/gamesetupstructbase.cpp @@ -144,6 +144,7 @@ const char *GetScriptAPIName(ScriptAPIVersion v) case kScriptAPI_v399: return "3.99.x"; case kScriptAPI_v400: return "4.0.0-alpha8"; case kScriptAPI_v400_07: return "4.0.0-alpha12"; + case kScriptAPI_v400_14: return "4.0.0-alpha18"; default: return "unknown"; } } diff --git a/Common/ac/gamestructdefines.h b/Common/ac/gamestructdefines.h index d18df1b86c1..a644da0c5f7 100644 --- a/Common/ac/gamestructdefines.h +++ b/Common/ac/gamestructdefines.h @@ -179,7 +179,8 @@ enum ScriptAPIVersion kScriptAPI_v399 = 3990000, kScriptAPI_v400 = 4000003, kScriptAPI_v400_07 = 4000007, - kScriptAPI_Current = kScriptAPI_v400_07 + kScriptAPI_v400_14 = 4000014, + kScriptAPI_Current = kScriptAPI_v400_14 }; const char *GetScriptAPIName(ScriptAPIVersion v); diff --git a/Editor/AGS.Editor/Resources/agsdefns.sh b/Editor/AGS.Editor/Resources/agsdefns.sh index 8484d7aa7af..e7c2677622b 100644 --- a/Editor/AGS.Editor/Resources/agsdefns.sh +++ b/Editor/AGS.Editor/Resources/agsdefns.sh @@ -88,14 +88,14 @@ #define OPT_SAVECOMPONENTSIGNORE 55 #define OPT_LIPSYNCTEXT 99 -#define COLOR_TRANSPARENT -1 -#define DIALOG_PARSER_SELECTED -3053 +#define COLOR_TRANSPARENT 0 +#define SCR_NO_VALUE 31998 // $AUTOCOMPLETEIGNORE$ + +#define DIALOG_PARSER_SELECTED -3053 #define RUN_DIALOG_RETURN -1 #define RUN_DIALOG_STOP_DIALOG -2 #define RUN_DIALOG_GOTO_PREVIOUS -4 -#define SCR_NO_VALUE 31998 // $AUTOCOMPLETEIGNORE$ - #ifdef SCRIPT_API_v399 #define AXIS_DEFAULT_DEADZONE 0.125 #endif // SCRIPT_API_v399 diff --git a/Editor/AGS.Types/Enums/ScriptAPIVersion.cs b/Editor/AGS.Types/Enums/ScriptAPIVersion.cs index 28a046f4ae8..f7e7125db12 100644 --- a/Editor/AGS.Types/Enums/ScriptAPIVersion.cs +++ b/Editor/AGS.Types/Enums/ScriptAPIVersion.cs @@ -47,6 +47,8 @@ public enum ScriptAPIVersion v400 = 4000003, [Description("4.0.0 Alpha 12")] v400_07 = 4000007, + [Description("4.0.0 Alpha 18")] + v400_14 = 4000014, // Highest constant is used for automatic upgrade to new API when // the game is loaded in the newer version of the Editor [Description("Latest version")] diff --git a/Engine/ac/runtime_defines.h b/Engine/ac/runtime_defines.h index c8534d245f4..bf4fbfa65b3 100644 --- a/Engine/ac/runtime_defines.h +++ b/Engine/ac/runtime_defines.h @@ -46,7 +46,7 @@ #define KEEP_MOVING 0 #define SCR_NO_VALUE 31998 -#define SCR_COLOR_TRANSPARENT -1 +#define SCR_COLOR_TRANSPARENT 0 #define FONT_STATUSBAR 0 #define FONT_NORMAL play.normal_font From b14ca7b302af530a01160c12e1e417dce111479f Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 10 Jan 2025 20:28:20 +0300 Subject: [PATCH 3/9] Engine: treat color numbers as ARGB 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. --- Common/ac/game_version.h | 7 ++++++- Common/game/main_game_file.cpp | 14 +++++++++----- Common/gfx/allegrobitmap.cpp | 11 ++--------- Common/gui/guimain.cpp | 2 +- Common/gui/guimain.h | 2 ++ Engine/ac/drawingsurface.cpp | 2 +- Engine/ac/game.cpp | 2 +- 7 files changed, 22 insertions(+), 18 deletions(-) diff --git a/Common/ac/game_version.h b/Common/ac/game_version.h index 4e35dee3033..2bd866fae7f 100644 --- a/Common/ac/game_version.h +++ b/Common/ac/game_version.h @@ -137,6 +137,10 @@ Palette component range changed from 64 to 256 Font file names 4.0.0.11: Incremented version, marking sync with 3.6.2.3 +4.0.0.13: +Room names are always serialized, not just in Debug config (had to adjust format) +4.0.0.14: +Obligatory alpha component in 32-bit color. SCR_COLOR_TRANSPARENT is redefined as 0. */ enum GameDataVersion @@ -155,8 +159,9 @@ enum GameDataVersion kGameVersion_400_10 = 4000010, kGameVersion_400_11 = 4000011, kGameVersion_400_13 = 4000013, + kGameVersion_400_14 = 4000014, kGameVersion_LowSupported = kGameVersion_360_21, - kGameVersion_Current = kGameVersion_400_13 + kGameVersion_Current = kGameVersion_400_14 }; // Data format version of the loaded game diff --git a/Common/game/main_game_file.cpp b/Common/game/main_game_file.cpp index 355d6d4c4c0..7bcc5232f44 100644 --- a/Common/game/main_game_file.cpp +++ b/Common/game/main_game_file.cpp @@ -324,19 +324,23 @@ static int RemapFromLegacyColourNumber(const GameSetupStruct &game, int color) if (game.color_depth == 1) return color; // keep palette index - // Special 0-31 color numbers were always interpreted as palette indexes; - // for them we compose a 32-bit xRGB from the palette entry + // Special color number 0 is treated as fully transparent + if (color == 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 (color >= 0 && color < 32) { const RGB &rgb = game.defpal[color]; - return rgb.b | (rgb.g << 8) | (rgb.r << 16); + return rgb.b | (rgb.g << 8) | (rgb.r << 16) | (0xFF << 24); } - // The rest is a R5G6B5 color; we convert it to a proper 32-bit xRGB + // The rest is a R5G6B5 color; we convert it to a proper 32-bit ARGB; + // color is always opaque when ported from legacy projects uint8_t red = RGBScale5[(color >> 11) & 0x1f]; uint8_t green = RGBScale6[(color >> 5) & 0x3f]; uint8_t blue = RGBScale5[(color) & 0x1f]; - return blue | (green << 8) | (red << 16); + return blue | (green << 8) | (red << 16) | (0xFF << 24); } void UpgradeGame(GameSetupStruct &game, GameDataVersion data_ver) diff --git a/Common/gfx/allegrobitmap.cpp b/Common/gfx/allegrobitmap.cpp index 550420e0ec3..b0e809c0186 100644 --- a/Common/gfx/allegrobitmap.cpp +++ b/Common/gfx/allegrobitmap.cpp @@ -540,18 +540,11 @@ void Bitmap::SetScanLine(int index, unsigned char *data, int data_size) namespace BitmapHelper { -int AGSColorToBitmapColor(int color, int color_depth) +int AGSColorToBitmapColor(int color, int /*color_depth*/) { // no conversion necessary, we assume that "ags color" is matching // palette index in 8-bit mode and 32-bit A8R8G8B8 in 32-bit mode - if (color_depth == 8) - { - return color; - } - else - { - return color | 0xFF000000; // temporary fix for missing alpha in color values - } + return color; } void AGSColorToRGB(int color, int color_depth, RGB &rgb) diff --git a/Common/gui/guimain.cpp b/Common/gui/guimain.cpp index 7816c051508..f39e8327e27 100644 --- a/Common/gui/guimain.cpp +++ b/Common/gui/guimain.cpp @@ -825,7 +825,7 @@ int GetStandardColor(int index) index = 0; if (Context.GameColorDepth == 8) return index; - return GuiContext::StandardColors[index]; + return GuiContext::StandardColors[index] | (0xFF << 24); } int GetStandardColorForBitmap(int index) diff --git a/Common/gui/guimain.h b/Common/gui/guimain.h index b330d8c3328..9a9dee6d16e 100644 --- a/Common/gui/guimain.h +++ b/Common/gui/guimain.h @@ -281,6 +281,8 @@ struct GuiContext // Last selected inventory item's pic int InventoryPic = -1; + // Standard colors are used as defaults if no user setting exists; + // all of them are fully opaque RGBs. const static int MaxStandardColors = 32; const static int StandardColors[MaxStandardColors]; }; diff --git a/Engine/ac/drawingsurface.cpp b/Engine/ac/drawingsurface.cpp index b366e88341e..afeaac0b69b 100644 --- a/Engine/ac/drawingsurface.cpp +++ b/Engine/ac/drawingsurface.cpp @@ -246,7 +246,7 @@ void DrawingSurface_Clear(ScriptDrawingSurface *sds, int colour) { Bitmap *ds = sds->StartDrawing(); int allegroColor; - if ((colour == -SCR_NO_VALUE) || (colour == SCR_COLOR_TRANSPARENT)) + if (colour == SCR_COLOR_TRANSPARENT) { allegroColor = ds->GetMaskColor(); } diff --git a/Engine/ac/game.cpp b/Engine/ac/game.cpp index 6deb412068b..dc647b64874 100644 --- a/Engine/ac/game.cpp +++ b/Engine/ac/game.cpp @@ -784,7 +784,7 @@ int Game_GetColorFromRGB(int red, int grn, int blu) { return makecol8(red, grn, blu); } - return makecol32(red, grn, blu); + return makeacol32(red, grn, blu, 0xFF); } const char* Game_InputBox(const char *msg) { From 621282cd85f04cad5318466659747948628319fa Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 10 Jan 2025 21:39:07 +0300 Subject: [PATCH 4/9] Engine: fix several cases where GUI::GetStandardColor() is missing --- Common/gui/guibutton.cpp | 2 +- Common/gui/guilabel.cpp | 2 +- Common/gui/guilistbox.cpp | 4 ++-- Common/gui/guimain.cpp | 3 ++- Common/gui/guitextbox.cpp | 2 +- Engine/ac/display.cpp | 4 ++-- Engine/ac/draw.cpp | 2 +- Engine/ac/overlay.cpp | 4 ++-- Engine/main/engine.cpp | 8 ++++---- 9 files changed, 16 insertions(+), 15 deletions(-) diff --git a/Common/gui/guibutton.cpp b/Common/gui/guibutton.cpp index 6f8626f137a..3a90c43d3df 100644 --- a/Common/gui/guibutton.cpp +++ b/Common/gui/guibutton.cpp @@ -366,7 +366,7 @@ void GUIButton::ReadFromFile(Stream *in, GuiVersion gui_version) TextAlignment = (FrameAlignment)in->ReadInt32(); if (TextColor == 0) - TextColor = 16; + TextColor = 16; // FIXME: adjust this using GetStandardColor where is safe to access GuiContext _currentImage = _image; } diff --git a/Common/gui/guilabel.cpp b/Common/gui/guilabel.cpp index e3f111bf79f..bdf2f70854f 100644 --- a/Common/gui/guilabel.cpp +++ b/Common/gui/guilabel.cpp @@ -108,7 +108,7 @@ void GUILabel::ReadFromFile(Stream *in, GuiVersion gui_version) TextAlignment = (FrameAlignment)in->ReadInt32(); if (TextColor == 0) - TextColor = 16; + TextColor = 16; // FIXME: adjust this using GetStandardColor where is safe to access GuiContext _textMacro = GUI::FindLabelMacros(Text); } diff --git a/Common/gui/guilistbox.cpp b/Common/gui/guilistbox.cpp index a085e82efad..6785581fdd1 100644 --- a/Common/gui/guilistbox.cpp +++ b/Common/gui/guilistbox.cpp @@ -35,7 +35,7 @@ GUIListBox::GUIListBox() TextColor = 0; SelectedTextColor = 7; ListBoxFlags = kListBox_DefFlags; - SelectedBgColor = 16; + SelectedBgColor = 16; // FIXME: adjust this using GetStandardColor where is safe to access GuiContext TextAlignment = kHAlignLeft; _scEventCount = 1; @@ -376,7 +376,7 @@ void GUIListBox::ReadFromFile(Stream *in, GuiVersion gui_version) } if (TextColor == 0) - TextColor = 16; + TextColor = 16; // FIXME: adjust this using GetStandardColor where is safe to access GuiContext // Reset dynamic values RowHeight = 0; diff --git a/Common/gui/guimain.cpp b/Common/gui/guimain.cpp index f39e8327e27..656b7097734 100644 --- a/Common/gui/guimain.cpp +++ b/Common/gui/guimain.cpp @@ -244,8 +244,9 @@ void GUIMain::DrawSelf(Bitmap *ds) set_our_eip(376); // stop border being transparent, if the whole GUI isn't + // FIXME: don't do this in DrawSelf, fix properties when they are set! if ((FgColor == 0) && (BgColor != 0)) - FgColor = 16; + FgColor = GUI::GetStandardColor(16); if (BgColor != 0) ds->Fill(ds->GetCompatibleColor(BgColor)); diff --git a/Common/gui/guitextbox.cpp b/Common/gui/guitextbox.cpp index a1685cd4400..851cdc10a9d 100644 --- a/Common/gui/guitextbox.cpp +++ b/Common/gui/guitextbox.cpp @@ -144,7 +144,7 @@ void GUITextBox::ReadFromFile(Stream *in, GuiVersion gui_version) TextBoxFlags = in->ReadInt32(); if (TextColor == 0) - TextColor = 16; + TextColor = 16; // FIXME: adjust this using GetStandardColor where is safe to access GuiContext } void GUITextBox::ReadFromSavegame(Stream *in, GuiSvgVersion svg_ver) diff --git a/Engine/ac/display.cpp b/Engine/ac/display.cpp index e8ff08ebe82..d103a89ab37 100644 --- a/Engine/ac/display.cpp +++ b/Engine/ac/display.cpp @@ -257,7 +257,7 @@ Bitmap *create_textual_image(const char *text, const DisplayTextLooks &look, col if (drawBackground) { - text_color = 15; // use fixed standard color here + text_color = GUI::GetStandardColorForBitmap(15); // use fixed standard color here draw_text_window_and_bar(&text_window_ds, wantFreeScreenop, topbar, disp, &ttxleft, &ttxtop, &adjustedXX, &adjustedYY, &wii, &text_color, 0, usingGui); } @@ -295,7 +295,7 @@ Bitmap *create_textual_image(const char *text, const DisplayTextLooks &look, col { // Textual overlay purposed for the standard message box int xoffs, yoffs, oriwid = wii - padding * 2; - text_color = 15; // use fixed standard color here + text_color = GUI::GetStandardColorForBitmap(15); // use fixed standard color here draw_text_window_and_bar(&text_window_ds, wantFreeScreenop, topbar, disp, &xoffs, &yoffs, &adjustedXX, &adjustedYY, &wii, &text_color); adjust_y_coordinate_for_text(&yoffs, usingfont); diff --git a/Engine/ac/draw.cpp b/Engine/ac/draw.cpp index 6ac68998cf5..30a51ce01a3 100644 --- a/Engine/ac/draw.cpp +++ b/Engine/ac/draw.cpp @@ -2958,7 +2958,7 @@ void update_room_debug() int targetx = cmls.pos[i + 1].X; int targety = cmls.pos[i + 1].Y; debugMoveListObj.Bmp->DrawLine(Line(srcx / mult, srcy / mult, targetx / mult, targety / mult), - MakeColor(i + 1)); + GUI::GetStandardColorForBitmap(i + 1)); } } sync_object_texture(debugMoveListObj); diff --git a/Engine/ac/overlay.cpp b/Engine/ac/overlay.cpp index 49899068120..afeffd672e0 100644 --- a/Engine/ac/overlay.cpp +++ b/Engine/ac/overlay.cpp @@ -80,7 +80,7 @@ void Overlay_SetText(ScreenOverlay &over, int x, int y, int width, int fontid, i // from Overlay_CreateTextCore if (width < 8) width = play.GetUIViewport().GetWidth() / 2; - if (text_color == 0) text_color = 16; + if (text_color == 0) text_color = GUI::GetStandardColor(16); const char *draw_text = get_translation(text); // Skip a voice-over token, if present @@ -241,7 +241,7 @@ ScreenOverlay *Overlay_CreateTextCore(bool room_layer, int x, int y, int width, { if (width < 8) width = play.GetUIViewport().GetWidth() / 2; if (x < 0) x = play.GetUIViewport().GetWidth() / 2 - width / 2; - if (text_color == 0) text_color = 16; + if (text_color == 0) text_color = GUI::GetStandardColor(16); // Skip a voice-over token, if present const char *draw_text = skip_voiceover_token(text); return display_main(x, y, width, draw_text, nullptr, kDisplayText_NormalOverlay, over_type, diff --git a/Engine/main/engine.cpp b/Engine/main/engine.cpp index e3977d2e19b..2973424b80e 100644 --- a/Engine/main/engine.cpp +++ b/Engine/main/engine.cpp @@ -740,7 +740,7 @@ void engine_init_game_settings() play.speech_volume = 255; play.normal_font = 0; play.speech_font = 1; - play.speech_text_shadow = 16; + play.speech_text_shadow = GUI::GetStandardColor(16); play.screen_tint = -1; play.bad_parsed_word.Empty(); play.swap_portrait_side = 0; @@ -768,9 +768,9 @@ void engine_init_game_settings() play.disable_dialog_parser = 0; play.screen_is_faded_out = 0; play.player_on_region = 0; - play.top_bar_backcolor = 8; - play.top_bar_textcolor = 16; - play.top_bar_bordercolor = 8; + play.top_bar_backcolor = GUI::GetStandardColor(8); + play.top_bar_textcolor = GUI::GetStandardColor(16); + play.top_bar_bordercolor = GUI::GetStandardColor(8); play.top_bar_borderwidth = 1; play.top_bar_ypos = 25; play.top_bar_font = -1; From e3c0af71ed69870260de8b5d4b0536ecd8d38daa Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 10 Jan 2025 21:40:05 +0300 Subject: [PATCH 5/9] Common: GUIListBox: fix SelectedBgColor check, can contain alpha --- Common/gui/guilistbox.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/gui/guilistbox.cpp b/Common/gui/guilistbox.cpp index 6785581fdd1..4ad8e17f8c3 100644 --- a/Common/gui/guilistbox.cpp +++ b/Common/gui/guilistbox.cpp @@ -187,7 +187,7 @@ void GUIListBox::Draw(Bitmap *ds, int x, int y) if (item + TopItem == SelectedItem) { text_color = ds->GetCompatibleColor(SelectedTextColor); - if (SelectedBgColor > 0) + if (SelectedBgColor != 0) { int stretch_to = (x + width) - pixel_size; // draw the SelectedItem item bar (if colour not transparent) From 603aef452a93772af6b0b185fc84558a577354c9 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 10 Jan 2025 21:44:14 +0300 Subject: [PATCH 6/9] Engine: fix background color check in draw_button_background() --- Engine/ac/display.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/Engine/ac/display.cpp b/Engine/ac/display.cpp index d103a89ab37..89c024ea8c2 100644 --- a/Engine/ac/display.cpp +++ b/Engine/ac/display.cpp @@ -743,20 +743,21 @@ int get_but_pic(GUIMain*guo,int indx) return butid >= 0 ? guibuts[butid].GetNormalImage() : 0; } -void draw_button_background(Bitmap *ds, int xx1,int yy1,int xx2,int yy2,GUIMain*iep) { - color_t draw_color; - if (iep==nullptr) { // standard window - draw_color = GUI::GetStandardColorForBitmap(15); +void draw_button_background(Bitmap *ds, int xx1,int yy1,int xx2,int yy2,GUIMain*iep) +{ + if (iep == nullptr) + { + // Standard window + color_t draw_color = GUI::GetStandardColorForBitmap(15); ds->FillRect(Rect(xx1,yy1,xx2,yy2), draw_color); draw_color = GUI::GetStandardColorForBitmap(16); ds->DrawRect(Rect(xx1,yy1,xx2,yy2), draw_color); } - else { - if (iep->BgColor >= 0) draw_color = ds->GetCompatibleColor(iep->BgColor); - else draw_color = GUI::GetStandardColorForBitmap(0); // black backrgnd behind picture - - if (iep->BgColor > 0) - ds->FillRect(Rect(xx1,yy1,xx2,yy2), draw_color); + else + { + // Custom text window + if (iep->BgColor != 0) + ds->FillRect(Rect(xx1,yy1,xx2,yy2), MakeColor(iep->BgColor)); const int leftRightWidth = game.SpriteInfos[get_but_pic(iep,4)].Width; const int topBottomHeight = game.SpriteInfos[get_but_pic(iep,6)].Height; From e7696e16f998b68fe0d692e55d1770e225c0f8e9 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Sun, 12 Jan 2025 19:05:16 +0300 Subject: [PATCH 7/9] Editor: when upgrading colors separate fore and back color 0 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. --- Common/game/main_game_file.cpp | 18 +++++++---- Editor/AGS.Editor/Tasks.cs | 41 +++++++++++++++++--------- Editor/AGS.Editor/Utils/ColorMapper.cs | 11 +++++-- 3 files changed, 47 insertions(+), 23 deletions(-) diff --git a/Common/game/main_game_file.cpp b/Common/game/main_game_file.cpp index 7bcc5232f44..2bbf041528f 100644 --- a/Common/game/main_game_file.cpp +++ b/Common/game/main_game_file.cpp @@ -319,14 +319,19 @@ static const uint8_t RGBScale6[64] // Remaps color number from legacy to new format: // * palette index in 8-bit game, // * encoded 32-bit A8R8G8B8 in 32-bit game. -static int RemapFromLegacyColourNumber(const GameSetupStruct &game, int color) +static int RemapFromLegacyColourNumber(const GameSetupStruct &game, int color, bool is_bg = false) { if (game.color_depth == 1) return color; // keep palette index - // Special color number 0 is treated as fully transparent + // Special color number 0 is treated depending on its purpose: + // * background color becomes fully transparent; + // * foreground color becomes opaque black if (color == 0) - return 0; + { + return is_bg ? 0 : (0 | (0xFF << 24)); + } + // Special color numbers 1-31 were always interpreted as palette indexes; // for them we compose a 32-bit ARGB from the palette entry if (color >= 0 && color < 32) @@ -419,8 +424,9 @@ void UpgradeGUI(GameSetupStruct &game, LoadedGameEntities &ents, GameDataVersion { for (auto &gui : ents.Guis) { - gui.BgColor = RemapFromLegacyColourNumber(game, gui.BgColor); - gui.FgColor = RemapFromLegacyColourNumber(game, gui.FgColor); + gui.BgColor = RemapFromLegacyColourNumber(game, gui.BgColor, true); + gui.FgColor = RemapFromLegacyColourNumber(game, gui.FgColor, !gui.IsTextWindow() + /* right, treat border as background for normal gui */); } for (auto &btn : ents.GuiControls.Buttons) @@ -436,7 +442,7 @@ void UpgradeGUI(GameSetupStruct &game, LoadedGameEntities &ents, GameDataVersion for (auto &list : ents.GuiControls.ListBoxes) { list.TextColor = RemapFromLegacyColourNumber(game, list.TextColor); - list.SelectedBgColor = RemapFromLegacyColourNumber(game, list.SelectedBgColor); + list.SelectedBgColor = RemapFromLegacyColourNumber(game, list.SelectedBgColor, true); list.SelectedTextColor = RemapFromLegacyColourNumber(game, list.SelectedTextColor); } diff --git a/Editor/AGS.Editor/Tasks.cs b/Editor/AGS.Editor/Tasks.cs index 2b98c27ff43..f0bc61a4063 100644 --- a/Editor/AGS.Editor/Tasks.cs +++ b/Editor/AGS.Editor/Tasks.cs @@ -621,14 +621,16 @@ private string RemoveAllLeadingSpacesFromLines(string script) return returnValue; } + private delegate int RemapColourProperty(int color, bool isBackgroundColor = false); + /// /// Remaps all color properties in game from old color depth to a new color depth; /// for example: from palette mode to 32-bit mode, or other way. /// public static void RemapColourPropertiesOnDepthChange(Game game, GameColorDepth oldColorDepth) { - Func remapColor = (color) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; - RemapColourProperties(game, remapColor); + RemapColourProperty remapColor = (color, isBg) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; + RemapColourProperties(game, remapColor ); } /// @@ -637,7 +639,7 @@ public static void RemapColourPropertiesOnDepthChange(Game game, GameColorDepth /// public static void RemapCharacterColours(Character character, Game game, GameColorDepth oldColorDepth) { - Func remapColor = (color) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; + RemapColourProperty remapColor = (color, isBg) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; RemapColourProperties(character, remapColor); } @@ -647,7 +649,7 @@ public static void RemapCharacterColours(Character character, Game game, GameCol /// public static void RemapGUIColours(GUI gui, Game game, GameColorDepth oldColorDepth) { - Func remapColor = (color) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; + RemapColourProperty remapColor = (color, isBg) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; RemapColourProperties(gui, remapColor); } @@ -657,7 +659,7 @@ public static void RemapGUIColours(GUI gui, Game game, GameColorDepth oldColorDe /// public static void RemapGUIColours(GUIControl guiControl, Game game, GameColorDepth oldColorDepth) { - Func remapColor = (color) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; + RemapColourProperty remapColor = (color, isBg) => { return ColorMapper.RemapColourNumberToDepth(color, game.Palette, game.Settings.ColorDepth, oldColorDepth); }; RemapColourProperties(guiControl, remapColor); } @@ -666,20 +668,31 @@ public static void RemapGUIColours(GUIControl guiControl, Game game, GameColorDe /// private static void RemapLegacyColourProperties(Game game) { - Func remapColor = (color) => { return ColorMapper.RemapFromLegacyColourNumber(color, game.Palette, game.Settings.ColorDepth); }; + RemapColourProperty remapColor = (color, isBg) => { + return ColorMapper.RemapFromLegacyColourNumber(color, game.Palette, game.Settings.ColorDepth, isBg); + }; RemapColourProperties(game, remapColor); } + /// + /// Remaps 32-bit RGB color number to proper 32-bit ARGB. + /// This method has a nuance: the background colors of value 0 are treated as "transparent", + /// while foreground colors of value 0 are treated as "black". + /// private static void RemapOpaqueColourProperties(Game game) { - Func remapColor = (color) => { return ColorMapper.MakeOpaque(color, game.Settings.ColorDepth); }; + RemapColourProperty remapColor = (color, isBg) => { + if (isBg && (color == 0)) + return 0; + return ColorMapper.MakeOpaque(color, game.Settings.ColorDepth); + }; RemapColourProperties(game, remapColor); } /// /// Remaps all color properties in game using provided delegate. /// - private static void RemapColourProperties(Game game, Func remapColor) + private static void RemapColourProperties(Game game, RemapColourProperty remapColor) { var settings = game.Settings; settings.InventoryHotspotMarkerCrosshairColor = remapColor(settings.InventoryHotspotMarkerCrosshairColor); @@ -696,18 +709,18 @@ private static void RemapColourProperties(Game game, Func remapColor) } } - private static void RemapColourProperties(Character character, Func remapColor) + private static void RemapColourProperties(Character character, RemapColourProperty remapColor) { character.SpeechColor = remapColor(character.SpeechColor); } - private static void RemapColourProperties(GUI gui, Func remapColor) + private static void RemapColourProperties(GUI gui, RemapColourProperty remapColor) { - gui.BackgroundColor = remapColor(gui.BackgroundColor); + gui.BackgroundColor = remapColor(gui.BackgroundColor, isBackgroundColor: true); if (gui is NormalGUI) { var ngui = gui as NormalGUI; - ngui.BorderColor = remapColor(ngui.BorderColor); + ngui.BorderColor = remapColor(ngui.BorderColor, isBackgroundColor: true); } else if (gui is TextWindowGUI) { @@ -722,7 +735,7 @@ private static void RemapColourProperties(GUI gui, Func remapColor) } } - private static void RemapColourProperties(GUIControl guiControl, Func remapColor) + private static void RemapColourProperties(GUIControl guiControl, RemapColourProperty remapColor) { if (guiControl is GUIButton) { @@ -739,7 +752,7 @@ private static void RemapColourProperties(GUIControl guiControl, Func GUIListBox list = guiControl as GUIListBox; list.TextColor = remapColor(list.TextColor); list.SelectedTextColor = remapColor(list.SelectedTextColor); - list.SelectedBackgroundColor = remapColor(list.SelectedBackgroundColor); + list.SelectedBackgroundColor = remapColor(list.SelectedBackgroundColor, isBackgroundColor: true); } else if (guiControl is GUITextBox) { diff --git a/Editor/AGS.Editor/Utils/ColorMapper.cs b/Editor/AGS.Editor/Utils/ColorMapper.cs index da38cb618c5..e8d2a8ec072 100644 --- a/Editor/AGS.Editor/Utils/ColorMapper.cs +++ b/Editor/AGS.Editor/Utils/ColorMapper.cs @@ -159,7 +159,7 @@ public static int RemapColourNumberToDepth(int colourNumber, PaletteEntry[] pale /// /// Generates a new colour number value from a legacy number. /// - public static int RemapFromLegacyColourNumber(int legacyColourNumber, PaletteEntry[] palette, GameColorDepth gameColorDepth) + public static int RemapFromLegacyColourNumber(int legacyColourNumber, PaletteEntry[] palette, GameColorDepth gameColorDepth, bool isBackgroundColor) { // For 8-bit games simply treat the color number as a palette index if (gameColorDepth == GameColorDepth.Palette) @@ -167,9 +167,14 @@ public static int RemapFromLegacyColourNumber(int legacyColourNumber, PaletteEnt return legacyColourNumber; } - // Special color number 0 is treated as fully transparent + // Special color number 0 is treated depending on its purpose: + // * background color becomes fully transparent; + // * foreground color becomes opaque black if (legacyColourNumber == 0) - return 0; + { + return isBackgroundColor ? 0 : (0 | (0xFF << 24)); + } + // 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)) From af7177f11df066380a5e3534cb303abb2a0c3ec2 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Sun, 12 Jan 2025 20:09:45 +0300 Subject: [PATCH 8/9] Script API: DrawingSurface.Clear must have a COLOR_TRANSPARENT default --- Editor/AGS.Editor/Resources/agsdefns.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Editor/AGS.Editor/Resources/agsdefns.sh b/Editor/AGS.Editor/Resources/agsdefns.sh index e7c2677622b..2f5a37467ef 100644 --- a/Editor/AGS.Editor/Resources/agsdefns.sh +++ b/Editor/AGS.Editor/Resources/agsdefns.sh @@ -743,7 +743,7 @@ builtin managed struct ViewFrame { builtin managed struct DrawingSurface { /// Clears the surface to the specified colour, or transparent if you do not specify a colour. - import void Clear(int colour=-SCR_NO_VALUE); + import void Clear(int colour=COLOR_TRANSPARENT); /// Creates a copy of the surface. import DrawingSurface* CreateCopy(); /// Draws a circle onto the surface with its centre at (x,y). From 031c4f461b66955b51eb56280e1d9b6359c170d8 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Sun, 12 Jan 2025 20:46:14 +0300 Subject: [PATCH 9/9] Editor: serialize color properties in hex format This is purely for easier reading of the Game.agf. --- Editor/AGS.Types/AGS.Types.csproj | 1 + Editor/AGS.Types/Attributes/SerializeAsHex.cs | 12 ++++++++++ Editor/AGS.Types/Character.cs | 1 + Editor/AGS.Types/GUI.cs | 1 + Editor/AGS.Types/GUIButton.cs | 1 + Editor/AGS.Types/GUILabel.cs | 1 + Editor/AGS.Types/GUIListBox.cs | 3 +++ Editor/AGS.Types/GUITextBox.cs | 1 + Editor/AGS.Types/NormalGUI.cs | 1 + Editor/AGS.Types/SerializeUtils.cs | 23 ++++++++++++++----- Editor/AGS.Types/Settings.cs | 2 ++ Editor/AGS.Types/TextWindowGUI.cs | 1 + 12 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 Editor/AGS.Types/Attributes/SerializeAsHex.cs diff --git a/Editor/AGS.Types/AGS.Types.csproj b/Editor/AGS.Types/AGS.Types.csproj index 2dd9b248c8f..7f0533dc101 100644 --- a/Editor/AGS.Types/AGS.Types.csproj +++ b/Editor/AGS.Types/AGS.Types.csproj @@ -111,6 +111,7 @@ + diff --git a/Editor/AGS.Types/Attributes/SerializeAsHex.cs b/Editor/AGS.Types/Attributes/SerializeAsHex.cs new file mode 100644 index 00000000000..be48968c7f0 --- /dev/null +++ b/Editor/AGS.Types/Attributes/SerializeAsHex.cs @@ -0,0 +1,12 @@ +using System; + +namespace AGS.Types +{ + [AttributeUsage(AttributeTargets.Property)] + public class SerializeAsHex : Attribute + { + public SerializeAsHex() : base() + { + } + } +} diff --git a/Editor/AGS.Types/Character.cs b/Editor/AGS.Types/Character.cs index c42ae71395b..4f56019216d 100644 --- a/Editor/AGS.Types/Character.cs +++ b/Editor/AGS.Types/Character.cs @@ -259,6 +259,7 @@ public int SpeechAnimationDelay [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int SpeechColor { get { return _speechColor; } diff --git a/Editor/AGS.Types/GUI.cs b/Editor/AGS.Types/GUI.cs index c20811b6e6c..a880fac7ed0 100644 --- a/Editor/AGS.Types/GUI.cs +++ b/Editor/AGS.Types/GUI.cs @@ -52,6 +52,7 @@ public virtual int EditorHeight [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int BackgroundColor { get { return _bgcol; } diff --git a/Editor/AGS.Types/GUIButton.cs b/Editor/AGS.Types/GUIButton.cs index 0476f2debc5..0effb6ba62e 100644 --- a/Editor/AGS.Types/GUIButton.cs +++ b/Editor/AGS.Types/GUIButton.cs @@ -121,6 +121,7 @@ public int TextPaddingVertical [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int TextColor { get { return _textColor; } diff --git a/Editor/AGS.Types/GUILabel.cs b/Editor/AGS.Types/GUILabel.cs index 8401caf7e3a..37f11cf1f07 100644 --- a/Editor/AGS.Types/GUILabel.cs +++ b/Editor/AGS.Types/GUILabel.cs @@ -47,6 +47,7 @@ public FrameAlignment TextAlignment [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int TextColor { get { return _textColor; } diff --git a/Editor/AGS.Types/GUIListBox.cs b/Editor/AGS.Types/GUIListBox.cs index 2a6d271e1a6..2ce1613314b 100644 --- a/Editor/AGS.Types/GUIListBox.cs +++ b/Editor/AGS.Types/GUIListBox.cs @@ -83,6 +83,7 @@ public HorizontalAlignment TextAlignment [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int TextColor { get { return _textColor; } @@ -95,6 +96,7 @@ public int TextColor [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int SelectedTextColor { get { return _selectedTextColor; } @@ -107,6 +109,7 @@ public int SelectedTextColor [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int SelectedBackgroundColor { get { return _selectedBackgroundColor; } diff --git a/Editor/AGS.Types/GUITextBox.cs b/Editor/AGS.Types/GUITextBox.cs index 16917bc7c34..67a8f6587ca 100644 --- a/Editor/AGS.Types/GUITextBox.cs +++ b/Editor/AGS.Types/GUITextBox.cs @@ -53,6 +53,7 @@ public string OnActivate [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int TextColor { get { return _textColor; } diff --git a/Editor/AGS.Types/NormalGUI.cs b/Editor/AGS.Types/NormalGUI.cs index dc3d921c339..109e144785a 100644 --- a/Editor/AGS.Types/NormalGUI.cs +++ b/Editor/AGS.Types/NormalGUI.cs @@ -174,6 +174,7 @@ public int ZOrder [RefreshProperties(RefreshProperties.All)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int BorderColor { get { return _bordercol; } diff --git a/Editor/AGS.Types/SerializeUtils.cs b/Editor/AGS.Types/SerializeUtils.cs index c74218440e2..483a740d093 100644 --- a/Editor/AGS.Types/SerializeUtils.cs +++ b/Editor/AGS.Types/SerializeUtils.cs @@ -179,11 +179,7 @@ public static void SerializePropertiesToXML(object obj, XmlTextWriter writer) } if ((prop.CanRead) && (prop.CanWrite)) { - bool canSerializeClass = false; - if (prop.GetCustomAttributes(typeof(AGSSerializeClassAttribute), true).Length > 0) - { - canSerializeClass = true; - } + bool canSerializeClass = prop.GetCustomAttribute(typeof(AGSSerializeClassAttribute), true) != null; if (prop.GetValue(obj, null) == null) { @@ -209,6 +205,13 @@ public static void SerializePropertiesToXML(object obj, XmlTextWriter writer) writer.WriteString(propValue); writer.WriteEndElement(); } + else if (prop.PropertyType == typeof(int)) + { + if (prop.GetCustomAttribute(typeof(SerializeAsHex), true) != null) + writer.WriteElementString(prop.Name, $"0x{((int)prop.GetValue(obj, null)).ToString("X8")}"); + else + writer.WriteElementString(prop.Name, prop.GetValue(obj, null).ToString()); + } // We must use InvariantCulture for floats and doubles, because their // format depends on local system settings used when the project was saved else if (prop.PropertyType == typeof(float)) @@ -305,7 +308,15 @@ public static void DeserializePropertiesFromXML(object obj, XmlNode node) } else if (prop.PropertyType == typeof(int)) { - prop.SetValue(obj, Convert.ToInt32(elementValue), null); + if (prop.GetCustomAttribute(typeof(SerializeAsHex), true) != null && + elementValue.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + { + prop.SetValue(obj, Convert.ToInt32(elementValue, 16), null); + } + else + { + prop.SetValue(obj, Convert.ToInt32(elementValue), null); + } } else if (prop.PropertyType == typeof(short)) { diff --git a/Editor/AGS.Types/Settings.cs b/Editor/AGS.Types/Settings.cs index e85a1a53fea..2317e4b0db4 100644 --- a/Editor/AGS.Types/Settings.cs +++ b/Editor/AGS.Types/Settings.cs @@ -504,6 +504,7 @@ public int InventoryHotspotMarkerSprite [DefaultValue(0)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int InventoryHotspotMarkerDotColor { get { return _inventoryHotspotMarker.DotColor; } @@ -516,6 +517,7 @@ public int InventoryHotspotMarkerDotColor [DefaultValue(0)] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int InventoryHotspotMarkerCrosshairColor { get { return _inventoryHotspotMarker.CrosshairColor; } diff --git a/Editor/AGS.Types/TextWindowGUI.cs b/Editor/AGS.Types/TextWindowGUI.cs index 6f458eb12dc..b1c21bfa29b 100644 --- a/Editor/AGS.Types/TextWindowGUI.cs +++ b/Editor/AGS.Types/TextWindowGUI.cs @@ -36,6 +36,7 @@ public override int EditorHeight [Category("Appearance")] [Editor(typeof(ColorUIEditor), typeof(System.Drawing.Design.UITypeEditor))] [TypeConverter(typeof(CustomColorConverter))] + [SerializeAsHex] public int TextColor { get { return _textColor; }