/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*/
//=============================================================================
//
// Implementation base for graphics driver
//
//=============================================================================
#ifndef AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
#define AGS_ENGINE_GFX_GFX_DRIVER_BASE_H
#include "common/std/memory.h"
#include "common/std/map.h"
#include "common/std/vector.h"
#include "ags/engine/gfx/ddb.h"
#include "ags/shared/gfx/gfx_def.h"
#include "ags/engine/gfx/graphics_driver.h"
#include "ags/shared/util/scaling.h"
namespace AGS3 {
namespace AGS {
namespace Engine {
using Shared::Bitmap;
using Shared::PlaneScaling;
// Sprite batch, defines viewport and an optional model transformation for the list of sprites
struct SpriteBatchDesc {
uint32_t Parent = UINT32_MAX;
// View rectangle for positioning and clipping, in resolution coordinates
// (this may be screen or game frame resolution, depending on circumstances)
Rect Viewport;
// Optional model transformation, to be applied to each sprite
SpriteTransform Transform;
// Optional flip, applied to the whole batch as the last transform
Shared::GraphicFlip Flip = Shared::kFlip_None;
// Optional bitmap to draw sprites upon. Used exclusively by the software rendering mode.
PBitmap Surface;
// Optional filter flags; this lets to filter certain batches out during some operations,
// such as fading effects or making screenshots.
uint32_t FilterFlags = 0u;
SpriteBatchDesc() = default;
SpriteBatchDesc(uint32_t parent, const Rect viewport, const SpriteTransform & transform,
Shared::GraphicFlip flip = Shared::kFlip_None, PBitmap surface = nullptr, uint32_t filter_flags = 0)
: Parent(parent)
, Viewport(viewport)
, Transform(transform)
, Flip(flip)
, Surface(surface)
, FilterFlags(filter_flags) {
}
};
typedef std::vector SpriteBatchDescs;
// The single sprite entry in the render list
template
struct SpriteDrawListEntry {
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) {
}
};
// GraphicsDriverBase - is the parent class for all graphics drivers in AGS,
// that incapsulates the most common functionality.
class GraphicsDriverBase : public IGraphicsDriver {
public:
GraphicsDriverBase();
bool IsModeSet() const override;
bool IsNativeSizeValid() const override;
bool IsRenderFrameValid() const override;
DisplayMode GetDisplayMode() const override;
Size GetNativeSize() const override;
Rect GetRenderDestination() const override;
bool SetVsync(bool enabled) override;
bool GetVsync() const override;
void BeginSpriteBatch(const Rect &viewport, const SpriteTransform &transform,
Shared::GraphicFlip flip = Shared::kFlip_None, PBitmap surface = nullptr,
uint32_t filter_flags = 0) override;
void EndSpriteBatch() override;
void ClearDrawLists() override;
void SetCallbackForPolling(GFXDRV_CLIENTCALLBACK callback) override {
_pollingCallback = callback;
}
void SetCallbackToDrawScreen(GFXDRV_CLIENTCALLBACK callback, GFXDRV_CLIENTCALLBACK post_callback) override {
_drawScreenCallback = callback;
_drawPostScreenCallback = post_callback;
}
void SetCallbackOnInit(GFXDRV_CLIENTCALLBACKINITGFX callback) override {
_initGfxCallback = callback;
}
void SetCallbackOnSpriteEvt(GFXDRV_CLIENTCALLBACKEVT callback) override {
_spriteEvtCallback = callback;
}
protected:
// Special internal values, applied to DrawListEntry
static const uintptr_t DRAWENTRY_STAGECALLBACK = 0x0;
static const uintptr_t DRAWENTRY_FADE = 0x1;
static const uintptr_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
// resources released
virtual void OnUnInit();
// Called after new mode was successfully initialized
virtual void OnModeSet(const DisplayMode &mode);
// Called when the new native size is set
virtual void OnSetNativeRes(const GraphicResolution &native_res);
// Called before display mode is going to be released
virtual void OnModeReleased();
// Called when new render frame is set
virtual void OnSetRenderFrame(const Rect &dst_rect);
// Called when the new filter is set
virtual void OnSetFilter();
// Try changing vsync setting; fills new current mode in vsync_res,
// returns whether the new setting was set successfully.
virtual bool SetVsyncImpl(bool vsync, bool &vsync_res) { return false; }
// Initialize sprite batch and allocate necessary resources
virtual void InitSpriteBatch(size_t index, const SpriteBatchDesc &desc) = 0;
// Gets the index of a last draw entry (sprite)
virtual size_t GetLastDrawEntryIndex() = 0;
// Clears sprite lists
virtual void ResetAllBatches() = 0;
void OnScalingChanged();
DisplayMode _mode; // display mode settings
Rect _srcRect; // rendering source rect
int _srcColorDepth; // rendering source color depth (in bits per pixel)
Rect _dstRect; // rendering destination rect
Rect _filterRect; // filter scaling destination rect (before final scaling)
PlaneScaling _scaling; // native -> render dest coordinate transformation
// Capability flags
bool _capsVsync = false; // is vsync available
// Callbacks
GFXDRV_CLIENTCALLBACK _pollingCallback;
GFXDRV_CLIENTCALLBACK _drawScreenCallback;
GFXDRV_CLIENTCALLBACK _drawPostScreenCallback;
GFXDRV_CLIENTCALLBACKEVT _spriteEvtCallback;
GFXDRV_CLIENTCALLBACKINITGFX _initGfxCallback;
// Sprite batch parameters
SpriteBatchDescs _spriteBatchDesc;
// The range of sprites in this sprite batch (counting nested sprites):
// the index of a first of the current batch, and the next index past the last one.
std::vector> _spriteBatchRange;
// The index of a currently filled sprite batch
size_t _actSpriteBatch;
// The index of a currently rendered sprite batch
// (or -1 / UINT32_MAX if we are outside of the render pass)
uint32_t _rendSpriteBatch;
};
// Parent class for the video memory DDBs
class BaseDDB : public IDriverDependantBitmap {
public:
int GetWidth() const override {
return _width;
}
int GetHeight() const override {
return _height;
}
int GetColorDepth() const override {
return _colDepth;
}
bool MatchesFormat(AGS::Shared::Bitmap *other) const {
return _width == other->GetWidth() && _height == other->GetHeight() && _colDepth == other->GetColorDepth();
}
int _width = 0, _height = 0;
int _colDepth = 0;
bool _hasAlpha = false; // has meaningful alpha channel
bool _opaque = false; // no mask color
protected:
BaseDDB() {}
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 {
uint32_t ID = UINT32_MAX;
bool RenderTarget = false; // replace with flags later
virtual ~TextureData() = default;
protected:
TextureData() = default;
};
// Generic TextureTile base
struct TextureTile {
int x = 0, y = 0;
int width = 0, height = 0;
// allocWidth and allocHeight tell the actual allocated texture size
int allocWidth = 0, allocHeight = 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.
class VideoMemoryGraphicsDriver : public GraphicsDriverBase {
public:
VideoMemoryGraphicsDriver();
~VideoMemoryGraphicsDriver() override;
bool RequiresFullRedrawEachFrame() override { return true; }
bool HasAcceleratedTransform() override { return true; }
// NOTE: although we do use ours, we do not let engine draw upon it;
// only plugin handling are allowed to request our mem buffer
// for compatibility reasons.
bool UsesMemoryBackBuffer() override { return false; }
Bitmap *GetMemoryBackBuffer() override;
void SetMemoryBackBuffer(Bitmap *backBuffer) override;
Bitmap *GetStageBackBuffer(bool mark_dirty) override;
void SetStageBackBuffer(Bitmap *backBuffer) override;
bool GetStageMatrixes(RenderMatrixes &rm) override;
// Creates new texture using given parameters
IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) override = 0;
// Creates new texture and copy bitmap contents over
IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool has_alpha, 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 has_alpha, 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 has_alpha, 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;
// Update texture data from the given bitmap
virtual void UpdateTextureData(TextureData *txdata, Bitmap *bmp, bool has_alpha, bool opaque) = 0;
// Create DDB using preexisting texture data
virtual IDriverDependantBitmap *CreateDDB(std::shared_ptr txdata,
int width, int height, int color_depth, bool opaque) = 0;
// Retrieve shared texture data object from the given DDB
virtual std::shared_ptr 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
// rendered as additional sprites in their respected order.
// 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, and optional x,y position;
// clears the raw bitmap after copying to the texture.
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 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);
// Resets fx pool counter
void ResetFxPool();
// Disposes all items in the fx pool
void DestroyFxPool();
// Prepares bitmap to be applied to the texture, copies pixels to the provided buffer
void BitmapToVideoMem(const Bitmap *bitmap, const bool has_alpha, const TextureTile *tile,
uint8_t *dst_ptr, const int dst_pitch, const bool usingLinearFiltering);
// Same but optimized for opaque source bitmaps which ignore transparent "mask color"
void BitmapToVideoMemOpaque(const Bitmap *bitmap, const TextureTile *tile,
uint8_t *dst_ptr, const int dst_pitch);
// Stage virtual screen is used to let plugins draw custom graphics
// in between render stages (between room and GUI, after GUI, and so on)
PBitmap _stageVirtualScreen;
IDriverDependantBitmap *_stageVirtualScreenDDB;
// Stage matrixes are used to let plugins with hardware acceleration know model matrix;
// these matrixes are filled compatible with each given renderer
RenderMatrixes _stageMatrixes;
// Color component shifts in video bitmap format (set by implementations)
int _vmem_a_shift_32;
int _vmem_r_shift_32;
int _vmem_g_shift_32;
int _vmem_b_shift_32;
private:
// Stage virtual screens are used to let plugins draw custom graphics
// in between render stages (between room and GUI, after GUI, and so on).
// TODO: possibly may be optimized further by having only 1 bitmap/ddb
// pair, and subbitmaps for raw drawing on separate stages.
struct StageScreen {
Rect Position; // bitmap size and pos preset (bitmap may be created later)
std::unique_ptr Raw;
IDriverDependantBitmap *DDB = nullptr;
};
std::vector _stageScreens;
// Flag which indicates whether stage screen was drawn upon during engine
// callback and has to be inserted into sprite stack.
bool _stageScreenDirty;
// Fx quads pool (for screen overlay effects)
struct ScreenFx {
Bitmap *Raw = nullptr;
IDriverDependantBitmap *DDB = nullptr;
int Red = -1;
int Green = -1;
int Blue = -1;
};
std::vector _fxPool;
size_t _fxIndex; // next free pool item
// specialized method to convert bitmap to video memory depending on bit depth
template
void BitmapToVideoMemImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch);
template
void BitmapToVideoMemOpaqueImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch);
template
void BitmapToVideoMemLinearImpl(const Bitmap *bitmap, const TextureTile *tile, uint8_t *dst_ptr, const int dst_pitch);
// 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.
// TODO: a curious topic to consider: reuse released TextureData for
// textures of the same size (research potential performance impact).
struct TextureCacheItem {
GraphicResolution Res;
std::weak_ptr Data;
TextureCacheItem() = default;
TextureCacheItem(std::shared_ptr data, const GraphicResolution &res)
: Data(data), Res(res) {}
};
std::unordered_map _txRefs;
};
} // namespace Engine
} // namespace AGS
} // namespace AGS3
#endif