[Scummvm-git-logs] scummvm master -> ebe2096af75e02e50b95ea45a57d864eb13eeef8
dreammaster
noreply at scummvm.org
Mon May 2 00:23:56 UTC 2022
This automated email contains information about 33 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
2df62bdd55 AGS: Only redraw gui controls when they are marked as changed
a476850123 AGS: Calculate visible graphic size of gui controls for textures
9fff1dc1fa AGS: Separate sprite lists and batch lists in renderers
2b96f0ff67 AGS: Sprite batches may have parents
2f558ae1ed AGS: Fixed 8-bit sprites unexpectedly converted on load
d09117334d AGS: Removed obscure hack in DrawSpriteWithTransparency()
fec8ab3183 AGS: Simplified DrawSpriteWithTransparency() a little
d52e2fb954 AGS: Gui control textures are rendered as gui sub-batches
211abe3744 AGS: Implemented HasAlphaChannel() in GuiButton and GuiSlider
d7375f0772 AGS: Fixed GUIObject::SetVisible(), should MarkChanged
50b2b1af05 AGS: Replaced OnControlPositionChanged() with MarkControlsChanged()
53e1c22185 AGS: Fixes for the updated sprite batch system
6ef504bba2 AGS: Store gui draw order in a std::vector
d8d593079a AGS: Don't MarkChanged guis changing Transparency or Visible flag
ec170ebd2f AGS: More strict MarkChanged use for gui controls, on changes only
fbd328b0ae AGS: On changed or deleted dynamic sprite, also update sliders
b9a9b00974 AGS: Graphic renderers use correct alpha as sprite transparency
8b027e0d82 AGS: Support sprite batch's alpha
8319217b7a AGS: Added GUIControl.Transparency
3b20393a17 AGS: Implemented gui control transparency in software mode
b2d5b6e586 AGS: Implemented Overlay.Width & Height working as scaling
684463c903 AGS: Implemented readonly Overlay.GraphicWidth & GraphicHeight
a94adb5968 AGS: Fixed TextBox duplicating letter input
598acd02b8 AGS: Updated build version (3.6.0.23)
f840223533 AGS: Fixed GUI's background image with alpha channel
87994139f6 AGS: Tidied gui drawing code a little
3b91a1124f AGS: Made internal BitmapFlip enum match the script, for convenience
d3f8627678 AGS: Refactored scale_and_flip_sprite() into transform_sprite()
8ac8c037c9 AGS: Use transform_sprite() with overlays for consistency
d9da1e3759 AGS: Don't try rendering gui controls with zero size
3be37608f0 AGS: Fixed potential division by zero in GUISlider
4cd0ca9a27 AGS: Removed DrawAsSeparateCharSprite walk-behind method
ebe2096af7 AGS: Call unload_game_file() in quit()
Commit: 2df62bdd5510a64a0bf8c3106fbd4c9101a63abc
https://github.com/scummvm/scummvm/commit/2df62bdd5510a64a0bf8c3106fbd4c9101a63abc
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:19-07:00
Commit Message:
AGS: Only redraw gui controls when they are marked as changed
>From upstream 27a6bd6a13494cd670fb6749e5bd663f088487ea
Changed paths:
engines/ags/engine/ac/button.cpp
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/game.cpp
engines/ags/engine/ac/inv_window.cpp
engines/ags/engine/ac/label.cpp
engines/ags/engine/ac/listbox.cpp
engines/ags/engine/ac/slider.cpp
engines/ags/engine/ac/textbox.cpp
engines/ags/engine/gui/gui_engine.cpp
engines/ags/shared/gui/gui_button.cpp
engines/ags/shared/gui/gui_inv.cpp
engines/ags/shared/gui/gui_label.cpp
engines/ags/shared/gui/gui_listbox.cpp
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
engines/ags/shared/gui/gui_slider.cpp
engines/ags/shared/gui/gui_textbox.cpp
diff --git a/engines/ags/engine/ac/button.cpp b/engines/ags/engine/ac/button.cpp
index 6f5fe9feb6d..8c3c8b0680f 100644
--- a/engines/ags/engine/ac/button.cpp
+++ b/engines/ags/engine/ac/button.cpp
@@ -50,7 +50,7 @@ void UpdateButtonState(const AnimatingGUIButton &abtn) {
_GP(guibuts)[abtn.buttonid].CurrentImage = _GP(guibuts)[abtn.buttonid].Image;
_GP(guibuts)[abtn.buttonid].PushedImage = 0;
_GP(guibuts)[abtn.buttonid].MouseOverImage = 0;
- _GP(guibuts)[abtn.buttonid].NotifyParentChanged();
+ _GP(guibuts)[abtn.buttonid].MarkChanged();
}
void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe) {
@@ -138,7 +138,7 @@ void Button_SetFont(GUIButton *butt, int newFont) {
if (butt->Font != newFont) {
butt->Font = newFont;
- butt->NotifyParentChanged();
+ butt->MarkChanged();
}
}
@@ -174,7 +174,7 @@ void Button_SetMouseOverGraphic(GUIButton *guil, int slotn) {
guil->CurrentImage = slotn;
guil->MouseOverImage = slotn;
- guil->NotifyParentChanged();
+ guil->MarkChanged();
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
@@ -197,7 +197,7 @@ void Button_SetNormalGraphic(GUIButton *guil, int slotn) {
guil->Height = _GP(game).SpriteInfos[slotn].Height;
}
- guil->NotifyParentChanged();
+ guil->MarkChanged();
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
@@ -212,7 +212,7 @@ void Button_SetPushedGraphic(GUIButton *guil, int slotn) {
guil->CurrentImage = slotn;
guil->PushedImage = slotn;
- guil->NotifyParentChanged();
+ guil->MarkChanged();
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
@@ -223,7 +223,7 @@ int Button_GetTextColor(GUIButton *butt) {
void Button_SetTextColor(GUIButton *butt, int newcol) {
if (butt->TextColor != newcol) {
butt->TextColor = newcol;
- butt->NotifyParentChanged();
+ butt->MarkChanged();
}
}
@@ -317,7 +317,7 @@ int Button_GetTextAlignment(GUIButton *butt) {
void Button_SetTextAlignment(GUIButton *butt, int align) {
if (butt->TextAlignment != align) {
butt->TextAlignment = (FrameAlignment)align;
- butt->NotifyParentChanged();
+ butt->MarkChanged();
}
}
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 62025f7069e..93c7066f64f 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -447,7 +447,7 @@ void clear_drawobj_cache() {
_GP(guibgbmp)[i] = nullptr;
}
- for (uint i = 0; i < _GP(guiobjbg).size(); ++i) {
+ for (size_t i = 0; i < _GP(guiobjbg).size(); ++i) {
delete _GP(guiobjbg)[i];
_GP(guiobjbg)[i] = nullptr;
if (_GP(guiobjbmp)[i])
@@ -1963,16 +1963,19 @@ void draw_gui_controls(GUIMain &gui) {
int draw_index = _GP(guiobjbmpref)[gui.ID];
for (int i = 0; i < gui.GetControlCount(); ++i, ++draw_index) {
GUIObject *obj = gui.GetControl(i);
+ if (!obj->IsVisible() ||
+ (!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
+ continue;
+ if (!obj->HasChanged())
+ continue;
+ obj->ClearChanged();
+
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]);
@@ -2027,43 +2030,45 @@ void draw_gui_and_overlays() {
{
for (aa = 0; aa < _GP(game).numgui; aa++) {
if (!_GP(guis)[aa].IsDisplayed()) continue; // not on screen
- if (!_GP(guis)[aa].HasChanged()) continue; // no changes: no need to update image
+ if (!_GP(guis)[aa].HasChanged() && !_GP(guis)[aa].HasControlsChanged()) continue; // no changes: no need to update image
if (_GP(guis)[aa].Transparency == 255) continue; // 100% transparent
- _GP(guis)[aa].ClearChanged();
if (_GP(guibg)[aa] == nullptr ||
_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;
- 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;
- if (_GP(guis)[aa].HasAlphaChannel()) {
- isAlpha = true;
-
- if ((_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Legacy) && (_GP(guis)[aa].BgImage > 0)) {
- // old-style (pre-3.0.2) GUI alpha rendering
- repair_alpha_channel(_GP(guibg)[aa], _GP(spriteset)[_GP(guis)[aa].BgImage]);
+ const bool draw_with_controls = !draw_controls_as_textures;
+ if (_GP(guis)[aa].HasChanged() || (draw_with_controls && _GP(guis)[aa].HasControlsChanged())) {
+ _GP(guibg)[aa]->ClearTransparent();
+ if (draw_with_controls)
+ _GP(guis)[aa].DrawWithControls(_GP(guibg)[aa]);
+ else
+ _GP(guis)[aa].DrawSelf(_GP(guibg)[aa]);
+
+ const bool is_alpha = _GP(guis)[aa].HasAlphaChannel();
+ if (is_alpha) {
+ if ((_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Legacy) && (_GP(guis)[aa].BgImage > 0)) {
+ // old-style (pre-3.0.2) GUI alpha rendering
+ repair_alpha_channel(_GP(guibg)[aa], _GP(spriteset)[_GP(guis)[aa].BgImage]);
+ }
}
+
+ if (_GP(guibgbmp)[aa])
+ _G(gfxDriver)->UpdateDDBFromBitmap(_GP(guibgbmp)[aa], _GP(guibg)[aa], is_alpha);
+ else
+ _GP(guibgbmp)[aa] = _G(gfxDriver)->CreateDDBFromBitmap(_GP(guibg)[aa], is_alpha);
}
- if (_GP(guibgbmp)[aa] != nullptr) {
- _G(gfxDriver)->UpdateDDBFromBitmap(_GP(guibgbmp)[aa], _GP(guibg)[aa], isAlpha);
- } else {
- _GP(guibgbmp)[aa] = _G(gfxDriver)->CreateDDBFromBitmap(_GP(guibg)[aa], isAlpha);
+ _G(our_eip) = 373;
+ if (!draw_with_controls && _GP(guis)[aa].HasControlsChanged()) {
+ draw_gui_controls(_GP(guis)[aa]);
}
_G(our_eip) = 374;
+
+ _GP(guis)[aa].ClearChanged();
}
}
_G(our_eip) = 38;
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index 6cfdf84f8b2..edd0feeaa00 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -1372,7 +1372,7 @@ void game_sprite_updated(int sprnum) {
// gui buttons
for (size_t i = 0; i < (size_t)_G(numguibuts); ++i) {
if (_GP(guibuts)[i].CurrentImage == sprnum) {
- _GP(guibuts)[i].NotifyParentChanged();
+ _GP(guibuts)[i].MarkChanged();
}
}
}
@@ -1411,7 +1411,7 @@ void game_sprite_deleted(int sprnum) {
if (_GP(guibuts)[i].CurrentImage == sprnum) {
_GP(guibuts)[i].CurrentImage = 0;
- _GP(guibuts)[i].NotifyParentChanged();
+ _GP(guibuts)[i].MarkChanged();
}
}
// views
diff --git a/engines/ags/engine/ac/inv_window.cpp b/engines/ags/engine/ac/inv_window.cpp
index 5ef33f83540..0a4f388465d 100644
--- a/engines/ags/engine/ac/inv_window.cpp
+++ b/engines/ags/engine/ac/inv_window.cpp
@@ -64,7 +64,7 @@ void InvWindow_SetCharacterToUse(GUIInvWindow *guii, CharacterInfo *chaa) {
// reset to top of list
guii->TopItem = 0;
- guii->NotifyParentChanged();
+ guii->MarkChanged();
}
CharacterInfo *InvWindow_GetCharacterToUse(GUIInvWindow *guii) {
@@ -95,7 +95,7 @@ int InvWindow_GetItemHeight(GUIInvWindow *guii) {
void InvWindow_SetTopItem(GUIInvWindow *guii, int topitem) {
if (guii->TopItem != topitem) {
guii->TopItem = topitem;
- guii->NotifyParentChanged();
+ guii->MarkChanged();
}
}
@@ -119,7 +119,7 @@ void InvWindow_ScrollDown(GUIInvWindow *guii) {
if ((_G(charextra)[guii->GetCharacterId()].invorder_count) >
(guii->TopItem + (guii->ColCount * guii->RowCount))) {
guii->TopItem += guii->ColCount;
- guii->NotifyParentChanged();
+ guii->MarkChanged();
}
}
@@ -129,7 +129,7 @@ void InvWindow_ScrollUp(GUIInvWindow *guii) {
if (guii->TopItem < 0)
guii->TopItem = 0;
- guii->NotifyParentChanged();
+ guii->MarkChanged();
}
}
diff --git a/engines/ags/engine/ac/label.cpp b/engines/ags/engine/ac/label.cpp
index 0d78cef55a0..d7e4f88411b 100644
--- a/engines/ags/engine/ac/label.cpp
+++ b/engines/ags/engine/ac/label.cpp
@@ -57,7 +57,7 @@ int Label_GetTextAlignment(GUILabel *labl) {
void Label_SetTextAlignment(GUILabel *labl, int align) {
if (labl->TextAlignment != align) {
labl->TextAlignment = (HorAlignment)align;
- labl->NotifyParentChanged();
+ labl->MarkChanged();
}
}
@@ -68,7 +68,7 @@ int Label_GetColor(GUILabel *labl) {
void Label_SetColor(GUILabel *labl, int colr) {
if (labl->TextColor != colr) {
labl->TextColor = colr;
- labl->NotifyParentChanged();
+ labl->MarkChanged();
}
}
@@ -82,7 +82,7 @@ void Label_SetFont(GUILabel *guil, int fontnum) {
if (fontnum != guil->Font) {
guil->Font = fontnum;
- guil->NotifyParentChanged();
+ guil->MarkChanged();
}
}
diff --git a/engines/ags/engine/ac/listbox.cpp b/engines/ags/engine/ac/listbox.cpp
index 3b708c6f78c..0e2667cfdb0 100644
--- a/engines/ags/engine/ac/listbox.cpp
+++ b/engines/ags/engine/ac/listbox.cpp
@@ -272,7 +272,7 @@ int ListBox_GetSelectedBackColor(GUIListBox *listbox) {
void ListBox_SetSelectedBackColor(GUIListBox *listbox, int colr) {
if (listbox->SelectedBgColor != colr) {
listbox->SelectedBgColor = colr;
- listbox->NotifyParentChanged();
+ listbox->MarkChanged();
}
}
@@ -283,7 +283,7 @@ int ListBox_GetSelectedTextColor(GUIListBox *listbox) {
void ListBox_SetSelectedTextColor(GUIListBox *listbox, int colr) {
if (listbox->SelectedTextColor != colr) {
listbox->SelectedTextColor = colr;
- listbox->NotifyParentChanged();
+ listbox->MarkChanged();
}
}
@@ -294,7 +294,7 @@ int ListBox_GetTextAlignment(GUIListBox *listbox) {
void ListBox_SetTextAlignment(GUIListBox *listbox, int align) {
if (listbox->TextAlignment != align) {
listbox->TextAlignment = (HorAlignment)align;
- listbox->NotifyParentChanged();
+ listbox->MarkChanged();
}
}
@@ -305,7 +305,7 @@ int ListBox_GetTextColor(GUIListBox *listbox) {
void ListBox_SetTextColor(GUIListBox *listbox, int colr) {
if (listbox->TextColor != colr) {
listbox->TextColor = colr;
- listbox->NotifyParentChanged();
+ listbox->MarkChanged();
}
}
@@ -328,7 +328,7 @@ void ListBox_SetSelectedIndex(GUIListBox *guisl, int newsel) {
if (newsel >= guisl->TopItem + guisl->VisibleItemCount)
guisl->TopItem = (newsel - guisl->VisibleItemCount) + 1;
}
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
@@ -344,7 +344,7 @@ void ListBox_SetTopItem(GUIListBox *guisl, int item) {
quit("!ListBoxSetTopItem: tried to set top to beyond top or bottom of list");
guisl->TopItem = item;
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
int ListBox_GetRowCount(GUIListBox *listbox) {
@@ -354,14 +354,14 @@ int ListBox_GetRowCount(GUIListBox *listbox) {
void ListBox_ScrollDown(GUIListBox *listbox) {
if (listbox->TopItem + listbox->VisibleItemCount < listbox->ItemCount) {
listbox->TopItem++;
- listbox->NotifyParentChanged();
+ listbox->MarkChanged();
}
}
void ListBox_ScrollUp(GUIListBox *listbox) {
if (listbox->TopItem > 0) {
listbox->TopItem--;
- listbox->NotifyParentChanged();
+ listbox->MarkChanged();
}
}
diff --git a/engines/ags/engine/ac/slider.cpp b/engines/ags/engine/ac/slider.cpp
index 01f5feacab1..a9663d276f5 100644
--- a/engines/ags/engine/ac/slider.cpp
+++ b/engines/ags/engine/ac/slider.cpp
@@ -40,7 +40,7 @@ void Slider_SetMax(GUISlider *guisl, int valn) {
if (guisl->MinValue > guisl->MaxValue)
quit("!Slider.Max: minimum cannot be greater than maximum");
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
@@ -59,7 +59,7 @@ void Slider_SetMin(GUISlider *guisl, int valn) {
if (guisl->MinValue > guisl->MaxValue)
quit("!Slider.Min: minimum cannot be greater than maximum");
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
@@ -74,7 +74,7 @@ void Slider_SetValue(GUISlider *guisl, int valn) {
if (valn != guisl->Value) {
guisl->Value = valn;
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
@@ -89,7 +89,7 @@ int Slider_GetBackgroundGraphic(GUISlider *guisl) {
void Slider_SetBackgroundGraphic(GUISlider *guisl, int newImage) {
if (newImage != guisl->BgImage) {
guisl->BgImage = newImage;
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
@@ -100,7 +100,7 @@ int Slider_GetHandleGraphic(GUISlider *guisl) {
void Slider_SetHandleGraphic(GUISlider *guisl, int newImage) {
if (newImage != guisl->HandleImage) {
guisl->HandleImage = newImage;
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
@@ -111,7 +111,7 @@ int Slider_GetHandleOffset(GUISlider *guisl) {
void Slider_SetHandleOffset(GUISlider *guisl, int newOffset) {
if (newOffset != guisl->HandleOffset) {
guisl->HandleOffset = newOffset;
- guisl->NotifyParentChanged();
+ guisl->MarkChanged();
}
}
diff --git a/engines/ags/engine/ac/textbox.cpp b/engines/ags/engine/ac/textbox.cpp
index 6750315bf17..a47629dfcfd 100644
--- a/engines/ags/engine/ac/textbox.cpp
+++ b/engines/ags/engine/ac/textbox.cpp
@@ -44,7 +44,7 @@ void TextBox_GetText(GUITextBox *texbox, char *buffer) {
void TextBox_SetText(GUITextBox *texbox, const char *newtex) {
if (texbox->Text != newtex) {
texbox->Text = newtex;
- texbox->NotifyParentChanged();
+ texbox->MarkChanged();
}
}
@@ -55,7 +55,7 @@ int TextBox_GetTextColor(GUITextBox *guit) {
void TextBox_SetTextColor(GUITextBox *guit, int colr) {
if (guit->TextColor != colr) {
guit->TextColor = colr;
- guit->NotifyParentChanged();
+ guit->MarkChanged();
}
}
@@ -69,7 +69,7 @@ void TextBox_SetFont(GUITextBox *guit, int fontnum) {
if (guit->Font != fontnum) {
guit->Font = fontnum;
- guit->NotifyParentChanged();
+ guit->MarkChanged();
}
}
@@ -80,7 +80,7 @@ bool TextBox_GetShowBorder(GUITextBox *guit) {
void TextBox_SetShowBorder(GUITextBox *guit, bool on) {
if (guit->IsBorderShown() != on) {
guit->SetShowBorder(on);
- guit->NotifyParentChanged();
+ guit->MarkChanged();
}
}
diff --git a/engines/ags/engine/gui/gui_engine.cpp b/engines/ags/engine/gui/gui_engine.cpp
index 5f968a2c8e5..3b3e2088a70 100644
--- a/engines/ags/engine/gui/gui_engine.cpp
+++ b/engines/ags/engine/gui/gui_engine.cpp
@@ -101,8 +101,17 @@ bool GUIObject::IsClickable() const {
return (Flags & kGUICtrl_Clickable) != 0;
}
-void GUIObject::NotifyParentChanged() {
- _GP(guis)[ParentId].MarkChanged();
+void GUIObject::MarkChanged() {
+ _hasChanged = true;
+ _GP(guis)[ParentId].MarkControlsChanged();
+}
+
+bool GUIObject::HasChanged() const {
+ return _hasChanged;
+}
+
+void GUIObject::ClearChanged() {
+ _hasChanged = false;
}
void GUILabel::PrepareTextToDraw() {
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index eb6784995c3..9a00df229ae 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -122,7 +122,7 @@ void GUIButton::SetClipImage(bool on) {
Flags |= kGUICtrl_Clip;
else
Flags &= ~kGUICtrl_Clip;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIButton::SetText(const String &text) {
@@ -142,14 +142,14 @@ void GUIButton::SetText(const String &text) {
// TODO: find a way to remove this bogus limitation ("New Button" is a valid Text too)
_unnamed = _text.Compare("New Button") == 0;
- NotifyParentChanged();
+ MarkChanged();
}
bool GUIButton::OnMouseDown() {
int new_image = (PushedImage > 0) ? PushedImage : CurrentImage;
if (CurrentImage != new_image || !IsImageButton())
- NotifyParentChanged();
+ MarkChanged();
CurrentImage = new_image;
IsPushed = true;
return false;
@@ -160,7 +160,7 @@ void GUIButton::OnMouseEnter() {
(MouseOverImage > 0) ? MouseOverImage : Image;
if ((CurrentImage != new_image) || (IsPushed && !IsImageButton())) {
CurrentImage = new_image;
- NotifyParentChanged();
+ MarkChanged();
}
IsMouseOver = true;
}
@@ -168,7 +168,7 @@ void GUIButton::OnMouseEnter() {
void GUIButton::OnMouseLeave() {
if ((CurrentImage != Image) || (IsPushed && !IsImageButton())) {
CurrentImage = Image;
- NotifyParentChanged();
+ MarkChanged();
}
IsMouseOver = false;
}
@@ -185,7 +185,7 @@ void GUIButton::OnMouseUp() {
if ((CurrentImage != new_image) || (IsPushed && !IsImageButton())) {
CurrentImage = new_image;
- NotifyParentChanged();
+ MarkChanged();
}
IsPushed = false;
}
diff --git a/engines/ags/shared/gui/gui_inv.cpp b/engines/ags/shared/gui/gui_inv.cpp
index 21bdbd9f55a..ef387aa61d7 100644
--- a/engines/ags/shared/gui/gui_inv.cpp
+++ b/engines/ags/shared/gui/gui_inv.cpp
@@ -57,7 +57,7 @@ void GUIInvWindow::OnMouseUp() {
void GUIInvWindow::OnResized() {
CalculateNumCells();
- NotifyParentChanged();
+ MarkChanged();
}
void GUIInvWindow::WriteToFile(Stream *out) const {
diff --git a/engines/ags/shared/gui/gui_label.cpp b/engines/ags/shared/gui/gui_label.cpp
index 481bb3e5214..a396d040b9b 100644
--- a/engines/ags/shared/gui/gui_label.cpp
+++ b/engines/ags/shared/gui/gui_label.cpp
@@ -75,7 +75,7 @@ void GUILabel::SetText(const String &text) {
Text = text;
// Check for macros within text
_textMacro = GUI::FindLabelMacros(Text);
- NotifyParentChanged();
+ MarkChanged();
}
// TODO: replace string serialization with StrUtil::ReadString and WriteString
diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 3557d018ea0..6926552c1f1 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -80,7 +80,7 @@ int GUIListBox::AddItem(const String &text) {
Items.push_back(text);
SavedGameIndex.push_back(-1);
ItemCount++;
- NotifyParentChanged();
+ MarkChanged();
return ItemCount - 1;
}
@@ -90,7 +90,7 @@ void GUIListBox::Clear() {
ItemCount = 0;
SelectedItem = 0;
TopItem = 0;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIListBox::Draw(Bitmap *ds, int x, int y) {
@@ -177,7 +177,7 @@ int GUIListBox::InsertItem(int index, const String &text) {
SelectedItem++;
ItemCount++;
- NotifyParentChanged();
+ MarkChanged();
return ItemCount - 1;
}
@@ -193,7 +193,7 @@ void GUIListBox::RemoveItem(int index) {
SelectedItem--;
if (SelectedItem >= ItemCount)
SelectedItem = -1;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIListBox::SetShowArrows(bool on) {
@@ -201,7 +201,7 @@ void GUIListBox::SetShowArrows(bool on) {
ListBoxFlags |= kListBox_ShowArrows;
else
ListBoxFlags &= ~kListBox_ShowArrows;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIListBox::SetShowBorder(bool on) {
@@ -209,7 +209,7 @@ void GUIListBox::SetShowBorder(bool on) {
ListBoxFlags |= kListBox_ShowBorder;
else
ListBoxFlags &= ~kListBox_ShowBorder;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIListBox::SetSvgIndex(bool on) {
@@ -222,13 +222,13 @@ void GUIListBox::SetSvgIndex(bool on) {
void GUIListBox::SetFont(int font) {
Font = font;
UpdateMetrics();
- NotifyParentChanged();
+ MarkChanged();
}
void GUIListBox::SetItemText(int index, const String &text) {
if (index >= 0 && index < ItemCount) {
Items[index] = text;
- NotifyParentChanged();
+ MarkChanged();
}
}
@@ -241,7 +241,7 @@ bool GUIListBox::OnMouseDown() {
top_item = TopItem + 1;
if (TopItem != top_item) {
TopItem = top_item;
- NotifyParentChanged();
+ MarkChanged();
}
return false;
}
@@ -251,7 +251,7 @@ bool GUIListBox::OnMouseDown() {
return false;
if (sel != SelectedItem) {
SelectedItem = sel;
- NotifyParentChanged();
+ MarkChanged();
}
IsActivated = true;
return false;
@@ -264,7 +264,7 @@ void GUIListBox::OnMouseMove(int x_, int y_) {
void GUIListBox::OnResized() {
UpdateMetrics();
- NotifyParentChanged();
+ MarkChanged();
}
void GUIListBox::UpdateMetrics() {
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 93c596a8414..bff16be8178 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -63,6 +63,8 @@ void GUIMain::InitDefaults() {
ID = 0;
Name.Empty();
_flags = kGUIMain_DefFlags;
+ _hasChanged = true;
+ _hasControlsChanged = true;
X = 0;
Y = 0;
@@ -186,12 +188,21 @@ bool GUIMain::HasChanged() const {
return _hasChanged;
}
+bool GUIMain::HasControlsChanged() const {
+ return _hasControlsChanged;
+}
+
void GUIMain::MarkChanged() {
_hasChanged = true;
}
+void GUIMain::MarkControlsChanged() {
+ _hasControlsChanged = true;
+}
+
void GUIMain::ClearChanged() {
_hasChanged = false;
+ _hasControlsChanged = false;
}
void GUIMain::AddControl(GUIControlType type, int32_t id, GUIObject *control) {
@@ -321,7 +332,6 @@ void GUIMain::Poll(int mx, int my) {
_controls[MouseOverCtrl]->OnMouseMove(mx, my);
}
}
- //MarkChanged(); // TODO: only do if anything really changed
} else if (MouseOverCtrl >= 0)
_controls[MouseOverCtrl]->OnMouseMove(mx, my);
}
@@ -466,7 +476,6 @@ void GUIMain::OnMouseButtonDown(int mx, int my) {
if (_controls[MouseOverCtrl]->OnMouseDown())
MouseOverCtrl = MOVER_MOUSEDOWNLOCKED;
_controls[MouseDownCtrl]->OnMouseMove(mx - X, my - Y);
- //MarkChanged(); // TODO: only do if anything really changed
}
void GUIMain::OnMouseButtonUp() {
@@ -482,7 +491,6 @@ void GUIMain::OnMouseButtonUp() {
_controls[MouseDownCtrl]->OnMouseUp();
MouseDownCtrl = -1;
- //MarkChanged(); // TODO: only do if anything really changed
}
void GUIMain::ReadFromFile(Stream *in, GuiVersion gui_version) {
@@ -660,32 +668,34 @@ void DrawTextAlignedHor(Bitmap *ds, const char *text, int font, color_t text_col
void MarkAllGUIForUpdate() {
for (auto &gui : _GP(guis)) {
gui.MarkChanged();
+ for (int i = 0; i < gui.GetControlCount(); ++i)
+ gui.GetControl(i)->MarkChanged();
}
}
void MarkForFontUpdate(int font) {
for (auto &btn : _GP(guibuts)) {
if (btn.Font == font)
- btn.NotifyParentChanged();
+ btn.MarkChanged();
}
for (auto &lbl : _GP(guilabels)) {
if (lbl.Font == font)
- lbl.NotifyParentChanged();
+ lbl.MarkChanged();
}
for (auto &list : _GP(guilist)) {
if (list.Font == font)
- list.NotifyParentChanged();
+ list.MarkChanged();
}
for (auto &tb : _GP(guitext)) {
if (tb.Font == font)
- tb.NotifyParentChanged();
+ tb.MarkChanged();
}
}
void MarkSpecialLabelsForUpdate(GUILabelMacro macro) {
for (auto &lbl : _GP(guilabels)) {
if ((lbl.GetTextMacros() & macro) != 0) {
- lbl.NotifyParentChanged();
+ lbl.MarkChanged();
}
}
}
@@ -693,7 +703,7 @@ void MarkSpecialLabelsForUpdate(GUILabelMacro macro) {
void MarkInventoryForUpdate(int char_id, bool is_player) {
for (auto &inv : _GP(guiinv)) {
if ((char_id < 0) || (inv.CharId == char_id) || (is_player && inv.CharId < 0)) {
- inv.NotifyParentChanged();
+ inv.MarkChanged();
}
}
}
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index 462bb70e359..c765f6aa51f 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -100,8 +100,10 @@ public:
// Tells if GUI has graphically changed recently
bool HasChanged() const;
+ bool HasControlsChanged() const;
// Manually marks GUI as graphically changed
void MarkChanged();
+ void MarkControlsChanged();
// Clears changed flag
void ClearChanged();
@@ -196,6 +198,7 @@ public:
private:
int32_t _flags; // style and behavior flags
bool _hasChanged; // flag tells whether GUI has graphically changed recently
+ bool _hasControlsChanged;
// Array of types and control indexes in global GUI object arrays;
// maps GUI child slots to actual controls and used for rebuilding Controls array
diff --git a/engines/ags/shared/gui/gui_object.cpp b/engines/ags/shared/gui/gui_object.cpp
index 4b238e45452..c2367983a7a 100644
--- a/engines/ags/shared/gui/gui_object.cpp
+++ b/engines/ags/shared/gui/gui_object.cpp
@@ -39,6 +39,7 @@ GUIObject::GUIObject() {
ZOrder = -1;
IsActivated = false;
_scEventCount = 0;
+ _hasChanged = true;
}
String GUIObject::GetScriptName() const {
@@ -97,7 +98,7 @@ void GUIObject::SetEnabled(bool on) {
Flags |= kGUICtrl_Enabled;
else
Flags &= ~kGUICtrl_Enabled;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIObject::SetTranslated(bool on) {
@@ -105,7 +106,7 @@ void GUIObject::SetTranslated(bool on) {
Flags |= kGUICtrl_Translated;
else
Flags &= ~kGUICtrl_Translated;
- NotifyParentChanged();
+ MarkChanged();
}
void GUIObject::SetVisible(bool on) {
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index 2c75bbcfae9..7f25ca7f7ce 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -106,7 +106,10 @@ public:
// TODO: these members are currently public; hide them later
public:
// Notifies parent GUI that this control has changed
- void NotifyParentChanged();
+ void MarkChanged();
+
+ bool HasChanged() const;
+ void ClearChanged();
int32_t Id; // GUI object's identifier
int32_t ParentId; // id of parent GUI
@@ -123,6 +126,7 @@ public:
protected:
uint32_t Flags; // generic style and behavior flags
+ bool _hasChanged;
// TODO: explicit event names & handlers for every event
int32_t _scEventCount; // number of supported script events
diff --git a/engines/ags/shared/gui/gui_slider.cpp b/engines/ags/shared/gui/gui_slider.cpp
index 11e6197299c..33aab93524d 100644
--- a/engines/ags/shared/gui/gui_slider.cpp
+++ b/engines/ags/shared/gui/gui_slider.cpp
@@ -185,7 +185,7 @@ void GUISlider::OnMouseMove(int x, int y) {
Value = (int)(((float)(((Y + Height) - y) - 2) * (float)(MaxValue - MinValue)) / (float)_handleRange) + MinValue;
Value = Math::Clamp(Value, MinValue, MaxValue);
- NotifyParentChanged();
+ MarkChanged();
IsActivated = true;
}
diff --git a/engines/ags/shared/gui/gui_textbox.cpp b/engines/ags/shared/gui/gui_textbox.cpp
index 8e7a8b67ec8..29393a1ea44 100644
--- a/engines/ags/shared/gui/gui_textbox.cpp
+++ b/engines/ags/shared/gui/gui_textbox.cpp
@@ -83,7 +83,7 @@ void GUITextBox::OnKeyPress(const KeyInput &ki) {
return;
}
- NotifyParentChanged();
+ MarkChanged();
// backspace, remove character
if (keycode == eAGSKeyCodeBackspace) {
Backspace(Text);
Commit: a476850123ecf2638636d42278d6f1c3189fefea
https://github.com/scummvm/scummvm/commit/a476850123ecf2638636d42278d6f1c3189fefea
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:19-07:00
Commit Message:
AGS: Calculate visible graphic size of gui controls for textures
>From upstream a91bec5f3fa7f37187a084cabd0ab2289e609a6e
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/globals.cpp
engines/ags/globals.h
engines/ags/shared/gui/gui_button.cpp
engines/ags/shared/gui/gui_button.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_main.h
engines/ags/shared/gui/gui_object.h
engines/ags/shared/gui/gui_slider.cpp
engines/ags/shared/gui/gui_slider.h
engines/ags/shared/util/geometry.cpp
engines/ags/shared/util/geometry.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 93c7066f64f..915fbd9e1ef 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -381,6 +381,7 @@ void init_game_drawdata() {
}
_GP(guiobjbg).resize(guio_num);
_GP(guiobjbmp).resize(guio_num);
+ _GP(guiobjoff).resize(guio_num);
}
void dispose_game_drawdata() {
@@ -397,6 +398,7 @@ void dispose_game_drawdata() {
_GP(guiobjbg).clear();
_GP(guiobjbmp).clear();
_GP(guiobjbmpref).clear();
+ _GP(guiobjoff).clear();
}
static void dispose_debug_room_drawdata() {
@@ -1970,19 +1972,21 @@ void draw_gui_controls(GUIMain &gui) {
continue;
obj->ClearChanged();
+ Rect obj_surf = obj->CalcGraphicRect(GUI::Options.ClipControls);
if (_GP(guiobjbg)[draw_index] == nullptr ||
- _GP(guiobjbg)[draw_index]->GetSize() != Size(obj->Width, obj->Height)) {
+ _GP(guiobjbg)[draw_index]->GetSize() != obj_surf.GetSize()) {
recreate_drawobj_bitmap(_GP(guiobjbg)[draw_index], _GP(guiobjbmp)[draw_index],
- obj->Width, obj->Height);
+ obj_surf.GetWidth(), obj_surf.GetHeight());
}
_GP(guiobjbg)[draw_index]->ClearTransparent();
- obj->Draw(_GP(guiobjbg)[draw_index]);
+ obj->Draw(_GP(guiobjbg)[draw_index], obj->X - obj_surf.Left, obj->Y - obj_surf.Top);
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());
+ _GP(guiobjoff)[draw_index] = Point(obj_surf.GetLT());
}
}
@@ -1991,11 +1995,9 @@ 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);
+ && (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper);
if (pl_any_want_hook(AGSE_PREGUIDRAW))
add_render_stage(AGSE_PREGUIDRAW);
@@ -2098,7 +2100,9 @@ void draw_gui_and_overlays() {
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);
+ _GP(guis)[aa].X + _GP(guiobjoff)[draw_index + obj_id].X,
+ _GP(guis)[aa].Y + _GP(guiobjoff)[draw_index + obj_id].Y,
+ _GP(guis)[aa].ZOrder, false);
}
}
}
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index 4a6f71c4f05..5201df62621 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -190,6 +190,7 @@ Globals::Globals() {
_guiobjbg = new std::vector<Shared::Bitmap *>();
_guiobjbmp = new std::vector<Engine::IDriverDependantBitmap *>();
+ _guiobjoff = new std::vector<Point>();
_guiobjbmpref = new std::vector<int>();
// draw_software.cpp globals
@@ -443,6 +444,7 @@ Globals::~Globals() {
delete _maincoltable;
delete _guiobjbg;
delete _guiobjbmp;
+ delete _guiobjoff;
delete _guiobjbmpref;
// draw_software.cpp globals
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 3dabde6a970..bc893abc87e 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -610,6 +610,7 @@ public:
// GUI control surfaces
std::vector<Shared::Bitmap *> *_guiobjbg;
std::vector<Engine::IDriverDependantBitmap *> *_guiobjbmp;
+ std::vector<Point> *_guiobjoff; // because surface may be larger than logical position
std::vector<int> *_guiobjbmpref; // first control texture index of each GUI
/**@}*/
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index 9a00df229ae..79f33f64dcc 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -20,6 +20,7 @@
*/
#include "ags/shared/ac/sprite_cache.h"
+#include "ags/shared/ac/game_struct_defines.h"
#include "ags/shared/gui/gui_button.h"
#include "ags/shared/gui/gui_main.h" // TODO: extract helper functions
#include "ags/shared/util/stream.h"
@@ -74,7 +75,7 @@ GUIButton::GUIButton() {
IsPushed = false;
IsMouseOver = false;
_placeholder = kButtonPlace_None;
- _unnamed = false;
+ _unnamed = true;
_scEventCount = 1;
_scEventNames[0] = "Click";
@@ -93,6 +94,47 @@ bool GUIButton::IsClippingImage() const {
return (Flags & kGUICtrl_Clip) != 0;
}
+Rect GUIButton::CalcGraphicRect(bool clipped) {
+ if (clipped)
+ return RectWH(X, Y, Width, Height);
+ // TODO: need to find a way to cache image and text position, or there'll be some repetition
+ Rect rc = RectWH(X, Y, Width, Height);
+ if (IsImageButton()) {
+ if (IsClippingImage())
+ return rc;
+ // Main button graphic
+ if (_GP(spriteset)[CurrentImage] != nullptr)
+ rc = SumRects(rc, RectWH(X, Y, get_adjusted_spritewidth(CurrentImage), get_adjusted_spriteheight(CurrentImage)));
+ // Optionally merge with the inventory pic
+ if (_placeholder != kButtonPlace_None && _G(gui_inv_pic) >= 0) {
+ Size inv_sz = Size(get_adjusted_spritewidth(_G(gui_inv_pic)), get_adjusted_spriteheight(_G(gui_inv_pic)));
+ GUIButtonPlaceholder place = _placeholder;
+ if (place == kButtonPlace_InvItemAuto) {
+ place = ((inv_sz.Width > Width - 6) || (inv_sz.Height > Height - 6)) ?
+ kButtonPlace_InvItemStretch : kButtonPlace_InvItemCenter;
+ }
+
+ Rect inv_rc = (place == kButtonPlace_InvItemStretch) ?
+ RectWH(X + 3, Y + 3, Width - 6, Height - 6) :
+ RectWH(X + Width / 2 - inv_sz.Width / 2,
+ Y + Height / 2 - inv_sz.Height / 2,
+ inv_sz.Width, inv_sz.Height);
+ rc = SumRects(rc, inv_rc);
+ }
+ }
+ // Optionally merge with the button text
+ if (!IsImageButton() || ((_placeholder == kButtonPlace_None) && !_unnamed)) {
+ PrepareTextToDraw();
+ Rect frame = RectWH(X + 2, Y + 2, Width - 4, Height - 4);
+ if (IsPushed && IsMouseOver) {
+ frame.Left++;
+ frame.Top++;
+ }
+ rc = SumRects(rc, GUI::CalcTextPosition(_textToDraw.GetCStr(), Font, frame, TextAlignment));
+ }
+ return rc;
+}
+
void GUIButton::Draw(Bitmap *ds, int x, int y) {
bool draw_disabled = !IsGUIEnabled(this);
@@ -109,8 +151,7 @@ void GUIButton::Draw(Bitmap *ds, int x, int y) {
// buttons off when disabled - no point carrying on
return;
- // CHECKME: why testing both CurrentImage and Image?
- if (CurrentImage > 0 && IsImageButton())
+ if (IsImageButton())
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())
@@ -141,7 +182,7 @@ void GUIButton::SetText(const String &text) {
_placeholder = kButtonPlace_None;
// TODO: find a way to remove this bogus limitation ("New Button" is a valid Text too)
- _unnamed = _text.Compare("New Button") == 0;
+ _unnamed = _text.IsEmpty() || _text.Compare("New Button") == 0;
MarkChanged();
}
@@ -174,13 +215,12 @@ void GUIButton::OnMouseLeave() {
}
void GUIButton::OnMouseUp() {
- int new_image;
+ int new_image = Image;
if (IsMouseOver) {
- new_image = MouseOverImage;
+ if (MouseOverImage > 0)
+ new_image = MouseOverImage;
if (IsGUIEnabled(this) && IsClickable())
IsActivated = true;
- } else {
- new_image = Image;
}
if ((CurrentImage != new_image) || (IsPushed && !IsImageButton())) {
@@ -291,23 +331,20 @@ void GUIButton::DrawImageButton(Bitmap *ds, int x, int y, bool draw_disabled) {
// Draw active inventory item
if (_placeholder != kButtonPlace_None && _G(gui_inv_pic) >= 0) {
+ Size inv_sz = Size(get_adjusted_spritewidth(_G(gui_inv_pic)), get_adjusted_spriteheight(_G(gui_inv_pic)));
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)) {
- place = kButtonPlace_InvItemStretch;
- } else {
- place = kButtonPlace_InvItemCenter;
- }
+ place = ((inv_sz.Width > Width - 6) || (inv_sz.Height > Height - 6)) ?
+ kButtonPlace_InvItemStretch : kButtonPlace_InvItemCenter;
}
if (place == kButtonPlace_InvItemStretch) {
ds->StretchBlt(_GP(spriteset)[_G(gui_inv_pic)], RectWH(x + 3, y + 3, Width - 6, Height - 6),
kBitmap_Transparency);
- } else if (place == kButtonPlace_InvItemCenter) {
+ } else {
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,
+ x + Width / 2 - inv_sz.Width / 2,
+ y + Height / 2 - inv_sz.Height / 2,
true);
}
}
@@ -320,7 +357,7 @@ void GUIButton::DrawImageButton(Bitmap *ds, int x, int y, bool draw_disabled) {
}
// Don't print Text of (INV) (INVSHR) (INVNS)
- if (_placeholder == kButtonPlace_None && !_unnamed)
+ if ((_placeholder == kButtonPlace_None) && !_unnamed)
DrawText(ds, x, y, draw_disabled);
if (IsClippingImage() && !GUI::Options.ClipControls)
@@ -328,8 +365,6 @@ void GUIButton::DrawImageButton(Bitmap *ds, int x, int y, 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();
diff --git a/engines/ags/shared/gui/gui_button.h b/engines/ags/shared/gui/gui_button.h
index df154a267fc..8390a7c569a 100644
--- a/engines/ags/shared/gui/gui_button.h
+++ b/engines/ags/shared/gui/gui_button.h
@@ -67,6 +67,7 @@ public:
bool IsClippingImage() const;
// Operations
+ Rect CalcGraphicRect(bool clipped) override;
void Draw(Bitmap *ds, int x = 0, int y = 0) override;
void SetClipImage(bool on);
void SetText(const String &text);
diff --git a/engines/ags/shared/gui/gui_label.cpp b/engines/ags/shared/gui/gui_label.cpp
index a396d040b9b..26c0c7eafb3 100644
--- a/engines/ags/shared/gui/gui_label.cpp
+++ b/engines/ags/shared/gui/gui_label.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "ags/lib/std/algorithm.h"
#include "ags/shared/ac/game_version.h"
#include "ags/shared/font/fonts.h"
#include "ags/shared/gui/gui_label.h"
@@ -48,6 +49,35 @@ GUILabelMacro GUILabel::GetTextMacros() const {
return _textMacro;
}
+Rect GUILabel::CalcGraphicRect(bool clipped) {
+ if (clipped)
+ return RectWH(X, Y, Width, Height);
+ // TODO: need to find a way to text position, or there'll be some repetition
+ // have to precache text and size on some events:
+ // - translation change
+ // - macro value change (score, overhotspot etc)
+ Rect rc = RectWH(X, Y, Width, Height);
+ PrepareTextToDraw();
+ if (SplitLinesForDrawing(_GP(Lines)) == 0)
+ return rc;
+ const int linespacing = // Older engine labels used (font height + 1) as linespacing for some reason
+ ((_G(loaded_game_file_version) < kGameVersion_360) && (get_font_flags(Font) & FFLG_DEFLINESPACING)) ?
+ (get_font_height(Font) + 1) :
+ 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 = 0;
+ Line max_line;
+ for (size_t i = 0;
+ i < _GP(Lines).Count() && (!limit_by_label_frame || at_y <= Height);
+ ++i, at_y += linespacing) {
+ Line lpos = GUI::CalcTextPositionHor(_GP(Lines)[i].GetCStr(), Font, 0, 0 + Width - 1, at_y,
+ (FrameAlignment)TextAlignment);
+ max_line.X2 = std::max(max_line.X2, lpos.X2);
+ }
+ return SumRects(rc, RectWH(X, Y, max_line.X2 - max_line.X1 + 1, at_y - linespacing + get_font_surface_height(Font)));
+}
+
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
diff --git a/engines/ags/shared/gui/gui_label.h b/engines/ags/shared/gui/gui_label.h
index 7dc68c1700e..5a2333c9cc3 100644
--- a/engines/ags/shared/gui/gui_label.h
+++ b/engines/ags/shared/gui/gui_label.h
@@ -43,6 +43,7 @@ public:
GUILabelMacro GetTextMacros() const;
// Operations
+ Rect CalcGraphicRect(bool clipped) override;
void Draw(Bitmap *ds, int x = 0, int y = 0) override;
void SetText(const String &text);
diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 6926552c1f1..92ff4b3f552 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "ags/lib/std/algorithm.h"
#include "ags/shared/gui/gui_listbox.h"
#include "ags/shared/ac/game_version.h"
#include "ags/shared/font/fonts.h"
@@ -76,6 +77,34 @@ bool GUIListBox::IsInRightMargin(int x) const {
return 0;
}
+Rect GUIListBox::CalcGraphicRect(bool clipped) {
+ if (clipped)
+ return RectWH(X, Y, Width, Height);
+ // TODO: need to find a way to text position, or there'll be some repetition
+ // have to precache text and size on some events:
+ // - translation change
+ // - macro value change (score, overhotspot etc)
+ Rect rc = RectWH(X, Y, Width, Height);
+ UpdateMetrics();
+ const int width = Width - 1;
+ const int height = Height - 1;
+ const int pixel_size = get_fixed_pixel_size(1);
+ int right_hand_edge = width - pixel_size - 1;
+ // calculate the scroll bar's width if necessary
+ if (ItemCount > VisibleItemCount &&IsBorderShown() && AreArrowsShown())
+ right_hand_edge -= get_fixed_pixel_size(7);
+ Line max_line;
+ for (int item = 0; (item < VisibleItemCount) && (item + TopItem < ItemCount); ++item) {
+ int at_y = pixel_size + item * RowHeight;
+ int item_index = item + TopItem;
+ PrepareTextToDraw(Items[item_index]);
+ Line lpos = GUI::CalcTextPositionHor(_textToDraw.GetCStr(), Font, 1 + pixel_size, right_hand_edge, at_y + 1,
+ (FrameAlignment)TextAlignment);
+ max_line.X2 = std::max(max_line.X2, lpos.X2);
+ }
+ return SumRects(rc, RectWH(X, Y, max_line.X2 - max_line.X1 + 1, Height));
+}
+
int GUIListBox::AddItem(const String &text) {
Items.push_back(text);
SavedGameIndex.push_back(-1);
@@ -139,10 +168,7 @@ void GUIListBox::Draw(Bitmap *ds, int x, int y) {
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;
-
+ for (int item = 0; (item < VisibleItemCount) && (item + TopItem < ItemCount); ++item) {
int at_y = y + pixel_size + item * RowHeight;
if (item + TopItem == SelectedItem) {
text_color = ds->GetCompatibleColor(SelectedTextColor);
diff --git a/engines/ags/shared/gui/gui_listbox.h b/engines/ags/shared/gui/gui_listbox.h
index 8a712fddafe..6fc08cda7ee 100644
--- a/engines/ags/shared/gui/gui_listbox.h
+++ b/engines/ags/shared/gui/gui_listbox.h
@@ -43,6 +43,7 @@ public:
// Operations
int AddItem(const String &text);
void Clear();
+ Rect CalcGraphicRect(bool clipped) override;
void Draw(Bitmap *ds, int x = 0, int y = 0) override;
int InsertItem(int index, const String &text);
void RemoveItem(int index);
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index bff16be8178..bf6e35c106f 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -643,6 +643,21 @@ namespace GUI {
GuiVersion GameGuiVersion = kGuiVersion_Initial;
+Rect CalcTextPosition(const char *text, int font, const Rect &frame, FrameAlignment align) {
+ int use_height = (_G(loaded_game_file_version) < kGameVersion_360_21) ?
+ get_font_height(font) + ((align & kMAlignVCenter) ? 1 : 0) :
+ get_font_height_outlined(font);
+ Rect rc = AlignInRect(frame, RectWH(0, 0, get_text_width_outlined(text, font), use_height), align);
+ rc.SetHeight(get_font_surface_height(font));
+ return rc;
+}
+
+Line CalcTextPositionHor(const char *text, int font, int x1, int x2, int y, FrameAlignment align) {
+ int w = get_text_width_outlined(text, font);
+ int x = AlignInHRange(x1, x2, 0, w, align);
+ return Line(x, y, x + w - 1, y);
+}
+
void DrawDisabledEffect(Bitmap *ds, const Rect &rc) {
color_t draw_color = ds->GetCompatibleColor(8);
for (int at_x = rc.Left; at_x <= rc.Right; ++at_x) {
@@ -653,16 +668,13 @@ void DrawDisabledEffect(Bitmap *ds, const Rect &rc) {
}
void DrawTextAligned(Bitmap *ds, const char *text, int font, color_t text_color, const Rect &frame, FrameAlignment align) {
- int text_height = (_G(loaded_game_file_version) < kGameVersion_360_21) ?
- get_font_height(font) + ((align & kMAlignVCenter) ? 1 : 0) :
- get_font_height_outlined(font);
- Rect item = AlignInRect(frame, RectWH(0, 0, get_text_width_outlined(text, font), text_height), align);
+ Rect item = CalcTextPosition(text, font, frame, align);
wouttext_outline(ds, item.Left, item.Top, font, text_color, text);
}
void DrawTextAlignedHor(Bitmap *ds, const char *text, int font, color_t text_color, int x1, int x2, int y, FrameAlignment align) {
- int x = AlignInHRange(x1, x2, 0, get_text_width_outlined(text, font), align);
- wouttext_outline(ds, x, y, font, text_color, text);
+ Line line = CalcTextPositionHor(text, font, x1, x2, y, align);
+ wouttext_outline(ds, line.X1, y, font, text_color, text);
}
void MarkAllGUIForUpdate() {
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index c765f6aa51f..91da669de22 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -215,6 +215,10 @@ namespace GUI {
extern GuiVersion GameGuiVersion;
extern GuiOptions Options;
+// Calculates the text's graphical position, given the alignment
+Rect CalcTextPosition(const char *text, int font, const Rect &frame, FrameAlignment align);
+// Calculates the text's graphical position, given the horizontal alignment
+Line CalcTextPositionHor(const char *text, int font, int x1, int x2, int y, FrameAlignment align);
// Draw standart "shading" effect over rectangle
void DrawDisabledEffect(Bitmap *ds, const Rect &rc);
// Draw text aligned inside rectangle
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index 7f25ca7f7ce..d7d857c2985 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -66,6 +66,11 @@ public:
virtual bool HasAlphaChannel() const;
// Operations
+ // Returns the (untransformed!) visual rectangle of this control,
+ // optionally clipped by the logical position
+ virtual Rect CalcGraphicRect(bool clipped) {
+ return RectWH(X, Y, Width, Height);
+ }
virtual void Draw(Bitmap *ds, int x = 0, int y = 0) {
(void)ds; (void)x; (void)y;
}
diff --git a/engines/ags/shared/gui/gui_slider.cpp b/engines/ags/shared/gui/gui_slider.cpp
index 33aab93524d..d8445428688 100644
--- a/engines/ags/shared/gui/gui_slider.cpp
+++ b/engines/ags/shared/gui/gui_slider.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "ags/lib/std/algorithm.h"
#include "ags/shared/ac/sprite_cache.h"
#include "ags/shared/gui/gui_main.h"
#include "ags/shared/gui/gui_slider.h"
@@ -56,7 +57,22 @@ bool GUISlider::IsOverControl(int x, int y, int leeway) const {
return _cachedHandle.IsInside(Point(x, y));
}
-void GUISlider::Draw(Bitmap *ds, int x, int y) {
+Rect GUISlider::CalcGraphicRect(bool clipped) {
+ // Sliders are never clipped as of 3.6.0
+ // TODO: precalculate everything on width/height/graphic change!!
+ UpdateMetrics();
+ Rect logical = RectWH(X, Y, Width, Height);
+ Rect bar = Rect::MoveBy(_cachedBar, X, Y);
+ Rect handle = Rect::MoveBy(_cachedHandle, X, Y);
+ return Rect(
+ std::min(std::min(logical.Left, bar.Left), handle.Left),
+ std::min(std::min(logical.Top, bar.Top), handle.Top),
+ std::max(std::max(logical.Right, bar.Right), handle.Right),
+ std::max(std::max(logical.Bottom, bar.Bottom), handle.Bottom)
+ );
+}
+
+void GUISlider::UpdateMetrics() {
// Clamp Value
// TODO: this is necessary here because some Slider fields are still public
if (MinValue >= MaxValue)
@@ -95,7 +111,7 @@ void GUISlider::Draw(Bitmap *ds, int x, int y) {
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(1, 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 +121,7 @@ void GUISlider::Draw(Bitmap *ds, int x, int y) {
}
// vertical slider
else {
- bar = RectWH(x + Width / 2 - thick_f, y + 1, bar_thick, Height - 1);
+ bar = RectWH(Width / 2 - thick_f, 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,
@@ -114,6 +130,17 @@ void GUISlider::Draw(Bitmap *ds, int x, int y) {
handle.MoveToX(handle.Left + data_to_game_coord(HandleOffset));
}
+ _cachedBar = bar;
+ _cachedHandle = handle;
+ _handleRange = handle_range;
+}
+
+void GUISlider::Draw(Bitmap *ds, int x, int y) {
+ UpdateMetrics();
+
+ Rect bar = Rect::MoveBy(_cachedBar, x, y);
+ Rect handle = Rect::MoveBy(_cachedHandle, x, y);
+
color_t draw_color;
if (BgImage > 0) {
// tiled image as slider background
@@ -164,9 +191,6 @@ void GUISlider::Draw(Bitmap *ds, int x, int y) {
ds->DrawLine(Line(handle.Right, handle.Top + 1, handle.Right, handle.Bottom), draw_color);
ds->DrawLine(Line(handle.Left + 1, handle.Bottom, handle.Right, handle.Bottom), draw_color);
}
-
- _cachedHandle = handle;
- _handleRange = handle_range;
}
bool GUISlider::OnMouseDown() {
diff --git a/engines/ags/shared/gui/gui_slider.h b/engines/ags/shared/gui/gui_slider.h
index 59ffbf07a55..671afad38f6 100644
--- a/engines/ags/shared/gui/gui_slider.h
+++ b/engines/ags/shared/gui/gui_slider.h
@@ -33,14 +33,15 @@ class GUISlider : public GUIObject {
public:
GUISlider();
- // Compatibility: sliders are not clipped as of 3.6.0
- bool IsContentClipped() const override { return false; }
-
// Tells if the slider is horizontal (otherwise - vertical)
bool IsHorizontal() const;
bool IsOverControl(int x, int y, int leeway) const override;
+ // Compatibility: sliders are not clipped as of 3.6.0
+ bool IsContentClipped() const override { return false; }
+
// Operations
+ Rect CalcGraphicRect(bool clipped) override;
void Draw(Bitmap *ds, int x = 0, int y = 0) override;
// Events
@@ -65,8 +66,12 @@ public:
bool IsMousePressed;
private:
- // The following variables are not persisted on disk
- // Cached coordinates of slider handle
+ // Updates dynamic metrics and positions of elements
+ void UpdateMetrics();
+
+ // Cached coordinates of slider bar; in relative coords
+ Rect _cachedBar;
+ // Cached coordinates of slider handle; in relative coords
Rect _cachedHandle;
// The length of the handle movement range, in pixels
int _handleRange;
diff --git a/engines/ags/shared/util/geometry.cpp b/engines/ags/shared/util/geometry.cpp
index 5da59792361..b0a88abee58 100644
--- a/engines/ags/shared/util/geometry.cpp
+++ b/engines/ags/shared/util/geometry.cpp
@@ -24,7 +24,8 @@
namespace AGS3 {
-bool AreRectsIntersecting(const Rect &r1, const Rect &r2) { // NOTE: remember that in AGS Y axis is pointed downwards
+bool AreRectsIntersecting(const Rect &r1, const Rect &r2) {
+ // NOTE: remember that in AGS Y axis is pointed downwards (top < bottom)
return r1.Left <= r2.Right && r1.Right >= r2.Left &&
r1.Top <= r2.Bottom && r1.Bottom >= r2.Top;
}
@@ -119,4 +120,14 @@ Rect PlaceInRect(const Rect &place, const Rect &item, const RectPlacement &place
}
}
+Rect SumRects(const Rect &r1, const Rect &r2) { // NOTE: remember that in AGS Y axis is pointed downwards (top < bottom)
+ return Rect(std::min(r1.Left, r2.Left), std::min(r1.Top, r2.Top),
+ std::max(r1.Right, r2.Right), std::max(r1.Bottom, r2.Bottom));
+}
+
+Rect IntersectRects(const Rect &r1, const Rect &r2) { // NOTE: the result may be empty (negative) rect if there's no intersection
+ return Rect(std::max(r1.Left, r2.Left), std::max(r1.Top, r2.Top),
+ std::min(r1.Right, r2.Right), std::min(r1.Bottom, r2.Bottom));
+}
+
} // namespace AGS3
diff --git a/engines/ags/shared/util/geometry.h b/engines/ags/shared/util/geometry.h
index 5e5653cae89..451c8892193 100644
--- a/engines/ags/shared/util/geometry.h
+++ b/engines/ags/shared/util/geometry.h
@@ -364,6 +364,10 @@ Rect OffsetRect(const Rect &r, const Point off);
Rect CenterInRect(const Rect &place, const Rect &item);
Rect ClampToRect(const Rect &place, const Rect &item);
Rect PlaceInRect(const Rect &place, const Rect &item, const RectPlacement &placement);
+// Sum two rectangles, the result is the rectangle bounding them both
+Rect SumRects(const Rect &r1, const Rect &r2);
+// Intersect two rectangles, the resolt is the rectangle bounding their intersection
+Rect IntersectRects(const Rect &r1, const Rect &r2);
//} // namespace Shared
//} // namespace AGS
Commit: 9fff1dc1fa6db3eb3640cdaa01b149c539b5d188
https://github.com/scummvm/scummvm/commit/9fff1dc1fa6db3eb3640cdaa01b149c539b5d188
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:19-07:00
Commit Message:
AGS: Separate sprite lists and batch lists in renderers
>From upstream ccbf3d16788720e94e5362ff8aeae1e32b4febe5
Changed paths:
engines/ags/engine/gfx/ali_3d_scummvm.cpp
engines/ags/engine/gfx/ali_3d_scummvm.h
engines/ags/engine/gfx/gfx_driver_base.h
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.cpp b/engines/ags/engine/gfx/ali_3d_scummvm.cpp
index dc13c9f6ff4..79efe05f1ac 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.cpp
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.cpp
@@ -234,7 +234,7 @@ void ScummVMRendererGraphicsDriver::InitSpriteBatch(size_t index, const SpriteBa
if (_spriteBatches.size() <= index)
_spriteBatches.resize(index + 1);
ALSpriteBatch &batch = _spriteBatches[index];
- batch.List.clear();
+ batch.ID = index;
// TODO: correct offsets to have pre-scale (source) and post-scale (dest) offsets!
const int src_w = desc.Viewport.GetWidth() / desc.Transform.ScaleX;
const int src_h = desc.Viewport.GetHeight() / desc.Transform.ScaleY;
@@ -271,12 +271,12 @@ void ScummVMRendererGraphicsDriver::InitSpriteBatch(size_t index, const SpriteBa
}
void ScummVMRendererGraphicsDriver::ResetAllBatches() {
- for (ALSpriteBatches::iterator it = _spriteBatches.begin(); it != _spriteBatches.end(); ++it)
- it->List.clear();
+ _spriteBatches.clear();
+ _spriteList.clear();
}
void ScummVMRendererGraphicsDriver::DrawSprite(int x, int y, IDriverDependantBitmap *bitmap) {
- _spriteBatches[_actSpriteBatch].List.push_back(ALDrawListEntry((ALSoftwareBitmap *)bitmap, x, y));
+ _spriteList.push_back(ALDrawListEntry((ALSoftwareBitmap *)bitmap, _actSpriteBatch, x, y));
}
void ScummVMRendererGraphicsDriver::SetScreenFade(int /*red*/, int /*green*/, int /*blue*/) {
@@ -289,7 +289,8 @@ void ScummVMRendererGraphicsDriver::SetScreenTint(int red, int green, int blue)
_tint_green = green;
_tint_blue = blue;
if (((_tint_red > 0) || (_tint_green > 0) || (_tint_blue > 0)) && (_srcColorDepth > 8)) {
- _spriteBatches[_actSpriteBatch].List.push_back(ALDrawListEntry((ALSoftwareBitmap *)0x1, 0, 0));
+ _spriteList.push_back(
+ ALDrawListEntry(reinterpret_cast<ALSoftwareBitmap *>(DRAWENTRY_TINT), _actSpriteBatch, 0, 0));
}
}
@@ -305,10 +306,11 @@ void ScummVMRendererGraphicsDriver::RenderToBackBuffer() {
// that here would slow things down significantly, so if we ever go that way sprite caching will
// be required (similarily to how AGS caches flipped/scaled object sprites now for).
//
- for (size_t i = 0; i <= _actSpriteBatch; ++i) {
- const Rect &viewport = _spriteBatchDesc[i].Viewport;
- const SpriteTransform &transform = _spriteBatchDesc[i].Transform;
- const ALSpriteBatch &batch = _spriteBatches[i];
+ for (size_t cur_spr = 0; cur_spr < _spriteList.size();) {
+ const auto &batch_desc = _spriteBatchDesc[_spriteList[cur_spr].node];
+ const ALSpriteBatch &batch = _spriteBatches[_spriteList[cur_spr].node];
+ const Rect &viewport = batch_desc.Viewport;
+ const SpriteTransform &transform = batch_desc.Transform;
virtualScreen->SetClip(viewport);
Bitmap *surface = batch.Surface.get();
@@ -318,38 +320,38 @@ void ScummVMRendererGraphicsDriver::RenderToBackBuffer() {
if (!batch.Opaque)
surface->ClearTransparent();
_stageVirtualScreen = surface;
- RenderSpriteBatch(batch, surface, transform.X, transform.Y);
+ cur_spr = RenderSpriteBatch(batch, cur_spr, surface, transform.X, transform.Y);
if (!batch.IsVirtualScreen)
virtualScreen->StretchBlt(surface, RectWH(view_offx, view_offy, viewport.GetWidth(), viewport.GetHeight()),
- batch.Opaque ? kBitmap_Copy : kBitmap_Transparency);
+ batch.Opaque ? kBitmap_Copy : kBitmap_Transparency);
} else {
- RenderSpriteBatch(batch, virtualScreen, view_offx + transform.X, view_offy + transform.Y);
+ cur_spr = RenderSpriteBatch(batch, cur_spr, virtualScreen, view_offx + transform.X, view_offy + transform.Y);
}
_stageVirtualScreen = virtualScreen;
}
ClearDrawLists();
}
-void ScummVMRendererGraphicsDriver::RenderSpriteBatch(const ALSpriteBatch &batch, Shared::Bitmap *surface, int surf_offx, int surf_offy) {
- const std::vector<ALDrawListEntry> &drawlist = batch.List;
- for (size_t i = 0; i < drawlist.size(); i++) {
- if (drawlist[i].bitmap == nullptr) {
+size_t ScummVMRendererGraphicsDriver::RenderSpriteBatch(const ALSpriteBatch &batch, size_t from, Bitmap *surface, int surf_offx, int surf_offy) {
+ for (; (from < _spriteList.size()) && (_spriteList[from].node == batch.ID); ++from) {
+ const auto &sprite = _spriteList[from];
+ if (sprite.ddb == nullptr) {
if (_nullSpriteCallback)
- _nullSpriteCallback(drawlist[i].x, drawlist[i].y);
+ _nullSpriteCallback(sprite.x, sprite.y);
else
error("Unhandled attempt to draw null sprite");
continue;
- } else if (drawlist[i].bitmap == (ALSoftwareBitmap *)0x1) {
+ } else if (sprite.ddb == reinterpret_cast<ALSoftwareBitmap *>(DRAWENTRY_TINT)) {
// draw screen tint fx
set_trans_blender(_tint_red, _tint_green, _tint_blue, 0);
surface->LitBlendBlt(surface, 0, 0, 128);
continue;
}
- ALSoftwareBitmap *bitmap = drawlist[i].bitmap;
- int drawAtX = drawlist[i].x + surf_offx;
- int drawAtY = drawlist[i].y + surf_offy;
+ ALSoftwareBitmap *bitmap = sprite.ddb;
+ int drawAtX = sprite.x + surf_offx;
+ int drawAtY = sprite.y + surf_offy;
if (bitmap->_transparency >= 255) {
} // fully transparent, do nothing
@@ -370,9 +372,10 @@ void ScummVMRendererGraphicsDriver::RenderSpriteBatch(const ALSpriteBatch &batch
} else {
// here _transparency is used as alpha (between 1 and 254), but 0 means opaque!
GfxUtil::DrawSpriteWithTransparency(surface, bitmap->_bmp, drawAtX, drawAtY,
- bitmap->_transparency ? bitmap->_transparency : 255);
+ bitmap->_transparency ? bitmap->_transparency : 255);
}
}
+ return from;
}
void ScummVMRendererGraphicsDriver::copySurface(const Graphics::Surface &src, bool mode) {
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.h b/engines/ags/engine/gfx/ali_3d_scummvm.h
index 7023f4ca1e6..e4a2f29adb8 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.h
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.h
@@ -143,14 +143,13 @@ private:
typedef SpriteDrawListEntry<ALSoftwareBitmap> ALDrawListEntry;
// Software renderer's sprite batch
struct ALSpriteBatch {
- // List of sprites to render
- std::vector<ALDrawListEntry> List;
+ uint32_t ID = 0;
// Intermediate surface which will be drawn upon and transformed if necessary
- std::shared_ptr<Bitmap> Surface;
+ std::shared_ptr<Bitmap> Surface;
// Whether surface is a virtual screen's region
- bool IsVirtualScreen;
+ bool IsVirtualScreen = false;
// Tells whether the surface is treated as opaque or transparent
- bool Opaque;
+ bool Opaque = false;
};
typedef std::vector<ALSpriteBatch> ALSpriteBatches;
@@ -181,10 +180,10 @@ public:
int GetCompatibleBitmapFormat(int color_depth) override;
IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) override;
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool hasAlpha, bool opaque) override;
- void UpdateDDBFromBitmap(IDriverDependantBitmap *bitmapToUpdate, Bitmap *bitmap, bool hasAlpha) override;
- void DestroyDDB(IDriverDependantBitmap *bitmap) override;
+ void UpdateDDBFromBitmap(IDriverDependantBitmap *ddb, Bitmap *bitmap, bool hasAlpha) override;
+ void DestroyDDB(IDriverDependantBitmap *ddb) override;
- void DrawSprite(int x, int y, IDriverDependantBitmap *bitmap) override;
+ void DrawSprite(int x, int y, IDriverDependantBitmap *ddb) override;
void SetScreenFade(int red, int green, int blue) override;
void SetScreenTint(int red, int green, int blue) override;
@@ -252,7 +251,10 @@ private:
Bitmap *_stageVirtualScreen;
int _tint_red, _tint_green, _tint_blue;
+ // Sprite batches (parent scene nodes)
ALSpriteBatches _spriteBatches;
+ // List of sprites to render
+ std::vector<ALDrawListEntry> _spriteList;
void InitSpriteBatch(size_t index, const SpriteBatchDesc &desc) override;
void ResetAllBatches() override;
@@ -263,7 +265,7 @@ private:
// Unset parameters and release resources related to the display mode
void ReleaseDisplayMode();
// Renders single sprite batch on the precreated surface
- void RenderSpriteBatch(const ALSpriteBatch &batch, Shared::Bitmap *surface, int surf_offx, int surf_offy);
+ size_t RenderSpriteBatch(const ALSpriteBatch &batch, size_t from, Shared::Bitmap *surface, int surf_offx, int surf_offy);
void highcolor_fade_in(Bitmap *vs, void(*draw_callback)(), int offx, int offy, int speed, int targetColourRed, int targetColourGreen, int targetColourBlue);
void highcolor_fade_out(Bitmap *vs, void(*draw_callback)(), int offx, int offy, int speed, int targetColourRed, int targetColourGreen, int targetColourBlue);
diff --git a/engines/ags/engine/gfx/gfx_driver_base.h b/engines/ags/engine/gfx/gfx_driver_base.h
index 5c669b549ef..b1fbd460dbf 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.h
+++ b/engines/ags/engine/gfx/gfx_driver_base.h
@@ -71,19 +71,15 @@ typedef std::vector<SpriteBatchDesc> SpriteBatchDescs;
// The single sprite entry in the render list
template<class T_DDB>
struct SpriteDrawListEntry {
- T_DDB *bitmap; // TODO: use shared pointer?
- int x, y; // sprite position, in camera coordinates
- bool skip;
-
- SpriteDrawListEntry()
- : bitmap(nullptr)
- , x(0)
- , y(0)
- , skip(false) {
- }
-
- SpriteDrawListEntry(T_DDB *ddb, int x_ = 0, int y_ = 0)
- : bitmap(ddb)
+ T_DDB *ddb = nullptr; // TODO: use shared pointer?
+ uint32_t node = 0; // sprite batch / scene node index
+ int x = 0, y = 0; // sprite position, in local batch / node coordinates
+ bool skip = false;
+
+ SpriteDrawListEntry() = default;
+ SpriteDrawListEntry(T_DDB * ddb_, uint32_t node_, int x_, int y_)
+ : ddb(ddb_)
+ , node(node_)
, x(x_)
, y(y_)
, skip(false) {
@@ -123,6 +119,11 @@ public:
}
protected:
+ // Special internal values, applied to DrawListEntry
+ static const intptr_t DRAWENTRY_STAGECALLBACK = 0x0;
+ static const intptr_t DRAWENTRY_FADE = 0x1;
+ static const intptr_t DRAWENTRY_TINT = 0x2;
+
// Called after graphics driver was initialized for use for the first time
virtual void OnInit();
// Called just before graphics mode is going to be uninitialized and its
Commit: 2b96f0ff67bf86b6218ad9f9deefe2de098d5614
https://github.com/scummvm/scummvm/commit/2b96f0ff67bf86b6218ad9f9deefe2de098d5614
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:20-07:00
Commit Message:
AGS: Sprite batches may have parents
>From upstream 369b3985400284df53695cee4d3f8f2dfc138beb
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/gfx/ali_3d_scummvm.cpp
engines/ags/engine/gfx/gfx_driver_base.cpp
engines/ags/engine/gfx/gfx_driver_base.h
engines/ags/engine/gfx/graphics_driver.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 915fbd9e1ef..15db3378dc9 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -661,15 +661,16 @@ void render_black_borders() {
_G(gfxDriver)->DrawSprite(0, 0, _G(blankSidebarImage));
_G(gfxDriver)->DrawSprite(viewport.Right + 1, 0, _G(blankSidebarImage));
}
+ _G(gfxDriver)->EndSpriteBatch();
}
}
-
void render_to_screen() {
// Stage: final plugin callback (still drawn on game screen
if (pl_any_want_hook(AGSE_FINALSCREENDRAW)) {
_G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform(), Point(0, _GP(play).shake_screen_yoff), (GlobalFlipType)_GP(play).screen_flipped);
_G(gfxDriver)->DrawSprite(AGSE_FINALSCREENDRAW, 0, nullptr);
+ _G(gfxDriver)->EndSpriteBatch();
}
// Stage: engine overlay
construct_engine_overlay();
@@ -2207,6 +2208,7 @@ static void construct_room_view() {
}
}
put_sprite_list_on_screen(true);
+ _G(gfxDriver)->EndSpriteBatch();
}
clear_draw_list();
@@ -2217,6 +2219,7 @@ static void construct_ui_view() {
_G(gfxDriver)->BeginSpriteBatch(_GP(play).GetUIViewportAbs(), SpriteTransform(), Point(0, _GP(play).shake_screen_yoff), (GlobalFlipType)_GP(play).screen_flipped);
draw_gui_and_overlays();
put_sprite_list_on_screen(false);
+ _G(gfxDriver)->EndSpriteBatch();
clear_draw_list();
}
@@ -2265,9 +2268,13 @@ void construct_game_scene(bool full_redraw) {
}
void construct_game_screen_overlay(bool draw_mouse) {
- _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform(), Point(0, _GP(play).shake_screen_yoff), (GlobalFlipType)_GP(play).screen_flipped);
- if (pl_any_want_hook(AGSE_POSTSCREENDRAW))
+ if (pl_any_want_hook(AGSE_POSTSCREENDRAW)) {
+ _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(),
+ SpriteTransform(), Point(0, _GP(play).shake_screen_yoff),
+ (GlobalFlipType)_GP(play).screen_flipped);
_G(gfxDriver)->DrawSprite(AGSE_POSTSCREENDRAW, 0, nullptr);
+ _G(gfxDriver)->EndSpriteBatch();
+ }
// 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
@@ -2301,18 +2308,19 @@ void construct_game_screen_overlay(bool draw_mouse) {
_G(lastmy) = _G(mousey);
}
- // 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),
- _G(mouseCursor));
- invalidate_sprite(_G(mousex) - _G(hotx), _G(mousey) - _G(hoty), _G(mouseCursor), false);
- }
-
if (_GP(play).screen_is_faded_out == 0) {
+ // Stage: mouse cursor
+ _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform(), Point(0, _GP(play).shake_screen_yoff), (GlobalFlipType)_GP(play).screen_flipped);
+ if (draw_mouse && !_GP(play).mouse_cursor_hidden) {
+ _G(gfxDriver)->DrawSprite(_G(mousex) - _G(hotx), _G(mousey) - _G(hoty), _G(mouseCursor));
+ invalidate_sprite(_G(mousex) - _G(hotx), _G(mousey) - _G(hoty), _G(mouseCursor), false);
+ }
// Stage: screen fx
if (_GP(play).screen_tint >= 1)
_G(gfxDriver)->SetScreenTint(_GP(play).screen_tint & 0xff, (_GP(play).screen_tint >> 8) & 0xff, (_GP(play).screen_tint >> 16) & 0xff);
- // Stage: legacy letterbox mode borders
+ _G(gfxDriver)->EndSpriteBatch();
+
+ // Stage: legacy letterbox mode borders (has its own sprite batch)
render_black_borders();
}
@@ -2320,6 +2328,7 @@ void construct_game_screen_overlay(bool draw_mouse) {
const Rect &main_viewport = _GP(play).GetMainViewport();
_G(gfxDriver)->BeginSpriteBatch(main_viewport, SpriteTransform());
_G(gfxDriver)->SetScreenFade(_GP(play).fade_to_red, _GP(play).fade_to_green, _GP(play).fade_to_blue);
+ _G(gfxDriver)->EndSpriteBatch();
}
}
@@ -2357,6 +2366,8 @@ void construct_engine_overlay() {
if (_G(display_fps) != kFPS_Hide)
draw_fps(viewport);
+
+ _G(gfxDriver)->EndSpriteBatch();
}
static void update_shakescreen() {
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.cpp b/engines/ags/engine/gfx/ali_3d_scummvm.cpp
index 79efe05f1ac..2ff6e418d61 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.cpp
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.cpp
@@ -295,6 +295,11 @@ void ScummVMRendererGraphicsDriver::SetScreenTint(int red, int green, int blue)
}
void ScummVMRendererGraphicsDriver::RenderToBackBuffer() {
+ // Close unended batches, and issue a warning
+ assert(_actSpriteBatch == 0);
+ while (_actSpriteBatch > 0)
+ EndSpriteBatch();
+
// Render all the sprite batches with necessary transformations
//
// NOTE: that's not immediately clear whether it would be faster to first draw upon a camera-sized
diff --git a/engines/ags/engine/gfx/gfx_driver_base.cpp b/engines/ags/engine/gfx/gfx_driver_base.cpp
index 874467d8d20..a74ba4e15c8 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.cpp
+++ b/engines/ags/engine/gfx/gfx_driver_base.cpp
@@ -66,12 +66,16 @@ Rect GraphicsDriverBase::GetRenderDestination() const {
}
void GraphicsDriverBase::BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform,
- const Point offset, GlobalFlipType flip, PBitmap surface) {
- _actSpriteBatch++;
- _spriteBatchDesc.push_back(SpriteBatchDesc(viewport, transform, offset, flip, surface));
+ const Point offset, GlobalFlipType flip, PBitmap surface) {
+ _spriteBatchDesc.push_back(SpriteBatchDesc(_actSpriteBatch, viewport, transform, offset, flip, surface));
+ _actSpriteBatch = _spriteBatchDesc.size() - 1;
InitSpriteBatch(_actSpriteBatch, _spriteBatchDesc[_actSpriteBatch]);
}
+void GraphicsDriverBase::EndSpriteBatch() {
+ _actSpriteBatch = _spriteBatchDesc[_actSpriteBatch].Parent;
+}
+
void GraphicsDriverBase::ClearDrawLists() {
ResetAllBatches();
_actSpriteBatch = 0;
diff --git a/engines/ags/engine/gfx/gfx_driver_base.h b/engines/ags/engine/gfx/gfx_driver_base.h
index b1fbd460dbf..35b62a657a2 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.h
+++ b/engines/ags/engine/gfx/gfx_driver_base.h
@@ -42,6 +42,7 @@ using Shared::PlaneScaling;
// Sprite batch, defines viewport and an optional model transformation for the list of sprites
struct SpriteBatchDesc {
+ uint32_t Parent = 0;
// View rectangle for positioning and clipping, in resolution coordinates
// (this may be screen or game frame resolution, depending on circumstances)
Rect Viewport;
@@ -50,15 +51,15 @@ struct SpriteBatchDesc {
// Global node offset applied to the whole batch as the last transform
Point Offset;
// Global node flip applied to the whole batch as the last transform
- GlobalFlipType Flip;
+ GlobalFlipType Flip = kFlip_None;
// Optional bitmap to draw sprites upon. Used exclusively by the software rendering mode.
PBitmap Surface;
- SpriteBatchDesc() : Flip(kFlip_None) {
- }
- SpriteBatchDesc(const Rect viewport, const SpriteTransform &transform, const Point offset = Point(),
- GlobalFlipType flip = kFlip_None, PBitmap surface = nullptr)
- : Viewport(viewport)
+ SpriteBatchDesc() = default;
+ SpriteBatchDesc(uint32_t parent, const Rect viewport, const SpriteTransform & transform, const Point offset = Point(),
+ GlobalFlipType flip = kFlip_None, PBitmap surface = nullptr)
+ : Parent(parent)
+ , Viewport(viewport)
, Transform(transform)
, Offset(offset)
, Flip(flip)
@@ -102,6 +103,7 @@ public:
void BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform,
const Point offset = Point(), GlobalFlipType flip = kFlip_None, PBitmap surface = nullptr) override;
+ void EndSpriteBatch() override;
void ClearDrawLists() override;
void SetCallbackForPolling(GFXDRV_CLIENTCALLBACK callback) override {
diff --git a/engines/ags/engine/gfx/graphics_driver.h b/engines/ags/engine/gfx/graphics_driver.h
index 7d20f1ad766..a8fa2d6381a 100644
--- a/engines/ags/engine/gfx/graphics_driver.h
+++ b/engines/ags/engine/gfx/graphics_driver.h
@@ -135,8 +135,12 @@ public:
// Prepares next sprite batch, a list of sprites with defined viewport and optional
// global model transformation; all subsequent calls to DrawSprite will be adding
// sprites to this batch's list.
+ // Beginning a batch while the previous was not ended will create a sub-batch
+ // (think of it as of a child scene node).
virtual void BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform,
- const Point offset = Point(), GlobalFlipType flip = kFlip_None, PBitmap surface = nullptr) = 0;
+ const Point offset = Point(), GlobalFlipType flip = kFlip_None, PBitmap surface = nullptr) = 0;
+ // Ends current sprite batch
+ virtual void EndSpriteBatch() = 0;
// Adds sprite to the active batch
virtual void DrawSprite(int x, int y, IDriverDependantBitmap *bitmap) = 0;
// Adds fade overlay fx to the active batch
Commit: 2f558ae1ed0d293091d690d9839f0abb256ade77
https://github.com/scummvm/scummvm/commit/2f558ae1ed0d293091d690d9839f0abb256ade77
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:20-07:00
Commit Message:
AGS: Fixed 8-bit sprites unexpectedly converted on load
>From upstream b9804f5ac307e390de205b20f7c803dcf6812df2
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 15db3378dc9..053c030fc24 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -168,8 +168,8 @@ Bitmap *AdjustBitmapForUseWithDisplayMode(Bitmap *bitmap, bool has_alpha) {
}
// Finally, if we did not create a new copy already, - convert to driver compatible format
- if ((new_bitmap == bitmap) && (bmp_col_depth != compat_col_depth))
- new_bitmap = GfxUtil::ConvertBitmap(bitmap, compat_col_depth);
+ if (new_bitmap == bitmap)
+ new_bitmap = GfxUtil::ConvertBitmap(bitmap, _G(gfxDriver)->GetCompatibleBitmapFormat(bitmap->GetColorDepth()));
if (must_switch_palette)
unselect_palette();
Commit: d09117334df1a8426dbc8e466b0c528e853198f9
https://github.com/scummvm/scummvm/commit/d09117334df1a8426dbc8e466b0c528e853198f9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:20-07:00
Commit Message:
AGS: Removed obscure hack in DrawSpriteWithTransparency()
>From upstream 083d8496f2d7c0eedc31c068ddf27720dee4ff2b
Changed paths:
engines/ags/engine/gfx/gfx_util.cpp
diff --git a/engines/ags/engine/gfx/gfx_util.cpp b/engines/ags/engine/gfx/gfx_util.cpp
index e872431d128..ff2743cc3d7 100644
--- a/engines/ags/engine/gfx/gfx_util.cpp
+++ b/engines/ags/engine/gfx/gfx_util.cpp
@@ -103,12 +103,7 @@ void DrawSpriteWithTransparency(Bitmap *ds, Bitmap *sprite, int x, int y, int al
int surface_depth = ds->GetColorDepth();
int sprite_depth = sprite->GetColorDepth();
- if (sprite_depth < surface_depth
- // CHECKME: what is the purpose of this hack and is this still relevant?
-#if AGS_PLATFORM_OS_IOS || AGS_PLATFORM_OS_ANDROID
- || (ds->GetBPP() < surface_depth && _G(psp_gfx_renderer) > 0) // Fix for corrupted speechbox outlines with the OGL driver
-#endif
- ) {
+ if (sprite_depth < surface_depth) {
// If sprite is lower color depth than destination surface, e.g.
// 8-bit sprites drawn on 16/32-bit surfaces.
if (sprite_depth == 8 && surface_depth >= 24) {
Commit: fec8ab31837743cca2342154087515f77e56281e
https://github.com/scummvm/scummvm/commit/fec8ab31837743cca2342154087515f77e56281e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:21-07:00
Commit Message:
AGS: Simplified DrawSpriteWithTransparency() a little
>From upstream 38922c2eb62b8082ae7ba07f07a8fe2192f1bac5
Changed paths:
engines/ags/engine/gfx/gfx_util.cpp
diff --git a/engines/ags/engine/gfx/gfx_util.cpp b/engines/ags/engine/gfx/gfx_util.cpp
index ff2743cc3d7..4772a6ef19c 100644
--- a/engines/ags/engine/gfx/gfx_util.cpp
+++ b/engines/ags/engine/gfx/gfx_util.cpp
@@ -100,8 +100,9 @@ void DrawSpriteWithTransparency(Bitmap *ds, Bitmap *sprite, int x, int y, int al
return;
}
- int surface_depth = ds->GetColorDepth();
- int sprite_depth = sprite->GetColorDepth();
+ Bitmap hctemp;
+ const int surface_depth = ds->GetColorDepth();
+ const int sprite_depth = sprite->GetColorDepth();
if (sprite_depth < surface_depth) {
// If sprite is lower color depth than destination surface, e.g.
@@ -115,7 +116,6 @@ void DrawSpriteWithTransparency(Bitmap *ds, Bitmap *sprite, int x, int y, int al
// 256-col sprite -> hi-color background, or
// 16-bit sprite -> 32-bit background
- Bitmap hctemp;
hctemp.CreateCopy(sprite, surface_depth);
if (sprite_depth == 8) {
// only do this for 256-col -> hi-color, cos the Blit call converts
@@ -133,19 +133,14 @@ void DrawSpriteWithTransparency(Bitmap *ds, Bitmap *sprite, int x, int y, int al
}
}
- if (alpha < 0xFF) {
- set_trans_blender(0, 0, 0, alpha);
- ds->TransBlendBlt(&hctemp, x, y);
- } else {
- ds->Blit(&hctemp, x, y, kBitmap_Transparency);
- }
+ sprite = &hctemp;
+ }
+
+ if ((alpha < 0xFF) && (surface_depth > 8) && (sprite_depth > 8)) {
+ set_trans_blender(0, 0, 0, alpha);
+ ds->TransBlendBlt(sprite, x, y);
} else {
- if (alpha < 0xFF && surface_depth > 8 && sprite_depth > 8) {
- set_trans_blender(0, 0, 0, alpha);
- ds->TransBlendBlt(sprite, x, y);
- } else {
- ds->Blit(sprite, x, y, kBitmap_Transparency);
- }
+ ds->Blit(sprite, x, y, kBitmap_Transparency);
}
}
Commit: d52e2fb9543f26207ec01dfde8808adaa8112791
https://github.com/scummvm/scummvm/commit/d52e2fb9543f26207ec01dfde8808adaa8112791
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:21-07:00
Commit Message:
AGS: Gui control textures are rendered as gui sub-batches
>From upstream 663394adb286384ba1b03ad95abc93a8dac40b05
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/sprite_list_entry.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 053c030fc24..13ecc187c2a 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -772,10 +772,10 @@ static void clear_draw_list() {
_GP(thingsToDrawList).clear();
}
-static void add_thing_to_draw(IDriverDependantBitmap *bmp, int x, int y) {
- assert(bmp != nullptr);
+static void add_thing_to_draw(IDriverDependantBitmap *ddb, int x, int y) {
+ assert(ddb != nullptr);
SpriteListEntry sprite;
- sprite.bmp = bmp;
+ sprite.ddb = ddb;
sprite.x = x;
sprite.y = y;
_GP(thingsToDrawList).push_back(sprite);
@@ -791,18 +791,18 @@ static void clear_sprite_list() {
_GP(sprlist).clear();
}
-static void add_to_sprite_list(IDriverDependantBitmap *spp, int xx, int yy, int zorder, bool isWalkBehind) {
- if (spp == nullptr)
- quit("add_to_sprite_list: attempted to draw NULL sprite");
+static void add_to_sprite_list(IDriverDependantBitmap *ddb, int x, int y, int zorder, bool isWalkBehind, int id = -1) {
+ assert(ddb);
// completely invisible, so don't draw it at all
- if (spp->GetTransparency() == 255)
+ if (ddb->GetTransparency() == 255)
return;
SpriteListEntry sprite;
- sprite.bmp = spp;
+ sprite.id = id;
+ sprite.ddb = ddb;
sprite.zorder = zorder;
- sprite.x = xx;
- sprite.y = yy;
+ sprite.x = x;
+ sprite.y = y;
if (_G(walkBehindMethod) == DrawAsSeparateSprite)
sprite.takesPriorityIfEqual = !isWalkBehind;
@@ -812,8 +812,14 @@ static void add_to_sprite_list(IDriverDependantBitmap *spp, int xx, int yy, int
_GP(sprlist).push_back(sprite);
}
-// function to sort the sprites into zorder order
+// z-order sorting function for sprites
static bool spritelistentry_less(const SpriteListEntry &e1, const SpriteListEntry &e2) {
+ return (e1.zorder < e2.zorder);
+}
+
+// room-specialized function to sort the sprites into baseline order
+// has special handling for walk-behinds (this is complicated...)
+static bool spritelistentry_room_less(const SpriteListEntry &e1, const SpriteListEntry &e2) {
if (e1.zorder == e2.zorder) {
if (e1.takesPriorityIfEqual)
return false;
@@ -824,11 +830,14 @@ static bool spritelistentry_less(const SpriteListEntry &e1, const SpriteListEntr
}
// copy the sorted sprites into the Things To Draw list
-static void draw_sprite_list() {
- std::sort(_GP(sprlist).begin(), _GP(sprlist).end(), spritelistentry_less);
- _GP(thingsToDrawList).insert(_GP(thingsToDrawList).end(), _GP(sprlist).begin(), _GP(sprlist).end());
+static void draw_sprite_list(bool is_room) {
+ std::sort(_GP(sprlist).begin(), _GP(sprlist).end(), is_room ? spritelistentry_room_less : spritelistentry_less);
+ _GP(thingsToDrawList).insert(_GP(thingsToDrawList).end(),
+ _GP(sprlist).begin(), _GP(sprlist).end());
}
+// Push the gathered list of sprites into the active graphic renderer
+void put_sprite_list_on_screen(bool in_room);
//
//------------------------------------------------------------------------
@@ -1857,7 +1866,7 @@ void prepare_room_sprites() {
if (pl_any_want_hook(AGSE_PRESCREENDRAW))
add_render_stage(AGSE_PRESCREENDRAW);
- draw_sprite_list();
+ draw_sprite_list(true);
}
}
_G(our_eip) = 36;
@@ -2001,37 +2010,32 @@ void draw_gui_and_overlays() {
&& (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper);
if (pl_any_want_hook(AGSE_PREGUIDRAW))
- add_render_stage(AGSE_PREGUIDRAW);
+ _G(gfxDriver)->DrawSprite(AGSE_PREGUIDRAW, 0, nullptr); // render stage
clear_sprite_list();
// Add active overlays to the sprite list
for (auto &over : _GP(screenover)) {
- if (over.transparency == 255)
- continue; // skip fully transparent
+ if (over.transparency == 255) continue; // skip fully transparent
over.bmp->SetTransparency(over.transparency);
-
int tdxp, tdyp;
get_overlay_position(over, &tdxp, &tdyp);
- add_to_sprite_list(over.bmp, tdxp, tdyp, over.zorder, false);
+ add_to_sprite_list(over.bmp, tdxp, tdyp, over.zorder, false, -1);
}
// Add GUIs
_G(our_eip) = 35;
if (((_G(debug_flags) & DBG_NOIFACE) == 0) && (_G(displayed_room) >= 0)) {
- int aa;
-
if (_G(playerchar)->activeinv >= MAX_INV) {
quit("!The player.activeinv variable has been corrupted, probably as a result\n"
- "of an incorrect assignment in the game script.");
+ "of an incorrect assignment in the game script.");
}
- if (_G(playerchar)->activeinv < 1)
- _G(gui_inv_pic) = -1;
- else
- _G(gui_inv_pic) = _GP(game).invinfo[_G(playerchar)->activeinv].pic;
+ if (_G(playerchar)->activeinv < 1) _G(gui_inv_pic) = -1;
+ else _G(gui_inv_pic) = _GP(game).invinfo[_G(playerchar)->activeinv].pic;
_G(our_eip) = 37;
+ // Prepare and update GUI textures
{
- for (aa = 0; aa < _GP(game).numgui; aa++) {
+ for (int aa = 0; aa < _GP(game).numgui; aa++) {
if (!_GP(guis)[aa].IsDisplayed()) continue; // not on screen
if (!_GP(guis)[aa].HasChanged() && !_GP(guis)[aa].HasControlsChanged()) continue; // no changes: no need to update image
if (_GP(guis)[aa].Transparency == 255) continue; // 100% transparent
@@ -2076,78 +2080,90 @@ void draw_gui_and_overlays() {
}
_G(our_eip) = 38;
// Draw the GUIs
- for (int gg = 0; gg < _GP(game).numgui; gg++) {
- aa = _GP(play).gui_draw_order[gg];
+ for (int aa = 0; aa < _GP(game).numgui; ++aa) {
if (!_GP(guis)[aa].IsDisplayed()) continue; // not on screen
if (_GP(guis)[aa].Transparency == 255) continue; // 100% transparent
// Don't draw GUI if "GUIs Turn Off When Disabled"
if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) &&
- (_G(all_buttons_disabled) >= 0) &&
- (_GP(guis)[aa].PopupStyle != kGUIPopupNoAutoRemove))
+ (_G(all_buttons_disabled) >= 0) &&
+ (_GP(guis)[aa].PopupStyle != kGUIPopupNoAutoRemove))
continue;
- _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 + _GP(guiobjoff)[draw_index + obj_id].X,
- _GP(guis)[aa].Y + _GP(guiobjoff)[draw_index + obj_id].Y,
- _GP(guis)[aa].ZOrder, false);
- }
- }
+ auto *gui_ddb = _GP(guibgbmp)[aa];
+ assert(gui_ddb); // Test for missing texture, might happen if not marked for update
+ if (!gui_ddb) continue;
+ gui_ddb->SetTransparency(_GP(guis)[aa].Transparency);
+ add_to_sprite_list(gui_ddb, _GP(guis)[aa].X, _GP(guis)[aa].Y, _GP(guis)[aa].ZOrder, false, aa);
}
// Poll the GUIs
// TODO: move this out of the draw routine into game update!!
- // only poll if the interface is enabled
- if (IsInterfaceEnabled()) {
+ if (IsInterfaceEnabled()) // only poll if the interface is enabled
+ {
for (int gg = 0; gg < _GP(game).numgui; gg++) {
if (!_GP(guis)[gg].IsDisplayed()) continue; // not on screen
// Don't touch GUI if "GUIs Turn Off When Disabled"
if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) &&
- (_G(all_buttons_disabled) >= 0) &&
- (_GP(guis)[gg].PopupStyle != kGUIPopupNoAutoRemove))
+ (_G(all_buttons_disabled) >= 0) &&
+ (_GP(guis)[gg].PopupStyle != kGUIPopupNoAutoRemove))
continue;
_GP(guis)[gg].Poll(_G(mousex), _G(mousey));
}
}
}
- // sort and append ui sprites to the global draw things list
- draw_sprite_list();
+ // If not adding gui controls as textures, simply move the resulting sprlist to render
+ if (!draw_controls_as_textures ||
+ (_G(all_buttons_disabled) && (GUI::Options.DisabledStyle == kGuiDis_Blackout))) {
+ draw_sprite_list(false);
+ put_sprite_list_on_screen(false);
+ return;
+ }
+ // If adding control textures, sort the ui list, and then pass into renderer,
+ // adding controls and creating sub-batches as necessary
+ std::sort(_GP(sprlist).begin(), _GP(sprlist).end(), spritelistentry_less);
+ for (const auto &s : _GP(sprlist)) {
+ invalidate_sprite(s.x, s.y, s.ddb, false);
+ _G(gfxDriver)->DrawSprite(s.x, s.y, s.ddb);
+ if (s.id < 0) continue; // not a group parent (gui)
+ // Create a sub-batch
+ _G(gfxDriver)->BeginSpriteBatch(RectWH(s.x, s.y, s.ddb->GetWidth(), s.ddb->GetHeight()), SpriteTransform());
+ const int draw_index = _GP(guiobjbmpref)[s.id];
+ for (const auto &obj_id : _GP(guis)[s.id].GetControlsDrawOrder()) {
+ GUIObject *obj = _GP(guis)[s.id].GetControl(obj_id);
+ if (!obj->IsVisible() ||
+ (!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
+ continue;
+ auto *obj_ddb = _GP(guiobjbmp)[draw_index + obj_id];
+ assert(obj_ddb); // Test for missing texture, might happen if not marked for update
+ if (!obj_ddb) continue;
+ obj_ddb->SetTransparency(_GP(guis)[s.id].Transparency);
+ _G(gfxDriver)->DrawSprite(
+ _GP(guiobjoff)[draw_index + obj_id].X,
+ _GP(guiobjoff)[draw_index + obj_id].Y,
+ obj_ddb);
+ }
+ _G(gfxDriver)->EndSpriteBatch();
+ }
_G(our_eip) = 1099;
}
// Push the gathered list of sprites into the active graphic renderer
void put_sprite_list_on_screen(bool in_room) {
- for (size_t i = 0; i < _GP(thingsToDrawList).size(); ++i) {
- const auto *thisThing = &_GP(thingsToDrawList)[i];
-
- if (thisThing->bmp != nullptr) {
- if (thisThing->bmp->GetTransparency() == 255)
+ for (const auto &t : _GP(thingsToDrawList)) {
+ assert(t.ddb || (t.renderStage >= 0));
+ if (t.ddb) {
+ if (t.ddb->GetTransparency() == 255)
continue; // skip completely invisible things
// mark the image's region as dirty
- invalidate_sprite(thisThing->x, thisThing->y, thisThing->bmp, in_room);
-
+ invalidate_sprite(t.x, t.y, t.ddb, in_room);
// push to the graphics driver
- _G(gfxDriver)->DrawSprite(thisThing->x, thisThing->y, thisThing->bmp);
- } else if (thisThing->renderStage >= 0) {
+ _G(gfxDriver)->DrawSprite(t.x, t.y, t.ddb);
+ } else if (t.renderStage >= 0) {
// meta entry to run the plugin hook
- _G(gfxDriver)->DrawSprite(thisThing->renderStage, 0, nullptr);
- } else {
- quit("Null pointer added to draw list");
+ _G(gfxDriver)->DrawSprite(t.renderStage, 0, nullptr);
}
}
@@ -2218,7 +2234,6 @@ static void construct_room_view() {
static void construct_ui_view() {
_G(gfxDriver)->BeginSpriteBatch(_GP(play).GetUIViewportAbs(), SpriteTransform(), Point(0, _GP(play).shake_screen_yoff), (GlobalFlipType)_GP(play).screen_flipped);
draw_gui_and_overlays();
- put_sprite_list_on_screen(false);
_G(gfxDriver)->EndSpriteBatch();
clear_draw_list();
}
diff --git a/engines/ags/engine/ac/sprite_list_entry.h b/engines/ags/engine/ac/sprite_list_entry.h
index 3d6d061708a..0aeee8a16b9 100644
--- a/engines/ags/engine/ac/sprite_list_entry.h
+++ b/engines/ags/engine/ac/sprite_list_entry.h
@@ -26,8 +26,10 @@
namespace AGS3 {
+// Describes a texture or node description, for sorting and passing into renderer
struct SpriteListEntry {
- Engine::IDriverDependantBitmap *bmp = nullptr;
+ int id = -1; // user identifier, for any custom purpose
+ Engine::IDriverDependantBitmap *ddb = nullptr;
AGS::Shared::Bitmap *pic = nullptr;
int x = 0, y = 0;
int zorder = 0;
Commit: 211abe3744b0b79d58d0705465620273425b60e2
https://github.com/scummvm/scummvm/commit/211abe3744b0b79d58d0705465620273425b60e2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:21-07:00
Commit Message:
AGS: Implemented HasAlphaChannel() in GuiButton and GuiSlider
>From upstream 05999579489e427b7df7a01bab9643b6677d5afb
Changed paths:
engines/ags/shared/gui/gui_button.cpp
engines/ags/shared/gui/gui_button.h
engines/ags/shared/gui/gui_object.cpp
engines/ags/shared/gui/gui_object.h
engines/ags/shared/gui/gui_slider.cpp
engines/ags/shared/gui/gui_slider.h
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index 79f33f64dcc..fdd6a997b16 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -94,6 +94,10 @@ bool GUIButton::IsClippingImage() const {
return (Flags & kGUICtrl_Clip) != 0;
}
+bool GUIButton::HasAlphaChannel() const {
+ return is_sprite_alpha(CurrentImage);
+}
+
Rect GUIButton::CalcGraphicRect(bool clipped) {
if (clipped)
return RectWH(X, Y, Width, Height);
diff --git a/engines/ags/shared/gui/gui_button.h b/engines/ags/shared/gui/gui_button.h
index 8390a7c569a..e83f0242a38 100644
--- a/engines/ags/shared/gui/gui_button.h
+++ b/engines/ags/shared/gui/gui_button.h
@@ -65,6 +65,7 @@ public:
const String &GetText() const;
bool IsImageButton() const;
bool IsClippingImage() const;
+ bool HasAlphaChannel() const override;
// Operations
Rect CalcGraphicRect(bool clipped) override;
diff --git a/engines/ags/shared/gui/gui_object.cpp b/engines/ags/shared/gui/gui_object.cpp
index c2367983a7a..50264e0dbcd 100644
--- a/engines/ags/shared/gui/gui_object.cpp
+++ b/engines/ags/shared/gui/gui_object.cpp
@@ -82,10 +82,6 @@ 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 d7d857c2985..b66eee51397 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -63,7 +63,7 @@ public:
// 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;
+ virtual bool HasAlphaChannel() const { return false; }
// Operations
// Returns the (untransformed!) visual rectangle of this control,
diff --git a/engines/ags/shared/gui/gui_slider.cpp b/engines/ags/shared/gui/gui_slider.cpp
index d8445428688..2704b3ea7e2 100644
--- a/engines/ags/shared/gui/gui_slider.cpp
+++ b/engines/ags/shared/gui/gui_slider.cpp
@@ -49,6 +49,10 @@ bool GUISlider::IsHorizontal() const {
return Width > Height;
}
+bool GUISlider::HasAlphaChannel() const {
+ return is_sprite_alpha(BgImage) || is_sprite_alpha(HandleImage);
+}
+
bool GUISlider::IsOverControl(int x, int y, int leeway) const {
// check the overall boundary
if (GUIObject::IsOverControl(x, y, leeway))
diff --git a/engines/ags/shared/gui/gui_slider.h b/engines/ags/shared/gui/gui_slider.h
index 671afad38f6..3a7074b0ffc 100644
--- a/engines/ags/shared/gui/gui_slider.h
+++ b/engines/ags/shared/gui/gui_slider.h
@@ -39,6 +39,7 @@ public:
// Compatibility: sliders are not clipped as of 3.6.0
bool IsContentClipped() const override { return false; }
+ bool HasAlphaChannel() const override;
// Operations
Rect CalcGraphicRect(bool clipped) override;
Commit: d7375f0772ca3034eddc4fe883cad3419794ef69
https://github.com/scummvm/scummvm/commit/d7375f0772ca3034eddc4fe883cad3419794ef69
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:21-07:00
Commit Message:
AGS: Fixed GUIObject::SetVisible(), should MarkChanged
>From upstream e5aa27dfb7c4e8cd8dfaf9c418bb56df2b28ae7e
Changed paths:
engines/ags/shared/gui/gui_object.cpp
diff --git a/engines/ags/shared/gui/gui_object.cpp b/engines/ags/shared/gui/gui_object.cpp
index 50264e0dbcd..aac31a627b7 100644
--- a/engines/ags/shared/gui/gui_object.cpp
+++ b/engines/ags/shared/gui/gui_object.cpp
@@ -110,6 +110,7 @@ void GUIObject::SetVisible(bool on) {
Flags |= kGUICtrl_Visible;
else
Flags &= ~kGUICtrl_Visible;
+ MarkChanged();
}
// TODO: replace string serialization with StrUtil::ReadString and WriteString
Commit: 50b2b1af05cc416d06834cb9ba0d668f5949c248
https://github.com/scummvm/scummvm/commit/50b2b1af05cc416d06834cb9ba0d668f5949c248
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:21-07:00
Commit Message:
AGS: Replaced OnControlPositionChanged() with MarkControlsChanged()
>From upstream 2f676fbad2b725fe0089de45ba9f925bc48ab586
Changed paths:
engines/ags/engine/ac/global_gui.cpp
engines/ags/engine/ac/gui.cpp
engines/ags/engine/ac/gui_control.cpp
engines/ags/shared/gui/gui_main.cpp
engines/ags/shared/gui/gui_main.h
engines/ags/shared/gui/gui_object.h
diff --git a/engines/ags/engine/ac/global_gui.cpp b/engines/ags/engine/ac/global_gui.cpp
index c31c7ac3ad0..018b46ee960 100644
--- a/engines/ags/engine/ac/global_gui.cpp
+++ b/engines/ags/engine/ac/global_gui.cpp
@@ -76,7 +76,7 @@ void InterfaceOn(int ifn) {
// modal interface
if (_GP(guis)[ifn].PopupStyle == kGUIPopupModal) PauseGame();
// clear the cached mouse position
- _GP(guis)[ifn].OnControlPositionChanged();
+ _GP(guis)[ifn].MarkControlsChanged();
_GP(guis)[ifn].Poll(_G(mousex), _G(mousey));
}
@@ -93,7 +93,7 @@ void InterfaceOff(int ifn) {
_GP(guis)[ifn].GetControl(_GP(guis)[ifn].MouseOverCtrl)->OnMouseLeave();
_GP(guis)[ifn].MouseOverCtrl = -1;
}
- _GP(guis)[ifn].OnControlPositionChanged();
+ _GP(guis)[ifn].MarkControlsChanged();
// modal interface
if (_GP(guis)[ifn].PopupStyle == kGUIPopupModal) UnPauseGame();
}
diff --git a/engines/ags/engine/ac/gui.cpp b/engines/ags/engine/ac/gui.cpp
index 9fd3dc3e7e8..2a9727a6a1b 100644
--- a/engines/ags/engine/ac/gui.cpp
+++ b/engines/ags/engine/ac/gui.cpp
@@ -462,7 +462,7 @@ void update_gui_disabled_status() {
// As controls become enabled we must notify parent GUIs
// to let them reset control-under-mouse detection
for (int aa = 0; aa < _GP(game).numgui; aa++) {
- _GP(guis)[aa].OnControlPositionChanged(); // this marks GUI as changed too
+ _GP(guis)[aa].MarkControlsChanged();
}
if (GUI::Options.DisabledStyle != kGuiDis_Unchanged) {
invalidate_screen();
diff --git a/engines/ags/engine/ac/gui_control.cpp b/engines/ags/engine/ac/gui_control.cpp
index be2872d5f88..c34100a1f68 100644
--- a/engines/ags/engine/ac/gui_control.cpp
+++ b/engines/ags/engine/ac/gui_control.cpp
@@ -65,7 +65,6 @@ void GUIControl_SetVisible(GUIObject *guio, int visible) {
const bool on = visible != 0;
if (on != guio->IsVisible()) {
guio->SetVisible(on);
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
}
}
@@ -81,7 +80,8 @@ void GUIControl_SetClickable(GUIObject *guio, int enabled) {
else
guio->SetClickable(false);
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
+ // clickable property may change control behavior under mouse
+ _GP(guis)[guio->ParentId].MarkControlsChanged();
}
int GUIControl_GetEnabled(GUIObject *guio) {
@@ -92,7 +92,6 @@ void GUIControl_SetEnabled(GUIObject *guio, int enabled) {
const bool on = enabled != 0;
if (on != guio->IsEnabled()) {
guio->SetEnabled(on);
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
}
}
@@ -153,7 +152,7 @@ int GUIControl_GetX(GUIObject *guio) {
void GUIControl_SetX(GUIObject *guio, int xx) {
guio->X = data_to_game_coord(xx);
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
+ _GP(guis)[guio->ParentId].MarkControlsChanged(); // update control under cursor
}
int GUIControl_GetY(GUIObject *guio) {
@@ -162,7 +161,7 @@ int GUIControl_GetY(GUIObject *guio) {
void GUIControl_SetY(GUIObject *guio, int yy) {
guio->Y = data_to_game_coord(yy);
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
+ _GP(guis)[guio->ParentId].MarkControlsChanged(); // update control under cursor
}
int GUIControl_GetZOrder(GUIObject *guio) {
@@ -186,7 +185,6 @@ int GUIControl_GetWidth(GUIObject *guio) {
void GUIControl_SetWidth(GUIObject *guio, int newwid) {
guio->Width = data_to_game_coord(newwid);
guio->OnResized();
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
}
int GUIControl_GetHeight(GUIObject *guio) {
@@ -196,7 +194,6 @@ int GUIControl_GetHeight(GUIObject *guio) {
void GUIControl_SetHeight(GUIObject *guio, int newhit) {
guio->Height = data_to_game_coord(newhit);
guio->OnResized();
- _GP(guis)[guio->ParentId].OnControlPositionChanged();
}
void GUIControl_SetSize(GUIObject *guio, int newwid, int newhit) {
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index bf6e35c106f..67012f55e97 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -198,6 +198,9 @@ void GUIMain::MarkChanged() {
void GUIMain::MarkControlsChanged() {
_hasControlsChanged = true;
+ // force it to re-check for which control is under the mouse
+ MouseWasAt.X = -1;
+ MouseWasAt.Y = -1;
}
void GUIMain::ClearChanged() {
@@ -432,7 +435,7 @@ bool GUIMain::SetControlZOrder(int32_t index, int zorder) {
}
}
ResortZOrder();
- OnControlPositionChanged(); // this marks GUI as changed
+ MarkControlsChanged();
return true;
}
@@ -456,13 +459,6 @@ void GUIMain::SetVisible(bool on) {
MarkChanged();
}
-void GUIMain::OnControlPositionChanged() {
- // force it to re-check for which control is under the mouse
- MouseWasAt.X = -1;
- MouseWasAt.Y = -1;
- MarkChanged();
-}
-
void GUIMain::OnMouseButtonDown(int mx, int my) {
if (MouseOverCtrl < 0)
return;
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index 91da669de22..7ad5fcfe988 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -153,7 +153,6 @@ public:
// Events
void OnMouseButtonDown(int mx, int my);
void OnMouseButtonUp();
- void OnControlPositionChanged();
// Serialization
void ReadFromFile(Stream *in, GuiVersion gui_version);
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index b66eee51397..c778be2367a 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -99,8 +99,7 @@ public:
virtual void OnMouseUp() {
}
// Control was resized
- virtual void OnResized() {
- }
+ virtual void OnResized() { MarkChanged(); }
// Serialization
virtual void ReadFromFile(Shared::Stream *in, GuiVersion gui_version);
Commit: 53e1c221856ac1f0112d8e037fedd284d41abfb4
https://github.com/scummvm/scummvm/commit/53e1c221856ac1f0112d8e037fedd284d41abfb4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:22-07:00
Commit Message:
AGS: Fixes for the updated sprite batch system
>From upstream db57e5b06aaf60728e1ade30a61f84d5850596dc
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/event.cpp
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 13ecc187c2a..9c43710e3e3 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2340,8 +2340,7 @@ void construct_game_screen_overlay(bool draw_mouse) {
}
if (_GP(play).screen_is_faded_out != 0 && _G(gfxDriver)->RequiresFullRedrawEachFrame()) {
- const Rect &main_viewport = _GP(play).GetMainViewport();
- _G(gfxDriver)->BeginSpriteBatch(main_viewport, SpriteTransform());
+ _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform());
_G(gfxDriver)->SetScreenFade(_GP(play).fade_to_red, _GP(play).fade_to_green, _GP(play).fade_to_blue);
_G(gfxDriver)->EndSpriteBatch();
}
@@ -2486,10 +2485,13 @@ void render_graphics(IDriverDependantBitmap *extraBitmap, int extraX, int extraY
construct_game_scene(false);
_G(our_eip) = 5;
- // NOTE: extraBitmap will always be drawn with the UI render stage
+ // TODO: extraBitmap is a hack, used to place an additional gui element
+ // on top of the screen. Normally this should be a part of the game UI stage.
if (extraBitmap != nullptr) {
+ _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetUIViewportAbs(), SpriteTransform(), Point(0, _GP(play).shake_screen_yoff), (GlobalFlipType)_GP(play).screen_flipped);
invalidate_sprite(extraX, extraY, extraBitmap, false);
_G(gfxDriver)->DrawSprite(extraX, extraY, extraBitmap);
+ _G(gfxDriver)->EndSpriteBatch();
}
construct_game_screen_overlay(true);
render_to_screen();
diff --git a/engines/ags/engine/ac/event.cpp b/engines/ags/engine/ac/event.cpp
index 413d4545ba0..d7cbd2c9a8c 100644
--- a/engines/ags/engine/ac/event.cpp
+++ b/engines/ags/engine/ac/event.cpp
@@ -280,7 +280,9 @@ void process_event(const EventHappened *evp) {
if (transparency > 16) {
// on last frame of fade (where transparency < 16), don't
// draw the old screen on top
+ _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform());
_G(gfxDriver)->DrawSprite(0, 0, ddb);
+ _G(gfxDriver)->EndSpriteBatch();
}
render_to_screen();
update_polled_stuff_if_runtime();
@@ -314,7 +316,9 @@ void process_event(const EventHappened *evp) {
_G(gfxDriver)->UpdateDDBFromBitmap(ddb, _G(saved_viewport_bitmap), false);
construct_game_scene(true);
construct_game_screen_overlay(false);
+ _G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform());
_G(gfxDriver)->DrawSprite(0, 0, ddb);
+ _G(gfxDriver)->EndSpriteBatch();
render_to_screen();
update_polled_stuff_if_runtime();
WaitForNextFrame();
Commit: 6ef504bba20ac88daaee8a66efe3e2ed87c94c56
https://github.com/scummvm/scummvm/commit/6ef504bba20ac88daaee8a66efe3e2ed87c94c56
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:22-07:00
Commit Message:
AGS: Store gui draw order in a std::vector
>From upstream fcc873ef0c26439faf67100f4d70d540434ca9f5
Changed paths:
engines/ags/engine/ac/game.cpp
engines/ags/engine/ac/game_state.h
engines/ags/engine/ac/global_gui.cpp
engines/ags/engine/ac/gui.cpp
engines/ags/engine/game/game_init.cpp
engines/ags/engine/game/savegame_v321.cpp
engines/ags/lib/std/vector.h
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index edd0feeaa00..d5f5874449f 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -444,7 +444,7 @@ void unload_game_file() {
ccUnregisterAllObjects();
free_do_once_tokens();
- free(_GP(play).gui_draw_order);
+ _GP(play).gui_draw_order.clear();
resetRoomStatuses();
diff --git a/engines/ags/engine/ac/game_state.h b/engines/ags/engine/ac/game_state.h
index 0dfec5c0eba..7f31420a9be 100644
--- a/engines/ags/engine/ac/game_state.h
+++ b/engines/ags/engine/ac/game_state.h
@@ -226,7 +226,7 @@ struct GameState {
int gamma_adjustment = 0;
short temporarily_turned_off_character = 0; // Hide Player Charactr ticked
short inv_backwards_compatibility = 0;
- int32_t *gui_draw_order = 0;
+ std::vector<int> gui_draw_order; // used only for hit detection now
std::vector<AGS::Shared::String> do_once_tokens = 0;
int text_min_display_time_ms = 0;
int ignore_user_input_after_text_timeout_ms = 0;
diff --git a/engines/ags/engine/ac/global_gui.cpp b/engines/ags/engine/ac/global_gui.cpp
index 018b46ee960..8d3f2df278f 100644
--- a/engines/ags/engine/ac/global_gui.cpp
+++ b/engines/ags/engine/ac/global_gui.cpp
@@ -243,11 +243,11 @@ int GetGUIObjectAt(int xx, int yy) {
int GetGUIAt(int xx, int yy) {
data_to_game_coords(&xx, &yy);
- int aa, ll;
- for (ll = _GP(game).numgui - 1; ll >= 0; ll--) {
- aa = _GP(play).gui_draw_order[ll];
- if (_GP(guis)[aa].IsInteractableAt(xx, yy))
- return aa;
+ // Test in the opposite order (from closer to further)
+ for (auto g = _GP(play).gui_draw_order.crbegin();
+ g < _GP(play).gui_draw_order.crend(); ++g) {
+ if (_GP(guis)[*g].IsInteractableAt(xx, yy))
+ return *g;
}
return -1;
}
diff --git a/engines/ags/engine/ac/gui.cpp b/engines/ags/engine/ac/gui.cpp
index 2a9727a6a1b..f5e5f996c70 100644
--- a/engines/ags/engine/ac/gui.cpp
+++ b/engines/ags/engine/ac/gui.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "ags/lib/std/algorithm.h"
#include "ags/engine/ac/gui.h"
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/draw.h"
@@ -406,28 +407,13 @@ void replace_macro_tokens(const char *text, String &fixed_text) {
}
-void update_gui_zorder() {
- int numdone = 0, b;
-
- // for each GUI
- for (int a = 0; a < _GP(game).numgui; a++) {
- // find the right place in the draw order array
- int insertAt = numdone;
- for (b = 0; b < numdone; b++) {
- if (_GP(guis)[a].ZOrder < _GP(guis)[_GP(play).gui_draw_order[b]].ZOrder) {
- insertAt = b;
- break;
- }
- }
- // insert the new item
- for (b = numdone - 1; b >= insertAt; b--)
- _GP(play).gui_draw_order[b + 1] = _GP(play).gui_draw_order[b];
- _GP(play).gui_draw_order[insertAt] = a;
- numdone++;
- }
-
+bool sort_gui_less(const int g1, const int g2) {
+ return _GP(guis)[g1].ZOrder < _GP(guis)[g2].ZOrder;
}
+void update_gui_zorder() {
+ std::sort(_GP(play).gui_draw_order.begin(), _GP(play).gui_draw_order.end(), sort_gui_less);
+}
void export_gui_controls(int ee) {
for (int ff = 0; ff < _GP(guis)[ee].GetControlCount(); ff++) {
@@ -529,9 +515,9 @@ int gui_on_mouse_move() {
else {
// Scan for mouse-y-pos GUIs, and pop one up if appropriate
// Also work out the mouse-over GUI while we're at it
- int ll;
- for (ll = 0; ll < _GP(game).numgui; ll++) {
- const int guin = _GP(play).gui_draw_order[ll];
+ // CHECKME: not sure why, but we're testing forward draw order here -
+ // from farthest to nearest (this was in original code?)
+ for (int guin : _GP(play).gui_draw_order) {
if (_GP(guis)[guin].IsInteractableAt(_G(mousex), _G(mousey))) mouse_over_gui = guin;
if (_GP(guis)[guin].PopupStyle != kGUIPopupMouseY) continue;
diff --git a/engines/ags/engine/game/game_init.cpp b/engines/ags/engine/game/game_init.cpp
index cd7421f2993..10d6b506b8a 100644
--- a/engines/ags/engine/game/game_init.cpp
+++ b/engines/ags/engine/game/game_init.cpp
@@ -409,7 +409,10 @@ HGameInitError InitGameState(const LoadedGameEntities &ents, GameDataVersion dat
// labels are not clickable by default
_GP(guilabels)[i].SetClickable(false);
}
- _GP(play).gui_draw_order = (int32_t *)calloc(game.numgui * sizeof(int), 1);
+ _GP(play).gui_draw_order.resize(game.numgui);
+ for (int i = 0; i < game.numgui; ++i)
+ _GP(play).gui_draw_order[i] = i;
+
update_gui_zorder();
calculate_reserved_channel_count();
diff --git a/engines/ags/engine/game/savegame_v321.cpp b/engines/ags/engine/game/savegame_v321.cpp
index 223223c2757..3ceab96aaad 100644
--- a/engines/ags/engine/game/savegame_v321.cpp
+++ b/engines/ags/engine/game/savegame_v321.cpp
@@ -154,21 +154,18 @@ static void restore_game_play_ex_data(Stream *in) {
_GP(play).do_once_tokens[i] = rbuffer;
}
- in->ReadArrayOfInt32(&_GP(play).gui_draw_order[0], _GP(game).numgui);
+ in->Seek(_GP(game).numgui * sizeof(int32_t)); // gui_draw_order
}
static void restore_game_play(Stream *in, RestoredData &r_data) {
int screenfadedout_was = _GP(play).screen_is_faded_out;
int roomchanges_was = _GP(play).room_changes;
- // make sure the pointer is preserved
- int32_t *gui_draw_order_was = _GP(play).gui_draw_order;
ReadGameState_Aligned(in, r_data);
r_data.Cameras[0].Flags = r_data.Camera0_Flags;
_GP(play).screen_is_faded_out = screenfadedout_was;
_GP(play).room_changes = roomchanges_was;
- _GP(play).gui_draw_order = gui_draw_order_was;
restore_game_play_ex_data(in);
}
diff --git a/engines/ags/lib/std/vector.h b/engines/ags/lib/std/vector.h
index 9d7bff210b1..06e93f800e8 100644
--- a/engines/ags/lib/std/vector.h
+++ b/engines/ags/lib/std/vector.h
@@ -76,12 +76,15 @@ public:
return *this;
}
- bool operator==(const const_reverse_iterator &rhs) {
+ bool operator==(const const_reverse_iterator &rhs) const {
return _owner == rhs._owner && _index == rhs._index;
}
- bool operator!=(const const_reverse_iterator &rhs) {
+ bool operator!=(const const_reverse_iterator &rhs) const {
return !operator==(rhs);
}
+ bool operator<(const const_reverse_iterator &rhs) const {
+ return _index > rhs._index;
+ }
};
using iterator = typename Common::Array<T>::iterator;
@@ -155,6 +158,12 @@ public:
const_reverse_iterator rend() const {
return const_reverse_iterator(this, -1);
}
+ const_reverse_iterator crbegin() const {
+ return const_reverse_iterator(this, (int)Common::Array<T>::size() - 1);
+ }
+ const_reverse_iterator crend() const {
+ return const_reverse_iterator(this, -1);
+ }
void pop_front() {
Common::Array<T>::remove_at(0);
Commit: d8d593079a08662c2d8b32d7ac71dfc84646f19e
https://github.com/scummvm/scummvm/commit/d8d593079a08662c2d8b32d7ac71dfc84646f19e
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:22-07:00
Commit Message:
AGS: Don't MarkChanged guis changing Transparency or Visible flag
>From upstream d4deb499893109a54ed7e011af22d2619c432549
Changed paths:
engines/ags/shared/gui/gui_main.cpp
engines/ags/shared/gui/gui_main.h
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 67012f55e97..3a280fa0684 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -403,7 +403,6 @@ void GUIMain::SetConceal(bool on) {
_flags |= kGUIMain_Concealed;
else
_flags &= ~kGUIMain_Concealed;
- MarkChanged();
}
bool GUIMain::SendControlToBack(int32_t index) {
@@ -448,7 +447,6 @@ void GUIMain::SetTextWindow(bool on) {
void GUIMain::SetTransparencyAsPercentage(int percent) {
Transparency = GfxDef::Trans100ToLegacyTrans255(percent);
- MarkChanged();
}
void GUIMain::SetVisible(bool on) {
@@ -456,7 +454,6 @@ void GUIMain::SetVisible(bool on) {
_flags |= kGUIMain_Visible;
else
_flags &= ~kGUIMain_Visible;
- MarkChanged();
}
void GUIMain::OnMouseButtonDown(int mx, int my) {
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index 7ad5fcfe988..dce0388725f 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -102,6 +102,8 @@ public:
bool HasChanged() const;
bool HasControlsChanged() const;
// Manually marks GUI as graphically changed
+ // NOTE: this only matters if GUI's own graphic changes (content, size etc),
+ // but not its state (visible) or texture drawing mode (transparency, etc).
void MarkChanged();
void MarkControlsChanged();
// Clears changed flag
Commit: ec170ebd2f83d867b29737cff86c8bfaf477bda2
https://github.com/scummvm/scummvm/commit/ec170ebd2f83d867b29737cff86c8bfaf477bda2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:22-07:00
Commit Message:
AGS: More strict MarkChanged use for gui controls, on changes only
>From upstream 1383ff33eb4620eae18598f96f7e0cc948977174
Changed paths:
engines/ags/engine/ac/button.cpp
engines/ags/engine/ac/listbox.cpp
engines/ags/engine/ac/slider.cpp
engines/ags/engine/gui/gui_engine.cpp
engines/ags/shared/gui/gui_button.cpp
engines/ags/shared/gui/gui_label.cpp
engines/ags/shared/gui/gui_listbox.cpp
engines/ags/shared/gui/gui_object.cpp
engines/ags/shared/gui/gui_object.h
engines/ags/shared/gui/gui_slider.cpp
diff --git a/engines/ags/engine/ac/button.cpp b/engines/ags/engine/ac/button.cpp
index 8c3c8b0680f..ae62bb535bc 100644
--- a/engines/ags/engine/ac/button.cpp
+++ b/engines/ags/engine/ac/button.cpp
@@ -47,10 +47,12 @@ using namespace AGS::Shared;
// Update the actual button's image from the current animation frame
void UpdateButtonState(const AnimatingGUIButton &abtn) {
_GP(guibuts)[abtn.buttonid].Image = _GP(views)[abtn.view].loops[abtn.loop].frames[abtn.frame].pic;
- _GP(guibuts)[abtn.buttonid].CurrentImage = _GP(guibuts)[abtn.buttonid].Image;
+ if (_GP(guibuts)[abtn.buttonid].CurrentImage != _GP(guibuts)[abtn.buttonid].Image) {
+ _GP(guibuts)[abtn.buttonid].CurrentImage = _GP(guibuts)[abtn.buttonid].Image;
+ _GP(guibuts)[abtn.buttonid].MarkChanged();
+ }
_GP(guibuts)[abtn.buttonid].PushedImage = 0;
_GP(guibuts)[abtn.buttonid].MouseOverImage = 0;
- _GP(guibuts)[abtn.buttonid].MarkChanged();
}
void Button_AnimateEx(GUIButton *butt, int view, int loop, int speed, int repeat, int blocking, int direction, int sframe) {
@@ -170,11 +172,11 @@ int Button_GetMouseOverGraphic(GUIButton *butt) {
void Button_SetMouseOverGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d mouseover set to slot %d", guil->ParentId, guil->Id, slotn);
- if ((guil->IsMouseOver != 0) && (guil->IsPushed == 0))
+ if ((guil->IsMouseOver != 0) && (guil->IsPushed == 0) && (guil->CurrentImage != slotn)) {
guil->CurrentImage = slotn;
+ guil->MarkChanged();
+ }
guil->MouseOverImage = slotn;
-
- guil->MarkChanged();
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
@@ -184,20 +186,26 @@ int Button_GetNormalGraphic(GUIButton *butt) {
void Button_SetNormalGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d normal set to slot %d", guil->ParentId, guil->Id, slotn);
- // normal pic - update if mouse is not over, or if there's no MouseOverImage
- if (((guil->IsMouseOver == 0) || (guil->MouseOverImage < 1)) && (guil->IsPushed == 0))
- guil->CurrentImage = slotn;
- guil->Image = slotn;
// update the clickable area to the same size as the graphic
+ int width, height;
if (slotn < 0 || (size_t)slotn >= _GP(game).SpriteInfos.size()) {
- guil->Width = 0;
- guil->Height = 0;
+ width = 0;
+ height = 0;
} else {
- guil->Width = _GP(game).SpriteInfos[slotn].Width;
- guil->Height = _GP(game).SpriteInfos[slotn].Height;
+ width = _GP(game).SpriteInfos[slotn].Width;
+ height = _GP(game).SpriteInfos[slotn].Height;
+ }
+
+ if ((slotn != guil->Image) || (width != guil->Width) || (height != guil->Height)) {
+ // normal pic - update if mouse is not over, or if there's no MouseOverImage
+ if (((guil->IsMouseOver == 0) || (guil->MouseOverImage < 1)) && (guil->IsPushed == 0))
+ guil->CurrentImage = slotn;
+ guil->Image = slotn;
+ guil->Width = width;
+ guil->Height = height;
+ guil->MarkChanged();
}
- guil->MarkChanged();
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
@@ -208,11 +216,11 @@ int Button_GetPushedGraphic(GUIButton *butt) {
void Button_SetPushedGraphic(GUIButton *guil, int slotn) {
debug_script_log("GUI %d Button %d pushed set to slot %d", guil->ParentId, guil->Id, slotn);
- if (guil->IsPushed)
+ if (guil->IsPushed && (guil->CurrentImage != slotn)) {
guil->CurrentImage = slotn;
+ guil->MarkChanged();
+ }
guil->PushedImage = slotn;
-
- guil->MarkChanged();
FindAndRemoveButtonAnimation(guil->ParentId, guil->Id);
}
diff --git a/engines/ags/engine/ac/listbox.cpp b/engines/ags/engine/ac/listbox.cpp
index 0e2667cfdb0..9435527b427 100644
--- a/engines/ags/engine/ac/listbox.cpp
+++ b/engines/ags/engine/ac/listbox.cpp
@@ -338,13 +338,14 @@ int ListBox_GetTopItem(GUIListBox *listbox) {
}
void ListBox_SetTopItem(GUIListBox *guisl, int item) {
- if ((guisl->ItemCount == 0) && (item == 0))
- ; // allow resetting an empty box to the top
- else if ((item >= guisl->ItemCount) || (item < 0))
- quit("!ListBoxSetTopItem: tried to set top to beyond top or bottom of list");
-
- guisl->TopItem = item;
- guisl->MarkChanged();
+ if ((item >= guisl->ItemCount) || (item < 0)) {
+ item = Math::Clamp(item, 0, guisl->ItemCount);
+ debug_script_warn("ListBoxSetTopItem: tried to set top to beyond top or bottom of list");
+ }
+ if (guisl->TopItem != item) {
+ guisl->TopItem = item;
+ guisl->MarkChanged();
+ }
}
int ListBox_GetRowCount(GUIListBox *listbox) {
diff --git a/engines/ags/engine/ac/slider.cpp b/engines/ags/engine/ac/slider.cpp
index a9663d276f5..93b15c55ff8 100644
--- a/engines/ags/engine/ac/slider.cpp
+++ b/engines/ags/engine/ac/slider.cpp
@@ -22,13 +22,14 @@
#include "ags/engine/ac/slider.h"
#include "ags/shared/ac/common.h"
#include "ags/shared/debugging/out.h"
+#include "ags/shared/util/math.h"
#include "ags/engine/script/script_api.h"
#include "ags/engine/script/script_runtime.h"
#include "ags/globals.h"
namespace AGS3 {
-// *** SLIDER FUNCTIONS
+using namespace AGS::Shared;
void Slider_SetMax(GUISlider *guisl, int valn) {
@@ -69,8 +70,7 @@ int Slider_GetMin(GUISlider *guisl) {
}
void Slider_SetValue(GUISlider *guisl, int valn) {
- if (valn > guisl->MaxValue) valn = guisl->MaxValue;
- if (valn < guisl->MinValue) valn = guisl->MinValue;
+ valn = Math::Clamp(valn, guisl->MinValue, guisl->MaxValue);
if (valn != guisl->Value) {
guisl->Value = valn;
diff --git a/engines/ags/engine/gui/gui_engine.cpp b/engines/ags/engine/gui/gui_engine.cpp
index 3b3e2088a70..61a08412193 100644
--- a/engines/ags/engine/gui/gui_engine.cpp
+++ b/engines/ags/engine/gui/gui_engine.cpp
@@ -106,6 +106,10 @@ void GUIObject::MarkChanged() {
_GP(guis)[ParentId].MarkControlsChanged();
}
+void GUIObject::NotifyParentChanged() {
+ _GP(guis)[ParentId].MarkControlsChanged();
+}
+
bool GUIObject::HasChanged() const {
return _hasChanged;
}
diff --git a/engines/ags/shared/gui/gui_button.cpp b/engines/ags/shared/gui/gui_button.cpp
index fdd6a997b16..64dd5e3dc7d 100644
--- a/engines/ags/shared/gui/gui_button.cpp
+++ b/engines/ags/shared/gui/gui_button.cpp
@@ -163,14 +163,18 @@ void GUIButton::Draw(Bitmap *ds, int x, int y) {
}
void GUIButton::SetClipImage(bool on) {
+ if (on != ((Flags & kGUICtrl_Clip) != 0))
+ MarkChanged();
if (on)
Flags |= kGUICtrl_Clip;
else
Flags &= ~kGUICtrl_Clip;
- MarkChanged();
}
void GUIButton::SetText(const String &text) {
+ if (_text == text)
+ return;
+
_text = text;
// Active inventory item placeholders
if (_text.CompareNoCase("(INV)") == 0)
diff --git a/engines/ags/shared/gui/gui_label.cpp b/engines/ags/shared/gui/gui_label.cpp
index 26c0c7eafb3..83719a81e59 100644
--- a/engines/ags/shared/gui/gui_label.cpp
+++ b/engines/ags/shared/gui/gui_label.cpp
@@ -102,6 +102,8 @@ void GUILabel::Draw(Bitmap *ds, int x, int y) {
}
void GUILabel::SetText(const String &text) {
+ if (text == Text)
+ return;
Text = text;
// Check for macros within text
_textMacro = GUI::FindLabelMacros(Text);
diff --git a/engines/ags/shared/gui/gui_listbox.cpp b/engines/ags/shared/gui/gui_listbox.cpp
index 92ff4b3f552..89da68878c7 100644
--- a/engines/ags/shared/gui/gui_listbox.cpp
+++ b/engines/ags/shared/gui/gui_listbox.cpp
@@ -114,6 +114,9 @@ int GUIListBox::AddItem(const String &text) {
}
void GUIListBox::Clear() {
+ if (Items.size() == 0)
+ return;
+
Items.clear();
SavedGameIndex.clear();
ItemCount = 0;
@@ -223,19 +226,21 @@ void GUIListBox::RemoveItem(int index) {
}
void GUIListBox::SetShowArrows(bool on) {
+ if (on != ((ListBoxFlags & kListBox_ShowArrows) != 0))
+ MarkChanged();
if (on)
ListBoxFlags |= kListBox_ShowArrows;
else
ListBoxFlags &= ~kListBox_ShowArrows;
- MarkChanged();
}
void GUIListBox::SetShowBorder(bool on) {
+ if (on != ((ListBoxFlags & kListBox_ShowBorder) != 0))
+ MarkChanged();
if (on)
ListBoxFlags |= kListBox_ShowBorder;
else
ListBoxFlags &= ~kListBox_ShowBorder;
- MarkChanged();
}
void GUIListBox::SetSvgIndex(bool on) {
@@ -246,13 +251,15 @@ void GUIListBox::SetSvgIndex(bool on) {
}
void GUIListBox::SetFont(int font) {
+ if (Font == font)
+ return;
Font = font;
UpdateMetrics();
MarkChanged();
}
void GUIListBox::SetItemText(int index, const String &text) {
- if (index >= 0 && index < ItemCount) {
+ if ((index >= 0) && (index < ItemCount) && (text != Items[index])) {
Items[index] = text;
MarkChanged();
}
diff --git a/engines/ags/shared/gui/gui_object.cpp b/engines/ags/shared/gui/gui_object.cpp
index aac31a627b7..c5f044c0816 100644
--- a/engines/ags/shared/gui/gui_object.cpp
+++ b/engines/ags/shared/gui/gui_object.cpp
@@ -90,27 +90,30 @@ void GUIObject::SetClickable(bool on) {
}
void GUIObject::SetEnabled(bool on) {
+ if (on != ((Flags & kGUICtrl_Enabled) != 0))
+ MarkChanged();
if (on)
Flags |= kGUICtrl_Enabled;
else
Flags &= ~kGUICtrl_Enabled;
- MarkChanged();
}
void GUIObject::SetTranslated(bool on) {
+ if (on != ((Flags & kGUICtrl_Translated) != 0))
+ MarkChanged();
if (on)
Flags |= kGUICtrl_Translated;
else
Flags &= ~kGUICtrl_Translated;
- MarkChanged();
}
void GUIObject::SetVisible(bool on) {
+ if (on != ((Flags & kGUICtrl_Visible) != 0))
+ NotifyParentChanged(); // for software mode
if (on)
Flags |= kGUICtrl_Visible;
else
Flags &= ~kGUICtrl_Visible;
- MarkChanged();
}
// TODO: replace string serialization with StrUtil::ReadString and WriteString
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index c778be2367a..557a38e9f13 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -109,8 +109,12 @@ public:
// TODO: these members are currently public; hide them later
public:
- // Notifies parent GUI that this control has changed
+ // Manually marks GUIObject as graphically changed
+ // NOTE: this only matters if control's own graphic changes (content, size etc),
+ // but not its state (visible) or texture drawing mode (transparency, etc).
void MarkChanged();
+ // Notifies parent GUI that this control has changed its state (but not graphic)
+ void NotifyParentChanged();
bool HasChanged() const;
void ClearChanged();
diff --git a/engines/ags/shared/gui/gui_slider.cpp b/engines/ags/shared/gui/gui_slider.cpp
index 2704b3ea7e2..3daac0cc33d 100644
--- a/engines/ags/shared/gui/gui_slider.cpp
+++ b/engines/ags/shared/gui/gui_slider.cpp
@@ -207,13 +207,17 @@ void GUISlider::OnMouseMove(int x, int y) {
if (!IsMousePressed)
return;
+ int value;
if (IsHorizontal())
- Value = (int)(((float)((x - X) - 2) * (float)(MaxValue - MinValue)) / (float)_handleRange) + MinValue;
+ value = (int)(((float)((x - X) - 2) * (float)(MaxValue - MinValue)) / (float)_handleRange) + MinValue;
else
- Value = (int)(((float)(((Y + Height) - y) - 2) * (float)(MaxValue - MinValue)) / (float)_handleRange) + MinValue;
+ value = (int)(((float)(((Y + Height) - y) - 2) * (float)(MaxValue - MinValue)) / (float)_handleRange) + MinValue;
- Value = Math::Clamp(Value, MinValue, MaxValue);
- MarkChanged();
+ value = Math::Clamp(value, MinValue, MaxValue);
+ if (value != Value) {
+ Value = value;
+ MarkChanged();
+ }
IsActivated = true;
}
Commit: fbd328b0ae86c18e3339e3b8299d512d9f818267
https://github.com/scummvm/scummvm/commit/fbd328b0ae86c18e3339e3b8299d512d9f818267
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:23-07:00
Commit Message:
AGS: On changed or deleted dynamic sprite, also update sliders
>From upstream f675c7ff7eb33bc2969098ab59afffac078b95bb
Changed paths:
engines/ags/engine/ac/game.cpp
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index d5f5874449f..f169adbe5ee 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -66,6 +66,7 @@
#include "ags/shared/gfx/bitmap.h"
#include "ags/engine/gfx/graphics_driver.h"
#include "ags/shared/gui/gui_button.h"
+#include "ags/shared/gui/gui_slider.h"
#include "ags/engine/gui/gui_dialog.h"
#include "ags/engine/main/engine.h"
#include "ags/engine/media/audio/audio_system.h"
@@ -1375,6 +1376,12 @@ void game_sprite_updated(int sprnum) {
_GP(guibuts)[i].MarkChanged();
}
}
+ // gui sliders
+ for (size_t i = 0; i < (size_t)_G(numguislider); ++i) {
+ if ((_GP(guislider)[i].BgImage == sprnum) || (_GP(guislider)[i].HandleImage == sprnum)) {
+ _GP(guislider)[i].MarkChanged();
+ }
+ }
}
void game_sprite_deleted(int sprnum) {
@@ -1414,6 +1421,15 @@ void game_sprite_deleted(int sprnum) {
_GP(guibuts)[i].MarkChanged();
}
}
+ // gui sliders
+ for (size_t i = 0; i < (size_t)_G(numguislider); ++i) {
+ if ((_GP(guislider)[i].BgImage == sprnum) || (_GP(guislider)[i].HandleImage == sprnum))
+ _GP(guislider)[i].MarkChanged();
+ if (_GP(guislider)[i].BgImage == sprnum)
+ _GP(guislider)[i].BgImage = 0;
+ if (_GP(guislider)[i].HandleImage == sprnum)
+ _GP(guislider)[i].HandleImage = 0;
+ }
// views
for (size_t v = 0; v < (size_t)_GP(game).numviews; ++v) {
for (size_t l = 0; l < (size_t)_GP(views)[v].numLoops; ++l) {
Commit: b9a9b00974ebb475fa1375f7f2dd352df7109360
https://github.com/scummvm/scummvm/commit/b9a9b00974ebb475fa1375f7f2dd352df7109360
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:23-07:00
Commit Message:
AGS: Graphic renderers use correct alpha as sprite transparency
>From upstream d2502a5240c6c06eb2fb65a9bf90b30584d79051
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/event.cpp
engines/ags/engine/gfx/ali_3d_scummvm.cpp
engines/ags/engine/gfx/ali_3d_scummvm.h
engines/ags/engine/gfx/ddb.h
engines/ags/shared/gfx/gfx_def.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 9c43710e3e3..3341bd150ab 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -794,7 +794,7 @@ static void clear_sprite_list() {
static void add_to_sprite_list(IDriverDependantBitmap *ddb, int x, int y, int zorder, bool isWalkBehind, int id = -1) {
assert(ddb);
// completely invisible, so don't draw it at all
- if (ddb->GetTransparency() == 255)
+ if (ddb->GetAlpha() == 0)
return;
SpriteListEntry sprite;
@@ -1517,7 +1517,7 @@ void prepare_objects_for_drawing() {
_GP(actspsbmp)[useindx]->SetLightLevel(0);
}
- _GP(actspsbmp)[useindx]->SetTransparency(_G(objs)[aa].transparent);
+ _GP(actspsbmp)[useindx]->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(_G(objs)[aa].transparent));
add_to_sprite_list(_GP(actspsbmp)[useindx], atxp, atyp, usebasel, false);
}
}
@@ -1810,7 +1810,7 @@ void prepare_characters_for_drawing() {
chin->actx = atxp;
chin->acty = atyp;
- _GP(actspsbmp)[useindx]->SetTransparency(chin->transparency);
+ _GP(actspsbmp)[useindx]->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(chin->transparency));
add_to_sprite_list(_GP(actspsbmp)[useindx], bgX, bgY, usebasel, false);
}
}
@@ -2017,7 +2017,7 @@ void draw_gui_and_overlays() {
// Add active overlays to the sprite list
for (auto &over : _GP(screenover)) {
if (over.transparency == 255) continue; // skip fully transparent
- over.bmp->SetTransparency(over.transparency);
+ over.bmp->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(over.transparency));
int tdxp, tdyp;
get_overlay_position(over, &tdxp, &tdyp);
add_to_sprite_list(over.bmp, tdxp, tdyp, over.zorder, false, -1);
@@ -2093,7 +2093,7 @@ void draw_gui_and_overlays() {
auto *gui_ddb = _GP(guibgbmp)[aa];
assert(gui_ddb); // Test for missing texture, might happen if not marked for update
if (!gui_ddb) continue;
- gui_ddb->SetTransparency(_GP(guis)[aa].Transparency);
+ gui_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(_GP(guis)[aa].Transparency));
add_to_sprite_list(gui_ddb, _GP(guis)[aa].X, _GP(guis)[aa].Y, _GP(guis)[aa].ZOrder, false, aa);
}
@@ -2138,7 +2138,7 @@ void draw_gui_and_overlays() {
auto *obj_ddb = _GP(guiobjbmp)[draw_index + obj_id];
assert(obj_ddb); // Test for missing texture, might happen if not marked for update
if (!obj_ddb) continue;
- obj_ddb->SetTransparency(_GP(guis)[s.id].Transparency);
+ obj_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(_GP(guis)[s.id].Transparency));
_G(gfxDriver)->DrawSprite(
_GP(guiobjoff)[draw_index + obj_id].X,
_GP(guiobjoff)[draw_index + obj_id].Y,
@@ -2155,7 +2155,7 @@ void put_sprite_list_on_screen(bool in_room) {
for (const auto &t : _GP(thingsToDrawList)) {
assert(t.ddb || (t.renderStage >= 0));
if (t.ddb) {
- if (t.ddb->GetTransparency() == 255)
+ if (t.ddb->GetAlpha() == 0)
continue; // skip completely invisible things
// mark the image's region as dirty
invalidate_sprite(t.x, t.y, t.ddb, in_room);
@@ -2419,7 +2419,7 @@ void debug_draw_room_mask(RoomAreaMask mask) {
}
_G(debugRoomMaskDDB) = recycle_ddb_bitmap(_G(debugRoomMaskDDB), bmp, false, true);
- _G(debugRoomMaskDDB)->SetTransparency(150);
+ _G(debugRoomMaskDDB)->SetAlpha(150);
_G(debugRoomMaskDDB)->SetStretch(_GP(thisroom).Width, _GP(thisroom).Height);
}
@@ -2438,7 +2438,7 @@ void update_room_debug() {
bmp = _GP(debugRoomMaskBmp).get();
}
_G(debugRoomMaskDDB) = recycle_ddb_bitmap(_G(debugRoomMaskDDB), bmp, false, true);
- _G(debugRoomMaskDDB)->SetTransparency(150);
+ _G(debugRoomMaskDDB)->SetAlpha(150);
_G(debugRoomMaskDDB)->SetStretch(_GP(thisroom).Width, _GP(thisroom).Height);
}
if (_G(debugMoveListChar) >= 0) {
@@ -2465,7 +2465,7 @@ void update_room_debug() {
}
}
_G(debugMoveListDDB) = recycle_ddb_bitmap(_G(debugMoveListDDB), _GP(debugMoveListBmp).get(), false, false);
- _G(debugMoveListDDB)->SetTransparency(150);
+ _G(debugRoomMaskDDB)->SetAlpha(150);
_G(debugMoveListDDB)->SetStretch(_GP(thisroom).Width, _GP(thisroom).Height);
}
}
diff --git a/engines/ags/engine/ac/event.cpp b/engines/ags/engine/ac/event.cpp
index d7cbd2c9a8c..924a2cd79a3 100644
--- a/engines/ags/engine/ac/event.cpp
+++ b/engines/ags/engine/ac/event.cpp
@@ -268,18 +268,14 @@ void process_event(const EventHappened *evp) {
IDriverDependantBitmap *ddb = prepare_screen_for_transition_in();
- int transparency = 254;
-
- while (transparency > 0) {
+ for (int alpha = 254; alpha > 0; alpha -= 16) {
// do the crossfade
- ddb->SetTransparency(transparency);
+ ddb->SetAlpha(alpha);
invalidate_screen();
construct_game_scene(true);
construct_game_screen_overlay(false);
-
- if (transparency > 16) {
- // on last frame of fade (where transparency < 16), don't
- // draw the old screen on top
+ // draw old screen on top while alpha > 16
+ if (alpha > 16) {
_G(gfxDriver)->BeginSpriteBatch(_GP(play).GetMainViewport(), SpriteTransform());
_G(gfxDriver)->DrawSprite(0, 0, ddb);
_G(gfxDriver)->EndSpriteBatch();
@@ -287,7 +283,6 @@ void process_event(const EventHappened *evp) {
render_to_screen();
update_polled_stuff_if_runtime();
WaitForNextFrame();
- transparency -= 16;
}
delete _G(saved_viewport_bitmap);
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.cpp b/engines/ags/engine/gfx/ali_3d_scummvm.cpp
index 2ff6e418d61..30bff013b8f 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.cpp
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.cpp
@@ -358,26 +358,25 @@ size_t ScummVMRendererGraphicsDriver::RenderSpriteBatch(const ALSpriteBatch &bat
int drawAtX = sprite.x + surf_offx;
int drawAtY = sprite.y + surf_offy;
- if (bitmap->_transparency >= 255) {
+ if (bitmap->_alpha == 0) {
} // fully transparent, do nothing
- else if ((bitmap->_opaque) && (bitmap->_bmp == surface) && (bitmap->_transparency == 0)) {
+ else if ((bitmap->_opaque) && (bitmap->_bmp == surface) && (bitmap->_alpha == 255)) {
} else if (bitmap->_opaque) {
surface->Blit(bitmap->_bmp, 0, 0, drawAtX, drawAtY, bitmap->_bmp->GetWidth(), bitmap->_bmp->GetHeight());
// TODO: we need to also support non-masked translucent blend, but...
// Allegro 4 **does not have such function ready** :( (only masked blends, where it skips magenta pixels);
// I am leaving this problem for the future, as coincidentally software mode does not need this atm.
} else if (bitmap->_hasAlpha) {
- if (bitmap->_transparency == 0) // no global transparency, simple alpha blend
+ if (bitmap->_alpha == 255) // no global transparency, simple alpha blend
set_alpha_blender();
else
- // here _transparency is used as alpha (between 1 and 254)
- set_blender_mode(kArgbToRgbBlender, 0, 0, 0, bitmap->_transparency);
+ set_blender_mode(kArgbToRgbBlender, 0, 0, 0, bitmap->_alpha);
surface->TransBlendBlt(bitmap->_bmp, drawAtX, drawAtY);
} else {
// here _transparency is used as alpha (between 1 and 254), but 0 means opaque!
GfxUtil::DrawSpriteWithTransparency(surface, bitmap->_bmp, drawAtX, drawAtY,
- bitmap->_transparency ? bitmap->_transparency : 255);
+ bitmap->_alpha);
}
}
return from;
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.h b/engines/ags/engine/gfx/ali_3d_scummvm.h
index e4a2f29adb8..b4a95236570 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.h
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.h
@@ -59,13 +59,11 @@ enum RendererFlip {
class ALSoftwareBitmap : public BaseDDB {
public:
- // Transparency is a bit counter-intuitive
- // 0=not transparent, 255=invisible, 1..254 barely visible .. mostly visible
- int GetTransparency() const override {
- return _transparency;
+ int GetAlpha() const override {
+ return _alpha;
}
- void SetTransparency(int transparency) override {
- _transparency = transparency;
+ void SetAlpha(int alpha) override {
+ _alpha = alpha;
}
void SetFlippedLeftRight(bool isFlipped) override {
_flipped = isFlipped;
@@ -80,9 +78,7 @@ public:
Bitmap *_bmp = nullptr;
bool _flipped = false;
int _stretchToWidth = 0, _stretchToHeight = 0;
- bool _opaque = false; // no mask color
- bool _hasAlpha = false;
- int _transparency = 0;
+ int _alpha = 255;
ALSoftwareBitmap(int width, int height, int color_depth, bool opaque) {
_width = width;
diff --git a/engines/ags/engine/gfx/ddb.h b/engines/ags/engine/gfx/ddb.h
index 2945d6bb93c..804e73219fc 100644
--- a/engines/ags/engine/gfx/ddb.h
+++ b/engines/ags/engine/gfx/ddb.h
@@ -38,8 +38,8 @@ namespace Engine {
class IDriverDependantBitmap {
public:
- virtual int GetTransparency() const = 0;
- virtual void SetTransparency(int transparency) = 0; // 0-255
+ virtual int GetAlpha() const = 0;
+ virtual void SetAlpha(int alpha) = 0; // 0-255
virtual void SetFlippedLeftRight(bool isFlipped) = 0;
virtual void SetStretch(int width, int height, bool useResampler = true) = 0;
virtual void SetLightLevel(int light_level) = 0; // 0-255
diff --git a/engines/ags/shared/gfx/gfx_def.h b/engines/ags/shared/gfx/gfx_def.h
index 57162163253..8b89917558e 100644
--- a/engines/ags/shared/gfx/gfx_def.h
+++ b/engines/ags/shared/gfx/gfx_def.h
@@ -43,10 +43,12 @@ enum BlendMode {
namespace GfxDef {
+// Converts percentage of transparency into alpha
inline int Trans100ToAlpha255(int transparency) {
return ((100 - transparency) * 255) / 100;
}
+// Converts alpha into percentage of transparency
inline int Alpha255ToTrans100(int alpha) {
return 100 - ((alpha * 100) / 255);
}
@@ -67,25 +69,29 @@ inline int Alpha250ToTrans100(int alpha) {
// 255 = invisible,
// 1 -to- 254 = barely visible -to- mostly visible (as proper alpha)
inline int Trans100ToLegacyTrans255(int transparency) {
- if (transparency == 0) {
+ switch (transparency) {
+ case 0:
return 0; // this means opaque
- } else if (transparency == 100) {
+ case 100:
return 255; // this means invisible
+ default:
+ // the rest of the range works as alpha
+ return Trans100ToAlpha250(transparency);
}
- // the rest of the range works as alpha
- return Trans100ToAlpha250(transparency);
}
// Convert legacy 255-ranged "incorrect" transparency into proper
// 100-ranged transparency.
inline int LegacyTrans255ToTrans100(int legacy_transparency) {
- if (legacy_transparency == 0) {
+ switch (legacy_transparency) {
+ case 0:
return 0; // this means opaque
- } else if (legacy_transparency == 255) {
+ case 255:
return 100; // this means invisible
+ default:
+ // the rest of the range works as alpha
+ return Alpha250ToTrans100(legacy_transparency);
}
- // the rest of the range works as alpha
- return Alpha250ToTrans100(legacy_transparency);
}
// Convert legacy 100-ranged transparency into proper 255-ranged alpha
@@ -93,13 +99,41 @@ inline int LegacyTrans255ToTrans100(int legacy_transparency) {
// 100 => alpha 0
// 1 - 99 => alpha 1 - 244
inline int LegacyTrans100ToAlpha255(int legacy_transparency) {
- if (legacy_transparency == 0) {
+ switch (legacy_transparency) {
+ case 0:
return 255; // this means opaque
- } else if (legacy_transparency == 100) {
+ case 100:
return 0; // this means invisible
+ default:
+ // the rest of the range works as alpha (only 100-ranged)
+ return legacy_transparency * 255 / 100;
+ }
+}
+
+// Convert legacy 255-ranged transparency into proper 255-ranged alpha
+inline int LegacyTrans255ToAlpha255(int legacy_transparency) {
+ switch (legacy_transparency) {
+ case 0:
+ return 255; // this means opaque
+ case 255:
+ return 0; // this means invisible
+ default:
+ // the rest of the range works as alpha
+ return legacy_transparency;
+ }
+}
+
+// Convert 255-ranged alpha into legacy 255-ranged transparency
+inline int Alpha255ToLegacyTrans255(int alpha) {
+ switch (alpha) {
+ case 255:
+ return 0; // this means opaque
+ case 0:
+ return 255; // this means invisible
+ default:
+ // the rest of the range works as alpha
+ return alpha;
}
- // the rest of the range works as alpha (only 100-ranged)
- return legacy_transparency * 255 / 100;
}
} // namespace GfxDef
Commit: 8b027e0d8274ed3e8fb8c7a0f186e001bd98f609
https://github.com/scummvm/scummvm/commit/8b027e0d8274ed3e8fb8c7a0f186e001bd98f609
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:23-07:00
Commit Message:
AGS: Support sprite batch's alpha
>From upstream 190897b97c8959954fea3f3561923e1b1c73a2b6
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/gfx/graphics_driver.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 3341bd150ab..2cfc265b549 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2128,7 +2128,8 @@ void draw_gui_and_overlays() {
_G(gfxDriver)->DrawSprite(s.x, s.y, s.ddb);
if (s.id < 0) continue; // not a group parent (gui)
// Create a sub-batch
- _G(gfxDriver)->BeginSpriteBatch(RectWH(s.x, s.y, s.ddb->GetWidth(), s.ddb->GetHeight()), SpriteTransform());
+ _G(gfxDriver)->BeginSpriteBatch(RectWH(s.x, s.y, s.ddb->GetWidth(), s.ddb->GetHeight()),
+ SpriteTransform(0, 0, 1.f, 1.f, 0.f, s.ddb->GetAlpha()));
const int draw_index = _GP(guiobjbmpref)[s.id];
for (const auto &obj_id : _GP(guis)[s.id].GetControlsDrawOrder()) {
GUIObject *obj = _GP(guis)[s.id].GetControl(obj_id);
@@ -2138,7 +2139,7 @@ void draw_gui_and_overlays() {
auto *obj_ddb = _GP(guiobjbmp)[draw_index + obj_id];
assert(obj_ddb); // Test for missing texture, might happen if not marked for update
if (!obj_ddb) continue;
- obj_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(_GP(guis)[s.id].Transparency));
+ obj_ddb->SetAlpha(255);
_G(gfxDriver)->DrawSprite(
_GP(guiobjoff)[draw_index + obj_id].X,
_GP(guiobjoff)[draw_index + obj_id].Y,
diff --git a/engines/ags/engine/gfx/graphics_driver.h b/engines/ags/engine/gfx/graphics_driver.h
index a8fa2d6381a..b893ca31da1 100644
--- a/engines/ags/engine/gfx/graphics_driver.h
+++ b/engines/ags/engine/gfx/graphics_driver.h
@@ -56,20 +56,27 @@ enum TintMethod {
TintSpecifyMaximum = 1
};
+struct SpriteColorTransform {
+ int Alpha = 255; // alpha color value (0 - 255)
+
+ SpriteColorTransform() = default;
+ SpriteColorTransform(int alpha) : Alpha(alpha) {
+ }
+};
+
// Sprite transformation
// TODO: combine with stretch parameters in the IDriverDependantBitmap?
struct SpriteTransform {
// Translate
- int X, Y;
- float ScaleX, ScaleY;
- float Rotate; // angle, in radians
-
- SpriteTransform()
- : X(0), Y(0), ScaleX(1.f), ScaleY(1.f), Rotate(0.f) {
- }
-
- SpriteTransform(int x, int y, float scalex = 1.0f, float scaley = 1.0f, float rotate = 0.0f)
- : X(x), Y(y), ScaleX(scalex), ScaleY(scaley), Rotate(rotate) {
+ int X = 0, Y = 0;
+ float ScaleX = 1.f, ScaleY = 1.f;
+ float Rotate = 0.f; // angle, in radians
+ SpriteColorTransform Color;
+
+ SpriteTransform() = default;
+ SpriteTransform(int x, int y, float scalex = 1.0f, float scaley = 1.0f, float rotate = 0.0f,
+ SpriteColorTransform color = SpriteColorTransform())
+ : X(x), Y(y), ScaleX(scalex), ScaleY(scaley), Rotate(rotate), Color(color) {
}
};
Commit: 8319217b7a528f57c4270bdd3b3cb9c9375772c9
https://github.com/scummvm/scummvm/commit/8319217b7a528f57c4270bdd3b3cb9c9375772c9
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:23-07:00
Commit Message:
AGS: Added GUIControl.Transparency
>From upstream a7c406b1d162bf9ac3896ecb8e26bc6d5327ecfe
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/gui_control.cpp
engines/ags/engine/game/savegame_components.cpp
engines/ags/shared/gui/gui_defines.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 2cfc265b549..6f20667e4c8 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -2139,7 +2139,7 @@ void draw_gui_and_overlays() {
auto *obj_ddb = _GP(guiobjbmp)[draw_index + obj_id];
assert(obj_ddb); // Test for missing texture, might happen if not marked for update
if (!obj_ddb) continue;
- obj_ddb->SetAlpha(255);
+ obj_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(obj->GetTransparency()));
_G(gfxDriver)->DrawSprite(
_GP(guiobjoff)[draw_index + obj_id].X,
_GP(guiobjoff)[draw_index + obj_id].Y,
diff --git a/engines/ags/engine/ac/gui_control.cpp b/engines/ags/engine/ac/gui_control.cpp
index c34100a1f68..a88eddb098b 100644
--- a/engines/ags/engine/ac/gui_control.cpp
+++ b/engines/ags/engine/ac/gui_control.cpp
@@ -213,6 +213,16 @@ void GUIControl_BringToFront(GUIObject *guio) {
_GP(guis)[guio->ParentId].BringControlToFront(guio->Id);
}
+int GUIControl_GetTransparency(GUIObject *guio) {
+ return GfxDef::LegacyTrans255ToTrans100(guio->GetTransparency());
+}
+
+void GUIControl_SetTransparency(GUIObject *guio, int trans) {
+ if ((trans < 0) | (trans > 100))
+ quit("!SetGUITransparency: transparency value must be between 0 and 100");
+ guio->SetTransparency(GfxDef::Trans100ToLegacyTrans255(trans));
+}
+
//=============================================================================
//
// Script API Functions
@@ -362,6 +372,13 @@ RuntimeScriptValue Sc_GUIControl_SetZOrder(void *self, const RuntimeScriptValue
API_OBJCALL_VOID_PINT(GUIObject, GUIControl_SetZOrder);
}
+RuntimeScriptValue Sc_GUIControl_GetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+ API_OBJCALL_INT(GUIObject, GUIControl_GetTransparency);
+}
+
+RuntimeScriptValue Sc_GUIControl_SetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+ API_OBJCALL_VOID_PINT(GUIObject, GUIControl_SetTransparency);
+}
void RegisterGUIControlAPI() {
@@ -394,6 +411,8 @@ void RegisterGUIControlAPI() {
ccAddExternalObjectFunction("GUIControl::set_Y", Sc_GUIControl_SetY);
ccAddExternalObjectFunction("GUIControl::get_ZOrder", Sc_GUIControl_GetZOrder);
ccAddExternalObjectFunction("GUIControl::set_ZOrder", Sc_GUIControl_SetZOrder);
+ ccAddExternalObjectFunction("GUIControl::get_Transparency", Sc_GUIControl_GetTransparency);
+ ccAddExternalObjectFunction("GUIControl::set_Transparency", Sc_GUIControl_SetTransparency);
}
} // namespace AGS3
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 0348c8bb4a1..52e4793ebe7 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -20,6 +20,7 @@
*/
#include "ags/lib/std/map.h"
+#include "ags/engine/game/savegame_components.h"
#include "ags/shared/ac/audio_clip_type.h"
#include "ags/shared/ac/common.h"
#include "ags/shared/ac/dialog_topic.h"
@@ -41,7 +42,6 @@
#include "ags/engine/ac/system.h"
#include "ags/engine/ac/dynobj/cc_serializer.h"
#include "ags/shared/debugging/out.h"
-#include "ags/engine/game/savegame_components.h"
#include "ags/engine/game/savegame_internal.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/engine/gui/animating_gui_button.h"
@@ -1048,7 +1048,7 @@ ComponentHandler ComponentHandlers[] = {
},
{
"GUI",
- kGuiSvgVersion_36020,
+ kGuiSvgVersion_36023,
kGuiSvgVersion_Initial,
WriteGUI,
ReadGUI
diff --git a/engines/ags/shared/gui/gui_defines.h b/engines/ags/shared/gui/gui_defines.h
index 10621fbaee2..bb1c44d6d70 100644
--- a/engines/ags/shared/gui/gui_defines.h
+++ b/engines/ags/shared/gui/gui_defines.h
@@ -185,7 +185,8 @@ enum GUITextBoxFlags {
enum GuiSvgVersion {
kGuiSvgVersion_Initial = 0,
kGuiSvgVersion_350,
- kGuiSvgVersion_36020
+ kGuiSvgVersion_36020,
+ kGuiSvgVersion_36023
};
enum GuiDisableStyle {
diff --git a/engines/ags/shared/gui/gui_object.cpp b/engines/ags/shared/gui/gui_object.cpp
index c5f044c0816..aaa1e49fc0a 100644
--- a/engines/ags/shared/gui/gui_object.cpp
+++ b/engines/ags/shared/gui/gui_object.cpp
@@ -38,6 +38,7 @@ GUIObject::GUIObject() {
Height = 0;
ZOrder = -1;
IsActivated = false;
+ _transparency = 0;
_scEventCount = 0;
_hasChanged = true;
}
@@ -116,6 +117,13 @@ void GUIObject::SetVisible(bool on) {
Flags &= ~kGUICtrl_Visible;
}
+void GUIObject::SetTransparency(int trans) {
+ if (_transparency != trans) {
+ _transparency = trans;
+ NotifyParentChanged(); // for software mode
+ }
+}
+
// TODO: replace string serialization with StrUtil::ReadString and WriteString
// methods in the future, to keep this organized.
void GUIObject::WriteToFile(Stream *out) const {
@@ -177,6 +185,12 @@ void GUIObject::ReadFromSavegame(Stream *in, GuiSvgVersion svg_ver) {
ZOrder = in->ReadInt32();
// Dynamic state
IsActivated = in->ReadBool() ? 1 : 0;
+ if (svg_ver >= kGuiSvgVersion_36023) {
+ _transparency = in->ReadInt32();
+ in->ReadInt32(); // reserve 3 ints
+ in->ReadInt32();
+ in->ReadInt32();
+ }
}
void GUIObject::WriteToSavegame(Stream *out) const {
@@ -189,6 +203,10 @@ void GUIObject::WriteToSavegame(Stream *out) const {
out->WriteInt32(ZOrder);
// Dynamic state
out->WriteBool(IsActivated != 0);
+ out->WriteInt32(_transparency);
+ out->WriteInt32(0); // reserve 3 ints
+ out->WriteInt32(0);
+ out->WriteInt32(0);
}
diff --git a/engines/ags/shared/gui/gui_object.h b/engines/ags/shared/gui/gui_object.h
index 557a38e9f13..1e8381e2e5f 100644
--- a/engines/ags/shared/gui/gui_object.h
+++ b/engines/ags/shared/gui/gui_object.h
@@ -60,7 +60,8 @@ public:
bool IsVisible() const;
// implemented separately in engine and editor
bool IsClickable() const;
- // Compatibility: should the control's graphic be clipped to its x,y,w,h
+ int GetTransparency() const { return _transparency; }
+ // 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 { return false; }
@@ -78,6 +79,7 @@ public:
void SetEnabled(bool on);
void SetTranslated(bool on);
void SetVisible(bool on);
+ void SetTransparency(int trans);
// Events
// Key pressed for control
@@ -134,6 +136,7 @@ public:
protected:
uint32_t Flags; // generic style and behavior flags
+ int32_t _transparency; // "incorrect" alpha (in legacy 255-range units)
bool _hasChanged;
// TODO: explicit event names & handlers for every event
Commit: 3b20393a177cc9bb9b5ab449ab313d5b6e6da820
https://github.com/scummvm/scummvm/commit/3b20393a177cc9bb9b5ab449ab313d5b6e6da820
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:23-07:00
Commit Message:
AGS: Implemented gui control transparency in software mode
>From upstream bcffc2cdeb24a426e2b048e8a98df9c84cb7c6f2
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/draw.h
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 6f20667e4c8..24473fad228 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -999,23 +999,30 @@ void repair_alpha_channel(Bitmap *dest, Bitmap *bgpic) {
// used by GUI renderer to draw images
+// NOTE: use_alpha arg is for backward compatibility (legacy draw modes)
void draw_gui_sprite(Bitmap *ds, int pic, int x, int y, bool use_alpha, BlendMode blend_mode) {
- Bitmap *sprite = _GP(spriteset)[pic];
- const bool ds_has_alpha = ds->GetColorDepth() == 32;
- const bool src_has_alpha = (_GP(game).SpriteInfos[pic].Flags & SPF_ALPHACHANNEL) != 0;
+ draw_gui_sprite(ds, use_alpha, x, y, _GP(spriteset)[pic],
+ (_GP(game).SpriteInfos[pic].Flags & SPF_ALPHACHANNEL) != 0, blend_mode);
+}
+
+void draw_gui_sprite(Bitmap *ds, bool use_alpha, int x, int y, Bitmap *sprite, bool src_has_alpha,
+ BlendMode blend_mode, int alpha) {
+ if (alpha <= 0)
+ return;
- if (use_alpha && _GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper) {
- GfxUtil::DrawSpriteBlend(ds, Point(x, y), sprite, blend_mode, ds_has_alpha, src_has_alpha);
+ const bool ds_has_alpha = use_alpha && (ds->GetColorDepth() == 32);
+ if (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper) {
+ GfxUtil::DrawSpriteBlend(ds, Point(x, y), sprite, blend_mode, ds_has_alpha, src_has_alpha, alpha);
}
// Backwards-compatible drawing
- else if (use_alpha && ds_has_alpha && _GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_AdditiveAlpha) {
+ else if (ds_has_alpha && (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_AdditiveAlpha) && (alpha == 0xFF)) {
if (src_has_alpha)
set_additive_alpha_blender();
else
set_opaque_alpha_blender();
ds->TransBlendBlt(sprite, x, y);
} else {
- GfxUtil::DrawSpriteWithTransparency(ds, sprite, x, y);
+ GfxUtil::DrawSpriteWithTransparency(ds, sprite, x, y, alpha);
}
}
diff --git a/engines/ags/engine/ac/draw.h b/engines/ags/engine/ac/draw.h
index d6d4e09b9a8..5008276d141 100644
--- a/engines/ags/engine/ac/draw.h
+++ b/engines/ags/engine/ac/draw.h
@@ -139,6 +139,9 @@ void draw_sprite_slot_support_alpha(Shared::Bitmap *ds, bool ds_has_alpha, int x
Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha, int alpha = 0xFF);
void draw_gui_sprite(Shared::Bitmap *ds, int pic, int x, int y, bool use_alpha = true, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha);
void draw_gui_sprite_v330(Shared::Bitmap *ds, int pic, int x, int y, bool use_alpha = true, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha);
+void draw_gui_sprite(Shared::Bitmap *ds, bool use_alpha, int xpos, int ypos,
+ Shared::Bitmap *image, bool src_has_alpha, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha, int alpha = 0xFF);
+
// Render game on screen
void render_to_screen();
// Callbacks for the graphics driver
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 3a280fa0684..73d401f497f 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -261,6 +261,7 @@ void GUIMain::DrawWithControls(Bitmap *ds) {
if ((_G(all_buttons_disabled) >= 0) && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
return; // don't draw GUI controls
+ Bitmap tempbmp; // in case we need transforms
for (size_t ctrl_index = 0; ctrl_index < _controls.size(); ++ctrl_index) {
set_eip_guiobj(_ctrlDrawOrder[ctrl_index]);
@@ -271,11 +272,20 @@ void GUIMain::DrawWithControls(Bitmap *ds) {
if (!objToDraw->IsVisible())
continue;
- if (GUI::Options.ClipControls && objToDraw->IsContentClipped())
- ds->SetClip(RectWH(objToDraw->X, objToDraw->Y, objToDraw->Width, objToDraw->Height));
- else
- ds->ResetClip();
- objToDraw->Draw(ds, objToDraw->X, objToDraw->Y);
+ // Depending on draw properties - draw directly on the gui surface, or use a buffer
+ if (objToDraw->GetTransparency() == 0) {
+ if (GUI::Options.ClipControls && objToDraw->IsContentClipped())
+ ds->SetClip(RectWH(objToDraw->X, objToDraw->Y, objToDraw->Width, objToDraw->Height));
+ else
+ ds->ResetClip();
+ objToDraw->Draw(ds, objToDraw->X, objToDraw->Y);
+ } else {
+ const Rect rc = objToDraw->CalcGraphicRect(GUI::Options.ClipControls && objToDraw->IsContentClipped());
+ tempbmp.CreateTransparent(rc.GetWidth(), rc.GetHeight());
+ objToDraw->Draw(&tempbmp, objToDraw->X - rc.Left, objToDraw->Y - rc.Top);
+ draw_gui_sprite(ds, true, objToDraw->X, objToDraw->Y, &tempbmp, objToDraw->HasAlphaChannel(), kBlendMode_Alpha,
+ GfxDef::LegacyTrans255ToAlpha255(objToDraw->GetTransparency()));
+ }
int selectedColour = 14;
diff --git a/engines/ags/shared/gui/gui_main.h b/engines/ags/shared/gui/gui_main.h
index dce0388725f..4e111a19a25 100644
--- a/engines/ags/shared/gui/gui_main.h
+++ b/engines/ags/shared/gui/gui_main.h
@@ -258,6 +258,10 @@ extern int get_adjusted_spritewidth(int spr);
extern int get_adjusted_spriteheight(int spr);
extern bool is_sprite_alpha(int spr);
+extern void draw_gui_sprite(Shared::Bitmap *ds, bool use_alpha, int x, int y,
+ Shared::Bitmap *image, bool src_has_alpha,
+ Shared::BlendMode blend_mode, int alpha);
+
#define SET_EIP(x) set_our_eip(x);
extern void set_eip_guiobj(int eip);
extern int get_eip_guiobj();
Commit: b2d5b6e58610ed9496de648c0f23e6d80fd2e4c1
https://github.com/scummvm/scummvm/commit/b2d5b6e58610ed9496de648c0f23e6d80fd2e4c1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:24-07:00
Commit Message:
AGS: Implemented Overlay.Width & Height working as scaling
>From upstream 3a27e81a710a1c3de4b745d84dca39554dc64385
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/overlay.cpp
engines/ags/engine/ac/screen_overlay.cpp
engines/ags/engine/ac/screen_overlay.h
engines/ags/engine/game/savegame_components.cpp
engines/ags/engine/main/update.cpp
engines/ags/globals.cpp
engines/ags/globals.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 24473fad228..686273e7e22 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -753,7 +753,7 @@ void draw_sprite_slot_support_alpha(Bitmap *ds, bool ds_has_alpha, int xpos, int
IDriverDependantBitmap *recycle_ddb_bitmap(IDriverDependantBitmap *bimp, Bitmap *source, bool hasAlpha, bool opaque) {
if (bimp != nullptr) {
// same colour depth, width and height -> reuse
- if (((bimp->GetColorDepth() + 1) / 8 == source->GetBPP()) &&
+ if ((bimp->GetColorDepth() == source->GetColorDepth()) &&
(bimp->GetWidth() == source->GetWidth()) && (bimp->GetHeight() == source->GetHeight())) {
_G(gfxDriver)->UpdateDDBFromBitmap(bimp, source, hasAlpha);
return bimp;
@@ -2021,13 +2021,30 @@ void draw_gui_and_overlays() {
clear_sprite_list();
+ const bool is_software_mode = !_G(gfxDriver)->HasAcceleratedTransform();
// Add active overlays to the sprite list
- for (auto &over : _GP(screenover)) {
+ if (_GP(overlaybmp).size() < _GP(screenover).size())
+ _GP(overlaybmp).resize(_GP(screenover).size());
+ for (size_t i = 0; i < _GP(screenover).size(); ++i) {
+ auto &over = _GP(screenover)[i];
if (over.transparency == 255) continue; // skip fully transparent
- over.bmp->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(over.transparency));
+ if (_GP(screenover)[i].HasChanged()) {
+ // For software mode - prepare transformed bitmap if necessary
+ Bitmap *use_bmp = over.pic;
+ if (is_software_mode && (over.pic->GetSize() != Size(over.scaleWidth, over.scaleHeight))) {
+ _GP(overlaybmp)[i] = recycle_bitmap(_GP(overlaybmp)[i], over.pic->GetColorDepth(), over.scaleWidth, over.scaleHeight);
+ _GP(overlaybmp)[i]->StretchBlt(over.pic, RectWH(_GP(overlaybmp)[i]->GetSize()));
+ use_bmp = _GP(overlaybmp)[i];
+ }
+ over.ddb = recycle_ddb_bitmap(over.ddb, use_bmp, over.hasAlphaChannel);
+ over.ClearChanged();
+ }
+
+ over.ddb->SetStretch(over.scaleWidth, over.scaleHeight);
+ over.ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(over.transparency));
int tdxp, tdyp;
get_overlay_position(over, &tdxp, &tdyp);
- add_to_sprite_list(over.bmp, tdxp, tdyp, over.zorder, false, -1);
+ add_to_sprite_list(over.ddb, tdxp, tdyp, over.zorder, false, -1);
}
// Add GUIs
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 60563c34a98..35a5d0bf138 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -33,6 +33,7 @@
#include "ags/engine/ac/runtime_defines.h"
#include "ags/engine/ac/screen_overlay.h"
#include "ags/engine/ac/string.h"
+#include "ags/engine/debugging/debug_log.h"
#include "ags/engine/gfx/graphics_driver.h"
#include "ags/shared/gfx/bitmap.h"
#include "ags/engine/script/runtime_script_value.h"
@@ -106,14 +107,41 @@ int Overlay_GetWidth(ScriptOverlay *scover) {
int ovri = find_overlay_of_type(scover->overlayId);
if (ovri < 0)
quit("!invalid overlay ID specified");
- return game_to_data_coord(_GP(screenover)[ovri].pic->GetWidth());
+ return game_to_data_coord(_GP(screenover)[ovri].scaleWidth);
}
int Overlay_GetHeight(ScriptOverlay *scover) {
int ovri = find_overlay_of_type(scover->overlayId);
if (ovri < 0)
quit("!invalid overlay ID specified");
- return game_to_data_coord(_GP(screenover)[ovri].pic->GetHeight());
+ return game_to_data_coord(_GP(screenover)[ovri].scaleHeight);
+}
+
+void Overlay_SetScaledSize(ScreenOverlay &over, int width, int height) {
+ data_to_game_coords(&width, &height);
+ if (width < 1 || height < 1) {
+ debug_script_warn("Overlay.SetSize: invalid dimensions: %d x %d", width, height);
+ return;
+ }
+ if ((width == over.scaleWidth) && (height == over.scaleHeight))
+ return; // no change
+ over.scaleWidth = width;
+ over.scaleHeight = height;
+ over.MarkChanged();
+}
+
+void Overlay_SetWidth(ScriptOverlay *scover, int width) {
+ int ovri = find_overlay_of_type(scover->overlayId);
+ if (ovri < 0)
+ quit("!invalid overlay ID specified");
+ Overlay_SetScaledSize(_GP(screenover)[ovri], width, game_to_data_coord(_GP(screenover)[ovri].scaleHeight));
+}
+
+void Overlay_SetHeight(ScriptOverlay *scover, int height) {
+ int ovri = find_overlay_of_type(scover->overlayId);
+ if (ovri < 0)
+ quit("!invalid overlay ID specified");
+ Overlay_SetScaledSize(_GP(screenover)[ovri], game_to_data_coord(_GP(screenover)[ovri].scaleWidth), height);
}
int Overlay_GetValid(ScriptOverlay *scover) {
@@ -211,9 +239,9 @@ static void invalidate_and_subref(ScreenOverlay &over, ScriptOverlay *&scover) {
static void dispose_overlay(ScreenOverlay &over) {
delete over.pic;
over.pic = nullptr;
- if (over.bmp != nullptr)
- _G(gfxDriver)->DestroyDDB(over.bmp);
- over.bmp = nullptr;
+ if (over.ddb != nullptr)
+ _G(gfxDriver)->DestroyDDB(over.ddb);
+ over.ddb = nullptr;
if (over.associatedOverlayHandle) // dispose script object if there are no more refs
ccAttemptDisposeObject(over.associatedOverlayHandle);
}
@@ -272,11 +300,13 @@ size_t add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic
ScreenOverlay over;
over.pic = piccy;
- over.bmp = _G(gfxDriver)->CreateDDBFromBitmap(piccy, alphaChannel);
+ over.ddb = nullptr; // is generated during first draw pass
over.x = x;
over.y = y;
over.offsetX = pic_offx;
over.offsetY = pic_offy;
+ over.scaleWidth = piccy->GetWidth();
+ over.scaleHeight = piccy->GetHeight();
// by default draw speech and portraits over GUI, and the rest under GUI
over.zorder = (type == OVER_TEXTMSG || type == OVER_PICTURE || type == OVER_TEXTSPEECH) ?
INT_MAX : INT_MIN;
@@ -298,6 +328,7 @@ size_t add_screen_overlay(int x, int y, int type, Shared::Bitmap *piccy, int pic
_GP(play).speech_face_scover = create_scriptobj_addref(over);
}
+ over.MarkChanged();
_GP(screenover).push_back(std::move(over));
return _GP(screenover).size() - 1;
}
@@ -346,12 +377,10 @@ void get_overlay_position(const ScreenOverlay &over, int *x, int *y) {
void recreate_overlay_ddbs() {
for (auto &over : _GP(screenover)) {
- if (over.bmp)
- _G(gfxDriver)->DestroyDDB(over.bmp);
- if (over.pic)
- over.bmp = _G(gfxDriver)->CreateDDBFromBitmap(over.pic, false);
- else
- over.bmp = nullptr;
+ if (over.ddb)
+ _G(gfxDriver)->DestroyDDB(over.ddb);
+ over.ddb = nullptr; // is generated during first draw pass
+ over.MarkChanged();
}
}
@@ -415,10 +444,18 @@ RuntimeScriptValue Sc_Overlay_GetWidth(void *self, const RuntimeScriptValue *par
API_OBJCALL_INT(ScriptOverlay, Overlay_GetWidth);
}
+RuntimeScriptValue Sc_Overlay_SetWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+ API_OBJCALL_VOID_PINT(ScriptOverlay, Overlay_SetWidth);
+}
+
RuntimeScriptValue Sc_Overlay_GetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptOverlay, Overlay_GetHeight);
}
+RuntimeScriptValue Sc_Overlay_SetHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+ API_OBJCALL_VOID_PINT(ScriptOverlay, Overlay_SetHeight);
+}
+
RuntimeScriptValue Sc_Overlay_GetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptOverlay, Overlay_GetTransparency);
}
@@ -459,7 +496,9 @@ void RegisterOverlayAPI() {
ccAddExternalObjectFunction("Overlay::get_Y", Sc_Overlay_GetY);
ccAddExternalObjectFunction("Overlay::set_Y", Sc_Overlay_SetY);
ccAddExternalObjectFunction("Overlay::get_Width", Sc_Overlay_GetWidth);
+ ccAddExternalObjectFunction("Overlay::set_Width", Sc_Overlay_SetWidth);
ccAddExternalObjectFunction("Overlay::get_Height", Sc_Overlay_GetHeight);
+ ccAddExternalObjectFunction("Overlay::set_Height", Sc_Overlay_SetHeight);
ccAddExternalObjectFunction("Overlay::get_Transparency", Sc_Overlay_GetTransparency);
ccAddExternalObjectFunction("Overlay::set_Transparency", Sc_Overlay_SetTransparency);
ccAddExternalObjectFunction("Overlay::get_ZOrder", Sc_Overlay_GetZOrder);
diff --git a/engines/ags/engine/ac/screen_overlay.cpp b/engines/ags/engine/ac/screen_overlay.cpp
index 2074bf78e37..275b8eb60c2 100644
--- a/engines/ags/engine/ac/screen_overlay.cpp
+++ b/engines/ags/engine/ac/screen_overlay.cpp
@@ -27,12 +27,11 @@ namespace AGS3 {
using AGS::Shared::Stream;
void ScreenOverlay::ReadFromFile(Stream *in, int32_t cmp_ver) {
- // Skipping bmp and pic pointer values
- // TODO: find out if it's safe to just drop these pointers!! replace with unique_ptr?
- bmp = nullptr;
pic = nullptr;
- in->ReadInt32(); // bmp
- hasSerializedBitmap = in->ReadInt32() != 0;
+ ddb = nullptr;
+ // Skipping pointers (were saved by old engine)
+ in->ReadInt32(); // ddb
+ hasSerializedBitmap = in->ReadInt32() != 0; // pic
type = in->ReadInt32();
x = in->ReadInt32();
y = in->ReadInt32();
@@ -48,14 +47,14 @@ void ScreenOverlay::ReadFromFile(Stream *in, int32_t cmp_ver) {
if (cmp_ver >= 2) {
zorder = in->ReadInt32();
transparency = in->ReadInt32();
- in->ReadInt32(); // reserve 2 ints
- in->ReadInt32();
+ scaleWidth = in->ReadInt32();
+ scaleHeight = in->ReadInt32();
}
}
void ScreenOverlay::WriteToFile(Stream *out) const {
// Writing bitmap "pointers" to correspond to full structure writing
- out->WriteInt32(0); // bmp
+ out->WriteInt32(0); // ddb
out->WriteInt32(pic ? 1 : 0); // pic
out->WriteInt32(type);
out->WriteInt32(x);
@@ -71,8 +70,8 @@ void ScreenOverlay::WriteToFile(Stream *out) const {
// since cmp_ver = 2
out->WriteInt32(zorder);
out->WriteInt32(transparency);
- out->WriteInt32(0); // reserve 2 ints
- out->WriteInt32(0);
+ out->WriteInt32(scaleWidth);
+ out->WriteInt32(scaleHeight);
}
} // namespace AGS3
diff --git a/engines/ags/engine/ac/screen_overlay.h b/engines/ags/engine/ac/screen_overlay.h
index 31b90384c4f..19214bcbe72 100644
--- a/engines/ags/engine/ac/screen_overlay.h
+++ b/engines/ags/engine/ac/screen_overlay.h
@@ -42,8 +42,18 @@ class IDriverDependantBitmap;
using namespace AGS; // FIXME later
+// Overlay class.
+// TODO: currently overlay creates and stores its own bitmap, even if
+// created using existing sprite. As a side-effect, changing that sprite
+// (if it were a dynamic one) will not affect overlay (unlike other objects).
+// For future perfomance optimization it may be desired to store sprite index
+// instead; but that would mean that overlay will have to receive sprite
+// changes. For backward compatibility there may be a game switch that
+// forces it to make a copy.
struct ScreenOverlay {
- Engine::IDriverDependantBitmap *bmp = nullptr;
+ // Texture
+ Engine::IDriverDependantBitmap *ddb = nullptr;
+ // Original bitmap
Shared::Bitmap *pic = nullptr;
bool hasAlphaChannel = false;
int type = 0, timeout = 0;
@@ -52,6 +62,8 @@ struct ScreenOverlay {
int x = 0, y = 0;
// Border/padding offset for the tiled text windows
int offsetX = 0, offsetY = 0;
+ // Width and height to stretch the texture to
+ int scaleWidth = 0, scaleHeight = 0;
int bgSpeechForChar = -1;
int associatedOverlayHandle = 0;
int zorder = INT_MIN;
@@ -59,8 +71,24 @@ struct ScreenOverlay {
bool hasSerializedBitmap = false;
int transparency = 0;
+ // Tells if Overlay has graphically changed recently
+ bool HasChanged() const {
+ return _hasChanged;
+ }
+ // Manually marks GUI as graphically changed
+ void MarkChanged() {
+ _hasChanged = true;
+ }
+ // Clears changed flag
+ void ClearChanged() {
+ _hasChanged = false;
+ }
+
void ReadFromFile(Shared::Stream *in, int32_t cmp_ver);
void WriteToFile(Shared::Stream *out) const;
+
+private:
+ bool _hasChanged = false;
};
} // namespace AGS3
diff --git a/engines/ags/engine/game/savegame_components.cpp b/engines/ags/engine/game/savegame_components.cpp
index 52e4793ebe7..ee5fe72990b 100644
--- a/engines/ags/engine/game/savegame_components.cpp
+++ b/engines/ags/engine/game/savegame_components.cpp
@@ -774,6 +774,10 @@ HSaveError ReadOverlays(Stream *in, int32_t cmp_ver, const PreservedParams & /*p
over.ReadFromFile(in, cmp_ver);
if (over.hasSerializedBitmap)
over.pic = read_serialized_bitmap(in);
+ if (over.scaleWidth <= 0 || over.scaleHeight <= 0) {
+ over.scaleWidth = over.pic->GetWidth();
+ over.scaleHeight = over.pic->GetHeight();
+ }
_GP(screenover).push_back(over);
}
return HSaveError::None();
diff --git a/engines/ags/engine/main/update.cpp b/engines/ags/engine/main/update.cpp
index 4847bf06252..37c4c72cbec 100644
--- a/engines/ags/engine/main/update.cpp
+++ b/engines/ags/engine/main/update.cpp
@@ -410,7 +410,8 @@ void update_sierra_speech() {
DrawViewFrame(frame_pic, blink_vf, view_frame_x, view_frame_y, face_has_alpha);
}
- _G(gfxDriver)->UpdateDDBFromBitmap(_GP(screenover)[_G(face_talking)].bmp, _GP(screenover)[_G(face_talking)].pic, face_has_alpha);
+ _GP(screenover)[_G(face_talking)].hasAlphaChannel = face_has_alpha;
+ _GP(screenover)[_G(face_talking)].MarkChanged();
} // end if updatedFrame
}
}
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index 5201df62621..3b453d90062 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -192,6 +192,7 @@ Globals::Globals() {
_guiobjbmp = new std::vector<Engine::IDriverDependantBitmap *>();
_guiobjoff = new std::vector<Point>();
_guiobjbmpref = new std::vector<int>();
+ _overlaybmp = new std::vector<Shared::Bitmap *>();
// draw_software.cpp globals
_BlackRects = new DirtyRects();
@@ -446,6 +447,7 @@ Globals::~Globals() {
delete _guiobjbmp;
delete _guiobjoff;
delete _guiobjbmpref;
+ delete _overlaybmp;
// draw_software.cpp globals
delete _BlackRects;
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index bc893abc87e..ab527217f13 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -612,6 +612,8 @@ public:
std::vector<Engine::IDriverDependantBitmap *> *_guiobjbmp;
std::vector<Point> *_guiobjoff; // because surface may be larger than logical position
std::vector<int> *_guiobjbmpref; // first control texture index of each GUI
+ // Overlay's cached transformed bitmap, for software mode
+ std::vector<Shared::Bitmap *> *_overlaybmp;
/**@}*/
Commit: 684463c903dcd20dfced1a89d79ff59cda59f9a4
https://github.com/scummvm/scummvm/commit/684463c903dcd20dfced1a89d79ff59cda59f9a4
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:24-07:00
Commit Message:
AGS: Implemented readonly Overlay.GraphicWidth & GraphicHeight
>From upstream dbfa017cf808beb4522c260f4a9cce20ac0009ee
Changed paths:
engines/ags/engine/ac/overlay.cpp
diff --git a/engines/ags/engine/ac/overlay.cpp b/engines/ags/engine/ac/overlay.cpp
index 35a5d0bf138..2966b1c4daa 100644
--- a/engines/ags/engine/ac/overlay.cpp
+++ b/engines/ags/engine/ac/overlay.cpp
@@ -117,6 +117,20 @@ int Overlay_GetHeight(ScriptOverlay *scover) {
return game_to_data_coord(_GP(screenover)[ovri].scaleHeight);
}
+int Overlay_GetGraphicWidth(ScriptOverlay *scover) {
+ int ovri = find_overlay_of_type(scover->overlayId);
+ if (ovri < 0)
+ quit("!invalid overlay ID specified");
+ return game_to_data_coord(_GP(screenover)[ovri].pic->GetWidth());
+}
+
+int Overlay_GetGraphicHeight(ScriptOverlay *scover) {
+ int ovri = find_overlay_of_type(scover->overlayId);
+ if (ovri < 0)
+ quit("!invalid overlay ID specified");
+ return game_to_data_coord(_GP(screenover)[ovri].pic->GetHeight());
+}
+
void Overlay_SetScaledSize(ScreenOverlay &over, int width, int height) {
data_to_game_coords(&width, &height);
if (width < 1 || height < 1) {
@@ -456,6 +470,14 @@ RuntimeScriptValue Sc_Overlay_SetHeight(void *self, const RuntimeScriptValue *pa
API_OBJCALL_VOID_PINT(ScriptOverlay, Overlay_SetHeight);
}
+RuntimeScriptValue Sc_Overlay_GetGraphicWidth(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+ API_OBJCALL_INT(ScriptOverlay, Overlay_GetGraphicWidth);
+}
+
+RuntimeScriptValue Sc_Overlay_GetGraphicHeight(void *self, const RuntimeScriptValue *params, int32_t param_count) {
+ API_OBJCALL_INT(ScriptOverlay, Overlay_GetGraphicHeight);
+}
+
RuntimeScriptValue Sc_Overlay_GetTransparency(void *self, const RuntimeScriptValue *params, int32_t param_count) {
API_OBJCALL_INT(ScriptOverlay, Overlay_GetTransparency);
}
@@ -499,6 +521,8 @@ void RegisterOverlayAPI() {
ccAddExternalObjectFunction("Overlay::set_Width", Sc_Overlay_SetWidth);
ccAddExternalObjectFunction("Overlay::get_Height", Sc_Overlay_GetHeight);
ccAddExternalObjectFunction("Overlay::set_Height", Sc_Overlay_SetHeight);
+ ccAddExternalObjectFunction("Overlay::get_GraphicWidth", Sc_Overlay_GetGraphicWidth);
+ ccAddExternalObjectFunction("Overlay::get_GraphicHeight", Sc_Overlay_GetGraphicHeight);
ccAddExternalObjectFunction("Overlay::get_Transparency", Sc_Overlay_GetTransparency);
ccAddExternalObjectFunction("Overlay::set_Transparency", Sc_Overlay_SetTransparency);
ccAddExternalObjectFunction("Overlay::get_ZOrder", Sc_Overlay_GetZOrder);
Commit: a94adb59683fe0ab666d6c116ad1ac4f2f44c3d1
https://github.com/scummvm/scummvm/commit/a94adb59683fe0ab666d6c116ad1ac4f2f44c3d1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:24-07:00
Commit Message:
AGS: Fixed TextBox duplicating letter input
>From upstream 6aead72e207b33a991a5e3d2d32f7991007f786c
Changed paths:
engines/ags/shared/gui/gui_textbox.cpp
diff --git a/engines/ags/shared/gui/gui_textbox.cpp b/engines/ags/shared/gui/gui_textbox.cpp
index 29393a1ea44..1f7a7ade5e5 100644
--- a/engines/ags/shared/gui/gui_textbox.cpp
+++ b/engines/ags/shared/gui/gui_textbox.cpp
@@ -72,28 +72,29 @@ static void Backspace(String &text) {
}
void GUITextBox::OnKeyPress(const KeyInput &ki) {
- eAGSKeyCode keycode = ki.Key;
-
- // other key, continue
- if ((keycode >= 128) && (!font_supports_extended_characters(Font)))
- return;
- // return/enter
- if (keycode == eAGSKeyCodeReturn) {
+ switch (ki.Key) {
+ case eAGSKeyCodeReturn:
IsActivated = true;
return;
- }
-
- MarkChanged();
- // backspace, remove character
- if (keycode == eAGSKeyCodeBackspace) {
+ case eAGSKeyCodeBackspace:
Backspace(Text);
+ MarkChanged();
return;
+ default: break;
}
- Text.AppendChar(keycode);
+ if (ki.UChar == 0)
+ return; // not a textual event
+ if ((ki.UChar >= 128) && (!font_supports_extended_characters(Font)))
+ return; // unsupported letter
+
+ (get_uformat() == U_UTF8) ?
+ Text.Append(ki.Text) :
+ Text.AppendChar(ki.UChar);
// if the new string is too long, remove the new character
if (get_text_width(Text.GetCStr(), Font) > (Width - (6 + get_fixed_pixel_size(5))))
Backspace(Text);
+ MarkChanged();
}
void GUITextBox::SetShowBorder(bool on) {
Commit: 598acd02b8e588478c0088e8bf152d17d939e5a3
https://github.com/scummvm/scummvm/commit/598acd02b8e588478c0088e8bf152d17d939e5a3
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:24-07:00
Commit Message:
AGS: Updated build version (3.6.0.23)
>From upstream 13499a1bd26822fd25e32b0855281e1534b30bd9
Changed paths:
engines/ags/shared/core/def_version.h
diff --git a/engines/ags/shared/core/def_version.h b/engines/ags/shared/core/def_version.h
index 838d76323eb..81073776aeb 100644
--- a/engines/ags/shared/core/def_version.h
+++ b/engines/ags/shared/core/def_version.h
@@ -22,9 +22,9 @@
#ifndef AGS_SHARED_CORE_DEFVERSION_H
#define AGS_SHARED_CORE_DEFVERSION_H
-#define ACI_VERSION_STR "3.6.0.22"
+#define ACI_VERSION_STR "3.6.0.23"
#if defined (RC_INVOKED) // for MSVC resource compiler
-#define ACI_VERSION_MSRC_DEF 3.6.0.22
+#define ACI_VERSION_MSRC_DEF 3.6.0.23
#endif
#define SPECIAL_VERSION ""
Commit: f84022353345c61009679a0fe2df9df8f15a76a1
https://github.com/scummvm/scummvm/commit/f84022353345c61009679a0fe2df9df8f15a76a1
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:24-07:00
Commit Message:
AGS: Fixed GUI's background image with alpha channel
>From upstream d3820e0fd369516008633bbc12fc3da359067798
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 686273e7e22..6f57f22c9ae 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1010,12 +1010,12 @@ void draw_gui_sprite(Bitmap *ds, bool use_alpha, int x, int y, Bitmap *sprite, b
if (alpha <= 0)
return;
- const bool ds_has_alpha = use_alpha && (ds->GetColorDepth() == 32);
- if (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper) {
+ const bool ds_has_alpha = (ds->GetColorDepth() == 32);
+ if (use_alpha && _GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Proper) {
GfxUtil::DrawSpriteBlend(ds, Point(x, y), sprite, blend_mode, ds_has_alpha, src_has_alpha, alpha);
}
// Backwards-compatible drawing
- else if (ds_has_alpha && (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_AdditiveAlpha) && (alpha == 0xFF)) {
+ else if (use_alpha && ds_has_alpha && (_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_AdditiveAlpha) && (alpha == 0xFF)) {
if (src_has_alpha)
set_additive_alpha_blender();
else
Commit: 87994139f64c849ef79e220f1bf8210d08bded25
https://github.com/scummvm/scummvm/commit/87994139f64c849ef79e220f1bf8210d08bded25
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:24-07:00
Commit Message:
AGS: Tidied gui drawing code a little
>From upstream c1bb2fb846c8ffe997ce2c1dda690467bc28edc4
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/globals.cpp
engines/ags/globals.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 6f57f22c9ae..95c7c5b52e5 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -370,17 +370,17 @@ void init_game_drawdata() {
_GP(actspswbbmp).resize(actsps_num);
_GP(actspswbcache).resize(actsps_num);
_GP(guibg).resize(_GP(game).numgui);
- _GP(guibgbmp).resize(_GP(game).numgui);
+ _GP(guibgddb).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);
+ _GP(guiobjddbref).resize(_GP(game).numgui);
for (const auto &gui : _GP(guis)) {
- _GP(guiobjbmpref)[gui.ID] = guio_num;
+ _GP(guiobjddbref)[gui.ID] = guio_num;
guio_num += gui.GetControlCount();
}
_GP(guiobjbg).resize(guio_num);
- _GP(guiobjbmp).resize(guio_num);
+ _GP(guiobjddb).resize(guio_num);
_GP(guiobjoff).resize(guio_num);
}
@@ -393,11 +393,11 @@ void dispose_game_drawdata() {
_GP(actspswbbmp).clear();
_GP(actspswbcache).clear();
_GP(guibg).clear();
- _GP(guibgbmp).clear();
+ _GP(guibgddb).clear();
_GP(guiobjbg).clear();
- _GP(guiobjbmp).clear();
- _GP(guiobjbmpref).clear();
+ _GP(guiobjddb).clear();
+ _GP(guiobjddbref).clear();
_GP(guiobjoff).clear();
}
@@ -444,17 +444,17 @@ void clear_drawobj_cache() {
for (int i = 0; i < _GP(game).numgui; ++i) {
delete _GP(guibg)[i];
_GP(guibg)[i] = nullptr;
- if (_GP(guibgbmp)[i])
- _G(gfxDriver)->DestroyDDB(_GP(guibgbmp)[i]);
- _GP(guibgbmp)[i] = nullptr;
+ if (_GP(guibgddb)[i])
+ _G(gfxDriver)->DestroyDDB(_GP(guibgddb)[i]);
+ _GP(guibgddb)[i] = nullptr;
}
for (size_t 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;
+ if (_GP(guiobjddb)[i])
+ _G(gfxDriver)->DestroyDDB(_GP(guiobjddb)[i]);
+ _GP(guiobjddb)[i] = nullptr;
}
dispose_debug_room_drawdata();
@@ -1049,16 +1049,6 @@ Bitmap *recycle_bitmap(Bitmap *bimp, int coldep, int wid, int hit, bool make_tra
return bimp;
}
-// Allocates texture for the GUI
-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;
- }
-}
-
// Get the local tint at the specified X & Y co-ordinates, based on
// room regions and SetAmbientTint
// tint_amnt will be set to 0 if there is no tint enabled
@@ -1979,7 +1969,7 @@ 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];
+ int draw_index = _GP(guiobjddbref)[gui.ID];
for (int i = 0; i < gui.GetControlCount(); ++i, ++draw_index) {
GUIObject *obj = gui.GetControl(i);
if (!obj->IsVisible() ||
@@ -1987,23 +1977,17 @@ void draw_gui_controls(GUIMain &gui) {
continue;
if (!obj->HasChanged())
continue;
- obj->ClearChanged();
+ auto *&objbg_bmp = _GP(guiobjbg)[draw_index];
+ auto *&objbg_ddb = _GP(guiobjddb)[draw_index];
Rect obj_surf = obj->CalcGraphicRect(GUI::Options.ClipControls);
- if (_GP(guiobjbg)[draw_index] == nullptr ||
- _GP(guiobjbg)[draw_index]->GetSize() != obj_surf.GetSize()) {
- recreate_drawobj_bitmap(_GP(guiobjbg)[draw_index], _GP(guiobjbmp)[draw_index],
- obj_surf.GetWidth(), obj_surf.GetHeight());
- }
-
- _GP(guiobjbg)[draw_index]->ClearTransparent();
- obj->Draw(_GP(guiobjbg)[draw_index], obj->X - obj_surf.Left, obj->Y - obj_surf.Top);
+ objbg_bmp = recycle_bitmap(objbg_bmp, _GP(game).GetColorDepth(), obj_surf.GetWidth(), obj_surf.GetHeight());
+ objbg_bmp->ClearTransparent();
+ obj->Draw(objbg_bmp, obj->X - obj_surf.Left, obj->Y - obj_surf.Top);
- 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());
+ objbg_ddb = recycle_ddb_bitmap(objbg_ddb, objbg_bmp, obj->HasAlphaChannel());
_GP(guiobjoff)[draw_index] = Point(obj_surf.GetLT());
+ obj->ClearChanged();
}
}
@@ -2059,80 +2043,78 @@ void draw_gui_and_overlays() {
_G(our_eip) = 37;
// Prepare and update GUI textures
{
- for (int aa = 0; aa < _GP(game).numgui; aa++) {
- if (!_GP(guis)[aa].IsDisplayed()) continue; // not on screen
- if (!_GP(guis)[aa].HasChanged() && !_GP(guis)[aa].HasControlsChanged()) continue; // no changes: no need to update image
- if (_GP(guis)[aa].Transparency == 255) continue; // 100% transparent
-
- if (_GP(guibg)[aa] == nullptr ||
- _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);
- }
+ for (int index = 0; index < _GP(game).numgui; ++index) {
+ auto &gui = _GP(guis)[index];
+ if (!gui.IsDisplayed()) continue; // not on screen
+ if (!gui.HasChanged() && !gui.HasControlsChanged()) continue; // no changes: no need to update image
+ if (gui.Transparency == 255) continue; // 100% transparent
- _G(eip_guinum) = aa;
+ auto *&guibg_bmp = _GP(guibg)[index];
+ auto *&guibg_ddb = _GP(guibgddb)[index];
+ guibg_bmp = recycle_bitmap(guibg_bmp, _GP(game).GetColorDepth(), gui.Width, gui.Height);
+
+ _G(eip_guinum) = index;
_G(our_eip) = 372;
const bool draw_with_controls = !draw_controls_as_textures;
- if (_GP(guis)[aa].HasChanged() || (draw_with_controls && _GP(guis)[aa].HasControlsChanged())) {
- _GP(guibg)[aa]->ClearTransparent();
+ if (gui.HasChanged() || (draw_with_controls && gui.HasControlsChanged())) {
+ guibg_bmp->ClearTransparent();
if (draw_with_controls)
- _GP(guis)[aa].DrawWithControls(_GP(guibg)[aa]);
+ gui.DrawWithControls(guibg_bmp);
else
- _GP(guis)[aa].DrawSelf(_GP(guibg)[aa]);
+ gui.DrawSelf(guibg_bmp);
- const bool is_alpha = _GP(guis)[aa].HasAlphaChannel();
+ const bool is_alpha = gui.HasAlphaChannel();
if (is_alpha) {
- if ((_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Legacy) && (_GP(guis)[aa].BgImage > 0)) {
+ if ((_GP(game).options[OPT_NEWGUIALPHA] == kGuiAlphaRender_Legacy) && (gui.BgImage > 0)) {
// old-style (pre-3.0.2) GUI alpha rendering
- repair_alpha_channel(_GP(guibg)[aa], _GP(spriteset)[_GP(guis)[aa].BgImage]);
+ repair_alpha_channel(guibg_bmp, _GP(spriteset)[gui.BgImage]);
}
}
- if (_GP(guibgbmp)[aa])
- _G(gfxDriver)->UpdateDDBFromBitmap(_GP(guibgbmp)[aa], _GP(guibg)[aa], is_alpha);
- else
- _GP(guibgbmp)[aa] = _G(gfxDriver)->CreateDDBFromBitmap(_GP(guibg)[aa], is_alpha);
+ guibg_ddb = recycle_ddb_bitmap(guibg_ddb, guibg_bmp, is_alpha);
}
_G(our_eip) = 373;
- if (!draw_with_controls && _GP(guis)[aa].HasControlsChanged()) {
- draw_gui_controls(_GP(guis)[aa]);
+ if (!draw_with_controls && gui.HasControlsChanged()) {
+ draw_gui_controls(gui);
}
_G(our_eip) = 374;
- _GP(guis)[aa].ClearChanged();
+ gui.ClearChanged();
}
}
_G(our_eip) = 38;
// Draw the GUIs
- for (int aa = 0; aa < _GP(game).numgui; ++aa) {
- if (!_GP(guis)[aa].IsDisplayed()) continue; // not on screen
- if (_GP(guis)[aa].Transparency == 255) continue; // 100% transparent
+ for (int index = 0; index < _GP(game).numgui; ++index) {
+ const auto &gui = _GP(guis)[index];
+ if (!gui.IsDisplayed()) continue; // not on screen
+ if (gui.Transparency == 255) continue; // 100% transparent
// Don't draw GUI if "GUIs Turn Off When Disabled"
if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) &&
(_G(all_buttons_disabled) >= 0) &&
- (_GP(guis)[aa].PopupStyle != kGUIPopupNoAutoRemove))
+ (gui.PopupStyle != kGUIPopupNoAutoRemove))
continue;
- auto *gui_ddb = _GP(guibgbmp)[aa];
+ auto *gui_ddb = _GP(guibgddb)[index];
assert(gui_ddb); // Test for missing texture, might happen if not marked for update
if (!gui_ddb) continue;
- gui_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(_GP(guis)[aa].Transparency));
- add_to_sprite_list(gui_ddb, _GP(guis)[aa].X, _GP(guis)[aa].Y, _GP(guis)[aa].ZOrder, false, aa);
+ gui_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(gui.Transparency));
+ add_to_sprite_list(gui_ddb, gui.X, gui.Y, gui.ZOrder, false, index);
}
// Poll the GUIs
// TODO: move this out of the draw routine into game update!!
if (IsInterfaceEnabled()) // only poll if the interface is enabled
{
- for (int gg = 0; gg < _GP(game).numgui; gg++) {
- if (!_GP(guis)[gg].IsDisplayed()) continue; // not on screen
+ for (auto &gui : _GP(guis)) {
+ if (!gui.IsDisplayed()) continue; // not on screen
// Don't touch GUI if "GUIs Turn Off When Disabled"
if ((_GP(game).options[OPT_DISABLEOFF] == kGuiDis_Off) &&
(_G(all_buttons_disabled) >= 0) &&
- (_GP(guis)[gg].PopupStyle != kGUIPopupNoAutoRemove))
+ (gui.PopupStyle != kGUIPopupNoAutoRemove))
continue;
- _GP(guis)[gg].Poll(_G(mousex), _G(mousey));
+ gui.Poll(_G(mousex), _G(mousey));
}
}
}
@@ -2154,13 +2136,13 @@ void draw_gui_and_overlays() {
// Create a sub-batch
_G(gfxDriver)->BeginSpriteBatch(RectWH(s.x, s.y, s.ddb->GetWidth(), s.ddb->GetHeight()),
SpriteTransform(0, 0, 1.f, 1.f, 0.f, s.ddb->GetAlpha()));
- const int draw_index = _GP(guiobjbmpref)[s.id];
+ const int draw_index = _GP(guiobjddbref)[s.id];
for (const auto &obj_id : _GP(guis)[s.id].GetControlsDrawOrder()) {
GUIObject *obj = _GP(guis)[s.id].GetControl(obj_id);
if (!obj->IsVisible() ||
(!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
continue;
- auto *obj_ddb = _GP(guiobjbmp)[draw_index + obj_id];
+ auto *obj_ddb = _GP(guiobjddb)[draw_index + obj_id];
assert(obj_ddb); // Test for missing texture, might happen if not marked for update
if (!obj_ddb) continue;
obj_ddb->SetAlpha(GfxDef::LegacyTrans255ToAlpha255(obj->GetTransparency()));
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index 3b453d90062..d62a174ab24 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -179,7 +179,7 @@ Globals::Globals() {
_actspswbbmp = new std::vector<Engine::IDriverDependantBitmap *>();
_actspswbcache = new std::vector<CachedActSpsData>();
_guibg = new std::vector<Shared::Bitmap *>();
- _guibgbmp = new std::vector<Engine::IDriverDependantBitmap *>();
+ _guibgddb = new std::vector<Engine::IDriverDependantBitmap *>();
_debugRoomMaskBmp = new std::unique_ptr<Shared::Bitmap>();
_debugMoveListBmp = new std::unique_ptr<Shared::Bitmap>();
@@ -189,9 +189,9 @@ Globals::Globals() {
_palette[i].clear();
_guiobjbg = new std::vector<Shared::Bitmap *>();
- _guiobjbmp = new std::vector<Engine::IDriverDependantBitmap *>();
+ _guiobjddb = new std::vector<Engine::IDriverDependantBitmap *>();
_guiobjoff = new std::vector<Point>();
- _guiobjbmpref = new std::vector<int>();
+ _guiobjddbref = new std::vector<int>();
_overlaybmp = new std::vector<Shared::Bitmap *>();
// draw_software.cpp globals
@@ -437,16 +437,16 @@ Globals::~Globals() {
delete _actspswbbmp;
delete _actspswbcache;
delete _guibg;
- delete _guibgbmp;
+ delete _guibgddb;
delete _debugRoomMaskBmp;
delete _debugMoveListBmp;
delete[] _dynamicallyCreatedSurfaces;
delete[] _palette;
delete _maincoltable;
delete _guiobjbg;
- delete _guiobjbmp;
+ delete _guiobjddb;
delete _guiobjoff;
- delete _guiobjbmpref;
+ delete _guiobjddbref;
delete _overlaybmp;
// draw_software.cpp globals
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index ab527217f13..609a5542226 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -586,7 +586,7 @@ public:
std::vector<CachedActSpsData> *_actspswbcache;
// GUI surfaces
std::vector<Shared::Bitmap *> *_guibg;
- std::vector<Engine::IDriverDependantBitmap *> *_guibgbmp;
+ std::vector<Engine::IDriverDependantBitmap *> *_guibgddb;
// For debugging room masks
RoomAreaMask _debugRoomMask = kRoomAreaNone;
std::unique_ptr<Shared::Bitmap> *_debugRoomMaskBmp;
@@ -609,9 +609,9 @@ public:
// GUI control surfaces
std::vector<Shared::Bitmap *> *_guiobjbg;
- std::vector<Engine::IDriverDependantBitmap *> *_guiobjbmp;
+ std::vector<Engine::IDriverDependantBitmap *> *_guiobjddb;
std::vector<Point> *_guiobjoff; // because surface may be larger than logical position
- std::vector<int> *_guiobjbmpref; // first control texture index of each GUI
+ std::vector<int> *_guiobjddbref; // first control texture index of each GUI
// Overlay's cached transformed bitmap, for software mode
std::vector<Shared::Bitmap *> *_overlaybmp;
Commit: 3b91a1124f0467bbab39d9b163049d87540ae18d
https://github.com/scummvm/scummvm/commit/3b91a1124f0467bbab39d9b163049d87540ae18d
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:25-07:00
Commit Message:
AGS: Made internal BitmapFlip enum match the script, for convenience
>From upstream 8be85c08ed87a56265d2f18fb798ec463edb3ef7
Changed paths:
engines/ags/engine/ac/dynamic_sprite.cpp
engines/ags/shared/gfx/allegro_bitmap.cpp
engines/ags/shared/gfx/bitmap.h
diff --git a/engines/ags/engine/ac/dynamic_sprite.cpp b/engines/ags/engine/ac/dynamic_sprite.cpp
index 208c11ad1c8..de63ee39363 100644
--- a/engines/ags/engine/ac/dynamic_sprite.cpp
+++ b/engines/ags/engine/ac/dynamic_sprite.cpp
@@ -127,13 +127,8 @@ void DynamicSprite_Flip(ScriptDynamicSprite *sds, int direction) {
// resize the sprite to the requested size
Bitmap *newPic = BitmapHelper::CreateTransparentBitmap(_GP(game).SpriteInfos[sds->slot].Width, _GP(game).SpriteInfos[sds->slot].Height, _GP(spriteset)[sds->slot]->GetColorDepth());
- if (direction == 1)
- newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, Shared::kBitmap_HFlip);
- else if (direction == 2)
- newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, Shared::kBitmap_VFlip);
- else if (direction == 3)
- newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, Shared::kBitmap_HVFlip);
-
+ // AGS script FlipDirection corresponds to internal BitmapFlip
+ newPic->FlipBlt(_GP(spriteset)[sds->slot], 0, 0, static_cast<BitmapFlip>(direction));
delete _GP(spriteset)[sds->slot];
// replace the bitmap in the sprite set
diff --git a/engines/ags/shared/gfx/allegro_bitmap.cpp b/engines/ags/shared/gfx/allegro_bitmap.cpp
index f8119bd7665..ee43959f64b 100644
--- a/engines/ags/shared/gfx/allegro_bitmap.cpp
+++ b/engines/ags/shared/gfx/allegro_bitmap.cpp
@@ -284,12 +284,19 @@ void Bitmap::LitBlendBlt(Bitmap *src, int dst_x, int dst_y, int light_amount) {
void Bitmap::FlipBlt(Bitmap *src, int dst_x, int dst_y, BitmapFlip flip) {
BITMAP *al_src_bmp = src->_alBitmap;
- if (flip == kBitmap_HFlip) {
+ switch (flip) {
+ case kBitmap_HFlip:
draw_sprite_h_flip(_alBitmap, al_src_bmp, dst_x, dst_y);
- } else if (flip == kBitmap_VFlip) {
+ break;
+ case kBitmap_VFlip:
draw_sprite_v_flip(_alBitmap, al_src_bmp, dst_x, dst_y);
- } else if (flip == kBitmap_HVFlip) {
+ break;
+ case kBitmap_HVFlip:
draw_sprite_vh_flip(_alBitmap, al_src_bmp, dst_x, dst_y);
+ break;
+ default: // blit with no transform
+ Blit(src, dst_x, dst_y);
+ break;
}
}
diff --git a/engines/ags/shared/gfx/bitmap.h b/engines/ags/shared/gfx/bitmap.h
index 7eb732ef85b..4f1147ca6b2 100644
--- a/engines/ags/shared/gfx/bitmap.h
+++ b/engines/ags/shared/gfx/bitmap.h
@@ -44,6 +44,7 @@ enum BitmapMaskOption {
};
enum BitmapFlip {
+ kBitmap_NoFlip,
kBitmap_HFlip,
kBitmap_VFlip,
kBitmap_HVFlip
Commit: d3f862767830bc56465de599a2a6f2b1c56fea34
https://github.com/scummvm/scummvm/commit/d3f862767830bc56465de599a2a6f2b1c56fea34
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:25-07:00
Commit Message:
AGS: Refactored scale_and_flip_sprite() into transform_sprite()
>From upstream 3a3f301709b65e6293028541df8fea084f9da7f9
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/draw.h
engines/ags/engine/ac/object_cache.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 95c7c5b52e5..be982afc28a 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1201,87 +1201,58 @@ void apply_tint_or_light(int actspsindex, int light_level,
}
-// Draws the specified 'sppic' sprite onto _GP(actsps)[useindx] at the
-// specified width and height, and flips the sprite if necessary.
-// Returns 1 if something was drawn to actsps; returns 0 if no
-// scaling or stretching was required, in which case nothing was done
-int scale_and_flip_sprite(int useindx, int coldept, int zoom_level,
- int sppic, int newwidth, int newheight,
- int isMirrored) {
-
- int actsps_used = 1;
-
- // create and blank out the new sprite
- _GP(actsps)[useindx] = recycle_bitmap(_GP(actsps)[useindx], coldept, newwidth, newheight, true);
- Bitmap *active_spr = _GP(actsps)[useindx];
-
- if (zoom_level != 100) {
- // Scaled character
-
- _G(our_eip) = 334;
-
- // Ensure that anti-aliasing routines have a palette to
- // use for mapping while faded out
- if (_G(in_new_room))
+Bitmap *transform_sprite(Bitmap *src, bool src_has_alpha, Bitmap *&dst, const Size dst_sz, BitmapFlip flip) {
+ if ((src->GetSize() == dst_sz) && (flip == kFlip_None))
+ return src; // No transform: return source image
+
+ dst = recycle_bitmap(dst, src->GetColorDepth(), dst_sz.Width, dst_sz.Height, true);
+ _G(our_eip) = 339;
+
+ // If scaled: first scale then optionally mirror
+ if (src->GetSize() != dst_sz) {
+ // 8-bit support: ensure that anti-aliasing routines have a palette
+ // to use for mapping while faded out.
+ // TODO: find out if this may be moved out and not repeated?
+ if (_G(in_new_room) > 0)
select_palette(_G(palette));
-
- if (isMirrored) {
- Bitmap *tempspr = BitmapHelper::CreateBitmap(newwidth, newheight, coldept);
- tempspr->Fill(_GP(actsps)[useindx]->GetMaskColor());
- if ((IS_ANTIALIAS_SPRITES) && ((_GP(game).SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) == 0))
- tempspr->AAStretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
+ if (flip != kFlip_None) {
+ Bitmap tempbmp;
+ tempbmp.CreateTransparent(dst_sz.Width, dst_sz.Height, src->GetColorDepth());
+ if ((IS_ANTIALIAS_SPRITES) && !src_has_alpha)
+ tempbmp.AAStretchBlt(src, RectWH(dst_sz), kBitmap_Transparency);
else
- tempspr->StretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
- active_spr->FlipBlt(tempspr, 0, 0, Shared::kBitmap_HFlip);
- delete tempspr;
- } else if ((IS_ANTIALIAS_SPRITES) && ((_GP(game).SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) == 0))
- active_spr->AAStretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
- else
- active_spr->StretchBlt(_GP(spriteset)[sppic], RectWH(0, 0, newwidth, newheight), Shared::kBitmap_Transparency);
-
- /* AASTR2 version of code (doesn't work properly, gives black borders)
- if (IS_ANTIALIAS_SPRITES) {
- int aa_mode = AA_MASKED;
- if (_GP(game).spriteflags[sppic] & SPF_ALPHACHANNEL)
- aa_mode |= AA_ALPHA | AA_RAW_ALPHA;
- if (isMirrored)
- aa_mode |= AA_HFLIP;
-
- aa_set_mode(aa_mode);
- ->AAStretchBlt(_GP(actsps)[useindx],_GP(spriteset)[sppic],0,0,newwidth,newheight);
- }
- else if (isMirrored) {
- Bitmap *tempspr = BitmapHelper::CreateBitmap_ (coldept, newwidth, newheight);
- ->Clear (tempspr, ->GetMaskColor(_GP(actsps)[useindx]));
- ->StretchBlt (tempspr, _GP(spriteset)[sppic], 0, 0, newwidth, newheight);
- ->FlipBlt(Shared::kBitmap_HFlip, (_GP(actsps)[useindx], tempspr, 0, 0);
- wfreeblock (tempspr);
+ tempbmp.StretchBlt(src, RectWH(dst_sz), kBitmap_Transparency);
+ dst->FlipBlt(&tempbmp, 0, 0, kBitmap_HFlip);
+ } else {
+ if ((IS_ANTIALIAS_SPRITES) && !src_has_alpha)
+ dst->AAStretchBlt(src, RectWH(dst_sz), kBitmap_Transparency);
+ else
+ dst->StretchBlt(src, RectWH(dst_sz), kBitmap_Transparency);
}
- else
- ->StretchBlt(_GP(actsps)[useindx],_GP(spriteset)[sppic],0,0,newwidth,newheight);
- */
- if (_G(in_new_room))
- unselect_palette();
+ if (_G(in_new_room) > 0)
+ unselect_palette();
} else {
- // Not a scaled character, draw at normal size
-
- _G(our_eip) = 339;
-
- if (isMirrored)
- active_spr->FlipBlt(_GP(spriteset)[sppic], 0, 0, Shared::kBitmap_HFlip);
- else
- actsps_used = 0;
- //->Blit (_GP(spriteset)[sppic], _GP(actsps)[useindx], 0, 0, 0, 0, _GP(actsps)[useindx]->GetWidth(), _GP(actsps)[useindx]->GetHeight());
+ // If not scaled, then simply blit mirrored
+ dst->FlipBlt(src, 0, 0, kBitmap_HFlip);
}
-
- return actsps_used;
+ return dst; // return transformed result
}
+// Draws the specified 'sppic' sprite onto _GP(actsps)[useindx] at the
+// specified width and height, and flips the sprite if necessary.
+// Returns 1 if something was drawn to actsps; returns 0 if no
+// scaling or stretching was required, in which case nothing was done
+static bool scale_and_flip_sprite(int useindx, int sppic, int newwidth, int newheight, bool hmirror) {
+ Bitmap *src = _GP(spriteset)[sppic];
+ Bitmap *&dst = _GP(actsps)[useindx];
+ Bitmap *result = transform_sprite(src, (_GP(game).SpriteInfos[sppic].Flags & SPF_ALPHACHANNEL) != 0,
+ dst, Size(newwidth, newheight), hmirror ? kBitmap_HFlip : kBitmap_NoFlip);
+ return result != src;
+}
-
-// create the _GP(actsps)[aa] image with the object drawn correctly
+// create the actsps[aa] image with the object drawn correctly
// returns 1 if nothing at all has changed and actsps is still
// intact from last time; 0 otherwise
int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysUseSoftware) {
@@ -1292,8 +1263,10 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
quitprintf("There was an error drawing object %d. Its current sprite, %d, is invalid.", aa, _G(objs)[aa].num);
int coldept = _GP(spriteset)[_G(objs)[aa].num]->GetColorDepth();
- int sprwidth = _GP(game).SpriteInfos[_G(objs)[aa].num].Width;
- int sprheight = _GP(game).SpriteInfos[_G(objs)[aa].num].Height;
+ const int src_sprwidth = _GP(game).SpriteInfos[_G(objs)[aa].num].Width;
+ const int src_sprheight = _GP(game).SpriteInfos[_G(objs)[aa].num].Height;
+ int sprwidth = src_sprwidth;
+ int sprheight = src_sprheight;
int tint_red, tint_green, tint_blue;
int tint_level, tint_light, light_level;
@@ -1350,11 +1323,11 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
}
// check whether the image should be flipped
- int isMirrored = 0;
+ bool isMirrored = false;
if ((_G(objs)[aa].view != (uint16_t)-1) &&
- (_GP(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].pic == _G(objs)[aa].num) &&
- ((_GP(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].flags & VFLG_FLIPSPRITE) != 0)) {
- isMirrored = 1;
+ (_GP(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].pic == _G(objs)[aa].num) &&
+ ((_GP(views)[_G(objs)[aa].view].loops[_G(objs)[aa].loop].frames[_G(objs)[aa].frame].flags & VFLG_FLIPSPRITE) != 0)) {
+ isMirrored = true;
}
if ((hardwareAccelerated) &&
@@ -1410,14 +1383,14 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
// Not cached, so draw the image
- int actspsUsed = 0;
+ bool actspsUsed = false;
if (!hardwareAccelerated) {
// draw the base sprite, scaled and flipped as appropriate
- actspsUsed = scale_and_flip_sprite(useindx, coldept, zoom_level,
- _G(objs)[aa].num, sprwidth, sprheight, isMirrored);
- } else {
- // ensure actsps exists
- _GP(actsps)[useindx] = recycle_bitmap(_GP(actsps)[useindx], coldept, _GP(game).SpriteInfos[_G(objs)[aa].num].Width, _GP(game).SpriteInfos[_G(objs)[aa].num].Height);
+ actspsUsed = scale_and_flip_sprite(useindx, _G(objs)[aa].num, sprwidth, sprheight, isMirrored);
+ }
+ if (!actspsUsed) {
+ // ensure actsps exists // CHECKME: why do we need this in hardware accel mode too?
+ _GP(actsps)[useindx] = recycle_bitmap(_GP(actsps)[useindx], coldept, src_sprwidth, src_sprheight);
}
// direct read from source bitmap, where possible
@@ -1429,10 +1402,10 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
// the source bitmap
if (!hardwareAccelerated && ((tint_level > 0) || (light_level != 0))) {
apply_tint_or_light(useindx, light_level, tint_level, tint_red,
- tint_green, tint_blue, tint_light, coldept,
- comeFrom);
+ tint_green, tint_blue, tint_light, coldept,
+ comeFrom);
} else if (!actspsUsed) {
- _GP(actsps)[useindx]->Blit(_GP(spriteset)[_G(objs)[aa].num], 0, 0, 0, 0, _GP(game).SpriteInfos[_G(objs)[aa].num].Width, _GP(game).SpriteInfos[_G(objs)[aa].num].Height);
+ _GP(actsps)[useindx]->Blit(_GP(spriteset)[_G(objs)[aa].num], 0, 0);
}
// Re-use the bitmap if it's the same size
@@ -1451,9 +1424,6 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
return 0;
}
-
-
-
// This is only called from draw_screen_background, but it's separated
// to help with profiling the program
void prepare_objects_for_drawing() {
@@ -1644,7 +1614,8 @@ void prepare_characters_for_drawing() {
}
_G(our_eip) = 3330;
- int isMirrored = 0, specialpic = sppic;
+ bool isMirrored = false;
+ int specialpic = sppic;
bool usingCachedImage = false;
coldept = _GP(spriteset)[sppic]->GetColorDepth();
@@ -1652,7 +1623,7 @@ void prepare_characters_for_drawing() {
// adjust the sppic if mirrored, so it doesn't accidentally
// cache the mirrored frame as the real one
if (_GP(views)[chin->view].loops[chin->loop].frames[chin->frame].flags & VFLG_FLIPSPRITE) {
- isMirrored = 1;
+ isMirrored = true;
specialpic = -sppic;
}
@@ -1686,6 +1657,9 @@ void prepare_characters_for_drawing() {
_G(our_eip) = 3332;
+ const int src_sprwidth = _GP(game).SpriteInfos[sppic].Width;
+ const int src_sprheight = _GP(game).SpriteInfos[sppic].Height;
+
if (zoom_level != 100) {
// it needs to be stretched, so calculate the new dimensions
@@ -1697,8 +1671,8 @@ void prepare_characters_for_drawing() {
// TODO: store width and height always, that's much simplier to use for reference!
_G(charextra)[aa].width = 0;
_G(charextra)[aa].height = 0;
- newwidth = _GP(game).SpriteInfos[sppic].Width;
- newheight = _GP(game).SpriteInfos[sppic].Height;
+ newwidth = src_sprwidth;
+ newheight = src_sprheight;
}
_G(our_eip) = 3336;
@@ -1723,14 +1697,13 @@ void prepare_characters_for_drawing() {
// create the base sprite in _GP(actsps)[useindx], which will
// be scaled and/or flipped, as appropriate
- int actspsUsed = 0;
+ bool actspsUsed = false;
if (!_G(gfxDriver)->HasAcceleratedTransform()) {
- actspsUsed = scale_and_flip_sprite(
- useindx, coldept, zoom_level, sppic,
- newwidth, newheight, isMirrored);
- } else {
- // ensure actsps exists
- _GP(actsps)[useindx] = recycle_bitmap(_GP(actsps)[useindx], coldept, _GP(game).SpriteInfos[sppic].Width, _GP(game).SpriteInfos[sppic].Height);
+ actspsUsed = scale_and_flip_sprite(useindx, sppic, newwidth, newheight, isMirrored);
+ }
+ if (!actspsUsed) {
+ // ensure actsps exists // CHECKME: why do we need this in hardware accel mode too?
+ _GP(actsps)[useindx] = recycle_bitmap(_GP(actsps)[useindx], coldept, src_sprwidth, src_sprheight);
}
_G(our_eip) = 335;
@@ -1748,7 +1721,7 @@ void prepare_characters_for_drawing() {
comeFrom);
} else if (!actspsUsed) {
// no scaling, flipping or tinting was done, so just blit it normally
- _GP(actsps)[useindx]->Blit(_GP(spriteset)[sppic], 0, 0, 0, 0, _GP(actsps)[useindx]->GetWidth(), _GP(actsps)[useindx]->GetHeight());
+ _GP(actsps)[useindx]->Blit(_GP(spriteset)[sppic], 0, 0);
}
// update the character cache with the new image
@@ -1785,7 +1758,7 @@ void prepare_characters_for_drawing() {
if (_G(gfxDriver)->HasAcceleratedTransform()) {
_GP(actspsbmp)[useindx]->SetStretch(newwidth, newheight);
- _GP(actspsbmp)[useindx]->SetFlippedLeftRight(isMirrored != 0);
+ _GP(actspsbmp)[useindx]->SetFlippedLeftRight(isMirrored);
_GP(actspsbmp)[useindx]->SetTint(tint_red, tint_green, tint_blue, (tint_amount * 256) / 100);
if (tint_amount != 0) {
@@ -1799,7 +1772,6 @@ void prepare_characters_for_drawing() {
_GP(actspsbmp)[useindx]->SetLightLevel((light_level * 25) / 10 + 256);
else
_GP(actspsbmp)[useindx]->SetLightLevel(0);
-
}
_G(our_eip) = 337;
diff --git a/engines/ags/engine/ac/draw.h b/engines/ags/engine/ac/draw.h
index 5008276d141..9250f0079a2 100644
--- a/engines/ags/engine/ac/draw.h
+++ b/engines/ags/engine/ac/draw.h
@@ -26,12 +26,12 @@
#include "ags/shared/core/types.h"
#include "ags/shared/ac/common_defines.h"
#include "ags/shared/gfx/gfx_def.h"
+#include "ags/shared/gfx/bitmap.h"
#include "ags/shared/game/room_struct.h"
namespace AGS3 {
namespace AGS {
namespace Shared {
-class Bitmap;
typedef std::shared_ptr<Shared::Bitmap> PBitmap;
} // namespace Shared
@@ -142,6 +142,11 @@ void draw_gui_sprite_v330(Shared::Bitmap *ds, int pic, int x, int y, bool use_al
void draw_gui_sprite(Shared::Bitmap *ds, bool use_alpha, int xpos, int ypos,
Shared::Bitmap *image, bool src_has_alpha, Shared::BlendMode blend_mode = Shared::kBlendMode_Alpha, int alpha = 0xFF);
+// Generates a transformed sprite, using src image and parameters;
+// * if transformation is necessary - writes into dst and returns dst;
+// * if no transformation is necessary - simply returns src;
+Shared::Bitmap *transform_sprite(Shared::Bitmap *src, bool src_has_alpha, Shared::Bitmap *&dst,
+ const Size dst_sz, Shared::BitmapFlip flip = Shared::kBitmap_NoFlip);
// Render game on screen
void render_to_screen();
// Callbacks for the graphics driver
diff --git a/engines/ags/engine/ac/object_cache.h b/engines/ags/engine/ac/object_cache.h
index 34a480be200..c0c09cc845d 100644
--- a/engines/ags/engine/ac/object_cache.h
+++ b/engines/ags/engine/ac/object_cache.h
@@ -19,8 +19,8 @@
*
*/
-#ifndef AGS_ENGINE_AC_OBJECTCACHE_H
-#define AGS_ENGINE_AC_OBJECTCACHE_H
+#ifndef AGS_ENGINE_AC_OBJECT_CACHE_H
+#define AGS_ENGINE_AC_OBJECT_CACHE_H
namespace AGS3 {
@@ -30,9 +30,11 @@ struct ObjectCache {
int sppic = 0;
short tintredwas = 0, tintgrnwas = 0, tintbluwas = 0;
short tintamntwas = 0, tintlightwas = 0;
- short lightlevwas = 0, mirroredWas = 0, zoomWas = 0;
+ short lightlevwas = 0, zoomWas = 0;
+ bool mirroredWas = false;
+
// The following are used to determine if the character has moved
- int xwas, ywas;
+ int xwas = 0, ywas = 0;
};
} // namespace AGS3
Commit: 8ac8c037c9c564548a70e3d16743792e1cb6e03b
https://github.com/scummvm/scummvm/commit/8ac8c037c9c564548a70e3d16743792e1cb6e03b
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:25-07:00
Commit Message:
AGS: Use transform_sprite() with overlays for consistency
>From upstream f0a1c70836d10330f16723eb304821211b1f1bdf
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 be982afc28a..fb328370fd3 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1986,12 +1986,9 @@ void draw_gui_and_overlays() {
if (over.transparency == 255) continue; // skip fully transparent
if (_GP(screenover)[i].HasChanged()) {
// For software mode - prepare transformed bitmap if necessary
- Bitmap *use_bmp = over.pic;
- if (is_software_mode && (over.pic->GetSize() != Size(over.scaleWidth, over.scaleHeight))) {
- _GP(overlaybmp)[i] = recycle_bitmap(_GP(overlaybmp)[i], over.pic->GetColorDepth(), over.scaleWidth, over.scaleHeight);
- _GP(overlaybmp)[i]->StretchBlt(over.pic, RectWH(_GP(overlaybmp)[i]->GetSize()));
- use_bmp = _GP(overlaybmp)[i];
- }
+ Bitmap *use_bmp = is_software_mode ?
+ transform_sprite(over.pic, over.hasAlphaChannel, overlaybmp[i], Size(over.scaleWidth, over.scaleHeight)) :
+ over.pic;
over.ddb = recycle_ddb_bitmap(over.ddb, use_bmp, over.hasAlphaChannel);
over.ClearChanged();
}
Commit: d9da1e3759286fd8eaf919bc9d7880bfeda52ae0
https://github.com/scummvm/scummvm/commit/d9da1e3759286fd8eaf919bc9d7880bfeda52ae0
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:25-07:00
Commit Message:
AGS: Don't try rendering gui controls with zero size
>From upstream 84179aecc419cc8feb56b947bb7519e69062fe70
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/shared/gui/gui_main.cpp
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index fb328370fd3..f93539ef0d9 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -1945,6 +1945,7 @@ void draw_gui_controls(GUIMain &gui) {
for (int i = 0; i < gui.GetControlCount(); ++i, ++draw_index) {
GUIObject *obj = gui.GetControl(i);
if (!obj->IsVisible() ||
+ (obj->Width <= 0 || obj->Height <= 0) ||
(!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
continue;
if (!obj->HasChanged())
@@ -1987,7 +1988,7 @@ void draw_gui_and_overlays() {
if (_GP(screenover)[i].HasChanged()) {
// For software mode - prepare transformed bitmap if necessary
Bitmap *use_bmp = is_software_mode ?
- transform_sprite(over.pic, over.hasAlphaChannel, overlaybmp[i], Size(over.scaleWidth, over.scaleHeight)) :
+ transform_sprite(over.pic, over.hasAlphaChannel, _GP(overlaybmp)[i], Size(over.scaleWidth, over.scaleHeight)) :
over.pic;
over.ddb = recycle_ddb_bitmap(over.ddb, use_bmp, over.hasAlphaChannel);
over.ClearChanged();
@@ -2109,6 +2110,7 @@ void draw_gui_and_overlays() {
for (const auto &obj_id : _GP(guis)[s.id].GetControlsDrawOrder()) {
GUIObject *obj = _GP(guis)[s.id].GetControl(obj_id);
if (!obj->IsVisible() ||
+ (obj->Width <= 0 || obj->Height <= 0) ||
(!obj->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout)))
continue;
auto *obj_ddb = _GP(guiobjddb)[draw_index + obj_id];
diff --git a/engines/ags/shared/gui/gui_main.cpp b/engines/ags/shared/gui/gui_main.cpp
index 73d401f497f..f1507ac601a 100644
--- a/engines/ags/shared/gui/gui_main.cpp
+++ b/engines/ags/shared/gui/gui_main.cpp
@@ -267,9 +267,9 @@ void GUIMain::DrawWithControls(Bitmap *ds) {
GUIObject *objToDraw = _controls[_ctrlDrawOrder[ctrl_index]];
- if (!objToDraw->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
+ if (!objToDraw->IsVisible() || (objToDraw->Width <= 0 || objToDraw->Height <= 0))
continue;
- if (!objToDraw->IsVisible())
+ if (!objToDraw->IsEnabled() && (GUI::Options.DisabledStyle == kGuiDis_Blackout))
continue;
// Depending on draw properties - draw directly on the gui surface, or use a buffer
Commit: 3be37608f04e20d67b704751b6b455f0d6815ff2
https://github.com/scummvm/scummvm/commit/3be37608f04e20d67b704751b6b455f0d6815ff2
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:25-07:00
Commit Message:
AGS: Fixed potential division by zero in GUISlider
>From upstream 36d21686e4a815a22b99e4fbceff11852241a25b
Changed paths:
engines/ags/shared/gui/gui_slider.cpp
diff --git a/engines/ags/shared/gui/gui_slider.cpp b/engines/ags/shared/gui/gui_slider.cpp
index 3daac0cc33d..3456fc8629a 100644
--- a/engines/ags/shared/gui/gui_slider.cpp
+++ b/engines/ags/shared/gui/gui_slider.cpp
@@ -136,7 +136,7 @@ void GUISlider::UpdateMetrics() {
_cachedBar = bar;
_cachedHandle = handle;
- _handleRange = handle_range;
+ _handleRange = std::max(1, handle_range);
}
void GUISlider::Draw(Bitmap *ds, int x, int y) {
@@ -208,6 +208,7 @@ void GUISlider::OnMouseMove(int x, int y) {
return;
int value;
+ assert(_handleRange > 0);
if (IsHorizontal())
value = (int)(((float)((x - X) - 2) * (float)(MaxValue - MinValue)) / (float)_handleRange) + MinValue;
else
Commit: 4cd0ca9a274e03d489126b0341a094755602f688
https://github.com/scummvm/scummvm/commit/4cd0ca9a274e03d489126b0341a094755602f688
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:25-07:00
Commit Message:
AGS: Removed DrawAsSeparateCharSprite walk-behind method
>From upstream e075376fd42c95ea2399809b7cc492cbc116b0db
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/draw.h
engines/ags/engine/ac/global_walk_behind.cpp
engines/ags/engine/ac/room.cpp
engines/ags/engine/ac/walk_behind.h
engines/ags/globals.cpp
engines/ags/globals.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index f93539ef0d9..34e22352cb3 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -366,9 +366,6 @@ void init_game_drawdata() {
size_t actsps_num = _GP(game).numcharacters + MAX_ROOM_OBJECTS;
_GP(actsps).resize(actsps_num);
_GP(actspsbmp).resize(actsps_num);
- _GP(actspswb).resize(actsps_num);
- _GP(actspswbbmp).resize(actsps_num);
- _GP(actspswbcache).resize(actsps_num);
_GP(guibg).resize(_GP(game).numgui);
_GP(guibgddb).resize(_GP(game).numgui);
@@ -389,9 +386,6 @@ void dispose_game_drawdata() {
_GP(actsps).clear();
_GP(actspsbmp).clear();
- _GP(actspswb).clear();
- _GP(actspswbbmp).clear();
- _GP(actspswbcache).clear();
_GP(guibg).clear();
_GP(guibgddb).clear();
@@ -431,13 +425,6 @@ void clear_drawobj_cache() {
if (_GP(actspsbmp)[i] != nullptr)
_G(gfxDriver)->DestroyDDB(_GP(actspsbmp)[i]);
_GP(actspsbmp)[i] = nullptr;
-
- delete _GP(actspswb)[i];
- _GP(actspswb)[i] = nullptr;
- if (_GP(actspswbbmp)[i] != nullptr)
- _G(gfxDriver)->DestroyDDB(_GP(actspswbbmp)[i]);
- _GP(actspswbbmp)[i] = nullptr;
- _GP(actspswbcache)[i].valid = 0;
}
// cleanup GUI backgrounds
@@ -841,14 +828,10 @@ void put_sprite_list_on_screen(bool in_room);
//
//------------------------------------------------------------------------
-void invalidate_cached_walkbehinds() {
- memset(&_GP(actspswbcache)[0], 0, sizeof(CachedActSpsData) * _GP(actspswbcache).size());
-}
-
// sort_out_walk_behinds: modifies the supplied sprite by overwriting parts
// of it with transparent pixels where there are walk-behind areas
// Returns whether any pixels were updated
-int sort_out_walk_behinds(Bitmap *sprit, int xx, int yy, int basel, Bitmap *copyPixelsFrom = nullptr, Bitmap *checkPixelsFrom = nullptr, int zoom = 100) {
+int sort_out_walk_behinds(Bitmap *sprit, int xx, int yy, int basel, int zoom = 100) {
if (_G(noWalkBehindsAtAll))
return 0;
@@ -862,15 +845,12 @@ int sort_out_walk_behinds(Bitmap *sprit, int xx, int yy, int basel, Bitmap *copy
int spcoldep = sprit->GetColorDepth();
int screenhit = _GP(thisroom).WalkBehindMask->GetHeight();
short *shptr, *shptr2;
- int *loptr, *loptr2;
+ int *loptr;
int pixelsChanged = 0;
int ee = 0;
if (xx < 0)
ee = 0 - xx;
- if ((checkPixelsFrom != nullptr) && (checkPixelsFrom->GetColorDepth() != spcoldep))
- quit("sprite colour depth does not match background colour depth");
-
for (; ee < sprit->GetWidth(); ee++) {
if (ee + xx >= _GP(thisroom).WalkBehindMask->GetWidth())
break;
@@ -898,7 +878,6 @@ int sort_out_walk_behinds(Bitmap *sprit, int xx, int yy, int basel, Bitmap *copy
rr = 0;
for (; rr < toheight; rr++) {
-
// we're ok with _getpixel because we've checked the screen edges
//tmm = _getpixel(_GP(thisroom).WalkBehindMask,ee+xx,rr+yy);
// actually, _getpixel is well inefficient, do it ourselves
@@ -907,82 +886,25 @@ int sort_out_walk_behinds(Bitmap *sprit, int xx, int yy, int basel, Bitmap *copy
if (tmm < 1) continue;
if (_G(croom)->walkbehind_base[tmm] <= basel) continue;
- if (copyPixelsFrom != nullptr) {
- if (spcoldep <= 8) {
- if (checkPixelsFrom->GetScanLine((rr * 100) / zoom)[(ee * 100) / zoom] != maskcol) {
- sprit->GetScanLineForWriting(rr)[ee] = copyPixelsFrom->GetScanLine(rr + yy)[ee + xx];
- pixelsChanged = 1;
- }
- } else if (spcoldep <= 16) {
- shptr = (short *)&sprit->GetScanLine(rr)[0];
- shptr2 = (short *)&checkPixelsFrom->GetScanLine((rr * 100) / zoom)[0];
- if (shptr2[(ee * 100) / zoom] != maskcol) {
- shptr[ee] = ((short *)(©PixelsFrom->GetScanLine(rr + yy)[0]))[ee + xx];
- pixelsChanged = 1;
- }
- } else if (spcoldep == 24) {
- char *chptr = (char *)&sprit->GetScanLine(rr)[0];
- char *chptr2 = (char *)&checkPixelsFrom->GetScanLine((rr * 100) / zoom)[0];
- if (memcmp(&chptr2[((ee * 100) / zoom) * 3], &maskcol, 3) != 0) {
- memcpy(&chptr[ee * 3], ©PixelsFrom->GetScanLine(rr + yy)[(ee + xx) * 3], 3);
- pixelsChanged = 1;
- }
- } else if (spcoldep <= 32) {
- loptr = (int *)&sprit->GetScanLine(rr)[0];
- loptr2 = (int *)&checkPixelsFrom->GetScanLine((rr * 100) / zoom)[0];
- if (loptr2[(ee * 100) / zoom] != maskcol) {
- loptr[ee] = ((int *)(©PixelsFrom->GetScanLine(rr + yy)[0]))[ee + xx];
- pixelsChanged = 1;
- }
- }
- } else {
- pixelsChanged = 1;
- if (spcoldep <= 8)
- sprit->GetScanLineForWriting(rr)[ee] = maskcol;
- else if (spcoldep <= 16) {
- shptr = (short *)&sprit->GetScanLine(rr)[0];
- shptr[ee] = maskcol;
- } else if (spcoldep == 24) {
- char *chptr = (char *)&sprit->GetScanLine(rr)[0];
- memcpy(&chptr[ee * 3], &maskcol, 3);
- } else if (spcoldep <= 32) {
- loptr = (int *)&sprit->GetScanLine(rr)[0];
- loptr[ee] = maskcol;
- } else
- quit("!Sprite colour depth >32 ??");
- }
+ pixelsChanged = 1;
+ if (spcoldep <= 8)
+ sprit->GetScanLineForWriting(rr)[ee] = maskcol;
+ else if (spcoldep <= 16) {
+ shptr = (short *)&sprit->GetScanLine(rr)[0];
+ shptr[ee] = maskcol;
+ } else if (spcoldep == 24) {
+ char *chptr = (char *)&sprit->GetScanLine(rr)[0];
+ memcpy(&chptr[ee * 3], &maskcol, 3);
+ } else if (spcoldep <= 32) {
+ loptr = (int *)&sprit->GetScanLine(rr)[0];
+ loptr[ee] = maskcol;
+ } else
+ quit("!Sprite colour depth >32 ??");
}
}
return pixelsChanged;
}
-void sort_out_char_sprite_walk_behind(int actspsIndex, int xx, int yy, int basel, int zoom, int width, int height) {
- if (_G(noWalkBehindsAtAll))
- return;
-
- if ((!_GP(actspswbcache)[actspsIndex].valid) ||
- (_GP(actspswbcache)[actspsIndex].xWas != xx) ||
- (_GP(actspswbcache)[actspsIndex].yWas != yy) ||
- (_GP(actspswbcache)[actspsIndex].baselineWas != basel)) {
- _GP(actspswb)[actspsIndex] = recycle_bitmap(_GP(actspswb)[actspsIndex], _GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic->GetColorDepth(), width, height, true);
- Bitmap *wbSprite = _GP(actspswb)[actspsIndex];
-
- _GP(actspswbcache)[actspsIndex].isWalkBehindHere = sort_out_walk_behinds(wbSprite, xx, yy, basel, _GP(thisroom).BgFrames[_GP(play).bg_frame].Graphic.get(), _GP(actsps)[actspsIndex], zoom);
- _GP(actspswbcache)[actspsIndex].xWas = xx;
- _GP(actspswbcache)[actspsIndex].yWas = yy;
- _GP(actspswbcache)[actspsIndex].baselineWas = basel;
- _GP(actspswbcache)[actspsIndex].valid = 1;
-
- if (_GP(actspswbcache)[actspsIndex].isWalkBehindHere) {
- _GP(actspswbbmp)[actspsIndex] = recycle_ddb_bitmap(_GP(actspswbbmp)[actspsIndex], _GP(actspswb)[actspsIndex], false);
- }
- }
-
- if (_GP(actspswbcache)[actspsIndex].isWalkBehindHere) {
- add_to_sprite_list(_GP(actspswbbmp)[actspsIndex], xx, yy, basel, true);
- }
-}
-
void repair_alpha_channel(Bitmap *dest, Bitmap *bgpic) {
// Repair the alpha channel, because sprites may have been drawn
// over it by the buttons, etc
@@ -1452,8 +1374,6 @@ void prepare_objects_for_drawing() {
if (_G(walkBehindMethod) == DrawAsSeparateSprite) {
usebasel += _GP(thisroom).Height;
}
- } else if (_G(walkBehindMethod) == DrawAsSeparateCharSprite) {
- sort_out_char_sprite_walk_behind(useindx, atxp, atyp, usebasel, _G(objs)[aa].zoom, _G(objs)[aa].last_width, _G(objs)[aa].last_height);
} else if ((!actspsIntact) && (_G(walkBehindMethod) == DrawOverCharSprite)) {
sort_out_walk_behinds(_GP(actsps)[useindx], atxp, atyp, usebasel);
}
@@ -1744,8 +1664,6 @@ void prepare_characters_for_drawing() {
if (_G(walkBehindMethod) == DrawAsSeparateSprite) {
usebasel += _GP(thisroom).Height;
}
- } else if (_G(walkBehindMethod) == DrawAsSeparateCharSprite) {
- sort_out_char_sprite_walk_behind(useindx, bgX, bgY, usebasel, _G(charextra)[aa].zoom, newwidth, newheight);
} else if (_G(walkBehindMethod) == DrawOverCharSprite) {
sort_out_walk_behinds(_GP(actsps)[useindx], bgX, bgY, usebasel);
}
diff --git a/engines/ags/engine/ac/draw.h b/engines/ags/engine/ac/draw.h
index 9250f0079a2..fb1648a841b 100644
--- a/engines/ags/engine/ac/draw.h
+++ b/engines/ags/engine/ac/draw.h
@@ -44,13 +44,6 @@ using namespace AGS; // FIXME later
#define IS_ANTIALIAS_SPRITES _GP(usetup).enable_antialiasing && (_GP(play).disable_antialiasing == 0)
-struct CachedActSpsData {
- int xWas, yWas;
- int baselineWas;
- int isWalkBehindHere;
- int valid;
-};
-
/**
* Buffer and info flags for viewport/camera pairs rendering in software mode
*/
@@ -112,7 +105,6 @@ void invalidate_camera_frame(int index);
void invalidate_rect(int x1, int y1, int x2, int y2, bool in_room);
void mark_current_background_dirty();
-void invalidate_cached_walkbehinds();
// Avoid freeing and reallocating the memory if possible
Shared::Bitmap *recycle_bitmap(Shared::Bitmap *bimp, int coldep, int wid, int hit, bool make_transparent = false);
diff --git a/engines/ags/engine/ac/global_walk_behind.cpp b/engines/ags/engine/ac/global_walk_behind.cpp
index b8f4cec71d4..1fe7ce1e307 100644
--- a/engines/ags/engine/ac/global_walk_behind.cpp
+++ b/engines/ags/engine/ac/global_walk_behind.cpp
@@ -36,7 +36,6 @@ void SetWalkBehindBase(int wa, int bl) {
if (bl != _G(croom)->walkbehind_base[wa]) {
_G(walk_behind_baselines_changed) = 1;
- invalidate_cached_walkbehinds();
_G(croom)->walkbehind_base[wa] = bl;
debug_script_log("Walk-behind %d baseline changed to %d", wa, bl);
}
diff --git a/engines/ags/engine/ac/room.cpp b/engines/ags/engine/ac/room.cpp
index 9854d5f22eb..301764865cd 100644
--- a/engines/ags/engine/ac/room.cpp
+++ b/engines/ags/engine/ac/room.cpp
@@ -1012,10 +1012,8 @@ void compile_room_script() {
}
void on_background_frame_change() {
-
invalidate_screen();
mark_current_background_dirty();
- invalidate_cached_walkbehinds();
// get the new frame's palette
memcpy(_G(palette), _GP(thisroom).BgFrames[_GP(play).bg_frame].Palette, sizeof(RGB) * 256);
diff --git a/engines/ags/engine/ac/walk_behind.h b/engines/ags/engine/ac/walk_behind.h
index acffb76c66e..a259a08534d 100644
--- a/engines/ags/engine/ac/walk_behind.h
+++ b/engines/ags/engine/ac/walk_behind.h
@@ -25,19 +25,15 @@
namespace AGS3 {
// A method of rendering walkbehinds on screen:
-// DrawAsSeparateSprite - draws whole walkbehind as a sprite; this
-// method is most simple and is optimal for 3D renderers.
-// DrawOverCharSprite and DrawAsSeparateCharSprite - are alternatives
-// optimized for software render.
+// DrawAsSeparateSprite - draws whole walkbehind as a sprite;
+// this method is most simple and is optimal for 3D renderers.
// DrawOverCharSprite - turns parts of the character and object sprites
// transparent when they are covered by walkbehind (walkbehind itself
-// is not drawn separately in this case).
-// DrawAsSeparateCharSprite - draws smaller *parts* of walkbehind as
-// separate sprites, only ones that cover characters or objects.
+// is not drawn separately in this case);
+// this method is optimized for software render.
enum WalkBehindMethodEnum {
DrawOverCharSprite,
- DrawAsSeparateSprite,
- DrawAsSeparateCharSprite
+ DrawAsSeparateSprite
};
void update_walk_behind_images();
diff --git a/engines/ags/globals.cpp b/engines/ags/globals.cpp
index d62a174ab24..4f15ea49e56 100644
--- a/engines/ags/globals.cpp
+++ b/engines/ags/globals.cpp
@@ -175,9 +175,6 @@ Globals::Globals() {
_actsps = new std::vector<Shared::Bitmap *>();
_actspsbmp = new std::vector<Engine::IDriverDependantBitmap *>();
- _actspswb = new std::vector<Shared::Bitmap *>();
- _actspswbbmp = new std::vector<Engine::IDriverDependantBitmap *>();
- _actspswbcache = new std::vector<CachedActSpsData>();
_guibg = new std::vector<Shared::Bitmap *>();
_guibgddb = new std::vector<Engine::IDriverDependantBitmap *>();
_debugRoomMaskBmp = new std::unique_ptr<Shared::Bitmap>();
@@ -433,9 +430,6 @@ Globals::~Globals() {
delete _thingsToDrawList;
delete _actsps;
delete _actspsbmp;
- delete _actspswb;
- delete _actspswbbmp;
- delete _actspswbcache;
delete _guibg;
delete _guibgddb;
delete _debugRoomMaskBmp;
diff --git a/engines/ags/globals.h b/engines/ags/globals.h
index 609a5542226..a34069c72dd 100644
--- a/engines/ags/globals.h
+++ b/engines/ags/globals.h
@@ -581,9 +581,6 @@ public:
std::vector<Shared::Bitmap *> *_actsps;
std::vector<Engine::IDriverDependantBitmap *> *_actspsbmp;
// temporary cache of walk-behind for this actsps image
- std::vector<Shared::Bitmap *> *_actspswb;
- std::vector<Engine::IDriverDependantBitmap *> *_actspswbbmp;
- std::vector<CachedActSpsData> *_actspswbcache;
// GUI surfaces
std::vector<Shared::Bitmap *> *_guibg;
std::vector<Engine::IDriverDependantBitmap *> *_guibgddb;
Commit: ebe2096af75e02e50b95ea45a57d864eb13eeef8
https://github.com/scummvm/scummvm/commit/ebe2096af75e02e50b95ea45a57d864eb13eeef8
Author: Paul Gilbert (dreammaster at scummvm.org)
Date: 2022-05-01T17:23:26-07:00
Commit Message:
AGS: Call unload_game_file() in quit()
>From upstream 1118be9d3f09037b995554d7aad47a400a76fafc
Changed paths:
engines/ags/engine/ac/game.cpp
engines/ags/engine/main/quit.cpp
diff --git a/engines/ags/engine/ac/game.cpp b/engines/ags/engine/ac/game.cpp
index f169adbe5ee..25e1b264d15 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -364,18 +364,16 @@ void unload_game_file() {
_GP(characterScriptObjNames).clear();
free(_G(charextra));
+ _G(charextra) = nullptr;
free(_G(mls));
+ _G(mls) = nullptr;
dispose_game_drawdata();
- if ((_G(gameinst) != nullptr) && (_G(gameinst)->pc != 0)) {
- quit("Error: unload_game called while script still running");
- } else {
- delete _G(gameinstFork);
- delete _G(gameinst);
- _G(gameinstFork) = nullptr;
- _G(gameinst) = nullptr;
- }
+ delete _G(gameinstFork);
+ delete _G(gameinst);
+ _G(gameinstFork) = nullptr;
+ _G(gameinst) = nullptr;
_GP(gamescript).reset();
diff --git a/engines/ags/engine/main/quit.cpp b/engines/ags/engine/main/quit.cpp
index 3d61ba31d62..23de13a9473 100644
--- a/engines/ags/engine/main/quit.cpp
+++ b/engines/ags/engine/main/quit.cpp
@@ -25,6 +25,7 @@
#include "ags/shared/core/platform.h"
#include "ags/engine/ac/cd_audio.h"
+#include "ags/engine/ac/game.h"
#include "ags/engine/ac/game_setup.h"
#include "ags/shared/ac/game_setup_struct.h"
#include "ags/engine/ac/game_state.h"
@@ -148,7 +149,7 @@ void quit_release_data() {
resetRoomStatuses();
_GP(thisroom).Free();
_GP(play).Free();
- _GP(AssetMgr).reset();
+ unload_game_file();
}
void quit_delete_temp_files() {
@@ -224,20 +225,16 @@ void quit_free() {
_GP(spriteset).Reset();
- _G(our_eip) = 9907;
-
- close_translation();
-
_G(our_eip) = 9908;
shutdown_pathfinder();
+ quit_release_data();
+
engine_shutdown_gfxmode();
quit_message_on_exit(quitmsg, alertis, qreason);
- quit_release_data();
-
_G(platform)->PreBackendExit();
// release backed library
More information about the Scummvm-git-logs
mailing list