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(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 &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(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 ALDrawListEntry; // Software renderer's sprite batch struct ALSpriteBatch { - // List of sprites to render - std::vector List; + uint32_t ID = 0; // Intermediate surface which will be drawn upon and transformed if necessary - std::shared_ptr Surface; + std::shared_ptr 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 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 _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 SpriteBatchDescs; // The single sprite entry in the render list template struct SpriteDrawListEntry { - T_DDB *bitmap; // TODO: use shared pointer? - int x, y; // sprite position, in camera coordinates - bool skip; + 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() - : bitmap(nullptr) - , x(0) - , y(0) - , skip(false) { - } - - SpriteDrawListEntry(T_DDB *ddb, int x_ = 0, int y_ = 0) - : bitmap(ddb) + 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