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