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 "BsPrerequisites.h"
6#include "2D/BsSpriteMaterial.h"
7#include "Math/BsVector2I.h"
8#include "Math/BsRect2I.h"
9#include "Image/BsColor.h"
10
11namespace bs
12{
13 /** @addtogroup 2D-Internal
14 * @{
15 */
16
17 /** Determines position of the sprite in its bounds. */
18 enum SpriteAnchor
19 {
20 SA_TopLeft,
21 SA_TopCenter,
22 SA_TopRight,
23 SA_MiddleLeft,
24 SA_MiddleCenter,
25 SA_MiddleRight,
26 SA_BottomLeft,
27 SA_BottomCenter,
28 SA_BottomRight
29 };
30
31 /** Contains information about a single sprite render element, including its geometry and material. */
32 struct SpriteRenderElement
33 {
34 SpriteRenderElement() = default;
35
36 Vector2* vertices = nullptr;
37 Vector2* uvs = nullptr;
38 UINT32* indexes = nullptr;
39 UINT32 numQuads = 0;
40 SpriteMaterialInfo matInfo;
41 SpriteMaterial* material = nullptr;
42 };
43
44 /** Generates geometry and contains information needed for rendering a two dimensional element. */
45 class BS_EXPORT Sprite
46 {
47 public:
48 Sprite() = default;
49 virtual ~Sprite() = default;
50
51 /**
52 * Returns clipped bounds of the sprite.
53 *
54 * @param[in] offset Offset that will be added to the returned bounds.
55 * @param[in] clipRect Local clip rect that is used for clipping the sprite bounds. (Clipping is done before
56 * the offset is applied). If clip rect width or height is zero, no clipping is done.
57 *
58 * @return Clipped sprite bounds.
59 */
60 Rect2I getBounds(const Vector2I& offset, const Rect2I& clipRect) const;
61
62 /**
63 * Returns the number of separate render elements in the sprite. Normally this is 1, but some sprites may consist
64 * of multiple materials, in which case each will require its own mesh (render element)
65 *
66 * @return The number render elements.
67 */
68 UINT32 getNumRenderElements() const;
69
70 /**
71 * Gets material information required for rendering the element at the specified index.
72 *
73 * @see getNumRenderElements()
74 */
75 const SpriteMaterialInfo& getMaterialInfo(UINT32 renderElementIdx) const;
76
77 /**
78 * Gets the material that will be used for rendering the element at the specified index.
79 *
80 * @see getNumRenderElements()
81 */
82 SpriteMaterial* getMaterial(UINT32 renderElementIdx) const;
83
84 /**
85 * Returns the number of quads that the specified render element will use. You will need this value when creating
86 * the buffers before calling fillBuffer().
87 *
88 * @return Number of quads for the specified render element.
89 *
90 * @note Number of vertices = Number of quads * 4
91 * Number of indices = Number of quads * 6
92 *
93 * @see getNumRenderElements()
94 * @see fillBuffer()
95 */
96 UINT32 getNumQuads(UINT32 renderElementIdx) const;
97
98 /**
99 * Fill the pre-allocated vertex, uv and index buffers with the mesh data for the specified render element.
100 *
101 * @param[out] vertices Previously allocated buffer where to store the vertices.
102 * @param[out] uv Previously allocated buffer where to store the uv coordinates.
103 * @param[out] indices Previously allocated buffer where to store the indices.
104 * @param[in] vertexOffset At which vertex should the method start filling the buffer.
105 * @param[in] indexOffset At which index should the method start filling the buffer.
106 * @param[in] maxNumVerts Total number of vertices the buffers were allocated for. Used only for memory
107 * safety.
108 * @param[in] maxNumIndices Total number of indices the buffers were allocated for. Used only for memory
109 * safety.
110 * @param[in] vertexStride Number of bytes between of vertices in the provided vertex and uv data.
111 * @param[in] indexStride Number of bytes between two indexes in the provided index data.
112 * @param[in] renderElementIdx Zero-based index of the render element.
113 * @param[in] offset Position offset to apply to all vertices, after clipping.
114 * @param[in] clipRect Rectangle to clip the vertices to.
115 * @param[in] clip Should the vertices be clipped to the provided @p clipRect.
116 *
117 * @see getNumRenderElements()
118 * @see getNumQuads()
119 */
120 UINT32 fillBuffer(UINT8* vertices, UINT8* uv, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset,
121 UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 vertexStride, UINT32 indexStride, UINT32 renderElementIdx,
122 const Vector2I& offset, const Rect2I& clipRect, bool clip = true) const;
123
124 /**
125 * Clips the provided 2D vertices to the provided clip rectangle. The vertices must form axis aligned quads.
126 *
127 * @param[in, out] vertices Pointer to the start of the buffer containing vertex positions.
128 * @param[in, out] uv Pointer to the start of the buffer containing UV coordinates.
129 * @param[in] numQuads Number of quads in the provided buffer pointers.
130 * @param[in] vertStride Number of bytes to skip when going to the next vertex. This assumes both position
131 * and uv coordinates have the same stride (as they are likely pointing to the same
132 * buffer).
133 * @param[in] clipRect Rectangle to clip the geometry to.
134 */
135 static void clipQuadsToRect(UINT8* vertices, UINT8* uv, UINT32 numQuads, UINT32 vertStride, const Rect2I& clipRect);
136
137 /**
138 * Clips the provided 2D vertices to the provided clip rectangle. The vertices can be arbitrary triangles.
139 *
140 * @param[in] vertices Pointer to the start of the buffer containing vertex positions.
141 * @param[in] uv Pointer to the start of the buffer containing UV coordinates. Can be null if UV is
142 * not needed.
143 * @param[in] numTris Number of triangles in the provided buffer pointers.
144 * @param[in] vertStride Number of bytes to skip when going to the next vertex. This assumes both position
145 * and uv coordinates have the same stride (as they are likely pointing to the same
146 * buffer).
147 * @param[in] clipRect Rectangle to clip the geometry to.
148 * @param[in] writeCallback Callback that will be triggered when clipped vertices and UV coordinates are
149 * generated and need to be stored. Vertices are always generate in tuples of three,
150 * forming a single triangle.
151 */
152 static void clipTrianglesToRect(UINT8* vertices, UINT8* uv, UINT32 numTris, UINT32 vertStride,
153 const Rect2I& clipRect, const std::function<void(Vector2*, Vector2*, UINT32)>& writeCallback);
154 protected:
155 /** Returns the offset needed to move the sprite in order for it to respect the provided anchor. */
156 static Vector2I getAnchorOffset(SpriteAnchor anchor, UINT32 width, UINT32 height);
157
158 /** Calculates the bounds of all sprite vertices. */
159 void updateBounds() const;
160
161 mutable Rect2I mBounds;
162 mutable Vector<SpriteRenderElement> mCachedRenderElements;
163 };
164
165 /** @} */
166}