[Scummvm-git-logs] scummvm master -> c768b94cf681500e71e00f5d26f04bba6a435cba

dreammaster noreply at scummvm.org
Sat Apr 30 05:20:57 UTC 2022


This automated email contains information about 15 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
0490236774 AGS: Use old-style keycodes for internal engine commands
99c97541e4 AGS: Set current savegame version to 360beta
21ab95f5ab AGS: Remove RegisterGameWithGameExplorer()
4fa512da6e AGS: Fixed returning error from SpriteFile::LoadSprite/RawData()
6ee31a530e AGS: Removed unnecessary ags_domouse() calls
d2b03800c6 AGS: Allow to place sounds on a crossfade channels for compatibility
bf5a649385 AGS: Managed wrapper for SpriteFileWriter
8d588c3a30 AGS: Fixed on_key_press not called all times
2ab7985361 AGS: Revert "Engine: fixed AdjustBitmapForUseWithDisplayMode()"
ad599a6425 AGS: In gui clipping mode prevent listbox items drawn over scrollbar
403892950c AGS: Removed ListBox::DrawItemsFix, add preview items externally
939d116fba AGS: Fixed GUIMain::Poll(), only affect clickable controls
673c8c242e AGS: Split GUIMain::DrawAt into DrawSelf and DrawWithControls
62ebde86a1 AGS: Gui controls draw themselves at requested offset
c768b94cf6 AGS: Draw GUI Controls on separate textures


Commit: 0490236774a86a40349ce0737df7f89dc7626343
    https://github.com/scummvm/scummvm/commit/0490236774a86a40349ce0737df7f89dc7626343
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:38-07:00

Commit Message:
AGS: Use old-style keycodes for internal engine commands

>From upstream e2f8b0f2357d2587016425ff6629ef37601d8e0f

Changed paths:
    engines/ags/engine/ac/sys_events.cpp
    engines/ags/engine/main/game_run.cpp
    engines/ags/shared/ac/keycode.h


diff --git a/engines/ags/engine/ac/sys_events.cpp b/engines/ags/engine/ac/sys_events.cpp
index 38ded9e6300..20b3d0ab097 100644
--- a/engines/ags/engine/ac/sys_events.cpp
+++ b/engines/ags/engine/ac/sys_events.cpp
@@ -66,6 +66,7 @@ KeyInput ags_keycode_from_scummvm(const Common::Event &event, bool old_keyhandle
 	KeyInput ki;
 
 	ki.Key = ::AGS::g_events->scummvm_key_to_ags_key(event, ki.Mod, old_keyhandle);
+	ki.CompatKey = ::AGS::g_events->scummvm_key_to_ags_key(event, ki.Mod, true);
 
 	return ki;
 }
diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index 6263c17d18c..009d19b6a88 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -308,7 +308,7 @@ bool run_service_key_controls(KeyInput &out_key) {
 		return false; // in backward mode the engine does not react to single mod keys
 
 	KeyInput ki = ags_keycode_from_scummvm(key_evt, old_keyhandle);
-	eAGSKeyCode agskey = ki.Key;
+	eAGSKeyCode agskey = ki.CompatKey; // use backward-compatible combined key here
 	if (agskey == eAGSKeyCodeNone)
 		return false; // should skip this key event
 
diff --git a/engines/ags/shared/ac/keycode.h b/engines/ags/shared/ac/keycode.h
index f0198ac2a1e..97b2a8b137b 100644
--- a/engines/ags/shared/ac/keycode.h
+++ b/engines/ags/shared/ac/keycode.h
@@ -268,6 +268,7 @@ struct KeyInput {
 	const static size_t UTF8_ARR_SIZE = 5;
 
 	eAGSKeyCode Key = eAGSKeyCodeNone; // actual key code
+	eAGSKeyCode CompatKey = eAGSKeyCodeNone; // old-style key code, combined with mods
 	int         Mod = 0; // key modifiers
 	int         UChar = 0; // full character value (supports unicode)
 	char        Text[UTF8_ARR_SIZE]{}; // character in a string format


Commit: 99c97541e4cc04ab383648b2dc274dd0bfa9703f
    https://github.com/scummvm/scummvm/commit/99c97541e4cc04ab383648b2dc274dd0bfa9703f
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:38-07:00

Commit Message:
AGS: Set current savegame version to 360beta

This is a portion of upstream 018d8790f8a8f3d39088cedace98b52d7ef730db,
but I didn't implement all of it, because we still need savegame
thumbnails for showing in the GMM

Changed paths:
    engines/ags/engine/game/savegame.h


diff --git a/engines/ags/engine/game/savegame.h b/engines/ags/engine/game/savegame.h
index 203cfa9a35b..9d6d9587f68 100644
--- a/engines/ags/engine/game/savegame.h
+++ b/engines/ags/engine/game/savegame.h
@@ -52,6 +52,7 @@ typedef std::shared_ptr<Stream> PStream;
 //
 // 8      last old style saved game format (of AGS 3.2.1)
 // 9      first new style (self-descriptive block-based) format version
+// Since 3.6.0: value is defined as AGS version represented as NN,NN,NN,NN.
 //-----------------------------------------------------------------------------
 enum SavegameVersion {
 	kSvgVersion_Undefined = 0,
@@ -61,7 +62,8 @@ enum SavegameVersion {
 	kSvgVersion_350_final = 11,
 	kSvgVersion_350_final2 = 12,
 	kSvgVersion_351 = 13,
-	kSvgVersion_Current = kSvgVersion_351,
+	kSvgVersion_360beta = 3060023,
+	kSvgVersion_Current = kSvgVersion_360beta,
 	kSvgVersion_LowestSupported = kSvgVersion_321 // change if support dropped
 };
 


Commit: 21ab95f5ab1637070c2d4db2aa3e4daa1221b880
    https://github.com/scummvm/scummvm/commit/21ab95f5ab1637070c2d4db2aa3e4daa1221b880
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Remove RegisterGameWithGameExplorer()

>From upstream 1554207f04dc6999994d02956587b302bb56f858

Changed paths:
    engines/ags/engine/ac/file.cpp
    engines/ags/engine/main/engine.cpp
    engines/ags/engine/main/main.cpp
    engines/ags/engine/platform/base/ags_platform_driver.cpp
    engines/ags/engine/platform/base/ags_platform_driver.h
    engines/ags/globals.h


diff --git a/engines/ags/engine/ac/file.cpp b/engines/ags/engine/ac/file.cpp
index 96c328b39e2..3fcf581d0b2 100644
--- a/engines/ags/engine/ac/file.cpp
+++ b/engines/ags/engine/ac/file.cpp
@@ -481,7 +481,7 @@ static long ags_pf_fwrite(AL_CONST void * /*p*/, long /*n*/, void * /*userdata*/
 	return -1; // don't support write
 }
 
-static int ags_pf_fseek(void */*userdata*/, int /*offset*/) {
+static int ags_pf_fseek(void * /*userdata*/, int /*offset*/) {
 	return -1; // don't support seek
 }
 
diff --git a/engines/ags/engine/main/engine.cpp b/engines/ags/engine/main/engine.cpp
index fb716eb89fd..8dc889f890c 100644
--- a/engines/ags/engine/main/engine.cpp
+++ b/engines/ags/engine/main/engine.cpp
@@ -383,22 +383,6 @@ int engine_load_game_data() {
 	return 0;
 }
 
-int engine_check_register_game() {
-	if (_G(justRegisterGame)) {
-		_G(platform)->RegisterGameWithGameExplorer();
-		_G(proper_exit) = 1;
-		return EXIT_NORMAL;
-	}
-
-	if (_G(justUnRegisterGame)) {
-		_G(platform)->UnRegisterGameWithGameExplorer();
-		_G(proper_exit) = 1;
-		return EXIT_NORMAL;
-	}
-
-	return 0;
-}
-
 // Replace special tokens inside a user path option
 static void resolve_configured_path(String &option) {
 	option.Replace("$GAMENAME$", _GP(game).gamename);
@@ -1162,10 +1146,6 @@ int initialize_engine(const ConfigTree &startup_opts) {
 	if (res != 0)
 		return res;
 
-	res = engine_check_register_game();
-	if (res != 0)
-		return res;
-
 	_G(our_eip) = -189;
 
 	res = engine_check_disk_space();
diff --git a/engines/ags/engine/main/main.cpp b/engines/ags/engine/main/main.cpp
index 3f8099c0ac6..19648954c68 100644
--- a/engines/ags/engine/main/main.cpp
+++ b/engines/ags/engine/main/main.cpp
@@ -203,10 +203,6 @@ int main_process_cmdline(ConfigTree &cfg, int argc, const char *argv[]) {
 		} else if (ags_stricmp(arg, "--noexceptionhandler") == 0) _GP(usetup).disable_exception_handling = true;
 		else if (ags_stricmp(arg, "--setup") == 0) {
 			_G(justRunSetup) = true;
-		} else if (ags_stricmp(arg, "--registergame") == 0) {
-			_G(justRegisterGame) = true;
-		} else if (ags_stricmp(arg, "--unregistergame") == 0) {
-			_G(justUnRegisterGame) = true;
 		} else if ((ags_stricmp(arg, "--loadsavedgame") == 0) && (argc > ee + 1)) {
 			_G(loadSaveGameOnStartup) = atoi(argv[ee + 1]);
 			ee++;
diff --git a/engines/ags/engine/platform/base/ags_platform_driver.cpp b/engines/ags/engine/platform/base/ags_platform_driver.cpp
index e6b88be6b1c..52fbf2312a2 100644
--- a/engines/ags/engine/platform/base/ags_platform_driver.cpp
+++ b/engines/ags/engine/platform/base/ags_platform_driver.cpp
@@ -92,12 +92,6 @@ void AGSPlatformDriver::AdjustWindowStyleForFullscreen() {
 void AGSPlatformDriver::AdjustWindowStyleForWindowed() {
 }
 
-void AGSPlatformDriver::RegisterGameWithGameExplorer() {
-}
-
-void AGSPlatformDriver::UnRegisterGameWithGameExplorer() {
-}
-
 void AGSPlatformDriver::ValidateWindowSize(int & /*x*/, int & /*y*/, bool /*borderless*/) const {
 }
 
diff --git a/engines/ags/engine/platform/base/ags_platform_driver.h b/engines/ags/engine/platform/base/ags_platform_driver.h
index 6e7d135a420..b4a087f9001 100644
--- a/engines/ags/engine/platform/base/ags_platform_driver.h
+++ b/engines/ags/engine/platform/base/ags_platform_driver.h
@@ -164,8 +164,6 @@ struct AGSPlatformDriver
 	virtual void AdjustWindowStyleForFullscreen();
 	// Adjust application window's parameters to suit windowed mode
 	virtual void AdjustWindowStyleForWindowed();
-	virtual void RegisterGameWithGameExplorer();
-	virtual void UnRegisterGameWithGameExplorer();
 	virtual int  ConvertKeycodeToScanCode(int keyCode);
 	// Adjust window size to ensure it is in the supported limits
 	virtual void ValidateWindowSize(int &x, int &y, bool /*borderless*/) const;
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 0ed35ac23b5..4b971d17e58 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -1076,8 +1076,6 @@ public:
 	bool _justDisplayHelp = false;
 	bool _justDisplayVersion = false;
 	bool _justRunSetup = false;
-	bool _justRegisterGame = false;
-	bool _justUnRegisterGame = false;
 	bool _justTellInfo = false;
 	std::set<String> _tellInfoKeys;
 	int _loadSaveGameOnStartup = -1;


Commit: 4fa512da6edd3d318f79fec8cebd58abd4a71b40
    https://github.com/scummvm/scummvm/commit/4fa512da6edd3d318f79fec8cebd58abd4a71b40
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Fixed returning error from SpriteFile::LoadSprite/RawData()

>From upstream e58569f1a1a95867cba00592b131372170c81c8b

Changed paths:
    engines/ags/shared/ac/sprite_file.cpp


diff --git a/engines/ags/shared/ac/sprite_file.cpp b/engines/ags/shared/ac/sprite_file.cpp
index 3aaf8ea607a..1f59d494148 100644
--- a/engines/ags/shared/ac/sprite_file.cpp
+++ b/engines/ags/shared/ac/sprite_file.cpp
@@ -346,7 +346,7 @@ HError SpriteFile::RebuildSpriteIndex(Stream *in, sprkey_t topmost,
 HError SpriteFile::LoadSprite(sprkey_t index, Shared::Bitmap *&sprite) {
 	sprite = nullptr;
 	if (index < 0 || (size_t)index >= _spriteData.size())
-		new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
+		return new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
 			index, 0, _spriteData.size() - 1));
 
 	if (_spriteData[index].Offset == 0)
@@ -430,7 +430,7 @@ HError SpriteFile::LoadRawData(sprkey_t index, SpriteDatHeader &hdr, std::vector
 	hdr = SpriteDatHeader();
 	data.resize(0);
 	if (index < 0 || (size_t)index >= _spriteData.size())
-		new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
+		return new Error(String::FromFormat("LoadSprite: slot index %d out of bounds (%d - %d).",
 			index, 0, _spriteData.size() - 1));
 
 	if (_spriteData[index].Offset == 0)


Commit: 6ee31a530e707301af81bbff723c328f6ad99c62
    https://github.com/scummvm/scummvm/commit/6ee31a530e707301af81bbff723c328f6ad99c62
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Removed unnecessary ags_domouse() calls

>From upstream de28de1dd44d991a479ae0adb5fdb4996fe33656

Changed paths:
    engines/ags/engine/ac/dialog.cpp
    engines/ags/engine/ac/display.cpp
    engines/ags/engine/ac/draw.cpp
    engines/ags/engine/ac/game.cpp


diff --git a/engines/ags/engine/ac/dialog.cpp b/engines/ags/engine/ac/dialog.cpp
index 8028019d7e6..6719c366edb 100644
--- a/engines/ags/engine/ac/dialog.cpp
+++ b/engines/ags/engine/ac/dialog.cpp
@@ -591,16 +591,8 @@ void DialogOptions::Show() {
 	wantRefresh = false;
 	mouseison = -10;
 
-	update_polled_stuff_if_runtime();
-	if (!_GP(play).mouse_cursor_hidden)
-		ags_domouse();
-	update_polled_stuff_if_runtime();
-
 	Redraw();
 	while (Run() && !SHOULD_QUIT) {}
-
-	if (!_GP(play).mouse_cursor_hidden)
-		ags_domouse();
 }
 
 void DialogOptions::Redraw() {
diff --git a/engines/ags/engine/ac/display.cpp b/engines/ags/engine/ac/display.cpp
index 7c2e3726a9e..a0553554bc9 100644
--- a/engines/ags/engine/ac/display.cpp
+++ b/engines/ags/engine/ac/display.cpp
@@ -271,8 +271,6 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 			return 0;
 		}
 
-		if (!_GP(play).mouse_cursor_hidden)
-			ags_domouse();
 		int countdown = GetTextDisplayTime(todis);
 		int skip_setting = user_to_internal_skip_speech((SkipSpeechStyle)_GP(play).skip_display);
 		// Loop until skipped
@@ -332,8 +330,7 @@ int _display_main(int xx, int yy, int wii, const char *text, int disp_type, int
 			if ((countdown < 1) && (_GP(play).fast_forward))
 				break;
 		}
-		if (!_GP(play).mouse_cursor_hidden)
-			ags_domouse();
+
 		remove_screen_overlay(OVER_TEXTMSG);
 		invalidate_screen();
 	} else {
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 3f55aca36f8..c1e8376698e 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2183,8 +2183,8 @@ void construct_game_screen_overlay(bool draw_mouse) {
 	// TODO: find out if it's okay to move cursor animation and state update
 	// to the update loop instead of doing it in the drawing routine
 	// update animating mouse cursor
+	ags_domouse(); // update mouse pos (mousex, mousey)
 	if (_GP(game).mcurs[_G(cur_cursor)].view >= 0) {
-		ags_domouse();
 		// only on mousemove, and it's not moving
 		if (((_GP(game).mcurs[_G(cur_cursor)].flags & MCF_ANIMMOVE) != 0) &&
 		        (_G(mousex) == _G(lastmx)) && (_G(mousey) == _G(lastmy)));
@@ -2212,8 +2212,6 @@ void construct_game_screen_overlay(bool draw_mouse) {
 		_G(lastmy) = _G(mousey);
 	}
 
-	ags_domouse();
-
 	// Stage: mouse cursor
 	if (draw_mouse && !_GP(play).mouse_cursor_hidden && _GP(play).screen_is_faded_out == 0) {
 		_G(gfxDriver)->DrawSprite(_G(mousex) - _G(hotx), _G(mousey) - _G(hoty),
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index c8929dd276b..6cfdf84f8b2 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -196,20 +196,14 @@ void set_game_speed(int new_fps) {
 void setup_for_dialog() {
 	_G(cbuttfont) = _GP(play).normal_font;
 	_G(acdialog_font) = _GP(play).normal_font;
-	if (!_GP(play).mouse_cursor_hidden)
-		ags_domouse();
 	_G(oldmouse) = _G(cur_cursor);
 	set_mouse_cursor(CURS_ARROW);
 }
 void restore_after_dialog() {
 	set_mouse_cursor(_G(oldmouse));
-	if (!_GP(play).mouse_cursor_hidden)
-		ags_domouse();
 	invalidate_screen();
 }
 
-
-
 String get_save_game_directory() {
 	return _G(saveGameDirectory);
 }


Commit: d2b03800c6a8dea780b6eb544568476db59d4b88
    https://github.com/scummvm/scummvm/commit/d2b03800c6a8dea780b6eb544568476db59d4b88
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Allow to place sounds on a crossfade channels for compatibility

>From upstream 86564e983572b4ffb3cd12b00c116ae91c6fcbe4

Changed paths:
    engines/ags/engine/game/game_init.cpp
    engines/ags/engine/media/audio/audio.cpp
    engines/ags/shared/ac/game_setup_struct.h


diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index c8f1e4d1d8e..cd7421f2993 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -90,7 +90,7 @@ String GetGameInitErrorText(GameInitErrorType err) {
 
 // Initializes audio channels and clips and registers them in the script system
 void InitAndRegisterAudioObjects(GameSetupStruct &game) {
-	for (int i = 0; i < game.numGameChannels; ++i) {
+	for (int i = 0; i < game.numCompatGameChannels; ++i) {
 		_G(scrAudioChannel)[i].id = i;
 		ccRegisterManagedObject(&_G(scrAudioChannel)[i], &_GP(ccDynamicAudio));
 	}
@@ -374,10 +374,13 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
 	_G(old_speech_lines) = ents.OldSpeechLines;
 
 	// Set number of game channels corresponding to the loaded game version
-	if (_G(loaded_game_file_version) < kGameVersion_360)
-		game.numGameChannels = MAX_GAME_CHANNELS_v320;
-	else
-		game.numGameChannels = MAX_GAME_CHANNELS;
+	if (_G(loaded_game_file_version) < kGameVersion_360) {
+		_GP(game).numGameChannels = MAX_GAME_CHANNELS_v320;
+		_GP(game).numCompatGameChannels = TOTAL_AUDIO_CHANNELS_v320;
+	} else {
+		_GP(game).numGameChannels = MAX_GAME_CHANNELS;
+		_GP(game).numCompatGameChannels = MAX_GAME_CHANNELS;
+	}
 
 	HError err = InitAndRegisterGameEntities(game);
 	if (!err)
diff --git a/engines/ags/engine/media/audio/audio.cpp b/engines/ags/engine/media/audio/audio.cpp
index 569e817ad2b..d79e7637e3d 100644
--- a/engines/ags/engine/media/audio/audio.cpp
+++ b/engines/ags/engine/media/audio/audio.cpp
@@ -152,8 +152,9 @@ static int find_free_audio_channel(ScriptAudioClip *clip, int priority, bool int
 	if (!interruptEqualPriority)
 		priority--;
 
+	// NOTE: in backward compat mode we allow to place sound on a crossfade channel
 	int startAtChannel = _G(reserved_channel_count);
-	int endBeforeChannel = _GP(game).numGameChannels;
+	int endBeforeChannel = _GP(game).numCompatGameChannels;
 
 	if (_GP(game).audioClipTypes[clip->type].reservedChannels > 0) {
 		startAtChannel = 0;
@@ -161,7 +162,7 @@ static int find_free_audio_channel(ScriptAudioClip *clip, int priority, bool int
 			startAtChannel += MIN(MAX_SOUND_CHANNELS,
 				_GP(game).audioClipTypes[i].reservedChannels);
 		}
-		endBeforeChannel = MIN(_GP(game).numGameChannels,
+		endBeforeChannel = MIN(_GP(game).numCompatGameChannels,
 			startAtChannel + _GP(game).audioClipTypes[clip->type].reservedChannels);
 	}
 
diff --git a/engines/ags/shared/ac/game_setup_struct.h b/engines/ags/shared/ac/game_setup_struct.h
index e28b95dbefb..cabc9eff3d3 100644
--- a/engines/ags/shared/ac/game_setup_struct.h
+++ b/engines/ags/shared/ac/game_setup_struct.h
@@ -90,6 +90,7 @@ struct GameSetupStruct : public GameSetupStructBase {
 	int               scoreClipID;
 	// number of allowed game audio channels (the ones under direct user control)
 	int               numGameChannels = 0;
+	int               numCompatGameChannels = 0;
 
 	// TODO: I converted original array of sprite infos to vector here, because
 	// statistically in most games sprites go in long continious sequences with minimal


Commit: bf5a649385c86fad2f9fc30f117c7eb8bc1eaff6
    https://github.com/scummvm/scummvm/commit/bf5a649385c86fad2f9fc30f117c7eb8bc1eaff6
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Managed wrapper for SpriteFileWriter

>From upstream 13d7b02a146cc669e2862064467599b10c18cbf9

Changed paths:
    engines/ags/shared/ac/sprite_file.h


diff --git a/engines/ags/shared/ac/sprite_file.h b/engines/ags/shared/ac/sprite_file.h
index 3f036aad94e..80c32cf7e23 100644
--- a/engines/ags/shared/ac/sprite_file.h
+++ b/engines/ags/shared/ac/sprite_file.h
@@ -188,7 +188,9 @@ public:
 		return _index;
 	}
 
-	// Initializes new sprite file format
+	// Initializes new sprite file format;
+	// store_flags are SpriteStorage;
+	// optionally hint how many sprites will be written.
 	void Begin(int store_flags, SpriteCompression compress, sprkey_t last_slot = -1);
 	// Writes a bitmap into file, compressing if necessary
 	void WriteBitmap(Bitmap *image);


Commit: 8d588c3a30470bf1ef1c34fe788a2af043b1d1af
    https://github.com/scummvm/scummvm/commit/8d588c3a30470bf1ef1c34fe788a2af043b1d1af
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Fixed on_key_press not called all times

>From upstream ffb73a0a7488e16b26c969b7efb3ca035f7dcea4

Changed paths:
    engines/ags/engine/main/game_run.cpp


diff --git a/engines/ags/engine/main/game_run.cpp b/engines/ags/engine/main/game_run.cpp
index 009d19b6a88..f2a615f3c98 100644
--- a/engines/ags/engine/main/game_run.cpp
+++ b/engines/ags/engine/main/game_run.cpp
@@ -308,10 +308,11 @@ bool run_service_key_controls(KeyInput &out_key) {
 		return false; // in backward mode the engine does not react to single mod keys
 
 	KeyInput ki = ags_keycode_from_scummvm(key_evt, old_keyhandle);
-	eAGSKeyCode agskey = ki.CompatKey; // use backward-compatible combined key here
-	if (agskey == eAGSKeyCodeNone)
+	if (ki.Key == eAGSKeyCodeNone)
 		return false; // should skip this key event
 
+	// Use backward-compatible combined key for service checks
+	eAGSKeyCode agskey = ki.CompatKey;
 	// LAlt or RAlt + Enter/Return
 	if ((cur_mod == Common::KBD_ALT) && agskey == eAGSKeyCodeReturn) {
 		engine_try_switch_windowed_gfxmode();


Commit: 2ab7985361c16c4b93440692ec72353bfd93e41a
    https://github.com/scummvm/scummvm/commit/2ab7985361c16c4b93440692ec72353bfd93e41a
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: Revert "Engine: fixed AdjustBitmapForUseWithDisplayMode()"

>From upstream 36e7d53fc1da189e402d9089c580d15844c6d4b5

Changed paths:
    engines/ags/engine/ac/draw.cpp


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index c1e8376698e..f442dfedb0e 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -121,8 +121,8 @@ Bitmap *convert_32_to_32bgr(Bitmap *tempbl) {
 //
 Bitmap *AdjustBitmapForUseWithDisplayMode(Bitmap *bitmap, bool has_alpha) {
 	const int bmp_col_depth = bitmap->GetColorDepth();
-	const int compat_col_depth = _G(gfxDriver)->GetCompatibleBitmapFormat(bmp_col_depth);
 	const int game_col_depth = _GP(game).GetColorDepth();
+	const int compat_col_depth = _G(gfxDriver)->GetCompatibleBitmapFormat(game_col_depth);
 
 	const bool must_switch_palette = bitmap->GetColorDepth() == 8 && game_col_depth > 8;
 	if (must_switch_palette)


Commit: ad599a6425452d154a0fbd21927b6e3fa9e44324
    https://github.com/scummvm/scummvm/commit/ad599a6425452d154a0fbd21927b6e3fa9e44324
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:39-07:00

Commit Message:
AGS: In gui clipping mode prevent listbox items drawn over scrollbar

>From upstream 37d757e88bfd7df47cf4154d37ec1a3df79e2c16

Changed paths:
    engines/ags/shared/gfx/allegro_bitmap.h
    engines/ags/shared/gui/gui_listbox.cpp


diff --git a/engines/ags/shared/gfx/allegro_bitmap.h b/engines/ags/shared/gfx/allegro_bitmap.h
index 829143ab904..cd97d5859ad 100644
--- a/engines/ags/shared/gfx/allegro_bitmap.h
+++ b/engines/ags/shared/gfx/allegro_bitmap.h
@@ -168,6 +168,7 @@ public:
 
 	//=========================================================================
 	// Clipping
+	// TODO: consider implementing push-pop clipping stack logic.
 	//=========================================================================
 	void    SetClip(const Rect &rc);
 	void    ResetClip();
diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 97276c8af6c..8fc9ebfa2f5 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -113,7 +113,8 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 	UpdateMetrics();
 
 	// draw the scroll bar in if necessary
-	if (ItemCount > VisibleItemCount && IsBorderShown() && AreArrowsShown()) {
+	bool scrollbar = (ItemCount > VisibleItemCount &&IsBorderShown() && AreArrowsShown());
+	if (scrollbar) {
 		int xstrt, ystrt;
 		ds->DrawRect(Rect(X + width - get_fixed_pixel_size(7), Y, (X + (pixel_size - 1) + width) - get_fixed_pixel_size(7), Y + height), draw_color);
 		ds->DrawRect(Rect(X + width - get_fixed_pixel_size(7), Y + height / 2, X + width, Y + height / 2 + (pixel_size - 1)), draw_color);
@@ -138,6 +139,10 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 	// FIXME: cut this out, and let editor add real items for display
 	DrawItemsFix();
 
+	Rect old_clip = ds->GetClip();
+	if (scrollbar && GUI::Options.ClipControls)
+		ds->SetClip(Rect(X, Y, right_hand_edge + 1, Y + Height - 1));
+
 	for (int item = 0; item < VisibleItemCount; ++item) {
 		if (item + TopItem >= ItemCount)
 			break;
@@ -163,6 +168,7 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 		GUI::DrawTextAlignedHor(ds, _textToDraw.GetCStr(), Font, text_color, X + 1 + pixel_size, right_hand_edge, at_y + 1,
 		                        (FrameAlignment)TextAlignment);
 	}
+	ds->SetClip(old_clip);
 
 	DrawItemsUnfix();
 }


Commit: 403892950cbaa9f18f60f6ce0308693053f8b152
    https://github.com/scummvm/scummvm/commit/403892950cbaa9f18f60f6ce0308693053f8b152
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:40-07:00

Commit Message:
AGS: Removed ListBox::DrawItemsFix, add preview items externally

>From upstream af126ccdef791d6f97a65018bc3188e9767d399f

Changed paths:
    engines/ags/engine/gui/gui_engine.cpp
    engines/ags/shared/gui/gui_listbox.cpp
    engines/ags/shared/gui/gui_listbox.h


diff --git a/engines/ags/engine/gui/gui_engine.cpp b/engines/ags/engine/gui/gui_engine.cpp
index 0c84265c0ae..bb3c5f04aca 100644
--- a/engines/ags/engine/gui/gui_engine.cpp
+++ b/engines/ags/engine/gui/gui_engine.cpp
@@ -124,14 +124,6 @@ void GUITextBox::DrawTextBoxContents(Bitmap *ds, color_t text_color) {
 	}
 }
 
-void GUIListBox::DrawItemsFix() {
-	// do nothing
-}
-
-void GUIListBox::DrawItemsUnfix() {
-	// do nothing
-}
-
 void GUIListBox::PrepareTextToDraw(const String &text) {
 	if (Flags & kGUICtrl_Translated)
 		_textToDraw = get_translation(text.GetCStr());
diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 8fc9ebfa2f5..644c506aa9e 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -136,9 +136,6 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 		right_hand_edge -= get_fixed_pixel_size(7);
 	}
 
-	// FIXME: cut this out, and let editor add real items for display
-	DrawItemsFix();
-
 	Rect old_clip = ds->GetClip();
 	if (scrollbar && GUI::Options.ClipControls)
 		ds->SetClip(Rect(X, Y, right_hand_edge + 1, Y + Height - 1));
@@ -169,8 +166,6 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 		                        (FrameAlignment)TextAlignment);
 	}
 	ds->SetClip(old_clip);
-
-	DrawItemsUnfix();
 }
 
 int GUIListBox::InsertItem(int index, const String &text) {
diff --git a/engines/ags/shared/gui/gui_listbox.h b/engines/ags/shared/gui/gui_listbox.h
index 9e737609bd2..9664857e747 100644
--- a/engines/ags/shared/gui/gui_listbox.h
+++ b/engines/ags/shared/gui/gui_listbox.h
@@ -87,9 +87,7 @@ private:
 
 	// Updates dynamic metrics such as row height and others
 	void UpdateMetrics();
-	// A temporary solution for special drawing in the Editor
-	void DrawItemsFix();
-	void DrawItemsUnfix();
+	// Applies translation
 	void PrepareTextToDraw(const String &text);
 
 	// prepared text buffer/cache


Commit: 939d116fba4310b2a7e2ca0eda33575356dbaa19
    https://github.com/scummvm/scummvm/commit/939d116fba4310b2a7e2ca0eda33575356dbaa19
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:40-07:00

Commit Message:
AGS: Fixed GUIMain::Poll(), only affect clickable controls

>From upstream 951e65274cd578b25436526dc12cc51ac5e20150

Changed paths:
    engines/ags/shared/gui/gui_main.cpp


diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index c05a9345c2c..efc0130cedd 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -297,7 +297,7 @@ void GUIMain::DrawBlob(Bitmap *ds, int x, int y, color_t draw_color) {
 void GUIMain::Poll(int mx, int my) {
 	mx -= X, my -= Y; // translate to GUI's local coordinates
 	if (mx != MouseWasAt.X || my != MouseWasAt.Y) {
-		int ctrl_index = FindControlAtLocal(mx, my, 0, false);
+		int ctrl_index = FindControlAtLocal(mx, my, 0, true);
 
 		if (MouseOverCtrl == MOVER_MOUSEDOWNLOCKED)
 			_controls[MouseDownCtrl]->OnMouseMove(mx, my);


Commit: 673c8c242ecee5e33e7fcc7f62d34e6690bbf83e
    https://github.com/scummvm/scummvm/commit/673c8c242ecee5e33e7fcc7f62d34e6690bbf83e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:40-07:00

Commit Message:
AGS: Split GUIMain::DrawAt into DrawSelf and DrawWithControls

>From upstream d353f8151d77c1c9e66f8b1aed7b24ecbadf0609

Changed paths:
    engines/ags/engine/ac/draw.cpp
    engines/ags/shared/gui/gui_main.cpp
    engines/ags/shared/gui/gui_main.h


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index f442dfedb0e..13e4ee43eb4 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1980,7 +1980,7 @@ void draw_gui_and_overlays() {
 				_G(our_eip) = 370;
 				_GP(guibg)[aa]->ClearTransparent();
 				_G(our_eip) = 372;
-				_GP(guis)[aa].DrawAt(_GP(guibg)[aa], 0, 0);
+				_GP(guis)[aa].DrawWithControls(_GP(guibg)[aa]);
 				_G(our_eip) = 373;
 
 				bool isAlpha = false;
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index efc0130cedd..e86227dc1c6 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -204,46 +204,44 @@ bool GUIMain::BringControlToFront(int32_t index) {
 	return SetControlZOrder(index, (int)_controls.size() - 1);
 }
 
-void GUIMain::Draw(Bitmap *ds) {
-	DrawAt(ds, X, Y);
-}
-
-void GUIMain::DrawAt(Bitmap *ds, int x, int y) {
-	SET_EIP(375)
+void GUIMain::DrawSelf(Bitmap *ds) {
+	SET_EIP(375);
 
 	if ((Width < 1) || (Height < 1))
 		return;
 
-	Bitmap subbmp;
-	subbmp.CreateSubBitmap(ds, RectWH(x, y, Width, Height));
-
-	SET_EIP(376)
+	SET_EIP(376);
 	// stop border being transparent, if the whole GUI isn't
 	if ((FgColor == 0) && (BgColor != 0))
 		FgColor = 16;
 
 	if (BgColor != 0)
-		subbmp.Fill(subbmp.GetCompatibleColor(BgColor));
+		ds->Fill(ds->GetCompatibleColor(BgColor));
 
-	SET_EIP(377)
+	SET_EIP(377);
 
 	color_t draw_color;
 	if (FgColor != BgColor) {
-		draw_color = subbmp.GetCompatibleColor(FgColor);
-		subbmp.DrawRect(Rect(0, 0, subbmp.GetWidth() - 1, subbmp.GetHeight() - 1), draw_color);
+		draw_color = ds->GetCompatibleColor(FgColor);
+		ds->DrawRect(Rect(0, 0, ds->GetWidth() - 1, ds->GetHeight() - 1), draw_color);
 		if (get_fixed_pixel_size(1) > 1)
-			subbmp.DrawRect(Rect(1, 1, subbmp.GetWidth() - 2, subbmp.GetHeight() - 2), draw_color);
+			ds->DrawRect(Rect(1, 1, ds->GetWidth() - 2, ds->GetHeight() - 2), draw_color);
 	}
 
-	SET_EIP(378)
+	SET_EIP(378);
 
 	if (BgImage > 0 && _GP(spriteset)[BgImage] != nullptr)
-		draw_gui_sprite(&subbmp, BgImage, 0, 0, false);
+		draw_gui_sprite(ds, BgImage, 0, 0, false);
+
+	SET_EIP(379);
+}
 
-	SET_EIP(379)
+void GUIMain::DrawWithControls(Bitmap *ds) {
+	ds->ResetClip();
+	DrawSelf(ds);
 
 	if ((_G(all_buttons_disabled) >= 0) && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
-        return; // don't draw GUI controls
+		return; // don't draw GUI controls
 
 	for (size_t ctrl_index = 0; ctrl_index < _controls.size(); ++ctrl_index) {
 		set_eip_guiobj(_ctrlDrawOrder[ctrl_index]);
@@ -256,38 +254,38 @@ void GUIMain::DrawAt(Bitmap *ds, int x, int y) {
 			continue;
 
 		if (GUI::Options.ClipControls && objToDraw->IsContentClipped())
-			subbmp.SetClip(RectWH(objToDraw->X, objToDraw->Y, objToDraw->Width, objToDraw->Height));
+			ds->SetClip(RectWH(objToDraw->X, objToDraw->Y, objToDraw->Width, objToDraw->Height));
 		else
-			subbmp.ResetClip();
-		objToDraw->Draw(&subbmp);
+			ds->ResetClip();
+		objToDraw->Draw(ds);
 
 		int selectedColour = 14;
 
 		if (HighlightCtrl == _ctrlDrawOrder[ctrl_index]) {
 			if (GUI::Options.OutlineControls)
 				selectedColour = 13;
-			draw_color = subbmp.GetCompatibleColor(selectedColour);
-			DrawBlob(&subbmp, objToDraw->X + objToDraw->Width - get_fixed_pixel_size(1) - 1, objToDraw->Y, draw_color);
-			DrawBlob(&subbmp, objToDraw->X, objToDraw->Y + objToDraw->Height - get_fixed_pixel_size(1) - 1, draw_color);
-			DrawBlob(&subbmp, objToDraw->X, objToDraw->Y, draw_color);
-			DrawBlob(&subbmp, objToDraw->X + objToDraw->Width - get_fixed_pixel_size(1) - 1,
-			         objToDraw->Y + objToDraw->Height - get_fixed_pixel_size(1) - 1, draw_color);
+			color_t draw_color = ds->GetCompatibleColor(selectedColour);
+			DrawBlob(ds, objToDraw->X + objToDraw->Width - get_fixed_pixel_size(1) - 1, objToDraw->Y, draw_color);
+			DrawBlob(ds, objToDraw->X, objToDraw->Y + objToDraw->Height - get_fixed_pixel_size(1) - 1, draw_color);
+			DrawBlob(ds, objToDraw->X, objToDraw->Y, draw_color);
+			DrawBlob(ds, objToDraw->X + objToDraw->Width - get_fixed_pixel_size(1) - 1,
+				objToDraw->Y + objToDraw->Height - get_fixed_pixel_size(1) - 1, draw_color);
 		}
 		if (GUI::Options.OutlineControls) {
 			// draw a dotted outline round all objects
-			draw_color = subbmp.GetCompatibleColor(selectedColour);
+			color_t draw_color = ds->GetCompatibleColor(selectedColour);
 			for (int i = 0; i < objToDraw->Width; i += 2) {
-				subbmp.PutPixel(i + objToDraw->X, objToDraw->Y, draw_color);
-				subbmp.PutPixel(i + objToDraw->X, objToDraw->Y + objToDraw->Height - 1, draw_color);
+				ds->PutPixel(i + objToDraw->X, objToDraw->Y, draw_color);
+				ds->PutPixel(i + objToDraw->X, objToDraw->Y + objToDraw->Height - 1, draw_color);
 			}
 			for (int i = 0; i < objToDraw->Height; i += 2) {
-				subbmp.PutPixel(objToDraw->X, i + objToDraw->Y, draw_color);
-				subbmp.PutPixel(objToDraw->X + objToDraw->Width - 1, i + objToDraw->Y, draw_color);
+				ds->PutPixel(objToDraw->X, i + objToDraw->Y, draw_color);
+				ds->PutPixel(objToDraw->X + objToDraw->Width - 1, i + objToDraw->Y, draw_color);
 			}
 		}
 	}
 
-	SET_EIP(380)
+	SET_EIP(380);
 }
 
 void GUIMain::DrawBlob(Bitmap *ds, int x, int y, color_t draw_color) {
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index c664469c271..4eae90da00d 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -125,8 +125,8 @@ public:
 
 	// Operations
 	bool    BringControlToFront(int32_t index);
-	void    Draw(Bitmap *ds);
-	void    DrawAt(Bitmap *ds, int x, int y);
+	void    DrawSelf(Bitmap *ds);
+	void    DrawWithControls(Bitmap *ds);
 	// Polls GUI state, providing current cursor (mouse) coordinates
 	void    Poll(int mx, int my);
 	HError  RebuildArray();


Commit: 62ebde86a1dca9174790727a787fae089de2c1b9
    https://github.com/scummvm/scummvm/commit/62ebde86a1dca9174790727a787fae089de2c1b9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:40-07:00

Commit Message:
AGS: Gui controls draw themselves at requested offset

>From upstream 9e9c8ffafe465b907ed0d22bcb1ba4df06803b8b

Changed paths:
    engines/ags/engine/ac/gui_inv.cpp
    engines/ags/engine/gui/gui_engine.cpp
    engines/ags/shared/gui/gui_button.cpp
    engines/ags/shared/gui/gui_button.h
    engines/ags/shared/gui/gui_inv.h
    engines/ags/shared/gui/gui_label.cpp
    engines/ags/shared/gui/gui_label.h
    engines/ags/shared/gui/gui_listbox.cpp
    engines/ags/shared/gui/gui_listbox.h
    engines/ags/shared/gui/gui_main.cpp
    engines/ags/shared/gui/gui_object.h
    engines/ags/shared/gui/gui_slider.cpp
    engines/ags/shared/gui/gui_slider.h
    engines/ags/shared/gui/gui_textbox.cpp
    engines/ags/shared/gui/gui_textbox.h


diff --git a/engines/ags/engine/ac/gui_inv.cpp b/engines/ags/engine/ac/gui_inv.cpp
index 5c314f2cc52..8c63a31eeb5 100644
--- a/engines/ags/engine/ac/gui_inv.cpp
+++ b/engines/ags/engine/ac/gui_inv.cpp
@@ -39,7 +39,7 @@ int GUIInvWindow::GetCharacterId() const {
 	return CharId;
 }
 
-void GUIInvWindow::Draw(Bitmap *ds) {
+void GUIInvWindow::Draw(Bitmap *ds, int x, int y) {
 	const bool enabled = IsGUIEnabled(this);
 	if (!enabled && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
 		return;
@@ -56,9 +56,9 @@ void GUIInvWindow::Draw(Bitmap *ds) {
 		TopItem = _GP(play).inv_top;
 
 	// draw the items
-	const int leftmost_x = X;
-	int at_x = X;
-	int at_y = Y;
+	const int leftmost_x = x;
+	int at_x = x;
+	int at_y = y;
 	int lastItem = TopItem + (ColCount * RowCount);
 	if (lastItem > _G(charextra)[GetCharacterId()].invorder_count)
 		lastItem = _G(charextra)[GetCharacterId()].invorder_count;
@@ -76,10 +76,10 @@ void GUIInvWindow::Draw(Bitmap *ds) {
 	}
 
 	if (!enabled &&
-			GUI::Options.DisabledStyle == kGuiDis_Greyout &&
-	        _GP(play).inventory_greys_out == 1) {
+		GUI::Options.DisabledStyle == kGuiDis_Greyout &&
+		_GP(play).inventory_greys_out == 1) {
 		// darken the inventory when disabled
-		GUI::DrawDisabledEffect(ds, RectWH(X, Y, Width, Height));
+		GUI::DrawDisabledEffect(ds, RectWH(x, y, Width, Height));
 	}
 }
 
diff --git a/engines/ags/engine/gui/gui_engine.cpp b/engines/ags/engine/gui/gui_engine.cpp
index bb3c5f04aca..5f968a2c8e5 100644
--- a/engines/ags/engine/gui/gui_engine.cpp
+++ b/engines/ags/engine/gui/gui_engine.cpp
@@ -114,12 +114,12 @@ size_t GUILabel::SplitLinesForDrawing(SplitLines &lines) {
 	return break_up_text_into_lines(_textToDraw.GetCStr(), lines, Width, Font);
 }
 
-void GUITextBox::DrawTextBoxContents(Bitmap *ds, color_t text_color) {
-	wouttext_outline(ds, X + 1 + get_fixed_pixel_size(1), Y + 1 + get_fixed_pixel_size(1), Font, text_color, Text.GetCStr());
+void GUITextBox::DrawTextBoxContents(Bitmap *ds, int x, int y, color_t text_color) {
+	wouttext_outline(ds, x + 1 + get_fixed_pixel_size(1), y + 1 + get_fixed_pixel_size(1), Font, text_color, Text.GetCStr());
 	if (IsGUIEnabled(this)) {
 		// draw a cursor
-		int draw_at_x = get_text_width(Text.GetCStr(), Font) + X + 3;
-		int draw_at_y = Y + 1 + get_font_height(Font);
+		int draw_at_x = get_text_width(Text.GetCStr(), Font) + x + 3;
+		int draw_at_y = y + 1 + get_font_height(Font);
 		ds->DrawRect(Rect(draw_at_x, draw_at_y, draw_at_x + get_fixed_pixel_size(5), draw_at_y + (get_fixed_pixel_size(1) - 1)), text_color);
 	}
 }
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index 9c9d611b364..eb6784995c3 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -93,7 +93,7 @@ bool GUIButton::IsClippingImage() const {
 	return (Flags & kGUICtrl_Clip) != 0;
 }
 
-void GUIButton::Draw(Bitmap *ds) {
+void GUIButton::Draw(Bitmap *ds, int x, int y) {
 	bool draw_disabled = !IsGUIEnabled(this);
 
 	// if it's "Unchanged when disabled" or "GUI Off", don't grey out
@@ -111,10 +111,10 @@ void GUIButton::Draw(Bitmap *ds) {
 
 	// CHECKME: why testing both CurrentImage and Image?
 	if (CurrentImage > 0 && IsImageButton())
-		DrawImageButton(ds, draw_disabled);
+		DrawImageButton(ds, x, y, draw_disabled);
 	// CHECKME: why don't draw frame if no Text? this will make button completely invisible!
 	else if (!_text.IsEmpty())
-		DrawTextButton(ds, draw_disabled);
+		DrawTextButton(ds, x, y, draw_disabled);
 }
 
 void GUIButton::SetClipImage(bool on) {
@@ -282,19 +282,19 @@ void GUIButton::WriteToSavegame(Stream *out) const {
 	out->WriteInt32(CurrentImage);
 }
 
-void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
+void GUIButton::DrawImageButton(Bitmap *ds, int x, int y, bool draw_disabled) {
 	// NOTE: the CLIP flag only clips the image, not the text
 	if (IsClippingImage() && !GUI::Options.ClipControls)
-		ds->SetClip(RectWH(X, Y, Width, Height));
+		ds->SetClip(RectWH(x, y, Width, Height));
 	if (_GP(spriteset)[CurrentImage] != nullptr)
-		draw_gui_sprite(ds, CurrentImage, X, Y, true);
+		draw_gui_sprite(ds, CurrentImage, x, y, true);
 
 	// Draw active inventory item
 	if (_placeholder != kButtonPlace_None && _G(gui_inv_pic) >= 0) {
 		GUIButtonPlaceholder place = _placeholder;
 		if (place == kButtonPlace_InvItemAuto) {
 			if ((get_adjusted_spritewidth(_G(gui_inv_pic)) > Width - 6) ||
-			        (get_adjusted_spriteheight(_G(gui_inv_pic)) > Height - 6)) {
+				(get_adjusted_spriteheight(_G(gui_inv_pic)) > Height - 6)) {
 				place = kButtonPlace_InvItemStretch;
 			} else {
 				place = kButtonPlace_InvItemCenter;
@@ -302,38 +302,39 @@ void GUIButton::DrawImageButton(Bitmap *ds, bool draw_disabled) {
 		}
 
 		if (place == kButtonPlace_InvItemStretch) {
-			ds->StretchBlt(_GP(spriteset)[_G(gui_inv_pic)], RectWH(X + 3, Y + 3, Width - 6, Height - 6), Shared::kBitmap_Transparency);
+			ds->StretchBlt(_GP(spriteset)[_G(gui_inv_pic)], RectWH(x + 3, y + 3, Width - 6, Height - 6),
+				kBitmap_Transparency);
 		} else if (place == kButtonPlace_InvItemCenter) {
 			draw_gui_sprite(ds, _G(gui_inv_pic),
-			                X + Width / 2 - get_adjusted_spritewidth(_G(gui_inv_pic)) / 2,
-			                Y + Height / 2 - get_adjusted_spriteheight(_G(gui_inv_pic)) / 2,
-			                true);
+				x + Width / 2 - get_adjusted_spritewidth(_G(gui_inv_pic)) / 2,
+				y + Height / 2 - get_adjusted_spriteheight(_G(gui_inv_pic)) / 2,
+				true);
 		}
 	}
 
 	if ((draw_disabled) && (GUI::Options.DisabledStyle == kGuiDis_Greyout)) {
 		// darken the button when disabled
-		GUI::DrawDisabledEffect(ds, RectWH(X, Y,
-		                                   _GP(spriteset)[CurrentImage]->GetWidth(),
-		                                   _GP(spriteset)[CurrentImage]->GetHeight()));
+		GUI::DrawDisabledEffect(ds, RectWH(x, y,
+			_GP(spriteset)[CurrentImage]->GetWidth(),
+			_GP(spriteset)[CurrentImage]->GetHeight()));
 	}
 
 	// Don't print Text of (INV) (INVSHR) (INVNS)
 	if (_placeholder == kButtonPlace_None && !_unnamed)
-		DrawText(ds, draw_disabled);
+		DrawText(ds, x, y, draw_disabled);
 
 	if (IsClippingImage() && !GUI::Options.ClipControls)
 		ds->ResetClip();
 }
 
-void GUIButton::DrawText(Bitmap *ds, bool draw_disabled) {
+void GUIButton::DrawText(Bitmap *ds, int x, int y, bool draw_disabled) {
 	if (_text.IsEmpty())
 		return;
 	// TODO: need to find a way to cache Text prior to drawing;
 	// but that will require to update all gui controls when translation is changed in game
 	PrepareTextToDraw();
 
-	Rect frame = RectWH(X + 2, Y + 2, Width - 4, Height - 4);
+	Rect frame = RectWH(x + 2, y + 2, Width - 4, Height - 4);
 	if (IsPushed && IsMouseOver) {
 		// move the Text a bit while pushed
 		frame.Left++;
@@ -345,12 +346,12 @@ void GUIButton::DrawText(Bitmap *ds, bool draw_disabled) {
 	GUI::DrawTextAligned(ds, _textToDraw.GetCStr(), Font, text_color, frame, TextAlignment);
 }
 
-void GUIButton::DrawTextButton(Bitmap *ds, bool draw_disabled) {
+void GUIButton::DrawTextButton(Bitmap *ds, int x, int y, bool draw_disabled) {
 	color_t draw_color = ds->GetCompatibleColor(7);
-	ds->FillRect(Rect(X, Y, X + Width - 1, Y + Height - 1), draw_color);
+	ds->FillRect(Rect(x, y, x + Width - 1, y + Height - 1), draw_color);
 	if (Flags & kGUICtrl_Default) {
 		draw_color = ds->GetCompatibleColor(16);
-		ds->DrawRect(Rect(X - 1, Y - 1, X + Width, Y + Height), draw_color);
+		ds->DrawRect(Rect(x - 1, y - 1, x + Width, y + Height), draw_color);
 	}
 
 	// TODO: use color constants instead of literal numbers
@@ -359,18 +360,18 @@ void GUIButton::DrawTextButton(Bitmap *ds, bool draw_disabled) {
 	else
 		draw_color = ds->GetCompatibleColor(8);
 
-	ds->DrawLine(Line(X, Y + Height - 1, X + Width - 1, Y + Height - 1), draw_color);
-	ds->DrawLine(Line(X + Width - 1, Y, X + Width - 1, Y + Height - 1), draw_color);
+	ds->DrawLine(Line(x, y + Height - 1, x + Width - 1, y + Height - 1), draw_color);
+	ds->DrawLine(Line(x + Width - 1, y, x + Width - 1, y + Height - 1), draw_color);
 
 	if (draw_disabled || (IsMouseOver && IsPushed))
 		draw_color = ds->GetCompatibleColor(8);
 	else
 		draw_color = ds->GetCompatibleColor(15);
 
-	ds->DrawLine(Line(X, Y, X + Width - 1, Y), draw_color);
-	ds->DrawLine(Line(X, Y, X, Y + Height - 1), draw_color);
+	ds->DrawLine(Line(x, y, x + Width - 1, y), draw_color);
+	ds->DrawLine(Line(x, y, x, y + Height - 1), draw_color);
 
-	DrawText(ds, draw_disabled);
+	DrawText(ds, x, y, draw_disabled);
 }
 
 } // namespace Shared
diff --git a/engines/ags/shared/gui/gui_button.h b/engines/ags/shared/gui/gui_button.h
index 3e0f0c133ac..df154a267fc 100644
--- a/engines/ags/shared/gui/gui_button.h
+++ b/engines/ags/shared/gui/gui_button.h
@@ -67,7 +67,7 @@ public:
 	bool IsClippingImage() const;
 
 	// Operations
-	void Draw(Bitmap *ds) override;
+	void Draw(Bitmap *ds, int x = 0, int y = 0) override;
 	void SetClipImage(bool on);
 	void SetText(const String &text);
 
@@ -102,9 +102,9 @@ public:
 	bool        IsMouseOver;
 
 private:
-	void DrawImageButton(Bitmap *ds, bool draw_disabled);
-	void DrawText(Bitmap *ds, bool draw_disabled);
-	void DrawTextButton(Bitmap *ds, bool draw_disabled);
+	void DrawImageButton(Bitmap *ds, int x, int y, bool draw_disabled);
+	void DrawText(Bitmap *ds, int x, int y, bool draw_disabled);
+	void DrawTextButton(Bitmap *ds, int x, int y, bool draw_disabled);
 	void PrepareTextToDraw();
 
 	// Defines button placeholder mode; the mode is set
diff --git a/engines/ags/shared/gui/gui_inv.h b/engines/ags/shared/gui/gui_inv.h
index 180e38cfd28..6d4f4e814e6 100644
--- a/engines/ags/shared/gui/gui_inv.h
+++ b/engines/ags/shared/gui/gui_inv.h
@@ -38,7 +38,7 @@ public:
 
 	// Operations
 	// This function has distinct implementations in Engine and Editor
-	void Draw(Bitmap *ds) override;
+	void Draw(Bitmap *ds, int x = 0, int y = 0) override;
 
 	// Events
 	void OnMouseEnter() override;
diff --git a/engines/ags/shared/gui/gui_label.cpp b/engines/ags/shared/gui/gui_label.cpp
index 7cb91f27d28..481bb3e5214 100644
--- a/engines/ags/shared/gui/gui_label.cpp
+++ b/engines/ags/shared/gui/gui_label.cpp
@@ -48,7 +48,7 @@ GUILabelMacro GUILabel::GetTextMacros() const {
 	return _textMacro;
 }
 
-void GUILabel::Draw(Shared::Bitmap *ds) {
+void GUILabel::Draw(Bitmap *ds, int x, int y) {
 	// TODO: need to find a way to cache text prior to drawing;
 	// but that will require to update all gui controls when translation is changed in game
 	PrepareTextToDraw();
@@ -62,12 +62,12 @@ void GUILabel::Draw(Shared::Bitmap *ds) {
 		get_font_linespacing(Font);
 	// < 2.72 labels did not limit vertical size of text
 	const bool limit_by_label_frame = _G(loaded_game_file_version) >= kGameVersion_272;
-	int at_y = Y;
+	int at_y = y;
 	for (size_t i = 0;
-	        i < _GP(Lines).Count() && (!limit_by_label_frame || at_y <= Y + Height);
-	        ++i, at_y += linespacing) {
-		GUI::DrawTextAlignedHor(ds, _GP(Lines)[i].GetCStr(), Font, text_color, X, X + Width - 1, at_y,
-		                        (FrameAlignment)TextAlignment);
+		i < _GP(Lines).Count() && (!limit_by_label_frame || at_y <= y + Height);
+		++i, at_y += linespacing) {
+		GUI::DrawTextAlignedHor(ds, _GP(Lines)[i].GetCStr(), Font, text_color, x, x + Width - 1, at_y,
+			(FrameAlignment)TextAlignment);
 	}
 }
 
diff --git a/engines/ags/shared/gui/gui_label.h b/engines/ags/shared/gui/gui_label.h
index d3bfdce2320..7dc68c1700e 100644
--- a/engines/ags/shared/gui/gui_label.h
+++ b/engines/ags/shared/gui/gui_label.h
@@ -43,7 +43,7 @@ public:
 	GUILabelMacro GetTextMacros() const;
 
 	// Operations
-	void Draw(Bitmap *ds) override;
+	void Draw(Bitmap *ds, int x = 0, int y = 0) override;
 	void SetText(const String &text);
 
 	// Serialization
diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 644c506aa9e..3557d018ea0 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -93,7 +93,7 @@ void GUIListBox::Clear() {
 	NotifyParentChanged();
 }
 
-void GUIListBox::Draw(Shared::Bitmap *ds) {
+void GUIListBox::Draw(Bitmap *ds, int x, int y) {
 	const int width = Width - 1;
 	const int height = Height - 1;
 	const int pixel_size = get_fixed_pixel_size(1);
@@ -101,60 +101,59 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 	color_t text_color = ds->GetCompatibleColor(TextColor);
 	color_t draw_color = ds->GetCompatibleColor(TextColor);
 	if (IsBorderShown()) {
-		ds->DrawRect(Rect(X, Y, X + width + (pixel_size - 1), Y + height + (pixel_size - 1)), draw_color);
+		ds->DrawRect(Rect(x, y, x + width + (pixel_size - 1), y + height + (pixel_size - 1)), draw_color);
 		if (pixel_size > 1)
-			ds->DrawRect(Rect(X + 1, Y + 1, X + width, Y + height), draw_color);
+			ds->DrawRect(Rect(x + 1, y + 1, x + width, y + height), draw_color);
 	}
 
-	int right_hand_edge = (X + width) - pixel_size - 1;
+	int right_hand_edge = (x + width) - pixel_size - 1;
 
 	// update the RowHeight and VisibleItemCount
 	// FIXME: find a way to update this whenever relevant things change in the engine
 	UpdateMetrics();
 
 	// draw the scroll bar in if necessary
-	bool scrollbar = (ItemCount > VisibleItemCount &&IsBorderShown() && AreArrowsShown());
+	bool scrollbar = (ItemCount > VisibleItemCount) && IsBorderShown() && AreArrowsShown();
 	if (scrollbar) {
 		int xstrt, ystrt;
-		ds->DrawRect(Rect(X + width - get_fixed_pixel_size(7), Y, (X + (pixel_size - 1) + width) - get_fixed_pixel_size(7), Y + height), draw_color);
-		ds->DrawRect(Rect(X + width - get_fixed_pixel_size(7), Y + height / 2, X + width, Y + height / 2 + (pixel_size - 1)), draw_color);
+		ds->DrawRect(Rect(x + width - get_fixed_pixel_size(7), y, (x + (pixel_size - 1) + width) - get_fixed_pixel_size(7), y + height), draw_color);
+		ds->DrawRect(Rect(x + width - get_fixed_pixel_size(7), y + height / 2, x + width, y + height / 2 + (pixel_size - 1)), draw_color);
 
-		xstrt = (X + width - get_fixed_pixel_size(6)) + (pixel_size - 1);
-		ystrt = (Y + height - 3) - get_fixed_pixel_size(5);
+		xstrt = (x + width - get_fixed_pixel_size(6)) + (pixel_size - 1);
+		ystrt = (y + height - 3) - get_fixed_pixel_size(5);
 
 		draw_color = ds->GetCompatibleColor(TextColor);
 		ds->DrawTriangle(Triangle(xstrt, ystrt, xstrt + get_fixed_pixel_size(4), ystrt,
-		                          xstrt + get_fixed_pixel_size(2),
-		                          ystrt + get_fixed_pixel_size(5)), draw_color);
+			xstrt + get_fixed_pixel_size(2),
+			ystrt + get_fixed_pixel_size(5)), draw_color);
 
-		ystrt = Y + 3;
+		ystrt = y + 3;
 		ds->DrawTriangle(Triangle(xstrt, ystrt + get_fixed_pixel_size(5),
-		                          xstrt + get_fixed_pixel_size(4),
-		                          ystrt + get_fixed_pixel_size(5),
-		                          xstrt + get_fixed_pixel_size(2), ystrt), draw_color);
+			xstrt + get_fixed_pixel_size(4),
+			ystrt + get_fixed_pixel_size(5),
+			xstrt + get_fixed_pixel_size(2), ystrt), draw_color);
 
 		right_hand_edge -= get_fixed_pixel_size(7);
 	}
 
 	Rect old_clip = ds->GetClip();
 	if (scrollbar && GUI::Options.ClipControls)
-		ds->SetClip(Rect(X, Y, right_hand_edge + 1, Y + Height - 1));
-
+		ds->SetClip(Rect(x, y, right_hand_edge + 1, y + Height - 1));
 	for (int item = 0; item < VisibleItemCount; ++item) {
 		if (item + TopItem >= ItemCount)
 			break;
 
-		int at_y = Y + pixel_size + item * RowHeight;
+		int at_y = y + pixel_size + item * RowHeight;
 		if (item + TopItem == SelectedItem) {
 			text_color = ds->GetCompatibleColor(SelectedTextColor);
 			if (SelectedBgColor > 0) {
-				int stretch_to = (X + width) - pixel_size;
+				int stretch_to = (x + width) - pixel_size;
 				// draw the SelectedItem item bar (if colour not transparent)
 				draw_color = ds->GetCompatibleColor(SelectedBgColor);
 				if ((VisibleItemCount < ItemCount) && IsBorderShown() && AreArrowsShown())
 					stretch_to -= get_fixed_pixel_size(7);
 
-				ds->FillRect(Rect(X + pixel_size, at_y, stretch_to, at_y + RowHeight - pixel_size), draw_color);
+				ds->FillRect(Rect(x + pixel_size, at_y, stretch_to, at_y + RowHeight - pixel_size), draw_color);
 			}
 		} else
 			text_color = ds->GetCompatibleColor(TextColor);
@@ -162,8 +161,8 @@ void GUIListBox::Draw(Shared::Bitmap *ds) {
 		int item_index = item + TopItem;
 		PrepareTextToDraw(Items[item_index]);
 
-		GUI::DrawTextAlignedHor(ds, _textToDraw.GetCStr(), Font, text_color, X + 1 + pixel_size, right_hand_edge, at_y + 1,
-		                        (FrameAlignment)TextAlignment);
+		GUI::DrawTextAlignedHor(ds, _textToDraw.GetCStr(), Font, text_color, x + 1 + pixel_size, right_hand_edge, at_y + 1,
+			(FrameAlignment)TextAlignment);
 	}
 	ds->SetClip(old_clip);
 }
diff --git a/engines/ags/shared/gui/gui_listbox.h b/engines/ags/shared/gui/gui_listbox.h
index 9664857e747..8a712fddafe 100644
--- a/engines/ags/shared/gui/gui_listbox.h
+++ b/engines/ags/shared/gui/gui_listbox.h
@@ -43,7 +43,7 @@ public:
 	// Operations
 	int  AddItem(const String &text);
 	void Clear();
-	void Draw(Bitmap *ds) override;
+	void Draw(Bitmap *ds, int x = 0, int y = 0) override;
 	int  InsertItem(int index, const String &text);
 	void RemoveItem(int index);
 	void SetShowArrows(bool on);
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index e86227dc1c6..f4ecec0038c 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -257,7 +257,7 @@ void GUIMain::DrawWithControls(Bitmap *ds) {
 			ds->SetClip(RectWH(objToDraw->X, objToDraw->Y, objToDraw->Width, objToDraw->Height));
 		else
 			ds->ResetClip();
-		objToDraw->Draw(ds);
+		objToDraw->Draw(ds, objToDraw->X, objToDraw->Y);
 
 		int selectedColour = 14;
 
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index e68378c7eaf..76753927102 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -64,7 +64,8 @@ public:
     virtual bool    IsContentClipped() const { return true; }
 
 	// Operations
-	virtual void    Draw(Bitmap *) {
+	virtual void    Draw(Bitmap *ds, int x = 0, int y = 0) {
+		(void)ds; (void)x; (void)y;
 	}
 	void            SetClickable(bool on);
 	void            SetEnabled(bool on);
diff --git a/engines/ags/shared/gui/gui_slider.cpp b/engines/ags/shared/gui/gui_slider.cpp
index 1951d78b4e0..11e6197299c 100644
--- a/engines/ags/shared/gui/gui_slider.cpp
+++ b/engines/ags/shared/gui/gui_slider.cpp
@@ -56,7 +56,7 @@ bool GUISlider::IsOverControl(int x, int y, int leeway) const {
 	return _cachedHandle.IsInside(Point(x, y));
 }
 
-void GUISlider::Draw(Shared::Bitmap *ds) {
+void GUISlider::Draw(Bitmap *ds, int x, int y) {
 	// Clamp Value
 	// TODO: this is necessary here because some Slider fields are still public
 	if (MinValue >= MaxValue)
@@ -95,7 +95,7 @@ void GUISlider::Draw(Shared::Bitmap *ds) {
 	if (IsHorizontal()) // horizontal slider
 	{
 		// Value pos is a coordinate corresponding to current slider's value
-		bar = RectWH(X + 1, Y + Height / 2 - thick_f, Width - 1, bar_thick);
+		bar = RectWH(x + 1, y + Height / 2 - thick_f, Width - 1, bar_thick);
 		handle_range = Width - 4;
 		int value_pos = (int)(((float)(Value - MinValue) * (float)handle_range) / (float)(MaxValue - MinValue));
 		handle = RectWH((bar.Left + get_fixed_pixel_size(2)) - (handle_sz.Width / 2) + 1 + value_pos - 2,
@@ -105,7 +105,7 @@ void GUISlider::Draw(Shared::Bitmap *ds) {
 	}
 	// vertical slider
 	else {
-		bar = RectWH(X + Width / 2 - thick_f, Y + 1, bar_thick, Height - 1);
+		bar = RectWH(x + Width / 2 - thick_f, y + 1, bar_thick, Height - 1);
 		handle_range = Height - 4;
 		int value_pos = (int)(((float)(MaxValue - Value) * (float)handle_range) / (float)(MaxValue - MinValue));
 		handle = RectWH(bar.Left + (bar.GetWidth() - handle_sz.Width) / 2,
@@ -122,11 +122,11 @@ void GUISlider::Draw(Shared::Bitmap *ds) {
 		if (IsHorizontal()) {
 			x_inc = get_adjusted_spritewidth(BgImage);
 			// centre the image vertically
-			bar.Top = Y + (Height / 2) - get_adjusted_spriteheight(BgImage) / 2;
+			bar.Top = y + (Height / 2) - get_adjusted_spriteheight(BgImage) / 2;
 		} else {
 			y_inc = get_adjusted_spriteheight(BgImage);
 			// centre the image horizontally
-			bar.Left = X + (Width / 2) - get_adjusted_spritewidth(BgImage) / 2;
+			bar.Left = x + (Width / 2) - get_adjusted_spritewidth(BgImage) / 2;
 		}
 		int cx = bar.Left;
 		int cy = bar.Top;
diff --git a/engines/ags/shared/gui/gui_slider.h b/engines/ags/shared/gui/gui_slider.h
index 8ea4d1dc71b..59ffbf07a55 100644
--- a/engines/ags/shared/gui/gui_slider.h
+++ b/engines/ags/shared/gui/gui_slider.h
@@ -41,7 +41,7 @@ public:
 	bool IsOverControl(int x, int y, int leeway) const override;
 
 	// Operations
-	void Draw(Bitmap *ds) override;
+	void Draw(Bitmap *ds, int x = 0, int y = 0) override;
 
 	// Events
 	bool OnMouseDown() override;
diff --git a/engines/ags/shared/gui/gui_textbox.cpp b/engines/ags/shared/gui/gui_textbox.cpp
index 3e390683ebe..8e7a8b67ec8 100644
--- a/engines/ags/shared/gui/gui_textbox.cpp
+++ b/engines/ags/shared/gui/gui_textbox.cpp
@@ -47,16 +47,16 @@ bool GUITextBox::IsBorderShown() const {
 	return (TextBoxFlags & kTextBox_ShowBorder) != 0;
 }
 
-void GUITextBox::Draw(Bitmap *ds) {
+void GUITextBox::Draw(Bitmap *ds, int x, int y) {
 	color_t text_color = ds->GetCompatibleColor(TextColor);
 	color_t draw_color = ds->GetCompatibleColor(TextColor);
 	if (IsBorderShown()) {
-		ds->DrawRect(RectWH(X, Y, Width, Height), draw_color);
+		ds->DrawRect(RectWH(x, y, Width, Height), draw_color);
 		if (get_fixed_pixel_size(1) > 1) {
-			ds->DrawRect(Rect(X + 1, Y + 1, X + Width - get_fixed_pixel_size(1), Y + Height - get_fixed_pixel_size(1)), draw_color);
+			ds->DrawRect(Rect(x + 1, y + 1, x + Width - get_fixed_pixel_size(1), y + Height - get_fixed_pixel_size(1)), draw_color);
 		}
 	}
-	DrawTextBoxContents(ds, text_color);
+	DrawTextBoxContents(ds, x, y, text_color);
 }
 
 // TODO: a shared utility function
diff --git a/engines/ags/shared/gui/gui_textbox.h b/engines/ags/shared/gui/gui_textbox.h
index eccb57ef851..b90bfd59c8c 100644
--- a/engines/ags/shared/gui/gui_textbox.h
+++ b/engines/ags/shared/gui/gui_textbox.h
@@ -37,7 +37,7 @@ public:
 	bool IsBorderShown() const;
 
 	// Operations
-	void Draw(Bitmap *ds) override;
+	void Draw(Bitmap *ds, int x = 0, int y = 0) override;
 	void SetShowBorder(bool on);
 
 	// Events
@@ -58,7 +58,7 @@ public:
 private:
 	int32_t TextBoxFlags;
 
-	void DrawTextBoxContents(Bitmap *ds, color_t text_color);
+	void DrawTextBoxContents(Bitmap *ds, int x, int y, color_t text_color);
 };
 
 } // namespace Shared


Commit: c768b94cf681500e71e00f5d26f04bba6a435cba
    https://github.com/scummvm/scummvm/commit/c768b94cf681500e71e00f5d26f04bba6a435cba
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-04-29T22:20:41-07:00

Commit Message:
AGS: Draw GUI Controls on separate textures

>From upstream 5cbe36626842ddd900cbda8fd4b6ddfc3804456f

Changed paths:
    engines/ags/engine/ac/draw.cpp
    engines/ags/globals.cpp
    engines/ags/globals.h
    engines/ags/shared/gui/gui_main.cpp
    engines/ags/shared/gui/gui_main.h
    engines/ags/shared/gui/gui_object.cpp
    engines/ags/shared/gui/gui_object.h


diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 13e4ee43eb4..62025f7069e 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -61,6 +61,7 @@
 #include "ags/engine/debugging/debug_log.h"
 #include "ags/shared/font/fonts.h"
 #include "ags/shared/gui/gui_main.h"
+#include "ags/shared/gui/gui_object.h"
 #include "ags/engine/platform/base/ags_platform_driver.h"
 #include "ags/plugins/ags_plugin.h"
 #include "ags/plugins/plugin_engine.h"
@@ -370,6 +371,16 @@ void init_game_drawdata() {
 	_GP(actspswbcache).resize(actsps_num);
 	_GP(guibg).resize(_GP(game).numgui);
 	_GP(guibgbmp).resize(_GP(game).numgui);
+
+	size_t guio_num = 0;
+	// Prepare GUI cache lists and build the quick reference for controls cache
+	_GP(guiobjbmpref).resize(_GP(game).numgui);
+	for (const auto &gui : _GP(guis)) {
+		_GP(guiobjbmpref)[gui.ID] = guio_num;
+		guio_num += gui.GetControlCount();
+	}
+	_GP(guiobjbg).resize(guio_num);
+	_GP(guiobjbmp).resize(guio_num);
 }
 
 void dispose_game_drawdata() {
@@ -382,6 +393,10 @@ void dispose_game_drawdata() {
 	_GP(actspswbcache).clear();
 	_GP(guibg).clear();
 	_GP(guibgbmp).clear();
+
+	_GP(guiobjbg).clear();
+	_GP(guiobjbmp).clear();
+	_GP(guiobjbmpref).clear();
 }
 
 static void dispose_debug_room_drawdata() {
@@ -432,6 +447,14 @@ void clear_drawobj_cache() {
 		_GP(guibgbmp)[i] = nullptr;
 	}
 
+	for (uint i = 0; i < _GP(guiobjbg).size(); ++i) {
+		delete _GP(guiobjbg)[i];
+		_GP(guiobjbg)[i] = nullptr;
+		if (_GP(guiobjbmp)[i])
+			_G(gfxDriver)->DestroyDDB(_GP(guiobjbmp)[i]);
+		_GP(guiobjbmp)[i] = nullptr;
+	}
+
 	dispose_debug_room_drawdata();
 }
 
@@ -747,6 +770,7 @@ static void clear_draw_list() {
 }
 
 static void add_thing_to_draw(IDriverDependantBitmap *bmp, int x, int y) {
+	assert(bmp != nullptr);
 	SpriteListEntry sprite;
 	sprite.bmp = bmp;
 	sprite.x = x;
@@ -1007,14 +1031,12 @@ Bitmap *recycle_bitmap(Bitmap *bimp, int coldep, int wid, int hit, bool make_tra
 }
 
 // Allocates texture for the GUI
-void recreate_guibg_image(GUIMain *tehgui) {
-	int ifn = tehgui->ID;
-	delete _GP(guibg)[ifn];
-	_GP(guibg)[ifn] = CreateCompatBitmap(tehgui->Width, tehgui->Height);
-
-	if (_GP(guibgbmp)[ifn] != nullptr) {
-		_G(gfxDriver)->DestroyDDB(_GP(guibgbmp)[ifn]);
-		_GP(guibgbmp)[ifn] = nullptr;
+void recreate_drawobj_bitmap(Bitmap *&raw, IDriverDependantBitmap *&ddb, int width, int height) {
+	delete raw;
+	raw = CreateCompatBitmap(width, height);
+	if (ddb != nullptr) {
+		_G(gfxDriver)->DestroyDDB(ddb);
+		ddb = nullptr;
 	}
 }
 
@@ -1933,8 +1955,45 @@ void draw_fps(const Rect &viewport) {
 	invalidate_sprite_glob(1, yp, ddb);
 }
 
+// Draw GUI controls as separate sprites
+void draw_gui_controls(GUIMain &gui) {
+	if (_G(all_buttons_disabled) && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
+		return; // don't draw GUI controls
+
+	int draw_index = _GP(guiobjbmpref)[gui.ID];
+	for (int i = 0; i < gui.GetControlCount(); ++i, ++draw_index) {
+		GUIObject *obj = gui.GetControl(i);
+		if (_GP(guiobjbg)[draw_index] == nullptr ||
+			_GP(guiobjbg)[draw_index]->GetSize() != Size(obj->Width, obj->Height)) {
+			recreate_drawobj_bitmap(_GP(guiobjbg)[draw_index], _GP(guiobjbmp)[draw_index],
+				obj->Width, obj->Height);
+		}
+
+		if (!obj->IsVisible() ||
+			(!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
+			continue;
+
+		_GP(guiobjbg)[draw_index]->ClearTransparent();
+		obj->Draw(_GP(guiobjbg)[draw_index]);
+
+		if (_GP(guiobjbmp)[draw_index] != nullptr)
+			_G(gfxDriver)->UpdateDDBFromBitmap(_GP(guiobjbmp)[draw_index], _GP(guiobjbg)[draw_index], obj->HasAlphaChannel());
+		else
+			_GP(guiobjbmp)[draw_index] = _G(gfxDriver)->CreateDDBFromBitmap(_GP(guiobjbg)[draw_index], obj->HasAlphaChannel());
+	}
+}
+
 // Draw GUI and overlays of all kinds, anything outside the room space
 void draw_gui_and_overlays() {
+	// Draw gui controls on separate textures if:
+	// - it is a 3D renderer (software one may require adjustments -- needs testing)
+	// - not legacy alpha blending (may we implement specific texture blend?)
+	// - gui controls clipping is on (need to implement content size calc for all controls)
+	const bool draw_controls_as_textures =
+		_G(gfxDriver)->HasAcceleratedTransform()
+		&& (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper)
+		&& (_GP(game).options[OPT_CLIPGUICONTROLS] != 0);
+
 	if (pl_any_want_hook(AGSE_PREGUIDRAW))
 		add_render_stage(AGSE_PREGUIDRAW);
 
@@ -1973,14 +2032,20 @@ void draw_gui_and_overlays() {
 
 				_GP(guis)[aa].ClearChanged();
 				if (_GP(guibg)[aa] == nullptr ||
-					_GP(guibg)[aa]->GetSize() != Size(_GP(guis)[aa].Width, _GP(guis)[aa].Height))
-					recreate_guibg_image(&_GP(guis)[aa]);
+					_GP(guibg)[aa]->GetSize() != Size(_GP(guis)[aa].Width, _GP(guis)[aa].Height)) {
+					recreate_drawobj_bitmap(_GP(guibg)[aa], _GP(guibgbmp)[aa], _GP(guis)[aa].Width, _GP(guis)[aa].Height);
+				}
 
 				_G(eip_guinum) = aa;
 				_G(our_eip) = 370;
 				_GP(guibg)[aa]->ClearTransparent();
 				_G(our_eip) = 372;
-				_GP(guis)[aa].DrawWithControls(_GP(guibg)[aa]);
+				if (draw_controls_as_textures) {
+					_GP(guis)[aa].DrawSelf(_GP(guibg)[aa]);
+					draw_gui_controls(_GP(guis)[aa]);
+				} else {
+					_GP(guis)[aa].DrawWithControls(_GP(guibg)[aa]);
+				}
 				_G(our_eip) = 373;
 
 				bool isAlpha = false;
@@ -2016,6 +2081,21 @@ void draw_gui_and_overlays() {
 
 			_GP(guibgbmp)[aa]->SetTransparency(_GP(guis)[aa].Transparency);
 			add_to_sprite_list(_GP(guibgbmp)[aa], _GP(guis)[aa].X, _GP(guis)[aa].Y, _GP(guis)[aa].ZOrder, false);
+
+			// Add all the gui controls as separate textures
+			if (draw_controls_as_textures &&
+				!(_G(all_buttons_disabled) && (GUI::Options.DisabledStyle == kGuiDis_Blackout))) {
+				const int draw_index = _GP(guiobjbmpref)[aa];
+				for (const auto &obj_id : _GP(guis)[aa].GetControlsDrawOrder()) {
+					GUIObject *obj = _GP(guis)[aa].GetControl(obj_id);
+					if (!obj->IsVisible() ||
+						(!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
+						continue;
+					_GP(guiobjbmp)[draw_index + obj_id]->SetTransparency(_GP(guis)[aa].Transparency);
+					add_to_sprite_list(_GP(guiobjbmp)[draw_index + obj_id],
+						_GP(guis)[aa].X + obj->X, _GP(guis)[aa].Y + obj->Y, _GP(guis)[aa].ZOrder, false);
+				}
+			}
 		}
 
 		// Poll the GUIs
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index 6fc0a768aae..4a6f71c4f05 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -188,6 +188,10 @@ Globals::Globals() {
 	for (int i = 0; i < PALETTE_COUNT; ++i)
 		_palette[i].clear();
 
+	_guiobjbg = new std::vector<Shared::Bitmap *>();
+	_guiobjbmp = new std::vector<Engine::IDriverDependantBitmap *>();
+	_guiobjbmpref = new std::vector<int>();
+
 	// draw_software.cpp globals
 	_BlackRects = new DirtyRects();
 	_GlobalOffs = new Point();
@@ -437,6 +441,9 @@ Globals::~Globals() {
 	delete[] _dynamicallyCreatedSurfaces;
 	delete[] _palette;
 	delete _maincoltable;
+	delete _guiobjbg;
+	delete _guiobjbmp;
+	delete _guiobjbmpref;
 
 	// draw_software.cpp globals
 	delete _BlackRects;
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 4b971d17e58..3dabde6a970 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -607,6 +607,11 @@ public:
 	color *_palette;
 	COLOR_MAP *_maincoltable;
 
+	// GUI control surfaces
+	std::vector<Shared::Bitmap *> *_guiobjbg;
+	std::vector<Engine::IDriverDependantBitmap *> *_guiobjbmp;
+	std::vector<int> *_guiobjbmpref; // first control texture index of each GUI
+
 	/**@}*/
 
 	/**
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index f4ecec0038c..93c596a8414 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -143,6 +143,10 @@ int32_t GUIMain::GetControlID(int32_t index) const {
 	return _ctrlRefs[index].second;
 }
 
+const std::vector<int> &GUIMain::GetControlsDrawOrder() const {
+	return _ctrlDrawOrder;
+}
+
 bool GUIMain::IsClickable() const {
 	return (_flags & kGUIMain_Clickable) != 0;
 }
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index 4eae90da00d..462bb70e359 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -117,6 +117,8 @@ public:
 	GUIControlType GetControlType(int32_t index) const;
 	// Gets child control's global ID, looks up with child's index
 	int32_t GetControlID(int32_t index) const;
+	// Gets an array of child control indexes in the z-order, from bottom to top
+	const std::vector<int> &GetControlsDrawOrder() const;
 
 	// Child control management
 	// Note that currently GUIMain does not own controls (should not delete them)
diff --git a/engines/ags/shared/gui/gui_object.cpp b/engines/ags/shared/gui/gui_object.cpp
index a52aeabffd9..4b238e45452 100644
--- a/engines/ags/shared/gui/gui_object.cpp
+++ b/engines/ags/shared/gui/gui_object.cpp
@@ -81,6 +81,10 @@ bool GUIObject::IsVisible() const {
 	return (Flags & kGUICtrl_Visible) != 0;
 }
 
+bool GUIObject::HasAlphaChannel() const {
+	return false;
+}
+
 void GUIObject::SetClickable(bool on) {
 	if (on)
 		Flags |= kGUICtrl_Clickable;
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index 76753927102..2c75bbcfae9 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -62,6 +62,8 @@ public:
 	bool            IsClickable() const;
     // Compatibility: should the control's graphic be clipped to its x,y,w,h
     virtual bool    IsContentClipped() const { return true; }
+	// Tells if the object image supports alpha channel
+	virtual bool    HasAlphaChannel() const;
 
 	// Operations
 	virtual void    Draw(Bitmap *ds, int x = 0, int y = 0) {




More information about the Scummvm-git-logs mailing list