AGS: Engine: support optional size and position for gfxdriver's stage screen

This is primarily for backwards compatibility with the older plugins,
that relied only on software drawing.

Previously we added "stage screens" to the hardware-accelerated
graphic drivers (Direct3D/OpenGL), which provide a surface for
plugins to draw upon. If used, these surfaces would then be rendered
as plain sprites in 3D scene at certain place in the sprite sequence.

The remaining problem (left unnoticed) was that the surfaces which
correspond to the two room render callbacks (right after background,
and right after all objects) did not follow the room camera position and
scaling correctly (not all, tbh). This commit addresses these problems by
letting the engine to request certain size and optional position for these
"stage screens" for particular sprite batches.

Partially from upstream 2d43bffc2cb07935ae72d7c5677ad622c8b4d37e
This commit is contained in:
Walter Agazzi 2023-03-02 21:49:48 +01:00 committed by Thierry Crozat
parent 823eda7991
commit 1e3bb9c241
6 changed files with 36 additions and 14 deletions

View File

@ -2099,6 +2099,7 @@ static void construct_room_view() {
// and second - how room's image translates into the camera.
_G(gfxDriver)->BeginSpriteBatch(view_rc, SpriteTransform(view_rc.Left, view_rc.Top, view_sx, view_sy));
_G(gfxDriver)->BeginSpriteBatch(Rect(), SpriteTransform(-cam_rc.Left, -cam_rc.Top));
_G(gfxDriver)->SetStageScreen(cam_rc.GetSize(), cam_rc.Left, cam_rc.Top);
put_sprite_list_on_screen(true);
_G(gfxDriver)->EndSpriteBatch();
_G(gfxDriver)->EndSpriteBatch();

View File

@ -329,6 +329,10 @@ void ScummVMRendererGraphicsDriver::SetScreenTint(int red, int green, int blue)
}
}
void ScummVMRendererGraphicsDriver::SetStageScreen(const Size & /*sz*/, int /*x*/, int /*y*/) {
// unsupported, as using _stageVirtualScreen instead
}
void ScummVMRendererGraphicsDriver::RenderToBackBuffer() {
// Close unended batches, and issue a warning
assert(_actSpriteBatch == 0);

View File

@ -196,6 +196,7 @@ public:
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;
void SetStageScreen(const Size &sz, int x = 0, int y = 0) override;
void RenderToBackBuffer() override;
void Render() override;

View File

@ -226,10 +226,14 @@ void VideoMemoryGraphicsDriver::UpdateSharedDDB(uint32_t sprite_id, Bitmap *bitm
_txRefs.erase(found);
}
void VideoMemoryGraphicsDriver::SetStageScreen(size_t index, const Size &sz) {
void VideoMemoryGraphicsDriver::SetStageScreen(const Size &sz, int x, int y) {
SetStageScreen(_actSpriteBatch, sz, x, y);
}
void VideoMemoryGraphicsDriver::SetStageScreen(size_t index, const Size &sz, int x, int y) {
if (_stageScreens.size() <= index)
_stageScreens.resize(index + 1);
_stageScreens[index].PresetSize = sz;
_stageScreens[index].Position = RectWH(x, y, sz.Width, sz.Height);
}
Bitmap *VideoMemoryGraphicsDriver::GetStageScreenRaw(size_t index) {
@ -238,7 +242,7 @@ Bitmap *VideoMemoryGraphicsDriver::GetStageScreenRaw(size_t index) {
return nullptr;
auto &scr = _stageScreens[index];
const Size sz = scr.PresetSize;
const Size sz = scr.Position.GetSize();
if (scr.Raw && (scr.Raw->GetSize() != sz)) {
scr.Raw.reset();
if (scr.DDB)
@ -252,7 +256,7 @@ Bitmap *VideoMemoryGraphicsDriver::GetStageScreenRaw(size_t index) {
return scr.Raw.get();
}
IDriverDependantBitmap *VideoMemoryGraphicsDriver::UpdateStageScreenDDB(size_t index) {
IDriverDependantBitmap *VideoMemoryGraphicsDriver::UpdateStageScreenDDB(size_t index, int &x, int &y) {
assert((index < _stageScreens.size()) && _stageScreens[index].DDB);
if ((_stageScreens.size() <= index) || !_stageScreens[index].Raw || !_stageScreens[index].DDB)
return nullptr;
@ -260,6 +264,8 @@ IDriverDependantBitmap *VideoMemoryGraphicsDriver::UpdateStageScreenDDB(size_t i
auto &scr = _stageScreens[index];
UpdateDDBFromBitmap(scr.DDB, scr.Raw.get(), true);
scr.Raw->ClearTransparent();
x = scr.Position.Left;
y = scr.Position.Top;
return scr.DDB;
}
@ -275,7 +281,7 @@ void VideoMemoryGraphicsDriver::DestroyAllStageScreens() {
_stageScreens.clear();
}
IDriverDependantBitmap *VideoMemoryGraphicsDriver::DoSpriteEvtCallback(int evt, int data) {
IDriverDependantBitmap *VideoMemoryGraphicsDriver::DoSpriteEvtCallback(int evt, int data, int &x, int &y) {
if (!_spriteEvtCallback)
error("Unhandled attempt to draw null sprite");
_stageScreenDirty = false;
@ -285,7 +291,7 @@ IDriverDependantBitmap *VideoMemoryGraphicsDriver::DoSpriteEvtCallback(int evt,
// _stageScreenDirty in certain plugin API function implementations.
_stageScreenDirty |= _spriteEvtCallback(evt, data) != 0;
if (_stageScreenDirty) {
return UpdateStageScreenDDB(_rendSpriteBatch);
return UpdateStageScreenDDB(_rendSpriteBatch, x, y);
}
return nullptr;
}

View File

@ -244,6 +244,9 @@ public:
void UpdateSharedDDB(uint32_t sprite_id, Bitmap *bitmap, bool hasAlpha, bool opaque) override;
void DestroyDDB(IDriverDependantBitmap* ddb) override;
// Sets stage screen parameters for the current batch.
void SetStageScreen(const Size &sz, int x = 0, int y = 0) override;
protected:
// Create texture data with the given parameters
virtual TextureData *CreateTextureData(int width, int height, bool opaque, bool as_render_target = false) = 0;
@ -259,19 +262,20 @@ protected:
// 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.
// Presets a stage screen with the given size.
void SetStageScreen(size_t index, const Size &sz);
// Presets a stage screen with the given position (size is obligatory, offsets not).
void SetStageScreen(size_t index, const Size &sz, int x = 0, int y = 0);
// Returns a raw bitmap for the given stage screen.
Bitmap *GetStageScreenRaw(size_t index);
// Updates and returns a DDB for the given stage screen;
// Updates and returns a DDB for the given stage screen, and optional x,y position;
// clears the raw bitmap after copying to the texture.
IDriverDependantBitmap *UpdateStageScreenDDB(size_t index);
IDriverDependantBitmap *UpdateStageScreenDDB(size_t index, int &x, int &y);
// Disposes all the stage screen raw bitmaps and DDBs.
void DestroyAllStageScreens();
// Use engine callback to pass a render event;
// returns a DDB if the sprite was provided onto the virtual screen,
// and nullptr if this entry should be skipped.
IDriverDependantBitmap *DoSpriteEvtCallback(int evt, int data);
// returns a DDB if anything was drawn onto the current stage screen
// (in which case it also fills optional x,y position),
// or nullptr if this entry should be skipped.
IDriverDependantBitmap *DoSpriteEvtCallback(int evt, int data, int &x, int &y);
// Prepare and get fx item from the pool
IDriverDependantBitmap *MakeFx(int r, int g, int b);
@ -307,7 +311,7 @@ private:
// TODO: possibly may be optimized further by having only 1 bitmap/ddb
// pair, and subbitmaps for raw drawing on separate stages.
struct StageScreen {
Size PresetSize; // Size preset (bitmap may be created later)
Rect Position; // bitmap size and pos preset (bitmap may be created later)
std::unique_ptr<Bitmap> Raw;
IDriverDependantBitmap *DDB = nullptr;
};

View File

@ -169,6 +169,12 @@ public:
// Adds tint overlay fx to the active batch
// TODO: redesign this to allow various post-fx per sprite batch?
virtual void SetScreenTint(int red, int green, int blue) = 0;
// Sets stage screen parameters for the current batch.
// Currently includes size and optional position offset;
// the position is relative, as stage screens are using sprite batch transforms.
// Stage screens are used to let plugins do raw drawing during render callbacks.
// TODO: find a better term? note, it's used in several places around renderers.
virtual void SetStageScreen(const Size &sz, int x = 0, int y = 0) = 0;
// Clears all sprite batches, resets batch counter
virtual void ClearDrawLists() = 0;
virtual void RenderToBackBuffer() = 0;