AGS: Separate sprite lists and batch lists in renderers

From upstream ccbf3d16788720e94e5362ff8aeae1e32b4febe5
This commit is contained in:
Paul Gilbert 2022-04-30 21:37:18 -07:00
parent a476850123
commit 9fff1dc1fa
3 changed files with 49 additions and 43 deletions

View File

@ -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) {

View File

@ -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);

View File

@ -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;
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