/* 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 . * */ //============================================================================= // // Software graphics factory, draws raw bitmaps onto a virtual screen, // converts to SDL_Texture and finally presents with SDL_Renderer. // // TODO: replace nearest-neighbour software filter with SDL's own accelerated // scaling, maybe add more filter types if SDL renderer supports them. // Only keep Hqx filter as a software option (might need to change how the // filter code works). // //============================================================================= #ifndef AGS_ENGINE_GFX_ALI_3D_SCUMMVM_H #define AGS_ENGINE_GFX_ALI_3D_SCUMMVM_H #include "common/std/memory.h" #include "common/std/vector.h" #include "ags/shared/core/platform.h" #include "ags/shared/gfx/bitmap.h" #include "ags/engine/gfx/ddb.h" #include "ags/engine/gfx/gfx_driver_factory_base.h" #include "ags/engine/gfx/gfx_driver_base.h" namespace AGS3 { namespace AGS { namespace Engine { namespace ALSW { class ScummVMRendererGraphicsDriver; class ScummVMRendererGfxFilter; using AGS::Shared::Bitmap; enum RendererFlip { FLIP_NONE = 0x00000000, /**< Do not flip */ FLIP_HORIZONTAL = 0x00000001, /**< flip horizontally */ FLIP_VERTICAL = 0x00000002 /**< flip vertically */ }; class ALSoftwareBitmap : public BaseDDB { public: uint32_t GetRefID() const override { return UINT32_MAX /* not supported */; } int GetAlpha() const override { return _alpha; } void SetAlpha(int alpha) override { _alpha = alpha; } void SetFlippedLeftRight(bool isFlipped) override { _flipped = isFlipped; } void SetStretch(int width, int height, bool /*useResampler*/) override { _stretchToWidth = width; _stretchToHeight = height; } void SetLightLevel(int /*lightLevel*/) override {} void SetTint(int /*red*/, int /*green*/, int /*blue*/, int /*tintSaturation*/) override {} Bitmap *_bmp = nullptr; bool _flipped = false; int _stretchToWidth = 0, _stretchToHeight = 0; int _alpha = 255; ALSoftwareBitmap(int width, int height, int color_depth, bool opaque) { _width = width; _height = height; _colDepth = color_depth; _opaque = opaque; _stretchToWidth = _width; _stretchToHeight = _height; } ALSoftwareBitmap(Bitmap *bmp, bool has_alpha, bool opaque) { _bmp = bmp; _width = bmp->GetWidth(); _height = bmp->GetHeight(); _colDepth = bmp->GetColorDepth(); _opaque = opaque; _hasAlpha = has_alpha; _stretchToWidth = _width; _stretchToHeight = _height; } int GetWidthToRender() { return _stretchToWidth; } int GetHeightToRender() { return _stretchToHeight; } ~ALSoftwareBitmap() override = default; }; class ScummVMRendererGfxModeList : public IGfxModeList { public: ScummVMRendererGfxModeList(const std::vector &modes) : _modes(modes) { } int GetModeCount() const override { return _modes.size(); } bool GetMode(int index, DisplayMode &mode) const override { if (index >= 0 && (size_t)index < _modes.size()) { mode = _modes[index]; return true; } return false; } private: std::vector _modes; }; typedef SpriteDrawListEntry ALDrawListEntry; // Software renderer's sprite batch struct ALSpriteBatch { uint32_t ID = 0u; // Clipping viewport, also used as a destination for blitting optional Surface; // in *relative* coordinates to parent surface. Rect Viewport; // Optional model transformation, to be applied to each sprite SpriteTransform Transform; // Intermediate surface which will be drawn upon and transformed if necessary std::shared_ptr Surface; // Whether surface is a parent surface's region (e.g. virtual screen) bool IsParentRegion = false; // Tells whether the surface is treated as opaque or transparent bool Opaque = false; }; typedef std::vector ALSpriteBatches; class ScummVMRendererGraphicsDriver : public GraphicsDriverBase { public: ScummVMRendererGraphicsDriver(); ~ScummVMRendererGraphicsDriver() override; const char *GetDriverID() override { return "Software"; } bool RequiresFullRedrawEachFrame() override { return false; } bool HasAcceleratedTransform() override { return false; } bool UsesMemoryBackBuffer() override { return true; } bool ShouldReleaseRenderTargets() override { return false; } const char *GetDriverName() override { return "ScummVM 2D renderer"; } void SetTintMethod(TintMethod /*method*/) override; bool SetDisplayMode(const DisplayMode &mode) override; void UpdateDeviceScreen(const Size &screen_sz) override; bool SetNativeResolution(const GraphicResolution &native_res) override; bool SetRenderFrame(const Rect &dst_rect) override; bool IsModeSupported(const DisplayMode &mode) override; int GetDisplayDepthForNativeDepth(int native_color_depth) const override; IGfxModeList *GetSupportedModeList(int color_depth) override; PGfxFilter GetGraphicsFilter() const override; void UnInit(); // Clears the screen rectangle. The coordinates are expected in the **native game resolution**. void ClearRectangle(int x1, int y1, int x2, int y2, RGB *colorToUse) override; int GetCompatibleBitmapFormat(int color_depth) override; size_t GetAvailableTextureMemory() override { // not using textures for sprites anyway return 0; } IDriverDependantBitmap *CreateDDB(int width, int height, int color_depth, bool opaque) override; IDriverDependantBitmap *CreateDDBFromBitmap(Bitmap *bitmap, bool has_alpha, bool opaque) override; IDriverDependantBitmap *CreateRenderTargetDDB(int width, int height, int color_depth, bool opaque) override; void UpdateDDBFromBitmap(IDriverDependantBitmap *ddb, Bitmap *bitmap, bool has_alpha) override; void DestroyDDB(IDriverDependantBitmap *ddb) override; IDriverDependantBitmap *GetSharedDDB(uint32_t /*sprite_id*/, Bitmap *bitmap, bool has_alpha, bool opaque) override { // Software renderer does not require a texture cache, because it uses bitmaps directly return CreateDDBFromBitmap(bitmap, has_alpha, opaque); } void UpdateSharedDDB(uint32_t /*sprite_id*/, Bitmap */*bitmap*/, bool /*has_alpha*/, 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; void SetStageScreen(const Size &sz, int x = 0, int y = 0) override; void RenderToBackBuffer() override; void Render() override; void Render(int xoff, int yoff, Shared::GraphicFlip flip) override; bool GetCopyOfScreenIntoBitmap(Bitmap *destination, const Rect *src_rect, bool at_native_res, GraphicResolution *want_fmt, uint32_t batch_skip_filter = 0u) override; void FadeOut(int speed, int targetColourRed, int targetColourGreen, int targetColourBlue, uint32_t batch_skip_filter = 0u) override; void FadeIn(int speed, PALETTE pal, int targetColourRed, int targetColourGreen, int targetColourBlue, uint32_t batch_skip_filter = 0u) override; void BoxOutEffect(bool blackingOut, int speed, int delay, uint32_t batch_skip_filter = 0u) override; bool SupportsGammaControl() override; void SetGamma(int newGamma) override; void UseSmoothScaling(bool /*enabled*/) override {} bool DoesSupportVsyncToggle() override; void RenderSpritesAtScreenResolution(bool /*enabled*/) override {} Bitmap *GetMemoryBackBuffer() override; void SetMemoryBackBuffer(Bitmap *backBuffer) override; Bitmap *GetStageBackBuffer(bool mark_dirty) override; void SetStageBackBuffer(Bitmap *backBuffer) override; bool GetStageMatrixes(RenderMatrixes & /*rm*/) override { return false; /* not supported */ } typedef std::shared_ptr PSDLRenderFilter; void SetGraphicsFilter(PSDLRenderFilter filter); protected: bool SetVsyncImpl(bool vsync, bool &vsync_res) override; size_t GetLastDrawEntryIndex() override { return _spriteList.size(); } private: Graphics::Screen *_screen = nullptr; PSDLRenderFilter _filter; bool _hasGamma = false; #ifdef TODO uint16 _defaultGammaRed[256] {}; uint16 _defaultGammaGreen[256] {}; uint16 _defaultGammaBlue[256] {}; int _gamma = 100; #endif /* SDL_Renderer *_renderer = nullptr; SDL_Texture *_screenTex = nullptr; */ // BITMAP struct for wrapping screen texture locked pixels, so that we may use blit() BITMAP *_fakeTexBitmap = nullptr; unsigned char *_lastTexPixels = nullptr; int _lastTexPitch = -1; // Original virtual screen created and managed by the renderer. std::unique_ptr _origVirtualScreen; // Current virtual screen bitmap; may be either pointing to _origVirtualScreen, // or provided by external user (for example - plugin). // Its pixels are copied to the video texture to be presented by SDL_Renderer. Bitmap *virtualScreen; // Stage screen meant for particular rendering stages, may be referencing // actual virtual screen or separate bitmap of different size that is // blitted to virtual screen at the stage finalization. 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; // Use gfx filter to create a new virtual screen void CreateVirtualScreen(); void DestroyVirtualScreen(); // Unset parameters and release resources related to the display mode void ReleaseDisplayMode(); // Renders single sprite batch on the precreated surface 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 speed, int targetColourRed, int targetColourGreen, int targetColourBlue); void highcolor_fade_out(Bitmap *vs, void(*draw_callback)(), int speed, int targetColourRed, int targetColourGreen, int targetColourBlue); void __fade_from_range(PALETTE source, PALETTE dest, int speed, int from, int to); void __fade_out_range(int speed, int from, int to, int targetColourRed, int targetColourGreen, int targetColourBlue); // Copy raw screen bitmap pixels to the screen void copySurface(const Graphics::Surface &src, bool mode); // Render bitmap on screen void Present(int xoff = 0, int yoff = 0, Shared::GraphicFlip flip = Shared::kFlip_None); }; class ScummVMRendererGraphicsFactory : public GfxDriverFactoryBase { public: ~ScummVMRendererGraphicsFactory() override; size_t GetFilterCount() const override; const GfxFilterInfo *GetFilterInfo(size_t index) const override; String GetDefaultFilterID() const override; static ScummVMRendererGraphicsFactory *GetFactory(); private: ScummVMRendererGraphicsDriver *EnsureDriverCreated() override; ScummVMRendererGfxFilter *CreateFilter(const String &id) override; static ScummVMRendererGraphicsFactory *_factory; }; } // namespace ALSW } // namespace Engine } // namespace AGS } // namespace AGS3 #endif