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#include "2D/BsImageSprite.h"
4#include "2D/BsSpriteManager.h"
5#include "Image/BsTexture.h"
6#include "Image/BsSpriteTexture.h"
7
8namespace bs
9{
10 ImageSprite::~ImageSprite()
11 {
12 clearMesh();
13 }
14
15 void ImageSprite::update(const IMAGE_SPRITE_DESC& desc, UINT64 groupId)
16 {
17 if(!SpriteTexture::checkIsLoaded(desc.texture))
18 {
19 clearMesh();
20 return;
21 }
22
23 // Actually generate a mesh
24 if(mCachedRenderElements.size() < 1)
25 mCachedRenderElements.resize(1);
26
27 bool useScale9Grid = desc.borderLeft > 0 || desc.borderRight > 0 ||
28 desc.borderTop > 0 || desc.borderBottom > 0;
29
30 UINT32 numQuads = 1;
31 if(useScale9Grid)
32 numQuads = 9;
33
34 SpriteRenderElement& renderElem = mCachedRenderElements[0];
35 {
36 UINT32 newNumQuads = numQuads;
37 if(newNumQuads != renderElem.numQuads)
38 {
39 UINT32 oldVertexCount = renderElem.numQuads * 4;
40 UINT32 oldIndexCount = renderElem.numQuads * 6;
41
42 if(renderElem.vertices != nullptr) bs_deleteN(renderElem.vertices, oldVertexCount);
43 if(renderElem.uvs != nullptr) bs_deleteN(renderElem.uvs, oldVertexCount);
44 if(renderElem.indexes != nullptr) bs_deleteN(renderElem.indexes, oldIndexCount);
45
46 renderElem.vertices = bs_newN<Vector2>(newNumQuads * 4);
47 renderElem.uvs = bs_newN<Vector2>(newNumQuads * 4);
48 renderElem.indexes = bs_newN<UINT32>(newNumQuads * 6);
49 renderElem.numQuads = newNumQuads;
50 }
51
52 const HTexture& tex = desc.texture->getTexture();
53
54 SpriteMaterialInfo& matInfo = renderElem.matInfo;
55 matInfo.groupId = groupId;
56 matInfo.texture = tex;
57 matInfo.tint = desc.color;
58 matInfo.animationStartTime = desc.animationStartTime;
59
60 bool animated = desc.texture->getAnimation().count > 1;
61 if(animated)
62 matInfo.spriteTexture = desc.texture;
63
64 renderElem.material = SpriteManager::instance().getImageMaterial(desc.transparent, animated);
65 }
66
67 for(UINT32 i = 0; i < numQuads; i++)
68 {
69 renderElem.indexes[i * 6 + 0] = i * 4 + 0;
70 renderElem.indexes[i * 6 + 1] = i * 4 + 1;
71 renderElem.indexes[i * 6 + 2] = i * 4 + 2;
72 renderElem.indexes[i * 6 + 3] = i * 4 + 1;
73 renderElem.indexes[i * 6 + 4] = i * 4 + 3;
74 renderElem.indexes[i * 6 + 5] = i * 4 + 2;
75 }
76
77 Vector2I offset = getAnchorOffset(desc.anchor, desc.width, desc.height);
78 Vector2 uvOffset = desc.uvOffset;
79 Vector2 uvScale = desc.uvScale;
80
81 if(useScale9Grid)
82 {
83 UINT32 leftBorder = desc.borderLeft;
84 UINT32 rightBorder = desc.borderRight;
85 UINT32 topBorder = desc.borderTop;
86 UINT32 bottomBorder = desc.borderBottom;
87
88 float centerWidth = (float)std::max((INT32)0, (INT32)desc.width - (INT32)leftBorder - (INT32)rightBorder);
89 float centerHeight = (float)std::max((INT32)0, (INT32)desc.height - (INT32)topBorder - (INT32)bottomBorder);
90
91 float topCenterStart = (float)(offset.x + leftBorder);
92 float topRightStart = (float)(topCenterStart + centerWidth);
93
94 float middleStart = (float)(offset.y + topBorder);
95 float bottomStart = (float)(middleStart + centerHeight);
96
97 // Top left
98 renderElem.vertices[0] = Vector2((float)offset.x, (float)offset.y);
99 renderElem.vertices[1] = Vector2((float)offset.x + leftBorder, (float)offset.y);
100 renderElem.vertices[2] = Vector2((float)offset.x, middleStart);
101 renderElem.vertices[3] = Vector2((float)offset.x + leftBorder, middleStart);
102
103 // Top center
104 renderElem.vertices[4] = Vector2(topCenterStart, (float)offset.y);
105 renderElem.vertices[5] = Vector2(topCenterStart + centerWidth, (float)offset.y);
106 renderElem.vertices[6] = Vector2(topCenterStart, middleStart);
107 renderElem.vertices[7] = Vector2(topCenterStart + centerWidth, middleStart);
108
109 // Top right
110 renderElem.vertices[8] = Vector2(topRightStart, (float)offset.y);
111 renderElem.vertices[9] = Vector2(topRightStart + rightBorder, (float)offset.y);
112 renderElem.vertices[10] = Vector2(topRightStart, middleStart);
113 renderElem.vertices[11] = Vector2(topRightStart + rightBorder, middleStart);
114
115 // Middle left
116 renderElem.vertices[12] = Vector2((float)offset.x, middleStart);
117 renderElem.vertices[13] = Vector2((float)offset.x + leftBorder, middleStart);
118 renderElem.vertices[14] = Vector2((float)offset.x, bottomStart);
119 renderElem.vertices[15] = Vector2((float)offset.x + leftBorder, bottomStart);
120
121 // Middle center
122 renderElem.vertices[16] = Vector2(topCenterStart, middleStart);
123 renderElem.vertices[17] = Vector2(topCenterStart + centerWidth, middleStart);
124 renderElem.vertices[18] = Vector2(topCenterStart, bottomStart);
125 renderElem.vertices[19] = Vector2(topCenterStart + centerWidth, bottomStart);
126
127 // Middle right
128 renderElem.vertices[20] = Vector2(topRightStart, middleStart);
129 renderElem.vertices[21] = Vector2(topRightStart + rightBorder, middleStart);
130 renderElem.vertices[22] = Vector2(topRightStart, bottomStart);
131 renderElem.vertices[23] = Vector2(topRightStart + rightBorder, bottomStart);
132
133 // Bottom left
134 renderElem.vertices[24] = Vector2((float)offset.x, bottomStart);
135 renderElem.vertices[25] = Vector2((float)offset.x + leftBorder, bottomStart);
136 renderElem.vertices[26] = Vector2((float)offset.x, bottomStart + bottomBorder);
137 renderElem.vertices[27] = Vector2((float)offset.x + leftBorder, bottomStart + bottomBorder);
138
139 // Bottom center
140 renderElem.vertices[28] = Vector2(topCenterStart, bottomStart);
141 renderElem.vertices[29] = Vector2(topCenterStart + centerWidth, bottomStart);
142 renderElem.vertices[30] = Vector2(topCenterStart, bottomStart + bottomBorder);
143 renderElem.vertices[31] = Vector2(topCenterStart + centerWidth, bottomStart + bottomBorder);
144
145 // Bottom right
146 renderElem.vertices[32] = Vector2(topRightStart, bottomStart);
147 renderElem.vertices[33] = Vector2(topRightStart + rightBorder, bottomStart);
148 renderElem.vertices[34] = Vector2(topRightStart, bottomStart + bottomBorder);
149 renderElem.vertices[35] = Vector2(topRightStart + rightBorder, bottomStart + bottomBorder);
150
151 float invWidth = 1.0f / (float)desc.texture->getTexture()->getProperties().getWidth();
152 float invHeight = 1.0f / (float)desc.texture->getTexture()->getProperties().getHeight();
153
154 float uvLeftBorder = desc.borderLeft * invWidth;
155 float uvRightBorder = desc.borderRight * invWidth;
156 float uvTopBorder = desc.borderTop * invHeight;
157 float uvBottomBorder = desc.borderBottom * invHeight;
158
159 float uvCenterWidth = std::max(0.0f, uvScale.x - uvLeftBorder - uvRightBorder);
160 float uvCenterHeight = std::max(0.0f, uvScale.y - uvTopBorder - uvBottomBorder);
161
162 float uvTopCenterStart = uvOffset.x + uvLeftBorder;
163 float uvTopRightStart = uvTopCenterStart + uvCenterWidth;
164
165 float uvMiddleStart = uvOffset.y + uvTopBorder;
166 float uvBottomStart = uvMiddleStart + uvCenterHeight;
167
168 // UV - Top left
169 renderElem.uvs[0] = desc.texture->transformUV(Vector2(uvOffset.x, uvOffset.y));
170 renderElem.uvs[1] = desc.texture->transformUV(Vector2(uvOffset.x + uvLeftBorder, uvOffset.y));
171 renderElem.uvs[2] = desc.texture->transformUV(Vector2(uvOffset.x, uvOffset.y + uvTopBorder));
172 renderElem.uvs[3] = desc.texture->transformUV(Vector2(uvOffset.x + uvLeftBorder, uvOffset.y + uvTopBorder));
173
174 // UV - Top center
175 renderElem.uvs[4] = desc.texture->transformUV(Vector2(uvTopCenterStart, uvOffset.y));
176 renderElem.uvs[5] = desc.texture->transformUV(Vector2(uvTopCenterStart + uvCenterWidth, uvOffset.y));
177 renderElem.uvs[6] = desc.texture->transformUV(Vector2(uvTopCenterStart, uvOffset.y + uvTopBorder));
178 renderElem.uvs[7] = desc.texture->transformUV(Vector2(uvTopCenterStart + uvCenterWidth, uvOffset.y + uvTopBorder));
179
180 // UV - Top right
181 renderElem.uvs[8] = desc.texture->transformUV(Vector2(uvTopRightStart, uvOffset.y));
182 renderElem.uvs[9] = desc.texture->transformUV(Vector2(uvTopRightStart + uvRightBorder, uvOffset.y));
183 renderElem.uvs[10] = desc.texture->transformUV(Vector2(uvTopRightStart, uvOffset.y + uvTopBorder));
184 renderElem.uvs[11] = desc.texture->transformUV(Vector2(uvTopRightStart + uvRightBorder, uvOffset.y + uvTopBorder));
185
186 // UV - Middle left
187 renderElem.uvs[12] = desc.texture->transformUV(Vector2(uvOffset.x, uvMiddleStart));
188 renderElem.uvs[13] = desc.texture->transformUV(Vector2(uvOffset.x + uvLeftBorder, uvMiddleStart));
189 renderElem.uvs[14] = desc.texture->transformUV(Vector2(uvOffset.x, uvMiddleStart + uvCenterHeight));
190 renderElem.uvs[15] = desc.texture->transformUV(Vector2(uvOffset.x + uvLeftBorder, uvMiddleStart + uvCenterHeight));
191
192 // UV - Middle center
193 renderElem.uvs[16] = desc.texture->transformUV(Vector2(uvTopCenterStart, uvMiddleStart));
194 renderElem.uvs[17] = desc.texture->transformUV(Vector2(uvTopCenterStart + uvCenterWidth, uvMiddleStart));
195 renderElem.uvs[18] = desc.texture->transformUV(Vector2(uvTopCenterStart, uvMiddleStart + uvCenterHeight));
196 renderElem.uvs[19] = desc.texture->transformUV(Vector2(uvTopCenterStart + uvCenterWidth, uvMiddleStart + uvCenterHeight));
197
198 // UV - Middle right
199 renderElem.uvs[20] = desc.texture->transformUV(Vector2(uvTopRightStart, uvMiddleStart));
200 renderElem.uvs[21] = desc.texture->transformUV(Vector2(uvTopRightStart + uvRightBorder, uvMiddleStart));
201 renderElem.uvs[22] = desc.texture->transformUV(Vector2(uvTopRightStart, uvMiddleStart + uvCenterHeight));
202 renderElem.uvs[23] = desc.texture->transformUV(Vector2(uvTopRightStart + uvRightBorder, uvMiddleStart + uvCenterHeight));
203
204 // UV - Bottom left
205 renderElem.uvs[24] = desc.texture->transformUV(Vector2(uvOffset.x, uvBottomStart));
206 renderElem.uvs[25] = desc.texture->transformUV(Vector2(uvOffset.x + uvLeftBorder, uvBottomStart));
207 renderElem.uvs[26] = desc.texture->transformUV(Vector2(uvOffset.x, uvBottomStart + uvBottomBorder));
208 renderElem.uvs[27] = desc.texture->transformUV(Vector2(uvOffset.x + uvLeftBorder, uvBottomStart + uvBottomBorder));
209
210 // UV - Bottom center
211 renderElem.uvs[28] = desc.texture->transformUV(Vector2(uvTopCenterStart, uvBottomStart));
212 renderElem.uvs[29] = desc.texture->transformUV(Vector2(uvTopCenterStart + uvCenterWidth, uvBottomStart));
213 renderElem.uvs[30] = desc.texture->transformUV(Vector2(uvTopCenterStart, uvBottomStart + uvBottomBorder));
214 renderElem.uvs[31] = desc.texture->transformUV(Vector2(uvTopCenterStart + uvCenterWidth, uvBottomStart + uvBottomBorder));
215
216 // UV - Bottom right
217 renderElem.uvs[32] = desc.texture->transformUV(Vector2(uvTopRightStart, uvBottomStart));
218 renderElem.uvs[33] = desc.texture->transformUV(Vector2(uvTopRightStart + uvRightBorder, uvBottomStart));
219 renderElem.uvs[34] = desc.texture->transformUV(Vector2(uvTopRightStart, uvBottomStart + uvBottomBorder));
220 renderElem.uvs[35] = desc.texture->transformUV(Vector2(uvTopRightStart + uvRightBorder, uvBottomStart + uvBottomBorder));
221 }
222 else
223 {
224 renderElem.vertices[0] = Vector2((float)offset.x, (float)offset.y);
225 renderElem.vertices[1] = Vector2((float)offset.x + desc.width, (float)offset.y);
226 renderElem.vertices[2] = Vector2((float)offset.x, (float)offset.y + desc.height);
227 renderElem.vertices[3] = Vector2((float)offset.x + desc.width, (float)offset.y + desc.height);
228
229 renderElem.uvs[0] = desc.texture->transformUV(Vector2(uvOffset.x, uvOffset.y));
230 renderElem.uvs[1] = desc.texture->transformUV(Vector2(uvOffset.x + uvScale.x, uvOffset.y));
231 renderElem.uvs[2] = desc.texture->transformUV(Vector2(uvOffset.x, uvOffset.y + uvScale.y));
232 renderElem.uvs[3] = desc.texture->transformUV(Vector2(uvOffset.x + uvScale.x, uvOffset.y + uvScale.y));
233 }
234
235 updateBounds();
236 }
237
238 void ImageSprite::clearMesh()
239 {
240 for (auto& renderElem : mCachedRenderElements)
241 {
242 UINT32 vertexCount = renderElem.numQuads * 4;
243 UINT32 indexCount = renderElem.numQuads * 6;
244
245 if (renderElem.vertices != nullptr)
246 {
247 bs_deleteN(renderElem.vertices, vertexCount);
248 renderElem.vertices = nullptr;
249 }
250
251 if (renderElem.uvs != nullptr)
252 {
253 bs_deleteN(renderElem.uvs, vertexCount);
254 renderElem.uvs = nullptr;
255 }
256
257 if (renderElem.indexes != nullptr)
258 {
259 bs_deleteN(renderElem.indexes, indexCount);
260 renderElem.indexes = nullptr;
261 }
262 }
263
264 mCachedRenderElements.clear();
265 updateBounds();
266 }
267
268 Vector2 ImageSprite::getTextureUVScale(Vector2I sourceSize, Vector2I destSize, TextureScaleMode scaleMode)
269 {
270 Vector2 uvScale = Vector2(1.0f, 1.0f);
271
272 switch (scaleMode)
273 {
274 case TextureScaleMode::ScaleToFit:
275 uvScale.x = sourceSize.x / (float)destSize.x;
276 uvScale.y = sourceSize.y / (float)destSize.y;
277
278 if (uvScale.x > uvScale.y)
279 {
280 uvScale.x = 1.0f;
281 uvScale.y = (destSize.y * (sourceSize.y / (float)sourceSize.x)) / destSize.x;
282 }
283 else
284 {
285 uvScale.x = (destSize.x * (sourceSize.x / (float)sourceSize.y)) / destSize.y;
286 uvScale.y = 1.0f;
287 }
288
289 break;
290 case TextureScaleMode::CropToFit:
291 uvScale.x = sourceSize.x / (float)destSize.x;
292 uvScale.y = sourceSize.y / (float)destSize.y;
293
294 if (uvScale.x > uvScale.y)
295 {
296 uvScale.x = (destSize.x * (sourceSize.x / (float)sourceSize.y)) / destSize.y;
297 uvScale.y = 1.0f;
298 }
299 else
300 {
301 uvScale.x = 1.0f;
302 uvScale.y = (destSize.y * (sourceSize.y / (float)sourceSize.x)) / destSize.x;
303 }
304
305 break;
306 case TextureScaleMode::RepeatToFit:
307 uvScale.x = destSize.x / (float)sourceSize.x;
308 uvScale.y = destSize.y / (float)sourceSize.y;
309 break;
310 case TextureScaleMode::StretchToFit:
311 // Do nothing, (1.0f, 1.0f) is the default UV scale
312 break;
313 default:
314 break;
315 }
316
317 return uvScale;
318 }
319}