| #ifndef _RIVE_IMAGE_HPP_ | |
| #define _RIVE_IMAGE_HPP_ | |
| #include "rive/hit_info.hpp" | |
| #include "rive/generated/shapes/image_base.hpp" | |
| #include "rive/assets/file_asset_referencer.hpp" | |
| #include "rive/shapes/paint/image_sampler.hpp" | |
| namespace rive | |
| { | |
| class LayoutNodeStyle; | |
| class LayoutParticipant; | |
| enum class ImageFit : unsigned char | |
| { | |
| resize, | |
| contain, | |
| cover, | |
| fitWidth, | |
| fitHeight, | |
| none, | |
| scaleDown, | |
| fill, | |
| }; | |
| class ImageAsset; | |
| class MeshDrawable; | |
| #ifdef TESTING | |
| class Mesh; | |
| #endif | |
| class Image : public ImageBase, public FileAssetReferencer | |
| { | |
| private: | |
| MeshDrawable* m_Mesh = nullptr; | |
| // Since layouts only pass down width/height we store those | |
| // and use the image width/height to compute the proper scale | |
| float m_layoutWidth = NAN; | |
| float m_layoutHeight = NAN; | |
| float m_layoutOffsetX = 0.0f; | |
| float m_layoutOffsetY = 0.0f; | |
| // The layout-driven fit scale is stored separately (rather than written | |
| // into scaleX/scaleY) so the user-facing scale stays free to be | |
| // edited/animated. It is composed with the local transform in | |
| // updateTransform(). | |
| float m_layoutScaleX = 1.0f; | |
| float m_layoutScaleY = 1.0f; | |
| // Whether the file applies the layout fit as a separate scale (7.2+). | |
| // Legacy files overwrite scaleX/scaleY with the fit instead. Set from the | |
| // file version at import; defaults to the modern behavior for | |
| // runtime-created images. | |
| bool m_layoutScaleSeparate = true; | |
| void updateImageScale(); | |
| public: | |
| void setMesh(MeshDrawable* mesh); | |
| #ifdef WITH_RIVE_EDITOR | |
| /// Mesh / NSlicer call this from `editorParentChanged(_, this)` | |
| /// to register on transition to. Both share `m_Mesh` — the | |
| /// runtime invariant is one Mesh OR one NSlicer per Image, so | |
| /// the second one overrides. | |
| void setMeshForEditor(MeshDrawable* mesh) { m_Mesh = mesh; } | |
| /// Clear `m_Mesh` only if it currently points at `expected`. | |
| /// Called from `editorParentChanged(this, _)` to safely detach | |
| /// without clobbering a sibling's setter that ran more recently. | |
| void clearMeshIfForEditor(MeshDrawable* expected) | |
| { | |
| if (m_Mesh == expected) | |
| { | |
| m_Mesh = nullptr; | |
| } | |
| } | |
| #endif | |
| ImageAsset* imageAsset() const; | |
| ImageSampler imageSampler() const; | |
| void draw(Renderer* renderer) override; | |
| bool willDraw() override; | |
| Core* hitTest(HitInfo*, const Mat2D&) override; | |
| StatusCode import(ImportStack& importStack) override; | |
| void setAsset(rcp<FileAsset>) override; | |
| uint32_t assetId() override; | |
| Core* clone() const override; | |
| Vec2D measureLayout(float width, | |
| LayoutMeasureMode widthMode, | |
| float height, | |
| LayoutMeasureMode heightMode) override; | |
| void controlSize(Vec2D size, | |
| LayoutScaleType widthScaleType, | |
| LayoutScaleType heightScaleType, | |
| LayoutDirection direction) override; | |
| // Participation via an optional LayoutParticipant child. Origin | |
| // is 0 (unlike Text): the image composes its origin + fit into the render | |
| // separately, so the slot base is just the slot top-left. | |
| void composeWorldTransform() override; | |
| protected: | |
| void updateConstraints() override; | |
| public: | |
| Vec2D layoutBaseTranslation(LayoutParticipant* participant) const; | |
| LayoutParticipant* layoutParticipant() const; | |
| bool isParticipatingInLayout() const; | |
| float width() const; | |
| float height() const; | |
| // Effective render scale: the user-facing scaleX/scaleY composed with the | |
| // layout fit scale. Equals the user scale when not in a layout. | |
| float renderScaleX() const { return scaleX() * m_layoutScaleX; } | |
| float renderScaleY() const { return scaleY() * m_layoutScaleY; } | |
| float computedWidth() override { return width() * renderScaleX(); } | |
| float computedHeight() override { return height() * renderScaleY(); } | |
| void assetUpdated() override; | |
| AABB localBounds() const override; | |
| void updateTransform() override; | |
| #ifdef TESTING | |
| Mesh* mesh() const; | |
| #endif | |
| }; | |
| } // namespace rive | |
| #endif |