[Scummvm-git-logs] scummvm master -> 02085d54819aaae3c2f9a7f1148b1814d162b5c6
criezy
noreply at scummvm.org
Sun Jun 12 23:30:57 UTC 2022
This automated email contains information about 7 new commits which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
29ee2d2ab8 AGS: Separated texture data from DDB objects with render settings
487a58b3a8 AGS: Implements short-term texture cache in graphic renderers
7382a1a551 AGS: Game objects use texture cache when possible
aecb62429d AGS: Update shared texture when dynamic sprite changes
370e939ad7 AGS: Fixes for MemoryStream: proper seek support for writing mode
e26adb919e AGS: Moved global DlgOpt into show_dialog_options() function
02085d5481 AGS: Refactored do_conversation()
Commit: 29ee2d2ab8711c3dac94340b9c7e02d10936901d
https://github.com/scummvm/scummvm/commit/29ee2d2ab8711c3dac94340b9c7e02d10936901d
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Separated texture data from DDB objects with render settings
This allows to have multiple DDBs sharing same texture data.
>From upstream fbcb62c507fb15ffc288d5ebdc1f0d664e66ecb8
Changed paths:
engines/ags/engine/gfx/ali_3d_scummvm.h
engines/ags/engine/gfx/ddb.h
engines/ags/engine/gfx/gfx_driver_base.h
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.h b/engines/ags/engine/gfx/ali_3d_scummvm.h
index 423242e62a7..e882433dcd4 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.h
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.h
@@ -107,13 +107,7 @@ public:
return _stretchToHeight;
}
- void Dispose() {
- // do we want to free the bitmap?
- }
-
- ~ALSoftwareBitmap() override {
- Dispose();
- }
+ ~ALSoftwareBitmap() override = default;
};
diff --git a/engines/ags/engine/gfx/ddb.h b/engines/ags/engine/gfx/ddb.h
index 804e73219fc..ac300df24db 100644
--- a/engines/ags/engine/gfx/ddb.h
+++ b/engines/ags/engine/gfx/ddb.h
@@ -21,12 +21,12 @@
//=============================================================================
//
-// Driver-dependant bitmap interface
+// Driver-dependant bitmap interface.
//
-// TODO: split into texture object that has only tex data
-// and object describing a drawing operation, with ref to texture and
-// drawing parameters (modes, shaders, etc).
-// Then we will also be able to share one texture among multiple game entities.
+// This interface describes an individual sprite object. The actual texture
+// data (pixel data) may be shared among multiple DDBs, while DDB define
+// additional settings telling how to present the texture: transform, colorize,
+// and so on.
//=============================================================================
#ifndef AGS_ENGINE_GFX_DDB_H
diff --git a/engines/ags/engine/gfx/gfx_driver_base.h b/engines/ags/engine/gfx/gfx_driver_base.h
index 35b62a657a2..60ba9069070 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.h
+++ b/engines/ags/engine/gfx/gfx_driver_base.h
@@ -28,6 +28,7 @@
#ifndef AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
#define AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
+#include "ags/lib/std/memory.h"
#include "ags/lib/std/vector.h"
#include "ags/engine/gfx/ddb.h"
#include "ags/engine/gfx/graphics_driver.h"
@@ -169,11 +170,6 @@ protected:
-// Generic TextureTile base
-struct TextureTile {
- int x, y;
- int width, height;
-};
// Parent class for the video memory DDBs
class BaseDDB : public IDriverDependantBitmap {
@@ -198,6 +194,22 @@ protected:
virtual ~BaseDDB() {}
};
+// A base parent for the otherwise opaque texture data object;
+// TextureData refers to the pixel data itself, with no additional
+// properties. It may be shared between multiple sprites if necessary.
+struct TextureData {
+ virtual ~TextureData() = default;
+protected:
+ TextureData() = default;
+};
+
+// Generic TextureTile base
+struct TextureTile {
+ int x = 0, y = 0;
+ int width = 0, height = 0;
+};
+
+
// VideoMemoryGraphicsDriver - is the parent class for the graphic drivers
// which drawing method is based on passing the sprite stack into GPU,
// rather than blitting to flat screen bitmap.
@@ -211,9 +223,20 @@ public:
void SetMemoryBackBuffer(Bitmap *backBuffer) override;
Bitmap *GetStageBackBuffer(bool mark_dirty) override;
bool GetStageMatrixes(RenderMatrixes &rm) override;
+ IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) = 0;
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool hasAlpha, bool opaque = false) override;
protected:
+ // Create texture data with the given parameters
+ virtual TextureData *CreateTextureData(int width, int height, bool opaque) = 0;
+ // Update texture data from the given bitmap
+ virtual void UpdateTextureData(TextureData *txdata, Bitmap *bmp, bool opaque, bool hasAlpha) = 0;
+ // Create DDB using preexisting texture data
+ virtual IDriverDependantBitmap *CreateDDB(std::shared_ptr<TextureData> txdata,
+ int width, int height, int color_depth, bool opaque) = 0;
+ // Retrieve shared texture data object from the given DDB
+ virtual std::shared_ptr<TextureData> GetTextureData(IDriverDependantBitmap *ddb) = 0;
+
// Stage screens are raw bitmap buffers meant to be sent to plugins on demand
// at certain drawing stages. If used at least once these buffers are then
// rendered as additional sprites in their respected order.
Commit: 487a58b3a8b1971bebcec12e16d88ab017efadd2
https://github.com/scummvm/scummvm/commit/487a58b3a8b1971bebcec12e16d88ab017efadd2
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Implements short-term texture cache in graphic renderers
- caches textures while they are in the immediate use;
- this lets to share same texture data among multiple sprites on screen.
- texture entries are identified by an arbitrary uint32 number.
>From upstream 6f3f84e049df2f800aa4b06d221a393d904c2826
Changed paths:
engines/ags/engine/gfx/ali_3d_scummvm.h
engines/ags/engine/gfx/ddb.h
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/gfx/ali_3d_scummvm.h b/engines/ags/engine/gfx/ali_3d_scummvm.h
index e882433dcd4..23f28d00576 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.h
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.h
@@ -59,6 +59,8 @@ enum RendererFlip {
class ALSoftwareBitmap : public BaseDDB {
public:
+ uint32_t GetRefID() const override { return UINT32_MAX /* not supported */; }
+
int GetAlpha() const override {
return _alpha;
}
@@ -177,6 +179,12 @@ public:
void UpdateDDBFromBitmap(IDriverDependantBitmap *ddb, Bitmap *bitmap, bool hasAlpha) override;
void DestroyDDB(IDriverDependantBitmap *ddb) override;
+ IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id,
+ Bitmap *bitmap, bool hasAlpha, bool opaque) override {
+ // Software renderer does not require a texture cache, because it uses bitmaps directly
+ return CreateDDBFromBitmap(bitmap, hasAlpha, opaque);
+ }
+
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;
diff --git a/engines/ags/engine/gfx/ddb.h b/engines/ags/engine/gfx/ddb.h
index ac300df24db..c6f1f6865d8 100644
--- a/engines/ags/engine/gfx/ddb.h
+++ b/engines/ags/engine/gfx/ddb.h
@@ -38,6 +38,9 @@ namespace Engine {
class IDriverDependantBitmap {
public:
+ // Get an arbitrary sprite ID, returns UINT32_MAX if does not have one
+ virtual uint32_t GetRefID() const = 0;
+
virtual int GetAlpha() const = 0;
virtual void SetAlpha(int alpha) = 0; // 0-255
virtual void SetFlippedLeftRight(bool isFlipped) = 0;
diff --git a/engines/ags/engine/gfx/gfx_driver_base.cpp b/engines/ags/engine/gfx/gfx_driver_base.cpp
index a74ba4e15c8..601d5e8b46f 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.cpp
+++ b/engines/ags/engine/gfx/gfx_driver_base.cpp
@@ -173,6 +173,35 @@ IDriverDependantBitmap *VideoMemoryGraphicsDriver::CreateDDBFromBitmap(Bitmap *b
return ddb;
}
+IDriverDependantBitmap *VideoMemoryGraphicsDriver::GetSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool hasAlpha, bool opaque) {
+ const auto found = _txRefs.find(sprite_id);
+ if (found != _txRefs.end()) {
+ const auto &item = found->_value;
+ if (!item.Data.expired())
+ return CreateDDB(item.Data.lock(), item.Res.Width, item.Res.Height, item.Res.ColorDepth, opaque);
+ }
+
+ // Create and add a new element
+ std::shared_ptr<TextureData> txdata(CreateTextureData(bitmap->GetWidth(), bitmap->GetHeight(), opaque));
+ txdata->ID = sprite_id;
+ UpdateTextureData(txdata.get(), bitmap, opaque, hasAlpha);
+ // only add into the map when has valid sprite ID
+ if (sprite_id != UINT32_MAX) {
+ _txRefs[sprite_id] = TextureCacheItem(txdata,
+ GraphicResolution(bitmap->GetWidth(), bitmap->GetHeight(), bitmap->GetColorDepth()));
+ }
+ return CreateDDB(txdata, bitmap->GetWidth(), bitmap->GetHeight(), bitmap->GetColorDepth(), opaque);
+}
+
+ void VideoMemoryGraphicsDriver::DestroyDDB(IDriverDependantBitmap* ddb) {
+ uint32_t sprite_id = ddb->GetRefID();
+ DestroyDDBImpl(ddb);
+ // Remove shared object from ref list if no more active refs left
+ const auto found = _txRefs.find(sprite_id);
+ if (found != _txRefs.end() && found->_value.Data.expired())
+ _txRefs.erase(found);
+}
+
PBitmap VideoMemoryGraphicsDriver::CreateStageScreen(size_t index, const Size &sz) {
if (_stageScreens.size() <= index)
_stageScreens.resize(index + 1);
diff --git a/engines/ags/engine/gfx/gfx_driver_base.h b/engines/ags/engine/gfx/gfx_driver_base.h
index 60ba9069070..14b5842ec6a 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.h
+++ b/engines/ags/engine/gfx/gfx_driver_base.h
@@ -29,6 +29,7 @@
#define AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
#include "ags/lib/std/memory.h"
+#include "engines/ags/lib/std/map.h"
#include "ags/lib/std/vector.h"
#include "ags/engine/gfx/ddb.h"
#include "ags/engine/gfx/graphics_driver.h"
@@ -198,6 +199,7 @@ protected:
// TextureData refers to the pixel data itself, with no additional
// properties. It may be shared between multiple sprites if necessary.
struct TextureData {
+ uint32_t ID = UINT32_MAX;
virtual ~TextureData() = default;
protected:
TextureData() = default;
@@ -223,8 +225,11 @@ public:
void SetMemoryBackBuffer(Bitmap *backBuffer) override;
Bitmap *GetStageBackBuffer(bool mark_dirty) override;
bool GetStageMatrixes(RenderMatrixes &rm) override;
- IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) = 0;
+ IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) override = 0;
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool hasAlpha, bool opaque = false) override;
+ // Get shared texture from cache, or create from bitmap and assign ID
+ IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool hasAlpha, bool opaque) override;
+ void DestroyDDB(IDriverDependantBitmap* ddb) override;
protected:
// Create texture data with the given parameters
@@ -236,6 +241,7 @@ protected:
int width, int height, int color_depth, bool opaque) = 0;
// Retrieve shared texture data object from the given DDB
virtual std::shared_ptr<TextureData> GetTextureData(IDriverDependantBitmap *ddb) = 0;
+ virtual void DestroyDDBImpl(IDriverDependantBitmap* ddb) = 0;
// Stage screens are raw bitmap buffers meant to be sent to plugins on demand
// at certain drawing stages. If used at least once these buffers are then
@@ -293,6 +299,20 @@ private:
};
std::vector<ScreenFx> _fxPool;
size_t _fxIndex; // next free pool item
+
+ // Texture short-term cache:
+ // - caches textures while they are in the immediate use;
+ // - this lets to share same texture data among multiple sprites on screen.
+ // TextureCacheItem stores weak references to the existing texture tiles,
+ // identified by an arbitrary uint32 number.
+ struct TextureCacheItem {
+ GraphicResolution Res;
+ std::weak_ptr<TextureData> Data;
+ TextureCacheItem() = default;
+ TextureCacheItem(std::shared_ptr<TextureData> data, const GraphicResolution &res)
+ : Data(data), Res(res) {}
+ };
+ std::unordered_map<uint32_t, TextureCacheItem> _txRefs;
};
} // namespace Engine
diff --git a/engines/ags/engine/gfx/graphics_driver.h b/engines/ags/engine/gfx/graphics_driver.h
index b893ca31da1..b3d04ea3e6b 100644
--- a/engines/ags/engine/gfx/graphics_driver.h
+++ b/engines/ags/engine/gfx/graphics_driver.h
@@ -139,6 +139,10 @@ public:
virtual void UpdateDDBFromBitmap(IDriverDependantBitmap *bitmapToUpdate, Shared::Bitmap *bitmap, bool hasAlpha) = 0;
virtual void DestroyDDB(IDriverDependantBitmap *bitmap) = 0;
+ // Get shared texture from cache, or create from bitmap and assign ID
+ virtual IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id,
+ Shared::Bitmap *bitmap = nullptr, bool hasAlpha = true, bool opaque = false) = 0;
+
// 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.
Commit: 7382a1a551246f3cb85555de532b08343c2b62a9
https://github.com/scummvm/scummvm/commit/7382a1a551246f3cb85555de532b08343c2b62a9
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Game objects use texture cache when possible
Specify sprite ID for shared textures for: characters, objects, overlays
GUI and GUI objects are more complicated, a they may contain custom
(generated) graphics; using shared textures for them would require a
bigger change in how their sprites are organized when gathering draw
lists for render.
>From upstream b724b43fa7f13ea2e89a3e9213dd76b00e59f9f4
Changed paths:
engines/ags/engine/ac/draw.cpp
engines/ags/engine/ac/draw.h
diff --git a/engines/ags/engine/ac/draw.cpp b/engines/ags/engine/ac/draw.cpp
index 5660172d894..7985020eb4a 100644
--- a/engines/ags/engine/ac/draw.cpp
+++ b/engines/ags/engine/ac/draw.cpp
@@ -766,22 +766,27 @@ void draw_sprite_slot_support_alpha(Bitmap *ds, bool ds_has_alpha, int xpos, int
blend_mode, alpha);
}
-IDriverDependantBitmap *recycle_ddb_bitmap(IDriverDependantBitmap *ddb, Bitmap *source, bool has_alpha, bool opaque) {
- if (ddb) {
- // same colour depth, width and height -> reuse
- if ((ddb->GetColorDepth() == source->GetColorDepth()) &&
- (ddb->GetWidth() == source->GetWidth()) && (ddb->GetHeight() == source->GetHeight())) {
- _G(gfxDriver)->UpdateDDBFromBitmap(ddb, source, has_alpha);
- return ddb;
- }
-
- _G(gfxDriver)->DestroyDDB(ddb);
- }
- return _G(gfxDriver)->CreateDDBFromBitmap(source, has_alpha, opaque);
+Engine::IDriverDependantBitmap* recycle_ddb_sprite(Engine::IDriverDependantBitmap *ddb, int sprite_id, Shared::Bitmap *source, bool has_alpha, bool opaque) {
+ // no ddb, - get or create shared object
+ if (!ddb)
+ return _G(gfxDriver)->GetSharedDDB(sprite_id, source, has_alpha, opaque);
+ // same sprite id, - use existing
+ if ((sprite_id != UINT32_MAX) && (ddb->GetRefID() == sprite_id))
+ return ddb;
+ // not related to a sprite ID, but has same resolution, -
+ // repaint directly from the given bitmap
+ if ((sprite_id == UINT32_MAX) && (ddb->GetColorDepth() == source->GetColorDepth()) &&
+ (ddb->GetWidth() == source->GetWidth()) && (ddb->GetHeight() == source->GetHeight())) {
+ _G(gfxDriver)->UpdateDDBFromBitmap(ddb, source, has_alpha);
+ return ddb;
+ }
+ // have to recreate ddb
+ _G(gfxDriver)->DestroyDDB(ddb);
+ return _G(gfxDriver)->GetSharedDDB(sprite_id, source, has_alpha, opaque);
}
void sync_object_texture(ObjTexture &obj, bool has_alpha = false, bool opaque = false) {
- obj.Ddb = recycle_ddb_bitmap(obj.Ddb, obj.Bmp.get(), has_alpha, opaque);
+ obj.Ddb = recycle_ddb_sprite(obj.Ddb, obj.SpriteID, obj.Bmp.get(), has_alpha, opaque);
}
//------------------------------------------------------------------------
@@ -1211,6 +1216,7 @@ int construct_object_gfx(int aa, int *drawnWidth, int *drawnHeight, bool alwaysU
}
auto &actsp = _GP(actsps)[useindx];
+ actsp.SpriteID = _G(objs)[aa].num; // for texture sharing
if ((hardwareAccelerated) &&
(_G(walkBehindMethod) != DrawOverCharSprite) &&
(_G(objcache)[aa].image != nullptr) &&
@@ -1507,6 +1513,7 @@ void prepare_characters_for_drawing() {
_G(our_eip) = 3331;
auto &actsp = _GP(actsps)[useindx];
+ actsp.SpriteID = sppic; // for texture sharing
// if the character was the same sprite and scaling last time,
// just use the cached image
@@ -2127,7 +2134,7 @@ static void construct_overlays() {
use_bmp = _GP(overlaybmp)[i].get();
}
- over.ddb = recycle_ddb_bitmap(over.ddb, use_bmp, over.HasAlphaChannel());
+ over.ddb = recycle_ddb_sprite(over.ddb, over.GetSpriteNum(), use_bmp, over.HasAlphaChannel());
over.ClearChanged();
}
diff --git a/engines/ags/engine/ac/draw.h b/engines/ags/engine/ac/draw.h
index 6c032b51edb..426602011d6 100644
--- a/engines/ags/engine/ac/draw.h
+++ b/engines/ags/engine/ac/draw.h
@@ -63,6 +63,8 @@ struct RoomCameraDrawData {
// ObjTexture is a helper struct that pairs a raw bitmap with
// a renderer's texture and an optional position
struct ObjTexture {
+ // Sprite ID
+ uint32_t SpriteID = UINT32_MAX;
// Raw bitmap
std::unique_ptr<Shared::Bitmap> Bmp;
// Corresponding texture, created by renderer
@@ -149,7 +151,10 @@ void mark_current_background_dirty();
// 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);
void recycle_bitmap(std::unique_ptr<Shared::Bitmap> &bimp, int coldep, int wid, int hit, bool make_transparent = false);
-Engine::IDriverDependantBitmap *recycle_ddb_bitmap(Engine::IDriverDependantBitmap *ddb, Shared::Bitmap *source, bool has_alpha = false, bool opaque = false);
+Engine::IDriverDependantBitmap* recycle_ddb_sprite(Engine::IDriverDependantBitmap *ddb, int sprite_id, Shared::Bitmap *source, bool has_alpha = false, bool opaque = false);
+inline Engine::IDriverDependantBitmap* recycle_ddb_bitmap(Engine::IDriverDependantBitmap *ddb, Shared::Bitmap *source, bool has_alpha = false, bool opaque = false) {
+ return recycle_ddb_sprite(ddb, UINT32_MAX, source, has_alpha, opaque);
+}
// Draw everything
void render_graphics(Engine::IDriverDependantBitmap *extraBitmap = nullptr, int extraX = 0, int extraY = 0);
// Construct game scene, scheduling drawing list for the renderer
Commit: aecb62429d25a64f48c77d745450105092f363fd
https://github.com/scummvm/scummvm/commit/aecb62429d25a64f48c77d745450105092f363fd
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Update shared texture when dynamic sprite changes
>From upstream 6be0e6d094e70e96d93a9ee4dd31ca166663eeaf
Changed paths:
engines/ags/engine/ac/game.cpp
engines/ags/engine/gfx/ali_3d_scummvm.h
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/game.cpp b/engines/ags/engine/ac/game.cpp
index f5818ca7dff..dc8202979e6 100644
--- a/engines/ags/engine/ac/game.cpp
+++ b/engines/ags/engine/ac/game.cpp
@@ -1340,6 +1340,9 @@ bool unserialize_audio_script_object(int index, const char *objectType, Stream *
}
void game_sprite_updated(int sprnum) {
+ // update the shared texture (if exists)
+ _G(gfxDriver)->UpdateSharedDDB(sprnum, _GP(spriteset)[sprnum], _GP(game).SpriteInfos[sprnum].Flags & SPF_ALPHACHANNEL, false);
+
// character and object draw caches
reset_objcache_for_sprite(sprnum);
@@ -1369,6 +1372,8 @@ void game_sprite_updated(int sprnum) {
}
void game_sprite_deleted(int sprnum) {
+ // clear from texture cache
+ _G(gfxDriver)->ClearSharedDDB(sprnum);
// character and object draw caches
reset_objcache_for_sprite(sprnum);
// room object graphics
diff --git a/engines/ags/engine/gfx/ali_3d_scummvm.h b/engines/ags/engine/gfx/ali_3d_scummvm.h
index 23f28d00576..3a23c37535e 100644
--- a/engines/ags/engine/gfx/ali_3d_scummvm.h
+++ b/engines/ags/engine/gfx/ali_3d_scummvm.h
@@ -185,6 +185,13 @@ public:
return CreateDDBFromBitmap(bitmap, hasAlpha, opaque);
}
+ void UpdateSharedDDB(uint32_t /*sprite_id*/, Bitmap */*bitmap*/, bool /*hasAlpha*/, bool /*opaque*/) override {
+ /* do nothing */
+ }
+ void ClearSharedDDB(uint32_t /*sprite_id*/) override {
+ /* do nothing */
+ }
+
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;
diff --git a/engines/ags/engine/gfx/gfx_driver_base.cpp b/engines/ags/engine/gfx/gfx_driver_base.cpp
index 601d5e8b46f..6efab7c00ae 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.cpp
+++ b/engines/ags/engine/gfx/gfx_driver_base.cpp
@@ -193,6 +193,21 @@ IDriverDependantBitmap *VideoMemoryGraphicsDriver::GetSharedDDB(uint32_t sprite_
return CreateDDB(txdata, bitmap->GetWidth(), bitmap->GetHeight(), bitmap->GetColorDepth(), opaque);
}
+void VideoMemoryGraphicsDriver::UpdateSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool hasAlpha, bool opaque) {
+ const auto found = _txRefs.find(sprite_id);
+ if (found != _txRefs.end()) {
+ auto txdata = found->_value.Data.lock();
+ if (txdata)
+ UpdateTextureData(txdata.get(), bitmap, opaque, hasAlpha);
+ }
+ }
+
+ void VideoMemoryGraphicsDriver::ClearSharedDDB(uint32_t sprite_id) {
+ const auto found = _txRefs.find(sprite_id);
+ if (found != _txRefs.end())
+ _txRefs.erase(found);
+ }
+
void VideoMemoryGraphicsDriver::DestroyDDB(IDriverDependantBitmap* ddb) {
uint32_t sprite_id = ddb->GetRefID();
DestroyDDBImpl(ddb);
diff --git a/engines/ags/engine/gfx/gfx_driver_base.h b/engines/ags/engine/gfx/gfx_driver_base.h
index 14b5842ec6a..e178ddcf1bf 100644
--- a/engines/ags/engine/gfx/gfx_driver_base.h
+++ b/engines/ags/engine/gfx/gfx_driver_base.h
@@ -229,6 +229,10 @@ public:
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool hasAlpha, bool opaque = false) override;
// Get shared texture from cache, or create from bitmap and assign ID
IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool hasAlpha, bool opaque) override;
+ // Removes the shared texture reference, will force the texture to recreate next time
+ void ClearSharedDDB(uint32_t sprite_id) override;
+ // Updates shared texture data, but only if it is present in the cache
+ void UpdateSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool hasAlpha, bool opaque) override;
void DestroyDDB(IDriverDependantBitmap* ddb) override;
protected:
diff --git a/engines/ags/engine/gfx/graphics_driver.h b/engines/ags/engine/gfx/graphics_driver.h
index b3d04ea3e6b..da1371827be 100644
--- a/engines/ags/engine/gfx/graphics_driver.h
+++ b/engines/ags/engine/gfx/graphics_driver.h
@@ -142,6 +142,9 @@ public:
// Get shared texture from cache, or create from bitmap and assign ID
virtual IDriverDependantBitmap *GetSharedDDB(uint32_t sprite_id,
Shared::Bitmap *bitmap = nullptr, bool hasAlpha = true, bool opaque = false) = 0;
+ virtual void UpdateSharedDDB(uint32_t sprite_id, Shared::Bitmap *bitmap = nullptr, bool hasAlpha = true, bool opaque = false) = 0;
+ // Removes the shared texture reference, will force the texture to recreate next time
+ virtual void ClearSharedDDB(uint32_t sprite_id) = 0;
// Prepares next sprite batch, a list of sprites with defined viewport and optional
// global model transformation; all subsequent calls to DrawSprite will be adding
Commit: 370e939ad79bd1306a00256bbdc2aeb68fafbce0
https://github.com/scummvm/scummvm/commit/370e939ad79bd1306a00256bbdc2aeb68fafbce0
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Fixes for MemoryStream: proper seek support for writing mode
>From upstream 80a17c94f6fc44955dcee5c559247ea73a8c0a76
Changed paths:
engines/ags/shared/util/memory_stream.cpp
engines/ags/shared/util/memory_stream.h
diff --git a/engines/ags/shared/util/memory_stream.cpp b/engines/ags/shared/util/memory_stream.cpp
index 69bcd01f1bd..08fb485afc9 100644
--- a/engines/ags/shared/util/memory_stream.cpp
+++ b/engines/ags/shared/util/memory_stream.cpp
@@ -31,19 +31,25 @@ MemoryStream::MemoryStream(const uint8_t *cbuf, size_t buf_sz, DataEndianess str
, _cbuf(cbuf)
, _buf_sz(buf_sz)
, _len(buf_sz)
- , _buf(nullptr)
, _mode(kStream_Read)
- , _pos(0) {
+ , _pos(0)
+ , _buf(nullptr) {
}
MemoryStream::MemoryStream(uint8_t *buf, size_t buf_sz, StreamWorkMode mode, DataEndianess stream_endianess)
: DataStream(stream_endianess)
- , _buf(buf)
+ , _cbuf(nullptr)
, _buf_sz(buf_sz)
, _len(0)
- , _cbuf(nullptr)
, _mode(mode)
- , _pos(0) {
+ , _pos(0)
+ , _buf(nullptr) {
+ if (mode == kStream_Read) {
+ _cbuf = buf;
+ _len = buf_sz;
+ } else {
+ _buf = buf;
+ }
}
void MemoryStream::Close() {
@@ -83,7 +89,7 @@ bool MemoryStream::CanWrite() const {
}
bool MemoryStream::CanSeek() const {
- return CanRead(); // TODO: support seeking in writable stream?
+ return true;
}
size_t MemoryStream::Read(void *buffer, size_t size) {
@@ -123,20 +129,25 @@ bool MemoryStream::Seek(soff_t offset, StreamSeek origin) {
}
size_t MemoryStream::Write(const void *buffer, size_t size) {
- if (_pos >= _buf_sz) {
+ if (!_buf || (_pos >= _buf_sz)) {
return 0;
}
size = MIN(size, _buf_sz - _pos);
memcpy(_buf + _pos, buffer, size);
_pos += size;
- _len += size;
+ // will increase len if writing after eos, otherwise = overwrite at pos
+ _len = MAX(_len, _pos);
return size;
}
int32_t MemoryStream::WriteByte(uint8_t val) {
- if (_pos >= _buf_sz) { return -1; }
+ if (!_buf || (_pos >= _buf_sz)) {
+ return -1;
+ }
*(_buf + _pos) = val;
- _pos++; _len++;
+ _pos++;
+ // will increase len if writing after eos, otherwise = overwrite at pos
+ _len = MAX(_len, _pos);
return val;
}
@@ -147,7 +158,7 @@ VectorStream::VectorStream(const std::vector<uint8_t> &cbuf, DataEndianess strea
}
VectorStream::VectorStream(std::vector<uint8_t> &buf, StreamWorkMode mode, DataEndianess stream_endianess)
- : MemoryStream((mode == kStream_Read) ? &buf.front() : nullptr, buf.size(), mode, stream_endianess)
+ : MemoryStream(((mode == kStream_Read) && (buf.size() > 0)) ? &buf.front() : nullptr, buf.size(), mode, stream_endianess)
, _vec(&buf) {
}
@@ -156,17 +167,32 @@ void VectorStream::Close() {
MemoryStream::Close();
}
+bool VectorStream::CanRead() const {
+ return _mode == kStream_Read;
+}
+
+bool VectorStream::CanWrite() const {
+ return _mode == kStream_Write;
+}
+
size_t VectorStream::Write(const void *buffer, size_t size) {
- _vec->resize(_vec->size() + size);
+ if (_pos + size > _len) {
+ _vec->resize(_pos + size);
+ _len = _pos + size;
+ }
memcpy(_vec->data() + _pos, buffer, size);
_pos += size;
- _len += size;
return size;
}
int32_t VectorStream::WriteByte(uint8_t val) {
- _vec->push_back(val);
- _pos++; _len++;
+ if (_pos == _len) {
+ _vec->push_back(val);
+ _len++;
+ } else {
+ (*_vec)[_pos] = val;
+ }
+ _pos++;
return val;
}
diff --git a/engines/ags/shared/util/memory_stream.h b/engines/ags/shared/util/memory_stream.h
index 5cba412d206..d3394412b8d 100644
--- a/engines/ags/shared/util/memory_stream.h
+++ b/engines/ags/shared/util/memory_stream.h
@@ -78,14 +78,14 @@ public:
bool Seek(soff_t offset, StreamSeek origin) override;
protected:
- const uint8_t *_cbuf;
- size_t _buf_sz; // hard buffer limit
- size_t _len; // calculated length of stream
+ const uint8_t *_cbuf = nullptr; // readonly buffer ptr
+ size_t _buf_sz = 0u; // hard buffer limit
+ size_t _len = 0u; // calculated length of stream
const StreamWorkMode _mode;
- size_t _pos; // current stream pos
+ size_t _pos = 0u; // current stream pos
private:
- uint8_t *_buf;
+ uint8_t *_buf = nullptr; // writeable buffer ptr
};
@@ -101,11 +101,14 @@ public:
void Close() override;
+ bool CanRead() const override;
+ bool CanWrite() const override;
+
size_t Write(const void *buffer, size_t size) override;
int32_t WriteByte(uint8_t b) override;
private:
- std::vector<uint8_t> *_vec; // writeable vector (may be null)
+ std::vector<uint8_t> *_vec = nullptr; // writeable vector (may be null)
};
} // namespace Shared
Commit: e26adb919e9703f89a488b2175efa565af0aab4d
https://github.com/scummvm/scummvm/commit/e26adb919e9703f89a488b2175efa565af0aab4d
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Moved global DlgOpt into show_dialog_options() function
>From upstream 516231d87a582f32221e4a3f86ce9d437c37f642
Changed paths:
engines/ags/engine/ac/dialog.cpp
diff --git a/engines/ags/engine/ac/dialog.cpp b/engines/ags/engine/ac/dialog.cpp
index 6719c366edb..7ad6415bc05 100644
--- a/engines/ags/engine/ac/dialog.cpp
+++ b/engines/ags/engine/ac/dialog.cpp
@@ -1019,19 +1019,18 @@ void DialogOptions::Close() {
delete tempScrn;
}
-DialogOptions DlgOpt;
-
int show_dialog_options(int _dlgnum, int sayChosenOption, bool _runGameLoopsInBackground) {
- DlgOpt.Prepare(_dlgnum, _runGameLoopsInBackground);
- DlgOpt.Show();
- DlgOpt.Close();
+ DialogOptions dlgopt;
+ dlgopt.Prepare(_dlgnum, _runGameLoopsInBackground);
+ dlgopt.Show();
+ dlgopt.Close();
- int dialog_choice = DlgOpt.chose;
+ int dialog_choice = dlgopt.chose;
if (dialog_choice >= 0) { // NOTE: this condition also excludes CHOSE_TEXTPARSER
assert(dialog_choice >= 0 && dialog_choice < MAXTOPICOPTIONS);
- DialogTopic *dialog_topic = DlgOpt.dtop;
+ DialogTopic *dialog_topic = dlgopt.dtop;
int32_t &option_flags = dialog_topic->optionflags[dialog_choice];
- const char *option_name = DlgOpt.dtop->optionnames[dialog_choice];
+ const char *option_name = dlgopt.dtop->optionnames[dialog_choice];
option_flags |= DFLG_HASBEENCHOSEN;
bool sayTheOption = false;
Commit: 02085d54819aaae3c2f9a7f1148b1814d162b5c6
https://github.com/scummvm/scummvm/commit/02085d54819aaae3c2f9a7f1148b1814d162b5c6
Author: Thierry Crozat (criezy at scummvm.org)
Date: 2022-06-13T00:30:21+01:00
Commit Message:
AGS: Refactored do_conversation()
Split do_conversation into multiple functions, simplified the running
the dialog topics chain code and removed code duplication as possible.
+ Removed the limit of nested dialogs.
+ This also fixes "goto-previous" not working from the first sub-dialog.
>From upstream 7bb167f5f6ee6a1976b829a1d67423d69346dc6e
Changed paths:
engines/ags/engine/ac/dialog.cpp
diff --git a/engines/ags/engine/ac/dialog.cpp b/engines/ags/engine/ac/dialog.cpp
index 7ad6415bc05..1981f2d8c2c 100644
--- a/engines/ags/engine/ac/dialog.cpp
+++ b/engines/ags/engine/ac/dialog.cpp
@@ -19,6 +19,7 @@
*
*/
+#include "common/stack.h"
#include "ags/engine/ac/dialog.h"
#include "ags/shared/ac/common.h"
#include "ags/engine/ac/character.h"
@@ -390,7 +391,6 @@ bool get_custom_dialog_options_dimensions(int dlgnum) {
return false;
}
-#define MAX_TOPIC_HISTORY 50
#define DLG_OPTION_PARSER 99
struct DialogOptions {
@@ -1047,69 +1047,65 @@ int show_dialog_options(int _dlgnum, int sayChosenOption, bool _runGameLoopsInBa
return dialog_choice;
}
-void do_conversation(int dlgnum) {
- EndSkippingUntilCharStops();
-
- // AGS 2.x always makes the mouse cursor visible when displaying a dialog.
- if (_G(loaded_game_file_version) <= kGameVersion_272)
- _GP(play).mouse_cursor_hidden = 0;
-
- int dlgnum_was = dlgnum;
- int previousTopics[MAX_TOPIC_HISTORY];
- int numPrevTopics = 0;
- DialogTopic *dtop = &_G(dialog)[dlgnum];
+// Dialog execution state
+struct DialogExec {
+ int DlgNum = -1;
+ int DlgWas = -1;
+ // CHECKME: this may be unnecessary, investigate later
+ bool IsFirstEntry = true;
+ // nested dialogs "stack"
+ Common::Stack<int> TopicHist;
+
+ DialogExec(int start_dlgnum) : DlgNum(start_dlgnum) {}
+ int HandleDialogResult(int res);
+ void Run();
+};
- // run the startup script
- int tocar = run_dialog_script(dlgnum, dtop->startupentrypoint, 0);
- if ((tocar == RUN_DIALOG_STOP_DIALOG) ||
- (tocar == RUN_DIALOG_GOTO_PREVIOUS)) {
- // 'stop' or 'goto-previous' from first startup script
- remove_screen_overlay(OVER_COMPLETE);
- _GP(play).in_conversation--;
- return;
- } else if (tocar >= 0)
- dlgnum = tocar;
-
- while (dlgnum >= 0) {
- if (dlgnum >= _GP(game).numdialog)
- quit("!RunDialog: invalid dialog number specified");
-
- dtop = &_G(dialog)[dlgnum];
-
- if (dlgnum != dlgnum_was) {
- // dialog topic changed, so play the startup
- // script for the new topic
- tocar = run_dialog_script(dlgnum, dtop->startupentrypoint, 0);
- dlgnum_was = dlgnum;
- if (tocar == RUN_DIALOG_GOTO_PREVIOUS) {
- if (numPrevTopics < 1) {
- // goto-previous on first topic -- end dialog
- tocar = RUN_DIALOG_STOP_DIALOG;
- } else {
- tocar = previousTopics[numPrevTopics - 1];
- numPrevTopics--;
- }
- }
- if (tocar == RUN_DIALOG_STOP_DIALOG)
- break;
- else if (tocar >= 0) {
- // save the old topic number in the history
- if (numPrevTopics < MAX_TOPIC_HISTORY) {
- previousTopics[numPrevTopics] = dlgnum;
- numPrevTopics++;
- }
- dlgnum = tocar;
- continue;
- }
+int DialogExec::HandleDialogResult(int res) {
+ // Handle goto-previous, see if there's any previous dialog in history
+ if (res == RUN_DIALOG_GOTO_PREVIOUS) {
+ if (TopicHist.size() == 0)
+ return RUN_DIALOG_STOP_DIALOG;
+ res = TopicHist.top();
+ TopicHist.pop();
+ }
+ // Continue to the next dialog
+ if (res >= 0) {
+ // save the old topic number in the history, and switch to the new one
+ TopicHist.push(DlgNum);
+ DlgNum = res;
+ return DlgNum;
+ }
+ return res;
+ }
+
+void DialogExec::Run() {
+ while (DlgNum >= 0) {
+ if (DlgNum < 0 || DlgNum >= _GP(game).numdialog)
+ quitprintf("!RunDialog: invalid dialog number specified: %d", DlgNum);
+
+ // current dialog object
+ DialogTopic *dtop = &_G(dialog)[DlgNum];
+ int res = 0; // dialog execution result
+ // If a new dialog topic: run dialog entry point
+ if (DlgNum != DlgWas) {
+ res = run_dialog_script(DlgNum, dtop->startupentrypoint, 0);
+ DlgWas = DlgNum;
+
+ // Handle the dialog entry's result
+ res = HandleDialogResult(res);
+ if (res == RUN_DIALOG_STOP_DIALOG)
+ return; // stop the dialog
+ IsFirstEntry = false;
+ if (res != RUN_DIALOG_STAY)
+ continue; // skip to the next dialog
}
- int chose = show_dialog_options(dlgnum, SAYCHOSEN_USEFLAG, (_GP(game).options[OPT_RUNGAMEDLGOPTS] != 0));
-
+ // Show current dialog's options
+ int chose = show_dialog_options(DlgNum, SAYCHOSEN_USEFLAG, (_GP(game).options[OPT_RUNGAMEDLGOPTS] != 0));
if (chose == CHOSE_TEXTPARSER) {
_G(said_speech_line) = 0;
-
- tocar = run_dialog_request(dlgnum);
-
+ res = run_dialog_request(DlgNum);
if (_G(said_speech_line) > 0) {
// fix the problem with the close-up face remaining on screen
DisableInterface();
@@ -1118,28 +1114,34 @@ void do_conversation(int dlgnum) {
set_mouse_cursor(CURS_ARROW);
}
} else if (chose >= 0) {
- tocar = run_dialog_script(dlgnum, dtop->entrypoints[chose], chose + 1);
+ // chose some option - run its script
+ res = run_dialog_script(DlgNum, dtop->entrypoints[chose], chose + 1);
} else {
- tocar = RUN_DIALOG_STOP_DIALOG;
+ return; // no option chosen? - stop the dialog
}
- if (tocar == RUN_DIALOG_GOTO_PREVIOUS) {
- if (numPrevTopics < 1) {
- tocar = RUN_DIALOG_STOP_DIALOG;
- } else {
- tocar = previousTopics[numPrevTopics - 1];
- numPrevTopics--;
- }
- }
- if (tocar == RUN_DIALOG_STOP_DIALOG) break;
- else if (tocar >= 0) {
- // save the old topic number in the history
- if (numPrevTopics < MAX_TOPIC_HISTORY) {
- previousTopics[numPrevTopics] = dlgnum;
- numPrevTopics++;
- }
- dlgnum = tocar;
- }
+ // Handle the dialog option's result
+ res = HandleDialogResult(res);
+ if (res == RUN_DIALOG_STOP_DIALOG)
+ return; // stop the dialog
+ // continue to the next dialog or show same dialog's options again
+ }
+}
+
+void do_conversation(int dlgnum) {
+ EndSkippingUntilCharStops();
+
+ // AGS 2.x always makes the mouse cursor visible when displaying a dialog.
+ if (_G(loaded_game_file_version) <= kGameVersion_272)
+ _GP(play).mouse_cursor_hidden = 0;
+
+ DialogExec dlgexec(dlgnum);
+ dlgexec.Run();
+ // CHECKME: find out if this is safe to do always, regardless of number of iterations
+ if (dlgexec.IsFirstEntry) {
+ // bail out from first startup script
+ remove_screen_overlay(OVER_COMPLETE);
+ _GP(play).in_conversation--;
}
}
More information about the Scummvm-git-logs
mailing list