MyGUI 3.4.3
MyGUI_PolygonalSkin.cpp
Go to the documentation of this file.
1/*
2 * This source file is part of MyGUI. For the latest info, see http://mygui.info/
3 * Distributed under the MIT License
4 * (See accompanying file COPYING.MIT or copy at http://opensource.org/licenses/MIT)
5 */
6
7#include "MyGUI_Precompiled.h"
9#include "MyGUI_RenderItem.h"
11#include "MyGUI_RenderManager.h"
13
14namespace MyGUI
15{
16
21
22 inline float len(float x, float y)
23 {
24 return std::sqrt(x * x + y * y);
25 }
26
27 void PolygonalSkin::setPoints(const std::vector<FloatPoint>& _points)
28 {
29 if (_points.size() < 2)
30 {
31 mVertexCount = 0;
32 mResultVerticiesPos.clear();
33 mResultVerticiesUV.clear();
34 mLinePoints = _points;
35 return;
36 }
37
38 VectorFloatPoint finalPoints;
39 finalPoints.reserve(_points.size());
40
41 mLineLength = 0.0f;
42 FloatPoint point0 = _points[0];
43 finalPoints.push_back(point0);
44 // ignore repeating points
45 for (const auto& point : _points)
46 {
47 if (point0 != point)
48 {
49 finalPoints.push_back(point);
50 mLineLength += len(point.left - point0.left, point.top - point0.top);
51 point0 = point;
52 }
53 }
54
55 mLinePoints = finalPoints;
56
57#ifdef MYGUI_NO_POLYGONAL_SKIN_CROPPING
58 size_t count = (mLinePoints.size() - 1) * VertexQuad::VertexCount * 2;
59#else
60 // it's too hard to calculate maximum possible verticies count and worst
61 // approximation gives 7 times more verticies than in not cropped geometry
62 // so we multiply count by 2, because this looks enough
63 size_t count = (mLinePoints.size() - 1) * VertexQuad::VertexCount * 2 * 2;
64#endif
65 if (count > mVertexCount)
66 {
67 mVertexCount = count;
68 if (nullptr != mRenderItem)
69 mRenderItem->reallockDrawItem(this, mVertexCount);
70 }
71
73 }
74
75 void PolygonalSkin::setWidth(float _width)
76 {
77 mLineWidth = _width;
79 }
80
81 void PolygonalSkin::setStroke(size_t _value)
82 {
83 mLineStroke = _value;
85 }
86
87 void PolygonalSkin::setVisible(bool _visible)
88 {
89 if (mVisible == _visible)
90 return;
91
92 mVisible = _visible;
93 mGeometryOutdated = true;
94
95 if (nullptr != mNode)
96 mNode->outOfDate(mRenderItem);
97 }
98
99 void PolygonalSkin::setAlpha(float _alpha)
100 {
101 uint32 alpha = ((uint8)(_alpha * 255) << 24);
102 mCurrentColour = (mCurrentColour & 0x00FFFFFF) | (alpha & 0xFF000000);
103
104 if (nullptr != mNode)
105 mNode->outOfDate(mRenderItem);
106 }
107
109 {
110 mGeometryOutdated = true;
111
112 if (nullptr != mNode)
113 mNode->outOfDate(mRenderItem);
114 }
115
116 void PolygonalSkin::_setAlign(const IntSize& _oldsize)
117 {
118 // первоначальное выравнивание
119 if (mAlign.isHStretch())
120 {
121 // растягиваем
122 mCoord.width = mCoord.width + (mCroppedParent->getWidth() - _oldsize.width);
123 mIsMargin = true; // при изменении размеров все пересчитывать
124 }
125 else if (mAlign.isRight())
126 {
127 // двигаем по правому краю
128 mCoord.left = mCoord.left + (mCroppedParent->getWidth() - _oldsize.width);
129 }
130 else if (mAlign.isHCenter())
131 {
132 // выравнивание по горизонтали без растяжения
133 mCoord.left = (mCroppedParent->getWidth() - mCoord.width) / 2;
134 }
135
136 if (mAlign.isVStretch())
137 {
138 // растягиваем
139 mCoord.height = mCoord.height + (mCroppedParent->getHeight() - _oldsize.height);
140 mIsMargin = true; // при изменении размеров все пересчитывать
141 }
142 else if (mAlign.isBottom())
143 {
144 // двигаем по нижнему краю
145 mCoord.top = mCoord.top + (mCroppedParent->getHeight() - _oldsize.height);
146 }
147 else if (mAlign.isVCenter())
148 {
149 // выравнивание по вертикали без растяжения
150 mCoord.top = (mCroppedParent->getHeight() - mCoord.height) / 2;
151 }
152
153 mCurrentCoord = mCoord;
154 _updateView();
155 }
156
158 {
159 bool margin = _checkMargin();
160
161 mEmptyView = ((0 >= _getViewWidth()) || (0 >= _getViewHeight()));
162
163 mGeometryOutdated = true;
164
165 mCurrentCoord.left = mCoord.left + mMargin.left;
166 mCurrentCoord.top = mCoord.top + mMargin.top;
167
168 // вьюпорт стал битым
169 if (margin)
170 {
171 // проверка на полный выход за границу
172 if (_checkOutside())
173 {
174 // запоминаем текущее состояние
175 mIsMargin = margin;
176
177 // обновить перед выходом
178 if (nullptr != mNode)
179 mNode->outOfDate(mRenderItem);
180 return;
181 }
182 }
183
184 // мы обрезаны или были обрезаны
185 if (mIsMargin || margin)
186 {
187 mCurrentCoord.width = _getViewWidth();
188 mCurrentCoord.height = _getViewHeight();
189 }
190
191 // запоминаем текущее состояние
192 mIsMargin = margin;
193
194 if (nullptr != mNode)
195 mNode->outOfDate(mRenderItem);
196 }
197
199 {
200 MYGUI_ASSERT(!mRenderItem, "mRenderItem must be nullptr");
201
202 mNode = _node;
203 mRenderItem = mNode->addToRenderItem(_texture, true, false);
204 mRenderItem->addDrawItem(this, mVertexCount);
205 }
206
208 {
209 MYGUI_ASSERT(mRenderItem, "mRenderItem must be not nullptr");
210
211 mNode = nullptr;
212 mRenderItem->removeDrawItem(this);
213 mRenderItem = nullptr;
214 }
215
217 {
218 if (!mVisible || mEmptyView)
219 return;
220
221 bool update = mRenderItem->getCurrentUpdate();
222 if (update)
223 mGeometryOutdated = true;
224
225 Vertex* verticies = mRenderItem->getCurrentVertexBuffer();
226
227 float vertex_z = mNode->getNodeDepth();
228
229 if (mGeometryOutdated)
230 {
232 }
233
234 size_t size = mResultVerticiesPos.size();
235
236 for (size_t i = 0; i < size; ++i)
237 {
238 verticies[i].set(
239 mResultVerticiesPos[i].left,
240 mResultVerticiesPos[i].top,
241 vertex_z,
242 mResultVerticiesUV[i].left,
243 mResultVerticiesUV[i].top,
244 mCurrentColour);
245 }
246
247 mRenderItem->setLastVertexCount(size);
248 }
249
251 {
252 uint32 colour = texture_utility::toNativeColour(_value, mVertexFormat);
253 mCurrentColour = (colour & 0x00FFFFFF) | (mCurrentColour & 0xFF000000);
254
255 if (nullptr != mNode)
256 mNode->outOfDate(mRenderItem);
257 }
258
263
265 {
266 mCurrentTexture = _rect;
267
268 mGeometryOutdated = true;
269
270 if (nullptr != mNode)
271 mNode->outOfDate(mRenderItem);
272 }
273
275 {
276 if (mLinePoints.size() < 2)
277 return;
278 if (!mRenderItem || !mRenderItem->getRenderTarget())
279 return;
280
281 mGeometryOutdated = false;
282
283 // using mCurrentCoord as rectangle where we draw polygons
284
285 // base texture coordinates
286 FloatPoint baseVerticiesUV[4] = {
287 FloatPoint(mCurrentTexture.left, mCurrentTexture.top),
288 FloatPoint(mCurrentTexture.right, mCurrentTexture.top),
289 FloatPoint(mCurrentTexture.right, mCurrentTexture.bottom),
290 FloatPoint(mCurrentTexture.left, mCurrentTexture.bottom)};
291
292 // UV vectors
293 FloatPoint vectorU = baseVerticiesUV[1] - baseVerticiesUV[0];
294 //FloatPoint vectorV = baseVerticiesUV[3] - baseVerticiesUV[0];
295
296 mResultVerticiesPos.clear();
297 mResultVerticiesUV.clear();
298 // add first two verticies
299 FloatPoint normal = _getPerpendicular(mLinePoints[0], mLinePoints[1]);
300
301 FloatPoint points[2] = {mLinePoints[0] + normal, mLinePoints[0] - normal};
302 FloatPoint pointsUV[2] = {baseVerticiesUV[0], baseVerticiesUV[3]};
303
304 bool draw = true;
305 size_t stroke = 0;
306
307 // add other verticies
308 float currentLength = 0.0f;
309 for (size_t i = 1; i < mLinePoints.size(); ++i)
310 {
311 if (mLineStroke != 0)
312 {
313 stroke++;
314 if (stroke == mLineStroke)
315 {
316 stroke = 0;
317 draw = !draw;
318 }
319 }
320
321 currentLength +=
322 len(mLinePoints[i - 1].left - mLinePoints[i].left, mLinePoints[i - 1].top - mLinePoints[i].top);
323
324 // getting normal between previous and next point
325 if (i != mLinePoints.size() - 1)
326 normal = _getMiddleLine(mLinePoints[i - 1], mLinePoints[i + 1], mLinePoints[i]);
327 else
328 normal = _getPerpendicular(mLinePoints[i - 1], mLinePoints[i]);
329
330 bool edge = false;
331 bool sharp = false;
332 if (normal == FloatPoint() /*|| len(normal.left, normal.top) > mLineWidth * 2*/)
333 {
334 edge = true;
335 normal = _getPerpendicular(mLinePoints[i - 1], mLinePoints[i]);
336 }
337 else if (len(normal.left, normal.top) > mLineWidth * 1.5f)
338 {
339 sharp = true;
340 normal = _getPerpendicular(mLinePoints[i - 1], mLinePoints[i]);
341 }
342
343 // check orientation
344 FloatPoint lineDir = mLinePoints[i] - mLinePoints[i - 1];
345 if (lineDir.left * normal.top - lineDir.top * normal.left < 0)
346 {
347 normal.left = -normal.left;
348 normal.top = -normal.top;
349 }
350
351 FloatPoint UVoffset(currentLength / mLineLength * vectorU.left, currentLength / mLineLength * vectorU.top);
352
353 if (draw)
354 {
355 mResultVerticiesPos.push_back(points[0]);
356 mResultVerticiesPos.push_back(points[1]);
357 mResultVerticiesPos.push_back(mLinePoints[i] + normal);
358 mResultVerticiesUV.push_back(pointsUV[0]);
359 mResultVerticiesUV.push_back(pointsUV[1]);
360 mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset);
361
362 mResultVerticiesPos.push_back(points[1]);
363 mResultVerticiesPos.push_back(mLinePoints[i] - normal);
364 mResultVerticiesPos.push_back(mLinePoints[i] + normal);
365 mResultVerticiesUV.push_back(pointsUV[1]);
366 mResultVerticiesUV.push_back(baseVerticiesUV[3] + UVoffset);
367 mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset);
368 }
369
370 points[edge ? 1 : 0] = mLinePoints[i] + normal;
371 points[edge ? 0 : 1] = mLinePoints[i] - normal;
372 pointsUV[0] = baseVerticiesUV[0] + UVoffset;
373 pointsUV[1] = baseVerticiesUV[3] + UVoffset;
374
375 if (sharp)
376 {
377 normal = _getMiddleLine(mLinePoints[i - 1], mLinePoints[i + 1], mLinePoints[i]);
378
379 float sharpness = len(normal.left, normal.top) / mLineWidth;
380
381 float length = len(normal.left, normal.top);
382 normal.left *= 2 * mLineWidth / length / (sharpness - 0.5f);
383 normal.top *= 2 * mLineWidth / length / (sharpness - 0.5f);
384
385 // check orientation
386 lineDir = mLinePoints[i] - mLinePoints[i - 1];
387 if (lineDir.left * normal.top - lineDir.top * normal.left < 0)
388 {
389 normal.left = -normal.left;
390 normal.top = -normal.top;
391 }
392 FloatPoint lineDir1 = mLinePoints[i] - mLinePoints[i - 1];
393 FloatPoint lineDir2 = mLinePoints[i + 1] - mLinePoints[i];
394 if (lineDir1.left * lineDir2.top - lineDir1.top * lineDir2.left > 0)
395 {
396 normal.left = -normal.left;
397 normal.top = -normal.top;
398 }
399
400 // check orientation
401 FloatPoint normal2 = _getPerpendicular(mLinePoints[i], mLinePoints[i + 1]);
402 lineDir = mLinePoints[i - 1] - mLinePoints[i];
403 if (lineDir.left * normal2.top - lineDir.top * normal2.left < 0)
404 {
405 normal2.left = -normal2.left;
406 normal2.top = -normal2.top;
407 }
408
409 FloatPoint UVcenter(
410 (baseVerticiesUV[0].left + baseVerticiesUV[3].left) / 2,
411 (baseVerticiesUV[0].top + baseVerticiesUV[3].top) / 2);
412
413 if (draw)
414 {
415 mResultVerticiesPos.push_back(points[0]);
416 mResultVerticiesPos.push_back(mLinePoints[i] + normal);
417 mResultVerticiesPos.push_back(mLinePoints[i]);
418 mResultVerticiesUV.push_back(pointsUV[0]);
419 mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset);
420 mResultVerticiesUV.push_back(UVcenter + UVoffset);
421
422 mResultVerticiesPos.push_back(mLinePoints[i] + normal);
423 mResultVerticiesPos.push_back(mLinePoints[i] + normal2);
424 mResultVerticiesPos.push_back(mLinePoints[i]);
425 mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset);
426 mResultVerticiesUV.push_back(baseVerticiesUV[0] + UVoffset);
427 mResultVerticiesUV.push_back(UVcenter + UVoffset);
428 }
429
430 points[0] = mLinePoints[i] + normal2;
431 points[1] = mLinePoints[i] - normal2;
432 pointsUV[0] = baseVerticiesUV[0] + UVoffset;
433 pointsUV[1] = baseVerticiesUV[3] + UVoffset;
434 }
435 }
436
437
438#ifndef MYGUI_NO_POLYGONAL_SKIN_CROPPING
439 // crop triangles
440 IntCoord cropRectangle(mCurrentCoord.left, mCurrentCoord.top, mCurrentCoord.width, mCurrentCoord.height);
441
442 VectorFloatPoint newResultVerticiesPos;
443 VectorFloatPoint newResultVerticiesUV;
444 newResultVerticiesPos.reserve(mResultVerticiesPos.size());
445 newResultVerticiesUV.reserve(mResultVerticiesPos.size());
446 for (size_t i = 0; i < mResultVerticiesPos.size(); i += 3)
447 {
448 VectorFloatPoint croppedTriangle = geometry_utility::cropPolygon(&mResultVerticiesPos[i], 3, cropRectangle);
449 if (!croppedTriangle.empty())
450 {
451 FloatPoint v0 = mResultVerticiesUV[i + 2] - mResultVerticiesUV[i];
452 FloatPoint v1 = mResultVerticiesUV[i + 1] - mResultVerticiesUV[i];
453
454 for (size_t j = 1; j < croppedTriangle.size() - 1; ++j)
455 {
456 newResultVerticiesPos.push_back(croppedTriangle[0]);
457 newResultVerticiesPos.push_back(croppedTriangle[j]);
458 newResultVerticiesPos.push_back(croppedTriangle[j + 1]);
459
460 // calculate UV
461 FloatPoint point;
463 croppedTriangle[0],
464 mResultVerticiesPos[i],
465 mResultVerticiesPos[i + 1],
466 mResultVerticiesPos[i + 2]);
467 newResultVerticiesUV.push_back(
468 geometry_utility::getUVFromPositionInsideRect(point, v0, v1, mResultVerticiesUV[i]));
470 croppedTriangle[j],
471 mResultVerticiesPos[i],
472 mResultVerticiesPos[i + 1],
473 mResultVerticiesPos[i + 2]);
474 newResultVerticiesUV.push_back(
475 geometry_utility::getUVFromPositionInsideRect(point, v0, v1, mResultVerticiesUV[i]));
477 croppedTriangle[j + 1],
478 mResultVerticiesPos[i],
479 mResultVerticiesPos[i + 1],
480 mResultVerticiesPos[i + 2]);
481 newResultVerticiesUV.push_back(
482 geometry_utility::getUVFromPositionInsideRect(point, v0, v1, mResultVerticiesUV[i]));
483 }
484 }
485 }
486 std::swap(mResultVerticiesPos, newResultVerticiesPos);
487 std::swap(mResultVerticiesUV, newResultVerticiesUV);
488#endif
489
490
491 // now calculate widget base offset and then resulting position in screen coordinates
492 const RenderTargetInfo& info = mRenderItem->getRenderTarget()->getInfo();
493 float vertex_left_base = ((info.pixScaleX * (float)(mCroppedParent->getAbsoluteLeft()) + info.hOffset) * 2) - 1;
494 float vertex_top_base =
495 -(((info.pixScaleY * (float)(mCroppedParent->getAbsoluteTop()) + info.vOffset) * 2) - 1);
496
497 for (auto& pos : mResultVerticiesPos)
498 {
499 pos.left = vertex_left_base + pos.left * info.pixScaleX * 2;
500 pos.top = vertex_top_base + pos.top * info.pixScaleY * -2;
501 }
502 }
503
505 {
506 // dy, -dx
507 FloatPoint result(_point1.top - _point2.top, -(_point1.left - _point2.left));
508 // normalise
509 float length = len(result.top, result.left);
510 result.left /= length;
511 result.top /= length;
512 result.left *= mLineWidth / 2;
513 result.top *= mLineWidth / 2;
514 return result;
515 }
516
518 const FloatPoint& _point1,
519 const FloatPoint& _point2,
520 const FloatPoint& _point3) const
521 {
522 // bisectrix
523 FloatPoint line1 = _point3 - _point1;
524 FloatPoint line2 = _point3 - _point2;
525 float length = len(line1.top, line1.left);
526 line1.left /= length;
527 line1.top /= length;
528 length = len(line2.top, line2.left);
529 line2.left /= length;
530 line2.top /= length;
531 FloatPoint result = line1 + line2;
532 // normalise
533 length = len(result.top, result.left);
534 if (length < 1e-6f)
535 {
536 return _getPerpendicular(_point1, _point2);
537 }
538 result.left /= length;
539 result.top /= length;
540
541 float cos = result.left * line1.left + result.top * line1.top;
542 float angle = std::acos(cos);
543
544 // too sharp angle
545 if (std::fabs(angle) < 1e-6f /*< 0.2f*/)
546 return {};
547
548 float width = mLineWidth / 2 / std::sin(angle);
549 result.left *= width;
550 result.top *= width;
551 return result;
552 }
553
554} // namespace MyGUI
#define MYGUI_ASSERT(exp, dest)
virtual RenderItem * addToRenderItem(ITexture *_texture, bool _firstQueue, bool _separate)=0
Type * castType(bool _throw=true)
FloatPoint _getMiddleLine(const FloatPoint &_point1, const FloatPoint &_point2, const FloatPoint &_point3) const
void createDrawItem(ITexture *_texture, ILayerNode *_node) override
void _setAlign(const IntSize &_oldsize) override
FloatPoint _getPerpendicular(const FloatPoint &_point1, const FloatPoint &_point2) const
void setPoints(const std::vector< FloatPoint > &_points)
void setStateData(IStateInfo *_data) override
void setVisible(bool _visible) override
void setAlpha(float _alpha) override
void _setUVSet(const FloatRect &_rect) override
void setWidth(float _width)
void _setColour(const Colour &_value) override
void setStroke(size_t _value)
void addDrawItem(ISubWidget *_item, size_t _count)
virtual VertexColourType getVertexFormat() const =0
static RenderManager & getInstance()
const FloatRect & getRect() const
FloatPoint getUVFromPositionInsideRect(const FloatPoint &_point, const FloatPoint &_v0, const FloatPoint &_v1, const FloatPoint &_baseUV)
FloatPoint getPositionInsideRect(const FloatPoint &_point, const FloatPoint &_corner0, const FloatPoint &_corner1, const FloatPoint &_corner2)
VectorFloatPoint cropPolygon(FloatPoint *_baseVerticiesPos, size_t _size, const IntCoord &_cropRectangle)
uint32 toNativeColour(const Colour &_colour, VertexColourType _format)
Convert Colour to 32-bit representation.
uint32_t uint32
Definition MyGUI_Types.h:48
uint8_t uint8
Definition MyGUI_Types.h:46
types::TRect< float > FloatRect
Definition MyGUI_Types.h:34
types::TPoint< float > FloatPoint
Definition MyGUI_Types.h:28
std::vector< FloatPoint > VectorFloatPoint
types::TCoord< int > IntCoord
Definition MyGUI_Types.h:36
types::TSize< int > IntSize
Definition MyGUI_Types.h:30
float len(float x, float y)
void set(float _x, float _y, float _z, float _u, float _v, uint32 _colour)