From 982106c77f1ffaf381b2aec20a8ac092aaf42c3b Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Thu, 12 Dec 2024 23:32:06 +0300 Subject: [PATCH 1/5] Direct3D, OpenGL: support vertical sprite flip --- Common/gfx/gfx_def.h | 9 ++-- Engine/ac/draw.cpp | 2 +- Engine/gfx/ali3dogl.cpp | 18 +++++-- Engine/gfx/ali3dogl.h | 58 +++++----------------- Engine/gfx/ali3dsw.h | 27 +++-------- Engine/gfx/ddb.h | 2 +- Engine/gfx/gfxdriverbase.h | 22 +++++++++ Engine/platform/windows/gfx/ali3dd3d.cpp | 18 +++++-- Engine/platform/windows/gfx/ali3dd3d.h | 62 ++++++------------------ 9 files changed, 89 insertions(+), 129 deletions(-) diff --git a/Common/gfx/gfx_def.h b/Common/gfx/gfx_def.h index c168adeb383..bbd706dbbd4 100644 --- a/Common/gfx/gfx_def.h +++ b/Common/gfx/gfx_def.h @@ -30,12 +30,13 @@ namespace AGS namespace Common { +// GraphicFlip tells how to flip (mirror) a sprite enum GraphicFlip { - kFlip_None, - kFlip_Horizontal, // this means - mirror over horizontal middle line - kFlip_Vertical, // this means - mirror over vertical middle line - kFlip_Both // mirror over diagonal (horizontal and vertical) + kFlip_None = 0x0, + kFlip_Horizontal = 0x1, // this means - mirror over horizontal middle line + kFlip_Vertical = 0x2, // this means - mirror over vertical middle line + kFlip_Both = (kFlip_Horizontal | kFlip_Vertical) // mirror over diagonal }; // Blend modes for object sprites diff --git a/Engine/ac/draw.cpp b/Engine/ac/draw.cpp index 5c56c46e6d2..3213ee927bd 100644 --- a/Engine/ac/draw.cpp +++ b/Engine/ac/draw.cpp @@ -1935,7 +1935,7 @@ void prepare_and_add_object_gfx( { actsp.Ddb->SetStretch(scale_size.Width, scale_size.Height); actsp.Ddb->SetRotation(objsav.rotation); - actsp.Ddb->SetFlippedLeftRight(objsav.mirrored); + actsp.Ddb->SetFlip(objsav.mirrored ? kFlip_Horizontal : kFlip_None); apply_tint_or_light_ddb(actsp, objsav.lightlev, objsav.tintamnt, objsav.tintr, objsav.tintg, objsav.tintb, objsav.tintlight); } diff --git a/Engine/gfx/ali3dogl.cpp b/Engine/gfx/ali3dogl.cpp index cc0d139fd7b..00d27d12cc9 100644 --- a/Engine/gfx/ali3dogl.cpp +++ b/Engine/gfx/ali3dogl.cpp @@ -1085,12 +1085,15 @@ void OGLGraphicsDriver::RenderTexture(OGLBitmap *bmpToDraw, int draw_x, int draw { width = txdata->_tiles[ti].width * xProportion; height = txdata->_tiles[ti].height * yProportion; - float xOffs; - float yOffs = txdata->_tiles[ti].y * yProportion; - if (bmpToDraw->_flipped) + float xOffs, yOffs; + if ((bmpToDraw->_flip & kFlip_Horizontal) != 0) xOffs = (bmpToDraw->_width - (txdata->_tiles[ti].x + txdata->_tiles[ti].width)) * xProportion; else xOffs = txdata->_tiles[ti].x * xProportion; + if ((bmpToDraw->_flip & kFlip_Vertical) != 0) + yOffs = (bmpToDraw->_height - (txdata->_tiles[ti].y + txdata->_tiles[ti].height)) * yProportion; + else + yOffs = txdata->_tiles[ti].y * yProportion; float thisX = draw_x + xOffs; float thisY = draw_y + yOffs; thisX = (-(rend_sz.Width / 2.0f)) + thisX; @@ -1099,7 +1102,7 @@ void OGLGraphicsDriver::RenderTexture(OGLBitmap *bmpToDraw, int draw_x, int draw //Setup translation and scaling matrices float widthToScale = width; float heightToScale = height; - if (bmpToDraw->_flipped) + if ((bmpToDraw->_flip & kFlip_Horizontal) != 0) { // The usual transform changes 0..1 into 0..width // So first negate it (which changes 0..w into -w..0) @@ -1107,9 +1110,14 @@ void OGLGraphicsDriver::RenderTexture(OGLBitmap *bmpToDraw, int draw_x, int draw // and now shift it over to make it 0..w again thisX += width; } + if ((bmpToDraw->_flip & kFlip_Vertical) != 0) + { + heightToScale = -heightToScale; + thisY -= height; + } // Apply sprite origin thisX -= abs(widthToScale) * bmpToDraw->_originX; - thisY += heightToScale * bmpToDraw->_originY; // inverse axis + thisY += abs(heightToScale) * bmpToDraw->_originY; // inverse axis // Setup rotation and pivot float rotZ = bmpToDraw->_rotation; float pivotX = -(widthToScale * 0.5), pivotY = (heightToScale * 0.5); diff --git a/Engine/gfx/ali3dogl.h b/Engine/gfx/ali3dogl.h index 64d222cd379..b8bd5f035df 100644 --- a/Engine/gfx/ali3dogl.h +++ b/Engine/gfx/ali3dogl.h @@ -81,28 +81,6 @@ class OGLBitmap : public BaseDDB { public: uint32_t GetRefID() const override { return _data->ID; } - - 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 = true) override - { - _stretchToWidth = width; - _stretchToHeight = height; - _useResampler = useResampler; - } - // Rotation is set in degrees, clockwise - void SetRotation(float degrees) override { _rotation = -Common::Math::DegreesToRadians(degrees); } - void SetLightLevel(int lightLevel) override { _lightLevel = lightLevel; } - void SetTint(int red, int green, int blue, int tintSaturation) override - { - _red = red; - _green = green; - _blue = blue; - _tintSaturation = tintSaturation; - } - void SetBlendMode(Common::BlendMode blendMode) override { _blendMode = blendMode; } - // Tells if this DDB has an actual render data assigned to it. bool IsValid() override { return _data != nullptr; } // Attaches new texture data, sets basic render rules @@ -119,45 +97,35 @@ class OGLBitmap : public BaseDDB _data = nullptr; } + // Rotation is set in degrees clockwise, stored converted to radians + void SetRotation(float degrees) override { _rotation = -Common::Math::DegreesToRadians(degrees); } + void SetLightLevel(int lightLevel) override { _lightLevel = lightLevel; } + void SetTint(int red, int green, int blue, int tintSaturation) override + { + _red = red; + _green = green; + _blue = blue; + _tintSaturation = tintSaturation; + } + // OpenGL texture data std::shared_ptr _data; // Optional frame buffer object (for rendering onto a texture) unsigned int _fbo {}; + // Render parameters TextureHint _renderHint = kTxHint_Normal; - - // Drawing parameters - bool _flipped; - int _stretchToWidth, _stretchToHeight; - float _rotation; - bool _useResampler; - int _red, _green, _blue; - int _tintSaturation; - int _lightLevel; - int _alpha; - Common::BlendMode _blendMode; + bool _useResampler = false; OGLBitmap(int width, int height, int colDepth, bool opaque) { _width = width; _height = height; _colDepth = colDepth; - _flipped = false; _stretchToWidth = width; _stretchToHeight = height; - _originX = _originY = 0.f; - _useResampler = false; - _rotation = 0; - _red = _green = _blue = 0; - _tintSaturation = 0; - _lightLevel = 0; - _alpha = 255; _opaque = opaque; - _blendMode = Common::kBlend_Normal; } - int GetWidthToRender() const { return _stretchToWidth; } - int GetHeightToRender() const { return _stretchToHeight; } - ~OGLBitmap() override; }; diff --git a/Engine/gfx/ali3dsw.h b/Engine/gfx/ali3dsw.h index d37a2c3e43f..0b9a5c698bb 100644 --- a/Engine/gfx/ali3dsw.h +++ b/Engine/gfx/ali3dsw.h @@ -47,22 +47,6 @@ 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; - } - int GetWidthToRender() { return _stretchToWidth; } - int GetHeightToRender() { return _stretchToHeight; } - // Rotation is set in degrees - void SetRotation(float rotation) override { _rotation = rotation; } - void SetLightLevel(int /*lightLevel*/) override { } - void SetTint(int /*red*/, int /*green*/, int /*blue*/, int /*tintSaturation*/) override { } - void SetBlendMode(Common::BlendMode blendMode) override { _blendMode = blendMode; } - // Tells if this DDB has an actual render data assigned to it. bool IsValid() override { return _bmp != nullptr; } // Attaches new texture data, sets basic render rules @@ -70,12 +54,13 @@ class ALSoftwareBitmap : public BaseDDB // Detach any internal texture data from this DDB, make this an empty object void DetachData() override { _bmp = nullptr; } + // Rotation is set in degrees clockwise + void SetRotation(float rotation) override { _rotation = rotation; } + // Software renderer expects DDBs to have tint already applied + 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; - float _rotation = 0.f; - int _alpha = 255; - Common::BlendMode _blendMode = Common::kBlend_Normal; ALSoftwareBitmap(int width, int height, int color_depth, bool opaque) { diff --git a/Engine/gfx/ddb.h b/Engine/gfx/ddb.h index bb8c0ca6dcf..be93b2944e7 100644 --- a/Engine/gfx/ddb.h +++ b/Engine/gfx/ddb.h @@ -73,7 +73,7 @@ class IDriverDependantBitmap // E.g. (0.0, 0.0) means the texture will be aligned to sprite's position by its // left-top corner, (0.5, 0.5) means the texture will be centered around sprite's pos. virtual void SetOrigin(float originx, float originy) = 0; - virtual void SetFlippedLeftRight(bool isFlipped) = 0; + virtual void SetFlip(Common::GraphicFlip flip) = 0; virtual void SetStretch(int width, int height, bool useResampler = true) = 0; virtual void SetRotation(float rotation) = 0; // degrees virtual int GetAlpha() const = 0; diff --git a/Engine/gfx/gfxdriverbase.h b/Engine/gfx/gfxdriverbase.h index e96c464c99e..3539375c429 100644 --- a/Engine/gfx/gfxdriverbase.h +++ b/Engine/gfx/gfxdriverbase.h @@ -215,10 +215,32 @@ class BaseDDB : public IDriverDependantBitmap return _width == other->GetWidth() && _height == other->GetHeight() && _colDepth == other->GetColorDepth(); } + int GetAlpha() const override { return _alpha; } + void SetAlpha(int alpha) override { _alpha = alpha; } + void SetFlip(Common::GraphicFlip flip) override { _flip = flip; } + void SetStretch(int width, int height, bool /*useResampler*/) override + { + _stretchToWidth = width; + _stretchToHeight = height; + } + int GetWidthToRender() const { return _stretchToWidth; } + int GetHeightToRender() const { return _stretchToHeight; } + // Rotation input is in degrees clockwise, but the implementation may store it in radians internally + void SetRotation(float rotation) override { _rotation = rotation; } + void SetBlendMode(Common::BlendMode blendMode) override { _blendMode = blendMode; } + int _width = 0, _height = 0; float _originX = 0.f, _originY = 0.f; int _colDepth = 0; bool _opaque = false; // no mask color + Common::GraphicFlip _flip = Common::kFlip_None; + int _stretchToWidth = 0, _stretchToHeight = 0; + float _rotation = 0.f; // either in degrees or radians, depending on impl + int _alpha = 255; + Common::BlendMode _blendMode = Common::kBlend_Normal; + int _red = 0, _green = 0, _blue = 0; + int _tintSaturation = 0; + int _lightLevel = 0; protected: BaseDDB() = default; diff --git a/Engine/platform/windows/gfx/ali3dd3d.cpp b/Engine/platform/windows/gfx/ali3dd3d.cpp index 99811aa94e9..041f0027819 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.cpp +++ b/Engine/platform/windows/gfx/ali3dd3d.cpp @@ -1182,12 +1182,15 @@ void D3DGraphicsDriver::RenderTexture(D3DBitmap *bmpToDraw, int draw_x, int draw { width = txdata->_tiles[ti].width * xProportion; height = txdata->_tiles[ti].height * yProportion; - float xOffs; - float yOffs = txdata->_tiles[ti].y * yProportion; - if (bmpToDraw->_flipped) + float xOffs, yOffs; + if ((bmpToDraw->_flip & kFlip_Horizontal) != 0) xOffs = (bmpToDraw->_width - (txdata->_tiles[ti].x + txdata->_tiles[ti].width)) * xProportion; else xOffs = txdata->_tiles[ti].x * xProportion; + if ((bmpToDraw->_flip & kFlip_Vertical) != 0) + yOffs = (bmpToDraw->_height - (txdata->_tiles[ti].y + txdata->_tiles[ti].height)) * yProportion; + else + yOffs = txdata->_tiles[ti].y * yProportion; float thisX = draw_x + xOffs; float thisY = draw_y + yOffs; thisX = (-(rend_sz.Width / 2.0f)) + thisX; @@ -1196,7 +1199,7 @@ void D3DGraphicsDriver::RenderTexture(D3DBitmap *bmpToDraw, int draw_x, int draw //Setup translation and scaling matrices float widthToScale = width; float heightToScale = height; - if (bmpToDraw->_flipped) + if ((bmpToDraw->_flip & kFlip_Horizontal) != 0) { // The usual transform changes 0..1 into 0..width // So first negate it (which changes 0..w into -w..0) @@ -1204,9 +1207,14 @@ void D3DGraphicsDriver::RenderTexture(D3DBitmap *bmpToDraw, int draw_x, int draw // and now shift it over to make it 0..w again thisX += width; } + if ((bmpToDraw->_flip & kFlip_Vertical) != 0) + { + heightToScale = -heightToScale; + thisY -= height; // inverse axis + } // Apply sprite origin thisX -= abs(widthToScale) * bmpToDraw->_originX; - thisY += heightToScale * bmpToDraw->_originY; // inverse axis + thisY += abs(heightToScale) * bmpToDraw->_originY; // inverse axis // Setup rotation and pivot float rotZ = bmpToDraw->_rotation; float pivotX = -(widthToScale * 0.5), pivotY = (heightToScale * 0.5); diff --git a/Engine/platform/windows/gfx/ali3dd3d.h b/Engine/platform/windows/gfx/ali3dd3d.h index 552d1ca5e4b..f7b56fc2956 100644 --- a/Engine/platform/windows/gfx/ali3dd3d.h +++ b/Engine/platform/windows/gfx/ali3dd3d.h @@ -82,30 +82,6 @@ class D3DBitmap : public BaseDDB { public: uint32_t GetRefID() const override { return _data->ID; } - - 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 = true) override - { - _stretchToWidth = width; - _stretchToHeight = height; - _useResampler = useResampler; - } - int GetWidthToRender() { return _stretchToWidth; } - int GetHeightToRender() { return _stretchToHeight; } - // Rotation is set in degrees, clockwise - void SetRotation(float degrees) override { _rotation = -Common::Math::DegreesToRadians(degrees); } - void SetLightLevel(int lightLevel) override { _lightLevel = lightLevel; } - void SetTint(int red, int green, int blue, int tintSaturation) override - { - _red = red; - _green = green; - _blue = blue; - _tintSaturation = tintSaturation; - } - void SetBlendMode(Common::BlendMode blendMode) override { _blendMode = blendMode; } - // Tells if this DDB has an actual render data assigned to it. bool IsValid() override { return _data != nullptr; } // Attaches new texture data, sets basic render rules @@ -122,46 +98,38 @@ class D3DBitmap : public BaseDDB { _data = nullptr; } + // Releases internal texture data only, keeping the base struct + void ReleaseTextureData(); + + // Rotation is set in degrees clockwise, stored converted to radians + void SetRotation(float degrees) override { _rotation = -Common::Math::DegreesToRadians(degrees); } + void SetLightLevel(int lightLevel) override { _lightLevel = lightLevel; } + void SetTint(int red, int green, int blue, int tintSaturation) override + { + _red = red; + _green = green; + _blue = blue; + _tintSaturation = tintSaturation; + } // Direct3D texture data std::shared_ptr _data; // Optional surface for rendering onto a texture D3DSurfacePtr _renderSurface; + // Render parameters TextureHint _renderHint = kTxHint_Normal; - - // Drawing parameters - bool _flipped; - int _stretchToWidth, _stretchToHeight; - float _rotation; - bool _useResampler; - int _red, _green, _blue; - int _tintSaturation; - int _lightLevel; - int _alpha; - Common::BlendMode _blendMode; + bool _useResampler = false; D3DBitmap(int width, int height, int colDepth, bool opaque) { _width = width; _height = height; _colDepth = colDepth; - _flipped = false; _stretchToWidth = width; _stretchToHeight = height; - _originX = _originY = 0.f; - _useResampler = false; - _rotation = 0; - _red = _green = _blue = 0; - _tintSaturation = 0; - _lightLevel = 0; - _alpha = 255; _opaque = opaque; - _blendMode = Common::kBlend_Normal; } - // Releases internal texture data only, keeping the base struct - void ReleaseTextureData(); - ~D3DBitmap() override = default; }; From af2f8897d1fc2ac8e07c58bc1f0acdf30a8e8d9c Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 13 Dec 2024 03:44:54 +0300 Subject: [PATCH 2/5] Engine: store multiple flip flags in ViewFrame, and related variables --- Common/ac/view.cpp | 14 +------------ Common/ac/view.h | 17 ++++++++-------- Common/gfx/gfx_def.h | 33 +++++++++++++++++++++++++++++++ Common/gui/guibutton.cpp | 17 ++++++++-------- Common/gui/guibutton.h | 8 ++++---- Common/gui/guimain.h | 4 ++-- Engine/ac/button.cpp | 2 +- Engine/ac/character.cpp | 4 ++-- Engine/ac/draw.cpp | 39 +++++++++++++++++++------------------ Engine/ac/draw.h | 4 ++-- Engine/ac/global_object.cpp | 6 +++--- Engine/ac/object.cpp | 6 ++++-- Engine/ac/object.h | 2 +- Engine/ac/viewframe.cpp | 11 ++++++----- 14 files changed, 95 insertions(+), 72 deletions(-) diff --git a/Common/ac/view.cpp b/Common/ac/view.cpp index 774b3ce587b..0d98ed216c1 100644 --- a/Common/ac/view.cpp +++ b/Common/ac/view.cpp @@ -17,18 +17,6 @@ using namespace AGS::Common; -ViewFrame::ViewFrame() - : pic(0) - , xoffs(0) - , yoffs(0) - , speed(0) - , flags(0) - , sound(-1) -{ - reserved_for_future[0] = 0; - reserved_for_future[1] = 0; -} - void ViewFrame::ReadFromFile(Stream *in) { pic = in->ReadInt32(); @@ -36,7 +24,7 @@ void ViewFrame::ReadFromFile(Stream *in) yoffs = in->ReadInt16(); speed = in->ReadInt16(); in->ReadInt16(); // alignment padding to int32 - flags = in->ReadInt32(); + flags = (SpriteTransformFlags)in->ReadInt32(); sound = in->ReadInt32(); in->ReadInt32(); // reserved 1 in->ReadInt32(); // reserved 1 diff --git a/Common/ac/view.h b/Common/ac/view.h index 05d7227ec50..1240d12854f 100644 --- a/Common/ac/view.h +++ b/Common/ac/view.h @@ -15,20 +15,19 @@ #define __AC_VIEW_H #include +#include "gfx/gfx_def.h" namespace AGS { namespace Common { class Stream; } } using namespace AGS; // FIXME later -#define VFLG_FLIPSPRITE 1 - struct ViewFrame { - int pic; - short xoffs, yoffs; - short speed; - int flags; // VFLG_* flags - int sound; // play sound when this frame comes round - int reserved_for_future[2]; // kept only for plugin api - ViewFrame(); + int pic = 0; + short xoffs = 0, yoffs = 0; + short speed = 0; + Common::SpriteTransformFlags flags = Common::kSprTf_None; + int sound = -1; // play sound when this frame comes round + int reserved_for_future[2] = { 0 }; // kept only for plugin api // CLNUP: may remove in ags4? + ViewFrame() = default; void ReadFromFile(Common::Stream *in); void WriteToFile(Common::Stream *out); diff --git a/Common/gfx/gfx_def.h b/Common/gfx/gfx_def.h index bbd706dbbd4..feb68402e2f 100644 --- a/Common/gfx/gfx_def.h +++ b/Common/gfx/gfx_def.h @@ -55,6 +55,16 @@ enum BlendMode kNumBlendModes }; +// SpriteTransformFlags combine graphic effect options that do not have a value. +// These may be used both to store these options in memory and in serialization. +enum SpriteTransformFlags +{ + kSprTf_None = 0x0000, + kSprTf_FlipX = 0x0001, + kSprTf_FlipY = 0x0002, + kSprTf_FlipXY = (kSprTf_FlipX | kSprTf_FlipY), +}; + // GraphicResolution struct determines image size and color depth struct GraphicResolution : Size { @@ -125,6 +135,29 @@ class GraphicSpace namespace GfxDef { + inline bool FlagsHaveFlip(SpriteTransformFlags flags) + { + return (flags & kSprTf_FlipXY) != 0; + } + + inline GraphicFlip GetFlipFromFlags(SpriteTransformFlags flags) + { + switch (flags & kSprTf_FlipXY) + { + case kSprTf_FlipX: return kFlip_Horizontal; + case kSprTf_FlipY: return kFlip_Vertical; + case kSprTf_FlipXY: return kFlip_Both; + default: return kFlip_None; + } + } + + inline SpriteTransformFlags GetFlagsFromFlip(GraphicFlip flip) + { + return (SpriteTransformFlags)( + kSprTf_FlipX * ((flip & kFlip_Horizontal) != 0) + | kSprTf_FlipY * ((flip & kFlip_Vertical) != 0)); + } + // Converts value from range of 100 to range of 250 (sic!); // uses formula that reduces precision loss and supports flawless forth & // reverse conversion for multiplies of 10% diff --git a/Common/gui/guibutton.cpp b/Common/gui/guibutton.cpp index d886c2c6f43..3141ebc6a18 100644 --- a/Common/gui/guibutton.cpp +++ b/Common/gui/guibutton.cpp @@ -31,9 +31,9 @@ GUIButton::GUIButton() _image = -1; _mouseOverImage = -1; _pushedImage = -1; - _imageFlags = 0; + _imageFlags = kSprTf_None; _currentImage = -1; - _curImageFlags = 0; + _curImageFlags = kSprTf_None; Font = 0; TextColor = 0; TextAlignment = kAlignTopCenter; @@ -215,7 +215,7 @@ void GUIButton::SetPushedImage(int32_t image) UpdateCurrentImage(); } -void GUIButton::SetImages(int32_t normal, int32_t over, int32_t pushed, uint32_t flags) +void GUIButton::SetImages(int32_t normal, int32_t over, int32_t pushed, SpriteTransformFlags flags) { _image = normal; _mouseOverImage = over; @@ -229,7 +229,7 @@ int32_t GUIButton::CurrentImage() const return _currentImage; } -void GUIButton::SetCurrentImage(int32_t new_image, uint32_t flags) +void GUIButton::SetCurrentImage(int32_t new_image, SpriteTransformFlags flags) { if (_currentImage == new_image && _curImageFlags == flags) return; @@ -312,7 +312,7 @@ void GUIButton::OnMouseUp() void GUIButton::UpdateCurrentImage() { int new_image = _currentImage; - uint32_t new_flags = 0; + SpriteTransformFlags new_flags = kSprTf_None; if (IsPushed && (_pushedImage > 0)) { @@ -399,11 +399,11 @@ void GUIButton::ReadFromSavegame(Stream *in, GuiSvgVersion svg_ver) if (svg_ver >= kGuiSvgVersion_400) { - _imageFlags = in->ReadInt32(); + _imageFlags = (SpriteTransformFlags)in->ReadInt32(); } else { - _imageFlags = 0; + _imageFlags = kSprTf_None; } // Update current state after reading @@ -430,7 +430,6 @@ void GUIButton::WriteToSavegame(Stream *out) const out->WriteInt32(0); //since kGuiSvgVersion_3991 out->WriteInt32(_imageFlags); - } void GUIButton::DrawImageButton(Bitmap *ds, int x, int y, bool draw_disabled) @@ -447,7 +446,7 @@ void GUIButton::DrawImageButton(Bitmap *ds, int x, int y, bool draw_disabled) ds->SetClip(RectWH(x, y, _width, _height)); if (spriteset.DoesSpriteExist(_currentImage)) - draw_gui_sprite_flipped(ds, _currentImage, x, y, kBlend_Normal, _curImageFlags & VFLG_FLIPSPRITE); + draw_gui_sprite_flipped(ds, _currentImage, x, y, kBlend_Normal, GfxDef::GetFlipFromFlags(_curImageFlags)); // Draw active inventory item const int gui_inv_pic = GUI::Context.InventoryPic; diff --git a/Common/gui/guibutton.h b/Common/gui/guibutton.h index a91695478b7..b97a49868e1 100644 --- a/Common/gui/guibutton.h +++ b/Common/gui/guibutton.h @@ -71,11 +71,11 @@ class GUIButton : public GUIObject Rect CalcGraphicRect(bool clipped) override; void Draw(Bitmap *ds, int x = 0, int y = 0) override; void SetClipImage(bool on); - void SetCurrentImage(int32_t image, uint32_t flags = 0); + void SetCurrentImage(int32_t image, SpriteTransformFlags flags = kSprTf_None); void SetMouseOverImage(int32_t image); void SetNormalImage(int32_t image); void SetPushedImage(int32_t image); - void SetImages(int32_t normal, int32_t over, int32_t pushed, uint32_t flags = 0); + void SetImages(int32_t normal, int32_t over, int32_t pushed, SpriteTransformFlags flags = kSprTf_None); void SetText(const String &text); void SetWrapText(bool on); @@ -118,10 +118,10 @@ class GUIButton : public GUIObject int32_t _mouseOverImage; int32_t _pushedImage; // TODO: flags for each kind of image? - uint32_t _imageFlags; + SpriteTransformFlags _imageFlags; // Active displayed image int32_t _currentImage; - uint32_t _curImageFlags; + SpriteTransformFlags _curImageFlags; // Text property set by user String _text; // type of content placeholder, if any diff --git a/Common/gui/guimain.h b/Common/gui/guimain.h index 330be3c79f1..828687d0f6f 100644 --- a/Common/gui/guimain.h +++ b/Common/gui/guimain.h @@ -378,9 +378,9 @@ extern void draw_gui_sprite(AGS::Common::Bitmap *ds, int x, int y, AGS::Common::Bitmap *image, AGS::Common::BlendMode blend_mode, int alpha); -extern void draw_gui_sprite_flipped(AGS::Common::Bitmap *ds, int pic, int x, int y, AGS::Common::BlendMode blend_mode, bool is_flipped); +extern void draw_gui_sprite_flipped(AGS::Common::Bitmap *ds, int pic, int x, int y, AGS::Common::BlendMode blend_mode, AGS::Common::GraphicFlip flip); extern void draw_gui_sprite_flipped(AGS::Common::Bitmap *ds, int x, int y, - AGS::Common::Bitmap *image, AGS::Common::BlendMode blend_mode, int alpha, bool is_flipped); + AGS::Common::Bitmap *image, AGS::Common::BlendMode blend_mode, int alpha, AGS::Common::GraphicFlip flip); // Those function have distinct implementations in Engine and Editor extern void wouttext_outline(AGS::Common::Bitmap *ds, int xxp, int yyp, int usingfont, color_t text_color, const char *texx); diff --git a/Engine/ac/button.cpp b/Engine/ac/button.cpp index f5357be28bd..0b3b3bbf521 100644 --- a/Engine/ac/button.cpp +++ b/Engine/ac/button.cpp @@ -41,7 +41,7 @@ void UpdateButtonState(const AnimatingGUIButton &abtn) { // Assign view frame as normal image and reset all the rest int image = views[abtn.view].loops[abtn.loop].frames[abtn.frame].pic; - uint32_t flags = views[abtn.view].loops[abtn.loop].frames[abtn.frame].flags; + SpriteTransformFlags flags = views[abtn.view].loops[abtn.loop].frames[abtn.frame].flags; guibuts[abtn.buttonid].SetImages( views[abtn.view].loops[abtn.loop].frames[abtn.frame].pic, 0, 0, flags); } diff --git a/Engine/ac/character.cpp b/Engine/ac/character.cpp index 7a7842b03fd..3e0e1a9e9ed 100644 --- a/Engine/ac/character.cpp +++ b/Engine/ac/character.cpp @@ -2412,12 +2412,12 @@ int is_pos_on_character(int xx,int yy) { int usewid = game.SpriteInfos[sppic].Width; int usehit = game.SpriteInfos[sppic].Height; // TODO: support mirrored transformation in GraphicSpace - int mirrored = views[chin->view].loops[chin->loop].frames[chin->frame].flags & VFLG_FLIPSPRITE; + SpriteTransformFlags sprite_flags = views[chin->view].loops[chin->loop].frames[chin->frame].flags; Bitmap *theImage = GetCharacterSourceImage(cc); // Convert to local object coordinates Point local = charextra[cc].GetGraphicSpace().WorldToLocal(xx, yy); if (is_pos_in_sprite(local.X, local.Y, 0, 0, theImage, - usewid, usehit, mirrored) == FALSE) + usewid, usehit, sprite_flags) == FALSE) continue; int use_base = chin->get_baseline(); diff --git a/Engine/ac/draw.cpp b/Engine/ac/draw.cpp index 3213ee927bd..c0874560339 100644 --- a/Engine/ac/draw.cpp +++ b/Engine/ac/draw.cpp @@ -195,15 +195,15 @@ struct ObjectCache short tintr = 0, tintg = 0, tintb = 0, tintamnt = 0, tintlight = 0; short lightlev = 0, zoom = 0; float rotation = 0.f; - bool mirrored = 0; + GraphicFlip flip = kFlip_None; int x = 0, y = 0; ObjectCache() = default; ObjectCache(int pic_, int tintr_, int tintg_, int tintb_, int tint_amnt_, int tint_light_, - int light_, int zoom_, float rotation_, bool mirror_, int posx_, int posy_) + int light_, int zoom_, float rotation_, GraphicFlip flip_, int posx_, int posy_) : sppic(pic_), tintr(tintr_), tintg(tintg_), tintb(tintb_) , tintamnt(tint_amnt_), tintlight(tint_light_), lightlev(light_) - , zoom(zoom_), rotation(rotation_), mirrored(mirror_), x(posx_), y(posy_) { } + , zoom(zoom_), rotation(rotation_), flip(flip_), x(posx_), y(posy_) { } }; // @@ -1368,23 +1368,24 @@ void draw_gui_sprite(Bitmap *ds, int x, int y, Bitmap *sprite, BlendMode blend_m } } -void draw_gui_sprite_flipped(Bitmap *ds, int pic, int x, int y, BlendMode blend_mode, bool is_flipped) +void draw_gui_sprite_flipped(Bitmap *ds, int pic, int x, int y, BlendMode blend_mode, GraphicFlip flip) { draw_gui_sprite_flipped(ds, x, y, spriteset[pic], - blend_mode, 0xFF, is_flipped); + blend_mode, 0xFF, flip); } void draw_gui_sprite_flipped(Bitmap *ds, int x, int y, Bitmap *sprite, - BlendMode blend_mode, int alpha, bool is_flipped) + BlendMode blend_mode, int alpha, GraphicFlip flip) { if (alpha <= 0) return; std::unique_ptr tempspr; - if (is_flipped) { + if (flip != kFlip_None) + { tempspr.reset(new Bitmap(sprite->GetWidth(), sprite->GetHeight(), sprite->GetColorDepth())); tempspr->ClearTransparent(); - tempspr->FlipBlt(sprite, 0, 0, Common::kFlip_Horizontal); + tempspr->FlipBlt(sprite, 0, 0, flip); sprite = tempspr.get(); } @@ -1665,9 +1666,9 @@ static Bitmap *transform_sprite(Bitmap *src, std::unique_ptr &dst, } recycle_bitmap(dst, src->GetColorDepth(), dst_sz.Width, dst_sz.Height, true); - // If scaled: first scale then optionally mirror if (src->GetSize() != dst_sz) { + // If scaled: first scale then optionally flip // 8-bit support: ensure that anti-aliasing routines have a palette // to use for mapping while faded out. // FIXME: investigate if this may be moved out and not repeated, or at least passed as a parameter! @@ -1764,11 +1765,11 @@ static bool construct_object_gfx(const ViewFrame *vf, int pic, } // check whether the image should be flipped - bool is_mirrored = false; + GraphicFlip use_flip = kFlip_None; int specialpic = pic; - if (vf && (vf->pic == pic) && ((vf->flags & VFLG_FLIPSPRITE) != 0)) + if (vf && (vf->pic == pic) && GfxDef::FlagsHaveFlip(vf->flags)) { - is_mirrored = true; + use_flip = GfxDef::GetFlipFromFlags(vf->flags); specialpic = -pic; } @@ -1789,7 +1790,7 @@ static bool construct_object_gfx(const ViewFrame *vf, int pic, objsav.lightlev = light_level; objsav.zoom = objsrc.zoom; objsav.rotation = objsrc.rotation; - objsav.mirrored = is_mirrored; + objsav.flip = use_flip; return is_texture_intact; } @@ -1815,7 +1816,7 @@ static bool construct_object_gfx(const ViewFrame *vf, int pic, (objsav.lightlev == light_level) && (objsav.zoom == objsrc.zoom) && (objsav.rotation == objsrc.rotation) && - (objsav.mirrored == is_mirrored)) + (objsav.flip == use_flip)) { // If the image is the same, we can use it cached if ((drawstate.WalkBehindMethod != DrawOverCharSprite) && @@ -1844,7 +1845,7 @@ static bool construct_object_gfx(const ViewFrame *vf, int pic, const int src_sprwidth = sprite->GetWidth(); const int src_sprheight = sprite->GetHeight(); // draw the base sprite, scaled and flipped as appropriate - bool actsps_used = transform_sprite(actsp, pic, scale_size, objsrc.rotation, is_mirrored ? kFlip_Horizontal : kFlip_None); + bool actsps_used = transform_sprite(actsp, pic, scale_size, objsrc.rotation, use_flip); if (!actsps_used) { // ensure actsps exists // CHECKME: why do we need this in hardware accel mode too? @@ -1882,7 +1883,7 @@ static bool construct_object_gfx(const ViewFrame *vf, int pic, objsav.lightlev = light_level; objsav.zoom = objsrc.zoom; objsav.rotation = objsrc.rotation; - objsav.mirrored = is_mirrored; + objsav.flip = use_flip; objsav.x = objsrc.x; objsav.y = objsrc.y; return false; // image was modified @@ -1935,7 +1936,7 @@ void prepare_and_add_object_gfx( { actsp.Ddb->SetStretch(scale_size.Width, scale_size.Height); actsp.Ddb->SetRotation(objsav.rotation); - actsp.Ddb->SetFlip(objsav.mirrored ? kFlip_Horizontal : kFlip_None); + actsp.Ddb->SetFlip(objsav.flip); apply_tint_or_light_ddb(actsp, objsav.lightlev, objsav.tintamnt, objsav.tintr, objsav.tintg, objsav.tintb, objsav.tintlight); } @@ -1954,7 +1955,7 @@ bool construct_object_gfx(int objid, bool force_software) ObjectCache objsrc(obj.num, obj.tint_r, obj.tint_g, obj.tint_b, obj.tint_level, obj.tint_light, 0 /* skip */, obj.zoom, obj.rotation, - false /* skip */, obj.x, obj.y); + kFlip_None /* skip */, obj.x, obj.y); return construct_object_gfx( (obj.view != UINT16_MAX) ? &views[obj.view].loops[obj.loop].frames[obj.frame] : nullptr, @@ -2064,7 +2065,7 @@ bool construct_char_gfx(int charid, bool force_software) ObjectCache chsrc(pic, chex.tint_r, chex.tint_g, chex.tint_b, chex.tint_level, chex.tint_light, 0 /* skip */, chex.zoom, chex.rotation, - false /* skip */, chin.x, chin.y); + kFlip_None /* skip */, chin.x, chin.y); return construct_object_gfx( vf, diff --git a/Engine/ac/draw.h b/Engine/ac/draw.h index 3a1161a09cd..1f57c26990d 100644 --- a/Engine/ac/draw.h +++ b/Engine/ac/draw.h @@ -157,9 +157,9 @@ void draw_sprite_slot_support_alpha(Common::Bitmap *ds, int xpos, int ypos, int void draw_gui_sprite(Common::Bitmap *ds, int pic, int x, int y, Common::BlendMode blend_mode); void draw_gui_sprite(Common::Bitmap *ds, int xpos, int ypos, Common::Bitmap *image, Common::BlendMode blend_mode = Common::kBlend_Normal, int alpha = 0xFF); -void draw_gui_sprite_flipped(Common::Bitmap *ds, int pic, int x, int y, Common::BlendMode blend_mode, bool is_flipped); +void draw_gui_sprite_flipped(Common::Bitmap *ds, int pic, int x, int y, Common::BlendMode blend_mode, AGS::Common::GraphicFlip flip); void draw_gui_sprite_flipped(Common::Bitmap *ds, int xpos, int ypos, - Common::Bitmap *image, Common::BlendMode blend_mode = Common::kBlend_Normal, int alpha = 0xFF, bool is_flipped = false); + Common::Bitmap *image, Common::BlendMode blend_mode = Common::kBlend_Normal, int alpha = 0xFF, AGS::Common::GraphicFlip flip = AGS::Common::kFlip_None); // Render game on screen void render_to_screen(); diff --git a/Engine/ac/global_object.cpp b/Engine/ac/global_object.cpp index 18d4d0c6a35..e226041f9cc 100644 --- a/Engine/ac/global_object.cpp +++ b/Engine/ac/global_object.cpp @@ -78,18 +78,18 @@ int GetObjectIDAtRoom(int roomx, int roomy) if (objs[aa].flags & OBJF_NOINTERACT) continue; int xxx=objs[aa].x,yyy=objs[aa].y; - int isflipped = 0; + SpriteTransformFlags sprite_flags = kSprTf_None; int spWidth = objs[aa].get_width(); int spHeight = objs[aa].get_height(); // TODO: support mirrored transformation in GraphicSpace if (objs[aa].view != RoomObject::NoView) - isflipped = views[objs[aa].view].loops[objs[aa].loop].frames[objs[aa].frame].flags & VFLG_FLIPSPRITE; + sprite_flags = views[objs[aa].view].loops[objs[aa].loop].frames[objs[aa].frame].flags; Bitmap *theImage = GetObjectSourceImage(aa); // Convert to local object coordinates Point local = objs[aa].GetGraphicSpace().WorldToLocal(roomx, roomy); if (is_pos_in_sprite(local.X, local.Y, 0, 0, theImage, - spWidth, spHeight, isflipped) == FALSE) + spWidth, spHeight, sprite_flags) == FALSE) continue; int usebasel = objs[aa].get_baseline(); diff --git a/Engine/ac/object.cpp b/Engine/ac/object.cpp index a410d8eefec..c4585ec1730 100644 --- a/Engine/ac/object.cpp +++ b/Engine/ac/object.cpp @@ -701,7 +701,7 @@ int isposinbox(int mmx,int mmy,int lf,int tp,int rt,int bt) { // arx,ary,spww,sphh are the sprite's bounding box // bitmap_original tells whether bitmap is an original sprite, or transformed version int is_pos_in_sprite(int xx, int yy, int arx, int ary, Bitmap *sprit, - int spww, int sphh, int flipped) { + int spww, int sphh, Common::SpriteTransformFlags sprite_flags) { if (spww==0) spww = sprit->GetWidth() - 1; if (sphh==0) sphh = sprit->GetHeight() - 1; @@ -714,8 +714,10 @@ int is_pos_in_sprite(int xx, int yy, int arx, int ary, Bitmap *sprit, int xpos = xx - arx; int ypos = yy - ary; - if (flipped) + if (sprite_flags & kSprTf_FlipX) xpos = (sprit->GetWidth() - 1) - xpos; + if (sprite_flags & kSprTf_FlipY) + ypos = (sprit->GetHeight() - 1) - ypos; int gpcol = my_getpixel(sprit, xpos, ypos); diff --git a/Engine/ac/object.h b/Engine/ac/object.h index d3f5e21460c..1f1dda10706 100644 --- a/Engine/ac/object.h +++ b/Engine/ac/object.h @@ -93,7 +93,7 @@ int isposinbox(int mmx,int mmy,int lf,int tp,int rt,int bt); // arx,ary,spww,sphh are the sprite's bounding box (including sprite scaling); // bitmap_original tells whether bitmap is an original sprite, or transformed version int is_pos_in_sprite(int xx, int yy, int arx, int ary, - Common::Bitmap *sprit, int spww, int sphh, int flipped); + Common::Bitmap *sprit, int spww, int sphh, Common::SpriteTransformFlags sprite_flags); // X and Y co-ordinates must be in native format // X and Y are ROOM coordinates int check_click_on_object(int roomx, int roomy, int mood); diff --git a/Engine/ac/viewframe.cpp b/Engine/ac/viewframe.cpp index 0bab22f5055..38c8c40724e 100644 --- a/Engine/ac/viewframe.cpp +++ b/Engine/ac/viewframe.cpp @@ -32,7 +32,8 @@ extern CCAudioClip ccDynamicAudioClip; int ViewFrame_GetFlipped(ScriptViewFrame *svf) { - if (views[svf->view].loops[svf->loop].frames[svf->frame].flags & VFLG_FLIPSPRITE) + // TODO: can return GraphicFlip here, because old boolean value matches horizontal flip + if ((views[svf->view].loops[svf->loop].frames[svf->frame].flags & kSprTf_FlipX) != 0) return 1; return 0; } @@ -126,10 +127,10 @@ void DrawViewFrame(Bitmap *ds, const ViewFrame *vframe, int x, int y) if ((ds->GetColorDepth() == 32) && (vf_bmp->GetColorDepth() == 32)) { Bitmap *src = vf_bmp; - if (vframe->flags & VFLG_FLIPSPRITE) + if (GfxDef::FlagsHaveFlip(vframe->flags)) { src = new Bitmap(vf_bmp->GetWidth(), vf_bmp->GetHeight(), vf_bmp->GetColorDepth()); - src->FlipBlt(vf_bmp, 0, 0, Common::kFlip_Horizontal); + src->FlipBlt(vf_bmp, 0, 0, GfxDef::GetFlipFromFlags(vframe->flags)); } draw_sprite_support_alpha(ds, x, y, src); if (src != vf_bmp) @@ -137,8 +138,8 @@ void DrawViewFrame(Bitmap *ds, const ViewFrame *vframe, int x, int y) } else { - if (vframe->flags & VFLG_FLIPSPRITE) - ds->FlipBlt(vf_bmp, x, y, Common::kFlip_Horizontal); + if (GfxDef::FlagsHaveFlip(vframe->flags)) + ds->FlipBlt(vf_bmp, x, y, GfxDef::GetFlipFromFlags(vframe->flags)); else ds->Blit(vf_bmp, x, y, Common::kBitmap_Transparency); } From 97edec4a659c42fe2e89909f0a51d7b1ceb4325d Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 13 Dec 2024 03:54:19 +0300 Subject: [PATCH 3/5] AGS.Native: fix after removing VFLG_FLIPSPRITE --- Editor/AGS.Native/NativeMethods.cpp | 2 +- Editor/AGS.Native/agsnative.cpp | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Editor/AGS.Native/NativeMethods.cpp b/Editor/AGS.Native/NativeMethods.cpp index 8544fbf4da6..bbcacdfacd8 100644 --- a/Editor/AGS.Native/NativeMethods.cpp +++ b/Editor/AGS.Native/NativeMethods.cpp @@ -683,7 +683,7 @@ namespace AGS return bytes; } if (name->Equals("LOOPFLAG_RUNNEXTLOOP")) return LOOPFLAG_RUNNEXTLOOP; - if (name->Equals("VFLG_FLIPSPRITE")) return VFLG_FLIPSPRITE; + if (name->Equals("VFLG_FLIPSPRITE")) return (int)Common::kSprTf_FlipX; if (name->Equals("GUIMAGIC")) return GUIMAGIC; if (name->Equals("SAVEBUFFERSIZE")) return PLUGIN_SAVEBUFFERSIZE; if (name->Equals("GUIMAIN_CLICKABLE")) return (int)Common::kGUIMain_Clickable; diff --git a/Editor/AGS.Native/agsnative.cpp b/Editor/AGS.Native/agsnative.cpp index 389c20521dd..52c8a97ec55 100644 --- a/Editor/AGS.Native/agsnative.cpp +++ b/Editor/AGS.Native/agsnative.cpp @@ -566,12 +566,12 @@ void draw_gui_sprite(Common::Bitmap *g, int atxp, int atyp, draw_gui_sprite_impl(g, -1, blptr, atxp, atyp); } -void draw_gui_sprite_flipped(Common::Bitmap *ds, int pic, int x, int y, Common::BlendMode blend_mode, bool is_flipped) +void draw_gui_sprite_flipped(Common::Bitmap *ds, int pic, int x, int y, Common::BlendMode blend_mode, Common::GraphicFlip flip) { draw_gui_sprite_impl(ds, pic, get_sprite(pic), x, y); } void draw_gui_sprite_flipped(Common::Bitmap *ds, int x, int y, - Common::Bitmap *image, Common::BlendMode blend_mode, int alpha, bool is_flipped) + Common::Bitmap *image, Common::BlendMode blend_mode, int alpha, Common::GraphicFlip flip) { draw_gui_sprite_impl(ds, -1, image, x, y); } @@ -765,12 +765,12 @@ static void doDrawViewLoop(HDC hdc, const std::vector<::ViewFrame> &frames, bmpbuf->Blit (toblt, 0, 0, 0, 0, toblt->GetWidth(), toblt->GetHeight()); toblt = bmpbuf.get(); } - if (frames[i].flags & VFLG_FLIPSPRITE) + if (Common::GfxDef::FlagsHaveFlip(frames[i].flags)) { // Flipped bitmap? mirror the sprite AGSBitmap *flipped = Common::BitmapHelper::CreateBitmap (toblt->GetWidth(), toblt->GetHeight(), todraw->GetColorDepth ()); flipped->Clear (flipped->GetMaskColor ()); - flipped->FlipBlt(toblt, 0, 0, Common::kFlip_Horizontal); + flipped->FlipBlt(toblt, 0, 0, Common::GfxDef::GetFlipFromFlags(frames[i].flags)); bmpbuf.reset(flipped); toblt = flipped; } @@ -1658,7 +1658,7 @@ void drawViewLoop (HDC hdc, ViewLoop^ loopToDraw, int x, int y, int size, ListFrames->Count; ++i) { frames[i].pic = loopToDraw->Frames[i]->Image; - frames[i].flags = (loopToDraw->Frames[i]->Flipped) ? VFLG_FLIPSPRITE : 0; + frames[i].flags = (loopToDraw->Frames[i]->Flipped) ? Common::kSprTf_FlipX : Common::kSprTf_None; } std::vector selected(cursel->Count); for (int i = 0; i < cursel->Count; ++i) @@ -2487,7 +2487,7 @@ Game^ import_compiled_game_dta(const AGSString &filename) { AGS::Types::ViewFrame^ newFrame = gcnew AGS::Types::ViewFrame(); newFrame->ID = k; - newFrame->Flipped = (newViews[i].loops[j].frames[k].flags & VFLG_FLIPSPRITE); + newFrame->Flipped = (newViews[i].loops[j].frames[k].flags & Common::kSprTf_FlipX) != 0; newFrame->Image = newViews[i].loops[j].frames[k].pic; newFrame->Sound = newViews[i].loops[j].frames[k].sound; newFrame->Delay = newViews[i].loops[j].frames[k].speed; From ec3c87fead3b30b14696a762d1dac30d51d034ac Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 13 Dec 2024 04:16:16 +0300 Subject: [PATCH 4/5] Editor: ViewFrame supports all 3 flips --- Editor/AGS.Editor/AGSEditor.cs | 3 ++- Editor/AGS.Editor/AGSEditor.csproj | 1 + Editor/AGS.Editor/DataFileWriter.cs | 2 +- Editor/AGS.Editor/GUI/AssignToView.cs | 1 + Editor/AGS.Editor/ImportExport.cs | 4 +-- Editor/AGS.Editor/Panes/SpriteSelector.cs | 3 ++- Editor/AGS.Editor/Panes/ViewLoopEditor.cs | 11 +++----- Editor/AGS.Editor/Panes/ViewPreview.cs | 20 ++++++++++++--- Editor/AGS.Editor/Tasks.cs | 15 +++++++++++ Editor/AGS.Editor/Utils/NativeConstants.cs | 1 - Editor/AGS.Editor/Utils/ViewUtils.cs | 29 +++++++++++++++++++++ Editor/AGS.Native/NativeMethods.cpp | 1 - Editor/AGS.Native/agsnative.cpp | 4 +-- Editor/AGS.Types/AGS.Types.csproj | 1 + Editor/AGS.Types/Enums/SpriteFlipStyle.cs | 15 +++++++++++ Editor/AGS.Types/ViewFrame.cs | 30 +++++++++------------- Editor/AGS.Types/ViewLoop.cs | 19 ++------------ 17 files changed, 105 insertions(+), 55 deletions(-) create mode 100644 Editor/AGS.Editor/Utils/ViewUtils.cs create mode 100644 Editor/AGS.Types/Enums/SpriteFlipStyle.cs diff --git a/Editor/AGS.Editor/AGSEditor.cs b/Editor/AGS.Editor/AGSEditor.cs index 914477abf82..2293d148c30 100644 --- a/Editor/AGS.Editor/AGSEditor.cs +++ b/Editor/AGS.Editor/AGSEditor.cs @@ -127,9 +127,10 @@ public class AGSEditor : IAGSEditorDirectories * 4.00.00.10 - Font and FontFile separation; * Settings.ScriptCompiler as a selection of script compiler IDs, * ExtendedCompiler is deprecated. + * 4.00.00.12 - ViewFrame.Flip has full flip selection. * */ - public const int LATEST_XML_VERSION_INDEX = 4000010; + public const int LATEST_XML_VERSION_INDEX = 4000012; /// /// XML version index on the release of AGS 4.0.0, this constant be used to determine /// if upgrade of Rooms/Sprites/etc. to new format have been performed. diff --git a/Editor/AGS.Editor/AGSEditor.csproj b/Editor/AGS.Editor/AGSEditor.csproj index 93ac1cef458..c1e8c12aa54 100644 --- a/Editor/AGS.Editor/AGSEditor.csproj +++ b/Editor/AGS.Editor/AGSEditor.csproj @@ -461,6 +461,7 @@ + AdjustMasksDialog.cs diff --git a/Editor/AGS.Editor/DataFileWriter.cs b/Editor/AGS.Editor/DataFileWriter.cs index 18fe00283d8..b4d8cd77ca1 100644 --- a/Editor/AGS.Editor/DataFileWriter.cs +++ b/Editor/AGS.Editor/DataFileWriter.cs @@ -871,7 +871,7 @@ public bool WriteViews(IViewFolder folder, Game game, CompileMessages errors) writer.Write((short)0); // unused y-offset writer.Write((short)frame.Delay); writer.Write((short)0); // struct alignment padding - writer.Write(frame.Flipped ? NativeConstants.VFLG_FLIPSPRITE : 0); + writer.Write((int)frame.Flip); writer.Write(game.GetAudioArrayIDFromFixedIndex(frame.Sound)); writer.Write(0); // unused reservedForFuture[0] writer.Write(0); // unused reservedForFuture[1] diff --git a/Editor/AGS.Editor/GUI/AssignToView.cs b/Editor/AGS.Editor/GUI/AssignToView.cs index a7e7a2ed57f..449a9ba2fd3 100644 --- a/Editor/AGS.Editor/GUI/AssignToView.cs +++ b/Editor/AGS.Editor/GUI/AssignToView.cs @@ -62,6 +62,7 @@ public bool ContinueIntoNextLoop get { return _continueIntoNextLoop; } } + // TODO: support all flip choices? public bool FlipFrames { get { return _flipFrames; } diff --git a/Editor/AGS.Editor/ImportExport.cs b/Editor/AGS.Editor/ImportExport.cs index f4aec138d02..268b66f0efb 100644 --- a/Editor/AGS.Editor/ImportExport.cs +++ b/Editor/AGS.Editor/ImportExport.cs @@ -808,7 +808,7 @@ private static void WriteOldStyleView(BinaryWriter writer, View view) writer.Write((int)0); writer.Write((short)frame.Delay); WriteZeros(writer, 2); - writer.Write((frame.Flipped) ? 1 : 0); + writer.Write((frame.Flip != SpriteFlipStyle.None) ? 1 : 0); writer.Write(frame.Sound); WriteZeros(writer, 8); } @@ -917,7 +917,7 @@ private static View ReadOldStyleView(BinaryReader reader, Game game, SpriteFolde reader.ReadInt32(); frame.Delay = reader.ReadInt16(); reader.ReadBytes(2); - frame.Flipped = (reader.ReadInt32() == 1); + frame.Flip = (reader.ReadInt32() == 1) ? SpriteFlipStyle.Horizontal : SpriteFlipStyle.None; frame.Sound = reader.ReadInt32(); reader.ReadBytes(8); if ((i < numLoops) && (j < numFrames[i])) diff --git a/Editor/AGS.Editor/Panes/SpriteSelector.cs b/Editor/AGS.Editor/Panes/SpriteSelector.cs index 26055f1645c..afcb34e809f 100644 --- a/Editor/AGS.Editor/Panes/SpriteSelector.cs +++ b/Editor/AGS.Editor/Panes/SpriteSelector.cs @@ -1129,9 +1129,10 @@ private void AssignSpritesToView(List spriteNumbers, AssignToView dialog) ViewFrame newFrame = new ViewFrame(); newFrame.ID = view.Loops[loop].Frames.Count; newFrame.Image = spriteNum; + // TODO: support all flip choices? if (dialog.FlipFrames) { - newFrame.Flipped = true; + newFrame.Flip = SpriteFlipStyle.Horizontal; } view.Loops[loop].Frames.Add(newFrame); } diff --git a/Editor/AGS.Editor/Panes/ViewLoopEditor.cs b/Editor/AGS.Editor/Panes/ViewLoopEditor.cs index 05f73f71e03..46def817e48 100644 --- a/Editor/AGS.Editor/Panes/ViewLoopEditor.cs +++ b/Editor/AGS.Editor/Panes/ViewLoopEditor.cs @@ -131,7 +131,7 @@ public void FlipSelectedFrames() foreach (int sel in _selectedFrames) { ViewFrame frame = _loop.Frames[sel]; - frame.Flipped = !frame.Flipped; + frame.Flip ^= SpriteFlipStyle.Horizontal; } this.Invalidate(); } @@ -436,10 +436,7 @@ private void onCutLoopClicked(object sender, EventArgs e) private void pasteLoop(bool flipped) { - //int loopId = _loop.ID; - //_loop = _copiedLoop.Clone(flipped); - //_loop.ID = loopId; - _copiedLoop.Clone(_loop, flipped); + _copiedLoop.CloneInto(_loop, flipped); UpdateControlWidth(); this.Invalidate(); } @@ -455,8 +452,8 @@ private void onPasteFlippedClicked(object sender, EventArgs e) } private void onFlipAllClicked(object sender, EventArgs e) - { - _loop.Frames.ForEach(c => c.Flipped = !c.Flipped); + { + _loop.Frames.ForEach(f => f.Flip ^= SpriteFlipStyle.Horizontal); this.Invalidate(); } diff --git a/Editor/AGS.Editor/Panes/ViewPreview.cs b/Editor/AGS.Editor/Panes/ViewPreview.cs index 21d07cbf22a..7b81f57ca2c 100644 --- a/Editor/AGS.Editor/Panes/ViewPreview.cs +++ b/Editor/AGS.Editor/Panes/ViewPreview.cs @@ -260,11 +260,23 @@ private void previewPanel_Paint(object sender, PaintEventArgs e) Bitmap bmp = Utilities.GetBitmapForSpriteResizedKeepingAspectRatio(new Sprite(spriteNum, spriteSize.Width, spriteSize.Height), targetWidth, targetHeight, chkCentrePivot.Checked, false, Color.Magenta); - if (thisFrame.Flipped) + if (thisFrame.Flip != SpriteFlipStyle.None) { - Point urCorner = new Point(x, y); - Point ulCorner = new Point(x + bmp.Width, y); - Point llCorner = new Point(x + bmp.Width, y + bmp.Height); + int left = x, right = x + bmp.Width, top = y, bottom = y + bmp.Height; + if ((thisFrame.Flip & SpriteFlipStyle.Horizontal) != 0) + { + left = x + bmp.Width; + right = x; + } + if ((thisFrame.Flip & SpriteFlipStyle.Vertical) != 0) + { + top = y + bmp.Height; + bottom = y; + } + + Point urCorner = new Point(right, top); + Point ulCorner = new Point(left, top); + Point llCorner = new Point(left, bottom); Point[] destPara = { ulCorner, urCorner, llCorner }; e.Graphics.DrawImage(bmp, destPara); } diff --git a/Editor/AGS.Editor/Tasks.cs b/Editor/AGS.Editor/Tasks.cs index 35dae74b858..54fbc8f1142 100644 --- a/Editor/AGS.Editor/Tasks.cs +++ b/Editor/AGS.Editor/Tasks.cs @@ -565,6 +565,21 @@ private void SetDefaultValuesForNewFeatures(Game game) AGSEditor.DEFAULT_SCRIPT_COMPILER : AGSEditor.DEFAULT_LEGACY_SCRIPT_COMPILER; } + // Update viewframes + if (xmlVersionIndex < 4000012) + { + foreach (AGS.Types.View view in game.ViewFlatList) + { + foreach (ViewLoop loop in view.Loops) + { + foreach (ViewFrame frame in loop.Frames) + { + frame.Flip = frame.Flipped ? SpriteFlipStyle.Horizontal : SpriteFlipStyle.None; + } + } + } + } + if (string.IsNullOrEmpty(game.Settings.ScriptCompiler)) { var compiler = Factory.NativeProxy.GetEmbeddedScriptCompilers().FirstOrDefault(); diff --git a/Editor/AGS.Editor/Utils/NativeConstants.cs b/Editor/AGS.Editor/Utils/NativeConstants.cs index 3f4de1f450d..2238668d1e7 100644 --- a/Editor/AGS.Editor/Utils/NativeConstants.cs +++ b/Editor/AGS.Editor/Utils/NativeConstants.cs @@ -45,7 +45,6 @@ public class NativeConstants public static readonly byte SPF_KEEPDEPTH = (byte)(int)Factory.NativeProxy.GetNativeConstant("SPF_KEEPDEPTH"); public static readonly byte[] PASSWORD_ENC_STRING = (byte[])Factory.NativeProxy.GetNativeConstant("PASSWORD_ENC_STRING"); public static readonly int LOOPFLAG_RUNNEXTLOOP = (int)Factory.NativeProxy.GetNativeConstant("LOOPFLAG_RUNNEXTLOOP"); - public static readonly int VFLG_FLIPSPRITE = (int)Factory.NativeProxy.GetNativeConstant("VFLG_FLIPSPRITE"); public static readonly uint GUIMAGIC = (uint)Factory.NativeProxy.GetNativeConstant("GUIMAGIC"); public static readonly int SAVEBUFFERSIZE = (int)Factory.NativeProxy.GetNativeConstant("SAVEBUFFERSIZE"); public static readonly int GUIMAIN_CLICKABLE = (int)Factory.NativeProxy.GetNativeConstant("GUIMAIN_CLICKABLE"); diff --git a/Editor/AGS.Editor/Utils/ViewUtils.cs b/Editor/AGS.Editor/Utils/ViewUtils.cs new file mode 100644 index 00000000000..95197c5c806 --- /dev/null +++ b/Editor/AGS.Editor/Utils/ViewUtils.cs @@ -0,0 +1,29 @@ +using System; +using AGS.Types; + +namespace AGS.Editor +{ + /// + /// Extension methods for AGS.Types.View and accompanying classes. + /// + public static class ViewUtils + { + public static ViewFrame CloneFlipped(this ViewFrame frame, bool flipped) + { + ViewFrame newFrame = frame.Clone(); + newFrame.Flip = (frame.Flip & ~SpriteFlipStyle.Horizontal) + | (flipped ? SpriteFlipStyle.Horizontal : SpriteFlipStyle.None); + return newFrame; + } + + public static void CloneInto(this ViewLoop loop, ViewLoop target, bool flipped) + { + target.Frames.Clear(); + target.RunNextLoop = loop.RunNextLoop; + foreach (ViewFrame frame in loop.Frames) + { + target.Frames.Add(frame.CloneFlipped(flipped)); + } + } + } +} diff --git a/Editor/AGS.Native/NativeMethods.cpp b/Editor/AGS.Native/NativeMethods.cpp index bbcacdfacd8..039bb0d0423 100644 --- a/Editor/AGS.Native/NativeMethods.cpp +++ b/Editor/AGS.Native/NativeMethods.cpp @@ -683,7 +683,6 @@ namespace AGS return bytes; } if (name->Equals("LOOPFLAG_RUNNEXTLOOP")) return LOOPFLAG_RUNNEXTLOOP; - if (name->Equals("VFLG_FLIPSPRITE")) return (int)Common::kSprTf_FlipX; if (name->Equals("GUIMAGIC")) return GUIMAGIC; if (name->Equals("SAVEBUFFERSIZE")) return PLUGIN_SAVEBUFFERSIZE; if (name->Equals("GUIMAIN_CLICKABLE")) return (int)Common::kGUIMain_Clickable; diff --git a/Editor/AGS.Native/agsnative.cpp b/Editor/AGS.Native/agsnative.cpp index 52c8a97ec55..772924a82f1 100644 --- a/Editor/AGS.Native/agsnative.cpp +++ b/Editor/AGS.Native/agsnative.cpp @@ -1658,7 +1658,7 @@ void drawViewLoop (HDC hdc, ViewLoop^ loopToDraw, int x, int y, int size, ListFrames->Count; ++i) { frames[i].pic = loopToDraw->Frames[i]->Image; - frames[i].flags = (loopToDraw->Frames[i]->Flipped) ? Common::kSprTf_FlipX : Common::kSprTf_None; + frames[i].flags = Common::GfxDef::GetFlagsFromFlip((Common::GraphicFlip)loopToDraw->Frames[i]->Flip); } std::vector selected(cursel->Count); for (int i = 0; i < cursel->Count; ++i) @@ -2487,7 +2487,7 @@ Game^ import_compiled_game_dta(const AGSString &filename) { AGS::Types::ViewFrame^ newFrame = gcnew AGS::Types::ViewFrame(); newFrame->ID = k; - newFrame->Flipped = (newViews[i].loops[j].frames[k].flags & Common::kSprTf_FlipX) != 0; + newFrame->Flip = (SpriteFlipStyle)Common::GfxDef::GetFlipFromFlags(newViews[i].loops[j].frames[k].flags); newFrame->Image = newViews[i].loops[j].frames[k].pic; newFrame->Sound = newViews[i].loops[j].frames[k].sound; newFrame->Delay = newViews[i].loops[j].frames[k].speed; diff --git a/Editor/AGS.Types/AGS.Types.csproj b/Editor/AGS.Types/AGS.Types.csproj index 3d996799888..6c975e941d5 100644 --- a/Editor/AGS.Types/AGS.Types.csproj +++ b/Editor/AGS.Types/AGS.Types.csproj @@ -147,6 +147,7 @@ + diff --git a/Editor/AGS.Types/Enums/SpriteFlipStyle.cs b/Editor/AGS.Types/Enums/SpriteFlipStyle.cs new file mode 100644 index 00000000000..5d6e6d349a4 --- /dev/null +++ b/Editor/AGS.Types/Enums/SpriteFlipStyle.cs @@ -0,0 +1,15 @@ +using System; +using System.ComponentModel; + +namespace AGS.Types +{ + [Flags] + [DefaultValue(None)] + public enum SpriteFlipStyle + { + None = 0, + Horizontal = 1, + Vertical = 2, + Both = Horizontal | Vertical + } +} diff --git a/Editor/AGS.Types/ViewFrame.cs b/Editor/AGS.Types/ViewFrame.cs index b179bba79d0..a7ec9c94a38 100644 --- a/Editor/AGS.Types/ViewFrame.cs +++ b/Editor/AGS.Types/ViewFrame.cs @@ -11,7 +11,7 @@ public class ViewFrame { private int _id; private int _image = 0; - private bool _flipped = false; + private SpriteFlipStyle _flip = SpriteFlipStyle.None; private int _sound = AudioClip.FixedIndexNoValue; private int _speed = 0; @@ -42,12 +42,19 @@ public int Image set { _image = Math.Max(0, value); } } - [Description("Whether the sprite should be flipped left-to-right")] + [Description("Whether the sprite should be flipped")] [Category("Appearance")] + public SpriteFlipStyle Flip + { + get { return _flip; } + set { _flip = value; } + } + + [Obsolete] + [Browsable(false)] public bool Flipped { - get { return _flipped; } - set { _flipped = value; } + get; set; } [Description("The delay after this before the next frame is displayed, relative to the overall animation speed")] @@ -80,20 +87,7 @@ public void ToXml(XmlTextWriter writer) public ViewFrame Clone() { - return Clone(false); + return (ViewFrame)MemberwiseClone(); } - - public ViewFrame Clone(bool flip) - { - return new ViewFrame - { - ID = ID, - Image = Image, - Flipped = flip ? !Flipped : Flipped, - Delay = Delay, - Sound = Sound - }; - } - } } diff --git a/Editor/AGS.Types/ViewLoop.cs b/Editor/AGS.Types/ViewLoop.cs index 1163a0d2e03..a0d2680a3b8 100644 --- a/Editor/AGS.Types/ViewLoop.cs +++ b/Editor/AGS.Types/ViewLoop.cs @@ -97,12 +97,7 @@ public void ToXml(XmlTextWriter writer) public ViewLoop Clone() { - return Clone(false); - } - - public ViewLoop Clone(bool flipped) - { - ViewLoop clone = new ViewLoop + ViewLoop clone = new ViewLoop { _frames = new List(), _runNextLoop = RunNextLoop @@ -110,20 +105,10 @@ public ViewLoop Clone(bool flipped) foreach (ViewFrame frame in _frames) { - clone.Frames.Add(frame.Clone(flipped)); + clone.Frames.Add(frame.Clone()); } return clone; } - - public void Clone(ViewLoop target, bool flipped) - { - target.Frames.Clear(); - target.RunNextLoop = RunNextLoop; - foreach (ViewFrame frame in _frames) - { - target.Frames.Add(frame.Clone(flipped)); - } - } } } From c4007b464bd171ff41157f426ae835ac24f4cb79 Mon Sep 17 00:00:00 2001 From: Ivan Mogilko Date: Fri, 13 Dec 2024 17:34:31 +0300 Subject: [PATCH 5/5] Script API: turn ViewFrame.Flipped to eFlipDirection This is backwards compatible, because old boolean value matches "No Flip" and "Horizontal Flip". --- Editor/AGS.Editor/Resources/agsdefns.sh | 3 ++- Engine/ac/viewframe.cpp | 6 ++---- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/Editor/AGS.Editor/Resources/agsdefns.sh b/Editor/AGS.Editor/Resources/agsdefns.sh index 0488ef0bd5f..fba11359107 100644 --- a/Editor/AGS.Editor/Resources/agsdefns.sh +++ b/Editor/AGS.Editor/Resources/agsdefns.sh @@ -218,6 +218,7 @@ enum eVoiceMode { }; enum eFlipDirection { + eFlipNone = 0, eFlipLeftToRight = 1, eFlipUpsideDown = 2, eFlipBoth = 3 @@ -725,7 +726,7 @@ builtin managed struct AudioClip; builtin managed struct ViewFrame { /// Gets whether this frame is flipped. - readonly import attribute bool Flipped; + readonly import attribute eFlipDirection Flipped; /// Gets the frame number of this frame. readonly import attribute int Frame; /// Gets/sets the sprite that is displayed by this frame. diff --git a/Engine/ac/viewframe.cpp b/Engine/ac/viewframe.cpp index 38c8c40724e..a7907b16956 100644 --- a/Engine/ac/viewframe.cpp +++ b/Engine/ac/viewframe.cpp @@ -32,10 +32,8 @@ extern CCAudioClip ccDynamicAudioClip; int ViewFrame_GetFlipped(ScriptViewFrame *svf) { - // TODO: can return GraphicFlip here, because old boolean value matches horizontal flip - if ((views[svf->view].loops[svf->loop].frames[svf->frame].flags & kSprTf_FlipX) != 0) - return 1; - return 0; + // We can return GraphicFlip here, because old boolean value matches horizontal flip + return GfxDef::GetFlipFromFlags(views[svf->view].loops[svf->loop].frames[svf->frame].flags); } int ViewFrame_GetGraphic(ScriptViewFrame *svf) {