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