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 | |
8 | namespace 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 | } |