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 "GUI/BsGUIElement.h" |
7 | #include "2D/BsImageSprite.h" |
8 | #include "2D/BsTextSprite.h" |
9 | |
10 | namespace bs |
11 | { |
12 | /** @addtogroup GUI |
13 | * @{ |
14 | */ |
15 | |
16 | /** |
17 | * A GUI element that allows the user to draw custom graphics. All drawn elements relative to the canvas, to its origin |
18 | * in the top left corner. |
19 | */ |
20 | class BS_EXPORT GUICanvas : public GUIElement |
21 | { |
22 | public: |
23 | /** Returns type name of the GUI element used for finding GUI element styles. */ |
24 | static const String& getGUITypeName(); |
25 | |
26 | /** |
27 | * Creates a new GUI canvas element. |
28 | * |
29 | * @param[in] options Options that allow you to control how is the element positioned and sized. This will |
30 | * override any similar options set by style. |
31 | * @param[in] styleName Optional style to use for the element. Style will be retrieved from GUISkin of the |
32 | * GUIWidget the element is used on. If not specified default style is used. |
33 | */ |
34 | static GUICanvas* create(const GUIOptions& options, const String& styleName = StringUtil::BLANK); |
35 | |
36 | /** |
37 | * Creates a new GUI canvas element. |
38 | * |
39 | * @param[in] styleName Optional style to use for the element. Style will be retrieved from GUISkin of the |
40 | * GUIWidget the element is used on. If not specified default style is used. |
41 | */ |
42 | static GUICanvas* create(const String& styleName = StringUtil::BLANK); |
43 | |
44 | /** |
45 | * Draws a line going from @p a to @p b. |
46 | * |
47 | * @param[in] a Starting point of the line, relative to the canvas origin (top-left). |
48 | * @param[in] b Ending point of the line, relative to the canvas origin (top-left). |
49 | * @param[in] color Color of the line. |
50 | * @param[in] depth Depth at which to draw the element. Elements with higher depth will be drawn before others. |
51 | * Additionally elements of the same type (triangle or line) will be drawn in order they are |
52 | * submitted if they share the same depth. |
53 | */ |
54 | void drawLine(const Vector2I& a, const Vector2I& b, const Color& color = Color::White, UINT8 depth = 128); |
55 | |
56 | /** |
57 | * Draws multiple lines following the path by the provided vertices. First vertex connects to the second vertex, |
58 | * and every following vertex connects to the previous vertex. |
59 | * |
60 | * @param[in] vertices Points to use for drawing the line. Must have at least two elements. All points are |
61 | * relative to the canvas origin (top-left). |
62 | * @param[in] color Color of the line. |
63 | * @param[in] depth Depth at which to draw the element. Elements with higher depth will be drawn before |
64 | * others. Additionally elements of the same type (triangle or line) will be drawn in order |
65 | * they are submitted if they share the same depth. |
66 | */ |
67 | void drawPolyLine(const Vector<Vector2I>& vertices, const Color& color = Color::White, UINT8 depth = 128); |
68 | |
69 | /** |
70 | * Draws a quad with a the provided texture displayed. |
71 | * |
72 | * @param[in] texture Texture to draw. |
73 | * @param[in] area Position and size of the texture to draw. Position is relative to the canvas origin |
74 | * (top-left). If size is zero, the default texture size will be used. |
75 | * @param[in] scaleMode Scale mode to use when sizing the texture. Only relevant if the provided quad size |
76 | * doesn't match the texture size. |
77 | * @param[in] color Color to tint the drawn texture with. |
78 | * @param[in] depth Depth at which to draw the element. Elements with higher depth will be drawn before |
79 | * others. Additionally elements of the same type (triangle or line) will be drawn in order |
80 | * they are submitted if they share the same depth. |
81 | */ |
82 | void drawTexture(const HSpriteTexture& texture, const Rect2I& area, |
83 | TextureScaleMode scaleMode = TextureScaleMode::StretchToFit, const Color& color = Color::White, UINT8 depth = 128); |
84 | |
85 | /** |
86 | * Draws a triangle strip. First three vertices are used to form the initial triangle, and every next vertex will |
87 | * form a triangle with the previous two. |
88 | * |
89 | * @param[in] vertices A set of points defining the triangles. Must have at least three elements. All points |
90 | * are relative to the canvas origin (top-left). |
91 | * @param[in] color Color of the triangles. |
92 | * @param[in] depth Depth at which to draw the element. Elements with higher depth will be drawn before |
93 | * others. Additionally elements of the same type (triangle or line) will be drawn in order |
94 | * they are submitted if they share the same depth. |
95 | */ |
96 | void drawTriangleStrip(const Vector<Vector2I>& vertices, const Color& color = Color::White, UINT8 depth = 128); |
97 | |
98 | /** |
99 | * Draws a triangle list. Every three vertices in the list represent a unique triangle. |
100 | * |
101 | * @param[in] vertices A set of points defining the triangles. Must have at least three elements, and its size |
102 | * must be a multiple of three. |
103 | * @param[in] color Color of the triangles. |
104 | * @param[in] depth Depth at which to draw the element. Elements with higher depth will be drawn before |
105 | * others. Additionally elements of the same type (triangle or line) will be drawn in order |
106 | * they are submitted if they share the same depth. |
107 | */ |
108 | void drawTriangleList(const Vector<Vector2I>& vertices, const Color& color = Color::White, UINT8 depth = 128); |
109 | |
110 | /** |
111 | * Draws a piece of text with the wanted font. The text will be aligned to the top-left corner of the provided |
112 | * position, and will not be word wrapped. |
113 | * |
114 | * @param[in] text Text to draw. |
115 | * @param[in] position Position of the text to draw. This represents the top-left corner of the text. It is |
116 | * relative to the canvas origin (top-left). |
117 | * @param[in] font Font to draw the text with. |
118 | * @param[in] size Size of the font. |
119 | * @param[in] color Color of the text. |
120 | * @param[in] depth Depth at which to draw the element. Elements with higher depth will be drawn before |
121 | * others. Additionally elements of the same type (triangle or line) will be drawn in order |
122 | * they are submitted if they share the same depth. |
123 | */ |
124 | void drawText(const String& text, const Vector2I& position, const HFont& font, UINT32 size = 10, |
125 | const Color& color = Color::White, UINT8 depth = 128); |
126 | |
127 | /** Clears the canvas, removing any previously drawn elements. */ |
128 | void clear(); |
129 | |
130 | public: // ***** INTERNAL ****** |
131 | /** @name Internal |
132 | * @{ |
133 | */ |
134 | |
135 | /** @copydoc GUIElement::_getOptimalSize */ |
136 | Vector2I _getOptimalSize() const override; |
137 | |
138 | /** @copydoc GUIElement::_getRenderElementDepthRange */ |
139 | UINT32 _getRenderElementDepthRange() const override { return mDepthRange; } |
140 | |
141 | /** @} */ |
142 | protected: |
143 | /** Type of elements that may be drawn on the canvas. */ |
144 | enum class CanvasElementType |
145 | { |
146 | Line, |
147 | Triangle, |
148 | Image, |
149 | Text |
150 | }; |
151 | |
152 | /** Represents a single element drawn by the canvas. */ |
153 | struct CanvasElement |
154 | { |
155 | CanvasElementType type; |
156 | Color color; |
157 | UINT32 renderElemStart; |
158 | UINT32 renderElemEnd; |
159 | UINT32 dataId; |
160 | UINT8 depth; |
161 | |
162 | union |
163 | { |
164 | struct |
165 | { |
166 | UINT32 vertexStart; |
167 | UINT32 numVertices; |
168 | mutable UINT32 clippedVertexStart; |
169 | mutable UINT32 clippedNumVertices; |
170 | }; |
171 | |
172 | struct |
173 | { |
174 | ImageSprite* imageSprite; |
175 | TextureScaleMode scaleMode; |
176 | }; |
177 | |
178 | struct |
179 | { |
180 | TextSprite* textSprite; |
181 | UINT32 size; |
182 | }; |
183 | }; |
184 | }; |
185 | |
186 | /** Information required for drawing a text canvas element. */ |
187 | struct TextElementData |
188 | { |
189 | String string; |
190 | HFont font; |
191 | Vector2I position; |
192 | }; |
193 | |
194 | /** Information required for drawing an image canvas element. */ |
195 | struct ImageElementData |
196 | { |
197 | HSpriteTexture texture; |
198 | Rect2I area; |
199 | }; |
200 | |
201 | /** Information required for drawing an arbitrary triangle canvas element. */ |
202 | struct TriangleElementData |
203 | { |
204 | SpriteMaterialInfo matInfo; |
205 | }; |
206 | |
207 | GUICanvas(const String& styleName, const GUIDimensions& dimensions); |
208 | virtual ~GUICanvas(); |
209 | |
210 | /** @copydoc GUIElement::_getNumRenderElements */ |
211 | UINT32 _getNumRenderElements() const override; |
212 | |
213 | /** @copydoc GUIElement::_getMaterial */ |
214 | const SpriteMaterialInfo& _getMaterial(UINT32 renderElementIdx, SpriteMaterial** material) const override; |
215 | |
216 | /** @copydoc GUIElement::_getMeshInfo() */ |
217 | void _getMeshInfo(UINT32 renderElementIdx, UINT32& numVertices, UINT32& numIndices, GUIMeshType& type) const override; |
218 | |
219 | /** @copydoc GUIElement::_fillBuffer */ |
220 | void _fillBuffer(UINT8* vertices, UINT32* indices, UINT32 vertexOffset, UINT32 indexOffset, |
221 | UINT32 maxNumVerts, UINT32 maxNumIndices, UINT32 renderElementIdx) const override; |
222 | |
223 | /** @copydoc GUIElement::_getRenderElementDepth */ |
224 | UINT32 _getRenderElementDepth(UINT32 renderElementIdx) const override; |
225 | |
226 | /** @copydoc GUIElement::updateRenderElementsInternal */ |
227 | void updateRenderElementsInternal() override; |
228 | |
229 | /** Build an image sprite from the provided canvas element. */ |
230 | void buildImageElement(const CanvasElement& element); |
231 | |
232 | /** Build a text sprite from the provided canvas element. */ |
233 | void buildTextElement(const CanvasElement& element); |
234 | |
235 | /** Build a set of clipped triangles from the source triangles provided by the canvas element. */ |
236 | void buildTriangleElement(const CanvasElement& element, const Vector2& offset, const Rect2I& clipRect) const; |
237 | |
238 | /** |
239 | * Rebuilds all triangle elements on the canvas, by constructing a set of clipped and offset triangles from the |
240 | * triangles provided by the canvas elements. |
241 | */ |
242 | void buildAllTriangleElementsIfDirty(const Vector2& offset, const Rect2I& clipRect) const; |
243 | |
244 | /** Finds the canvas element that contains the render element with the specified index. */ |
245 | const CanvasElement& findElement(UINT32 renderElementIdx) const; |
246 | |
247 | Vector<CanvasElement> mElements; |
248 | UINT32 mNumRenderElements; |
249 | UINT8 mDepthRange; |
250 | |
251 | Vector<ImageElementData> mImageData; |
252 | Vector<TextElementData> mTextData; |
253 | mutable Vector<TriangleElementData> mTriangleElementData; |
254 | Vector<Vector2> mVertexData; |
255 | |
256 | mutable Vector<Vector2> mClippedVertices; |
257 | mutable Vector<Vector2> mClippedLineVertices; |
258 | mutable Vector2 mLastOffset; |
259 | mutable Rect2I mLastClipRect; |
260 | mutable bool mForceTriangleBuild; |
261 | |
262 | static const float LINE_SMOOTH_BORDER_WIDTH; |
263 | }; |
264 | |
265 | /** @} */ |
266 | } |