1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Resources/BsResource.h"
7#include "Math/BsVector2.h"
8
9namespace bs
10{
11 /** @addtogroup Resources
12 * @{
13 */
14
15 /**
16 * Descriptor that describes a simple sprite sheet animation. The parent texture is split into a grid of
17 * @p numRows x @p numColumns, each representing one frame of the animation. Every frame is of equal size. Frames are
18 * sequentially evaluated starting from the top-most row, iterating over all columns in a row and then moving to next
19 * row, up to @p count frames. Frames in rows/colums past @p count. @p fps frames are evaluated every second, allowing
20 * you to control animation speed.
21 */
22 struct BS_SCRIPT_EXPORT(m:Rendering,pl:true) SpriteSheetGridAnimation
23 {
24 SpriteSheetGridAnimation() = default;
25 SpriteSheetGridAnimation(UINT32 numRows, UINT32 numColumns, UINT32 count, UINT32 fps)
26 : numRows(numRows), numColumns(numColumns), count(count), fps(fps)
27 { }
28
29 /**
30 * Number of rows to divide the parent's texture area. Determines height of the individual frame (depends on
31 * parent texture size).
32 */
33 UINT32 numRows = 1;
34
35 /**
36 * Number of columns to divide the parent's texture area. Determines column of the individual frame (depends on
37 * parent texture size).
38 */
39 UINT32 numColumns = 1;
40
41 /** Number of frames in the animation. Must be less or equal than @p numRows * @p numColumns. */
42 UINT32 count = 1;
43
44 /** How many frames to evaluate each second. Determines the animation speed. */
45 UINT32 fps = 8;
46 };
47
48 /** Type of playback to use for an animation of a SpriteTexture. */
49 enum class BS_SCRIPT_EXPORT(m:Rendering) SpriteAnimationPlayback
50 {
51 /** Do not animate. */
52 None,
53 /** Animate once until the end of the animation is reached. */
54 Normal,
55 /** Animate to the end of the animation then loop around. */
56 Loop,
57 /** Loop the animation but reverse playback when the end is reached. */
58 PingPong
59 };
60
61 /** @} */
62
63 /** @addtogroup Implementation
64 * @{
65 */
66
67 /** Base class used for both sim and core thread SpriteTexture implementations. */
68 class BS_CORE_EXPORT SpriteTextureBase
69 {
70 public:
71 SpriteTextureBase(const Vector2& uvOffset, const Vector2& uvScale)
72 :mUVOffset(uvOffset), mUVScale(uvScale)
73 { }
74 virtual ~SpriteTextureBase() = default;
75
76 /**
77 * Determines the offset into the referenced texture where the sprite starts. The offset is in UV coordinates,
78 * in range [0, 1].
79 */
80 BS_SCRIPT_EXPORT(n:Offset,pr:setter)
81 void setOffset(const Vector2& offset) { mUVOffset = offset; _markCoreDirty(); }
82
83 /** @copydoc setOffset() */
84 BS_SCRIPT_EXPORT(n:Offset,pr:getter)
85 Vector2 getOffset() const { return mUVOffset; }
86
87 /** Determines the size of the sprite in the referenced texture. Size is in UV coordinates, range [0, 1]. */
88 BS_SCRIPT_EXPORT(n:Scale,pr:setter)
89 void setScale(const Vector2& scale) { mUVScale = scale; _markCoreDirty(); }
90
91 /** @copydoc setScale() */
92 BS_SCRIPT_EXPORT(n:Scale,pr:getter)
93 Vector2 getScale() const { return mUVScale; }
94
95 /** Transforms wanted UV coordinates into coordinates you can use for sampling the internal texture. */
96 Vector2 transformUV(const Vector2& uv) const { return mUVOffset + uv * mUVScale; }
97
98 /**
99 * Evaluates the UV coordinate offset and size to use at the specified time. If the sprite texture doesn't
100 * have animation playback enabled then just the default offset and size will be provided, otherwise the
101 * animation will be evaluated and appropriate UV returned.
102 */
103 Rect2 evaluate(float t) const;
104
105 /** Returns the row and column of the current animation frame for time @p t. */
106 void getAnimationFrame(float t, UINT32& row, UINT32& column) const;
107
108 /**
109 * Sets properties describing sprite animation. The animation splits the sprite area into a grid of sub-images
110 * which can be evaluated over time. In order to view the animation you must also enable playback through
111 * setAnimationPlayback().
112 */
113 BS_SCRIPT_EXPORT(n:Animation,pr:setter)
114 void setAnimation(const SpriteSheetGridAnimation& anim) { mAnimation = anim; _markCoreDirty(); }
115
116 /** @copydoc setAnimation */
117 BS_SCRIPT_EXPORT(n:Animation,pr:getter)
118 const SpriteSheetGridAnimation& getAnimation() const { return mAnimation; }
119
120 /** Determines if and how should the sprite animation play. */
121 BS_SCRIPT_EXPORT(n:AnimationPlayback,pr:setter)
122 void setAnimationPlayback(SpriteAnimationPlayback playback) { mPlayback = playback; _markCoreDirty(); }
123
124 /** @copydoc setAnimationPlayback */
125 BS_SCRIPT_EXPORT(n:AnimationPlayback,pr:getter)
126 SpriteAnimationPlayback getAnimationPlayback() const { return mPlayback; };
127
128 protected:
129 /** Marks the contents of the sim thread object as dirty, causing it to sync with its core thread counterpart. */
130 virtual void _markCoreDirty() { }
131
132 Vector2 mUVOffset;
133 Vector2 mUVScale;
134
135 SpriteAnimationPlayback mPlayback = SpriteAnimationPlayback::None;
136 SpriteSheetGridAnimation mAnimation;
137 };
138
139 /** Templated base class used for both sim and core thread SpriteTexture implementations. */
140 template<bool Core>
141 class BS_CORE_EXPORT TSpriteTexture : public SpriteTextureBase
142 {
143 public:
144 using TextureType = CoreVariantHandleType<Texture, Core>;
145
146 TSpriteTexture(const Vector2& uvOffset, const Vector2& uvScale, TextureType atlasTexture)
147 :SpriteTextureBase(uvOffset, uvScale), mAtlasTexture(std::move(atlasTexture))
148 { }
149
150 virtual ~TSpriteTexture() = default;
151
152 /** Enumerates all the fields in the type and executes the specified processor action for each field. */
153 template<class P>
154 void rttiEnumFields(P p);
155
156 protected:
157 TextureType mAtlasTexture;
158 };
159
160 /** @} */
161 /** @addtogroup Resources
162 * @{
163 */
164
165
166 /**
167 * Texture that references a part of a larger texture by specifying an UV subset. When the sprite texture is rendererd
168 * only the portion of the texture specified by the UV subset will be rendered. This allows you to use the same texture
169 * for multiple sprites (texture atlasing). Sprite textures also allow you to specify sprite sheet animation by varying
170 * which portion of the UV is selected over time.
171 */
172 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Rendering) SpriteTexture : public Resource, public TSpriteTexture<false>
173 {
174 public:
175 /** Determines the internal texture that the sprite texture references. */
176 BS_SCRIPT_EXPORT(n:Texture,pr:setter)
177 void setTexture(const HTexture& texture);
178
179 /** @copydoc setTexture() */
180 BS_SCRIPT_EXPORT(n:Texture,pr:getter)
181 const HTexture& getTexture() const { return mAtlasTexture; }
182
183 /** Returns width of the sprite texture in pixels. */
184 BS_SCRIPT_EXPORT(n:Width,pr:getter)
185 UINT32 getWidth() const;
186
187 /** Returns height of the sprite texture in pixels. */
188 BS_SCRIPT_EXPORT(n:Height,pr:getter)
189 UINT32 getHeight() const;
190
191 /**
192 * Returns width of a single animation frame sprite texture in pixels. If the texture has no animation this
193 * is the same as getWidth().
194 */
195 BS_SCRIPT_EXPORT(n:FrameWidth,pr:getter)
196 UINT32 getFrameWidth() const;
197
198 /**
199 * Returns height of a single animation frame sprite texture in pixels. If the texture has no animation this
200 * is the same as getHeight().
201 */
202 BS_SCRIPT_EXPORT(n:FrameHeight,pr:getter)
203 UINT32 getFrameHeight() const;
204
205 /** Retrieves a core implementation of a sprite texture usable only from the core thread. */
206 SPtr<ct::SpriteTexture> getCore() const;
207
208 /** Creates a new sprite texture that references the entire area of the provided texture. */
209 BS_SCRIPT_EXPORT(ec:SpriteTexture)
210 static HSpriteTexture create(const HTexture& texture);
211
212 /** Creates a new sprite texture that references a sub-area of the provided texture. */
213 BS_SCRIPT_EXPORT(ec:SpriteTexture)
214 static HSpriteTexture create(const Vector2& uvOffset, const Vector2& uvScale, const HTexture& texture);
215
216 /** Checks if the sprite texture and its internal texture have been loaded. */
217 static bool checkIsLoaded(const HSpriteTexture& tex);
218
219 /** Returns a dummy sprite texture. */
220 static const HSpriteTexture& dummy();
221
222 /** @name Internal
223 * @{
224 */
225
226 /** Creates a new SpriteTexture without a resource handle. Use create() for normal use. */
227 static SPtr<SpriteTexture> _createPtr(const HTexture& texture);
228
229 /** Creates a new SpriteTexture without a resource handle. Use create() for normal use. */
230 static SPtr<SpriteTexture> _createPtr(const Vector2& uvOffset, const Vector2& uvScale, const HTexture& texture);
231
232 /** @copydoc SpriteTextureBase::_markCoreDirty */
233 void _markCoreDirty() override;
234
235 /** @} */
236 private:
237 friend class SpriteTextureRTTI;
238
239 /** @copydoc create(const Vector2&, const Vector2&, const HTexture&) */
240 SpriteTexture(const Vector2& uvOffset, const Vector2& uvScale, const HTexture& texture);
241
242 /** @copydoc CoreObject::initialize */
243 void initialize() override;
244
245 /** @copydoc CoreObject::createCore */
246 SPtr<ct::CoreObject> createCore() const override;
247
248 /** @copydoc CoreObject::syncToCore */
249 CoreSyncData syncToCore(FrameAlloc* allocator) override;
250
251 /** @copydoc CoreObject::getCoreDependencies */
252 void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
253
254 /************************************************************************/
255 /* RTTI */
256 /************************************************************************/
257
258 /** Creates a new empty and uninitialized sprite texture. */
259 static SPtr<SpriteTexture> createEmpty();
260 public:
261 friend class SpriteTextureRTTI;
262 static RTTITypeBase* getRTTIStatic();
263 RTTITypeBase* getRTTI() const override;
264 };
265
266 /** @} */
267
268 namespace ct
269 {
270 /** @addtogroup Resources-Internal
271 * @{
272 */
273
274 /**
275 * Core thread version of a bs::SpriteTexture.
276 *
277 * @note Core thread.
278 */
279 class BS_CORE_EXPORT SpriteTexture : public CoreObject, public TSpriteTexture<true>
280 {
281 public:
282 /** Determines the internal texture that the sprite texture references. */
283 void setTexture(const SPtr<ct::Texture>& texture) { mAtlasTexture = texture; }
284
285 /** @copydoc setTexture() */
286 const SPtr<ct::Texture>& getTexture() const { return mAtlasTexture; }
287
288 private:
289 friend class bs::SpriteTexture;
290
291 SpriteTexture(const Vector2& uvOffset, const Vector2& uvScale, SPtr<Texture> texture,
292 const SpriteSheetGridAnimation& anim, SpriteAnimationPlayback playback);
293
294 /** @copydoc CoreObject::syncToCore */
295 void syncToCore(const CoreSyncData& data) override;
296 };
297
298 /** @} */
299 }
300}