Merge branch 'main/rendor-staging' into fixes
[ryzomcore.git] / nel / src / gui / css_border_renderer.cpp
blobcb2ef9709b076c9bedd8dcc5ef48f1ad736ab4a1
1 // Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
2 // Copyright (C) 2010-2019 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
18 #include "stdpch.h"
19 #include "nel/gui/css_border_renderer.h"
20 #include "nel/gui/view_renderer.h"
21 #include "nel/gui/widget_manager.h"
23 using namespace std;
24 using namespace NLMISC;
26 #ifdef DEBUG_NEW
27 #define new DEBUG_NEW
28 #endif
30 namespace NLGUI
32 // ----------------------------------------------------------------------------
33 CSSBorderRenderer::CSSBorderRenderer()
35 CurrentAlpha = 255;
37 m_Scale = 1.f;
38 m_RenderLayer = 0;
39 m_ModulateGlobalColor = false;
41 m_Dirty = true;
42 m_MustComputeValues = true;
43 m_XReal = 0;
44 m_YReal = 0;
45 m_WReal = 0;
46 m_HReal = 0;
48 m_Viewport = NULL;
49 m_FontSize = 16.f;
50 m_RootFontSize = 16.f;
52 m_Computed.Top = m_Computed.Right = m_Computed.Bottom = m_Computed.Left = 0;
55 // ----------------------------------------------------------------------------
56 void CSSBorderRenderer::setRenderLayer(sint layer)
58 m_RenderLayer = layer;
61 // ----------------------------------------------------------------------------
62 void CSSBorderRenderer::setModulateGlobalColor(bool s)
64 m_ModulateGlobalColor = s;
67 // ----------------------------------------------------------------------------
68 void CSSBorderRenderer::setRect(sint32 x, sint32 y, sint32 w, sint32 h)
70 m_XReal = x;
71 m_YReal = y;
72 m_WReal = w;
73 m_HReal = h;
75 m_Dirty = (w > 0 && h > 0);
78 // ----------------------------------------------------------------------------
79 bool CSSBorderRenderer::hasInnerShape(CSSLineStyle style) const
81 return style == CSS_LINE_STYLE_DOUBLE ||
82 style == CSS_LINE_STYLE_GROOVE ||
83 style == CSS_LINE_STYLE_RIDGE;
86 // ----------------------------------------------------------------------------
87 void CSSBorderRenderer::computeValues()
89 m_MustComputeValues = false;
91 // TODO :should save as computed value
92 sint32 vpW=0;
93 sint32 vpH=0;
94 if (m_Viewport)
96 vpW = m_Viewport->getWReal();
97 vpH = m_Viewport->getHReal();
100 m_Computed.Top = m_Border.Top.empty() ? 0 : m_Border.Top.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
101 m_Computed.Right = m_Border.Right.empty() ? 0 : m_Border.Right.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
102 m_Computed.Bottom = m_Border.Bottom.empty() ? 0 : m_Border.Bottom.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
103 m_Computed.Left = m_Border.Left.empty() ? 0 : m_Border.Left.Width.calculate(0, m_FontSize, m_RootFontSize, vpW, vpH);
106 // ----------------------------------------------------------------------------
107 void CSSBorderRenderer::getAdjacentBorders(EBorderSide side, EBorderSide &adjBorderL, EBorderSide &adjBorderR) const
109 switch(side)
111 case BORDER_TOP:
112 adjBorderL = BORDER_TOP_LEFT;
113 adjBorderR = BORDER_TOP_RIGHT;
114 break;
115 case BORDER_RIGHT:
116 adjBorderL = BORDER_RIGHT_BOTTOM;
117 adjBorderR = BORDER_RIGHT_TOP;
118 break;
119 case BORDER_BOTTOM:
120 adjBorderL = BORDER_BOTTOM_LEFT;
121 adjBorderR = BORDER_BOTTOM_RIGHT;
122 break;
123 case BORDER_LEFT:
124 adjBorderL = BORDER_LEFT_BOTTOM;
125 adjBorderR = BORDER_LEFT_TOP;
126 break;
127 default:
128 adjBorderL = adjBorderR = BORDER_INVALID;
129 break;
133 // ----------------------------------------------------------------------------
134 void CSSBorderRenderer::getAdjacentBorderWidth(EBorderSide side, sint32 &adjWidthL, sint32 &adjWidthR) const
136 switch(side)
138 case BORDER_TOP:
139 case BORDER_BOTTOM:
140 adjWidthL = m_Computed.Left;
141 adjWidthR = m_Computed.Right;
142 break;
143 case BORDER_LEFT:
144 case BORDER_RIGHT:
145 adjWidthL = m_Computed.Bottom;
146 adjWidthR = m_Computed.Top;
147 break;
148 default:
149 adjWidthL = adjWidthR = 0;
150 break;
154 // ----------------------------------------------------------------------------
155 void CSSBorderRenderer::buildDotCornerStart(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius)
157 NLMISC::CLine line;
158 switch(side)
160 case BORDER_TOP:
161 line.V0.set(m_XReal + m_Computed.Left, m_YReal + m_HReal - m_Computed.Top, 0);
162 line.V1.set(m_XReal, m_YReal + m_HReal, 0);
163 buildDotCorner(shape, x1, y1, radius, line);
164 break;
165 case BORDER_RIGHT:
166 line.V0.set(m_XReal + m_WReal, m_YReal, 0);
167 line.V1.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_Computed.Bottom, 0);
168 buildDotCorner(shape, x1, y1, radius, line);
169 break;
170 case BORDER_BOTTOM:
171 line.V0.set(m_XReal, m_YReal, 0);
172 line.V1.set(m_XReal + m_Computed.Left, m_YReal + m_Computed.Bottom, 0);
173 buildDotCorner(shape, x1, y1, radius, line);
174 break;
175 case BORDER_LEFT:
176 line.V0.set(m_XReal + m_Computed.Left, m_YReal + m_Computed.Bottom, 0);
177 line.V1.set(m_XReal, m_YReal, 0);
178 buildDotCorner(shape, x1, y1, radius, line);
179 break;
183 // ----------------------------------------------------------------------------
184 void CSSBorderRenderer::buildDotCornerEnd(EBorderSide side, SDrawBorder shape, float x1, float y1, float radius)
186 NLMISC::CLine line;
187 switch(side)
189 case BORDER_TOP:
190 line.V0.set(m_XReal + m_WReal, m_YReal + m_HReal, 0);
191 line.V1.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_HReal - m_Computed.Top, 0);
192 buildDotCorner(shape, x1, y1, radius, line);
193 break;
194 case BORDER_RIGHT:
195 line.V0.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_HReal - m_Computed.Top, 0);
196 line.V1.set(m_XReal + m_WReal, m_YReal + m_HReal, 0);
197 buildDotCorner(shape, x1, y1, radius, line);
198 break;
199 case BORDER_BOTTOM:
200 line.V0.set(m_XReal + m_WReal - m_Computed.Right, m_YReal + m_Computed.Bottom, 0);
201 line.V1.set(m_XReal + m_WReal, m_YReal, 0);
202 buildDotCorner(shape, x1, y1, radius, line);
203 break;
204 case BORDER_LEFT:
205 line.V0.set(m_XReal, m_YReal + m_HReal, 0);
206 line.V1.set(m_XReal + m_Computed.Left, m_YReal + m_HReal - m_Computed.Top, 0);
207 buildDotCorner(shape, x1, y1, radius, line);
208 break;
212 // ----------------------------------------------------------------------------
213 void CSSBorderRenderer::buildDashedBorder(EBorderSide side)
215 CSSBorder border;
217 float x, y;
218 bool horizontal;
219 sint32 width, thickness;
220 switch(side)
222 case BORDER_TOP:
223 horizontal = true;
224 border = m_Border.Top;
225 width = m_WReal;
226 thickness = m_Computed.Top;
227 x = m_XReal;
228 y = m_YReal + m_HReal - thickness;
229 break;
230 case BORDER_RIGHT:
231 horizontal = false;
232 border = m_Border.Right;
233 width = m_HReal;
234 thickness = m_Computed.Right;
235 x = m_XReal + m_WReal - thickness;
236 y = m_YReal;
237 break;
238 case BORDER_BOTTOM:
239 horizontal = true;
240 border = m_Border.Bottom;
241 width = m_WReal;
242 thickness = m_Computed.Bottom;
243 x = m_XReal;
244 y = m_YReal;
245 break;
246 case BORDER_LEFT:
247 horizontal = false;
248 border = m_Border.Left;
249 width = m_HReal;
250 thickness = m_Computed.Left;
251 x = m_XReal;
252 y = m_YReal;
253 break;
254 default:
255 return;
258 if (width < 1) return;
259 if (thickness < 1) return;
261 SDrawBorder shape;
262 shape.Color = border.Color;
263 shape.Quad.Uv0.set(0.f, 0.f);
264 shape.Quad.Uv1.set(1.f, 0.f);
265 shape.Quad.Uv2.set(1.f, 1.f);
266 shape.Quad.Uv3.set(0.f, 1.f);
268 EBorderSide adjBorderL, adjBorderR;
269 getAdjacentBorders(side, adjBorderL, adjBorderR);
271 sint32 adjWidthL, adjWidthR;
272 getAdjacentBorderWidth(side, adjWidthL, adjWidthR);
274 // get alias to x/y
275 float &xy = horizontal ? x : y;
277 if (border.Style == CSS_LINE_STYLE_DOTTED)
279 // thick border with little or no content might try to draw larger dot that fits
280 float radius = std::min(thickness / 2.f, width / 2.f);
281 float dot = thickness;
283 sint32 count = std::floor((float)width / dot);
284 // 3n (dot, gap, dot) groups; count should be odd
285 if ((count % 2) == 0) count += 1;
287 if (count == 1)
289 // fallback to single dot
290 if (horizontal)
292 x += width / 2.f;
293 y += radius;
295 else
297 x += radius;
298 y += width / 2.f;
301 buildDotSegments(shape, x, y, radius);
302 return;
305 // center-to-center spacing for dots
306 float spacing = dot + (width - dot * count) / (count-1);
308 x += radius;
309 y += radius;
311 if (adjWidthL > 0)
312 buildDotCornerStart(side, shape, x, y, radius);
313 else
314 buildDotSegments(shape, x, y, radius);
316 xy += spacing;
317 count--;
319 if (adjWidthR > 0)
320 count--;
322 bool isDot = false;
323 while(count > 0)
325 if (isDot)
326 buildDotSegments(shape, x, y, radius);
328 isDot = !isDot;
329 xy += spacing;
330 count--;
333 if (adjWidthR > 0)
334 buildDotCornerEnd(side, shape, x, y, radius);
336 else
338 sint32 innerWidth = width;
339 if (adjWidthL > 0) innerWidth -= adjWidthL;
340 if (adjWidthR > 0) innerWidth -= adjWidthR;
342 sint32 count = std::floor((float)innerWidth * 2.f / (thickness * 3));
344 if ((float)innerWidth < 2.f * thickness)
346 buildSolidBorder(side);
347 return;
350 // 4n groups (halfDash, halfGap, halfGap, halfDash)
351 if ((count % 4) == 1) count += 3;
352 else if ((count % 4) == 2) count += 2;
353 else if ((count % 4) == 3) count += 1;
355 float halfDash = (float)innerWidth / (float)count;
356 float fullDash = halfDash * 2.f;
358 // draw half dash or full corner
359 makeBorderQuad(side, shape, x, y, adjWidthL + halfDash, thickness);
360 if (adjWidthL > 0)
361 makeCornerQuad(adjBorderL, shape);
362 m_DrawBorders.push_back(shape);
363 xy += adjWidthL + halfDash;
365 // start/end half dash that are merged with corners
366 count -= 2;
368 bool isDash = false;
369 while(count > 0)
371 if (isDash)
373 makeBorderQuad(side, shape, x, y, fullDash, thickness);
374 m_DrawBorders.push_back(shape);
376 isDash = !isDash;
378 xy += fullDash;
379 count -= 2;
382 // draw half dash or full corner
383 makeBorderQuad(side, shape, x, y, adjWidthR + halfDash, thickness);
384 if (adjWidthR > 0)
385 makeCornerQuad(adjBorderR, shape);
387 m_DrawBorders.push_back(shape);
391 // ----------------------------------------------------------------------------
392 void CSSBorderRenderer::buildSolidBorder(EBorderSide side)
394 float x, y;
395 sint width, thickness;
396 CSSBorder border;
397 switch(side)
399 case BORDER_TOP:
400 border = m_Border.Top;
401 width = m_WReal;
402 thickness = m_Computed.Top;
403 x = m_XReal;
404 y = m_YReal + m_HReal - thickness;
405 break;
406 case BORDER_RIGHT:
407 border = m_Border.Right;
408 width = m_HReal;
409 thickness = m_Computed.Right;
410 x = m_XReal + m_WReal - thickness;
411 y = m_YReal;
412 break;
413 case BORDER_BOTTOM:
414 border = m_Border.Bottom;
415 width = m_WReal;
416 thickness = m_Computed.Bottom;
417 x = m_XReal;
418 y = m_YReal;
419 break;
420 case BORDER_LEFT:
421 border = m_Border.Left;
422 width = m_HReal;
423 thickness = m_Computed.Left;
424 x = m_XReal;
425 y = m_YReal;
426 break;
427 default:
428 return;
431 SDrawBorder shape;
432 shape.Color = border.Color;
433 shape.Quad.Uv0.set(0.f, 0.f);
434 shape.Quad.Uv1.set(1.f, 0.f);
435 shape.Quad.Uv2.set(1.f, 1.f);
436 shape.Quad.Uv3.set(0.f, 1.f);
438 if (border.Style == CSS_LINE_STYLE_INSET && (side == BORDER_TOP || side == BORDER_LEFT))
439 shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
440 else if (border.Style == CSS_LINE_STYLE_OUTSET && (side == BORDER_BOTTOM || side == BORDER_RIGHT))
441 shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
443 // solid border
445 EBorderSide adjBorderL, adjBorderR;
446 getAdjacentBorders(side, adjBorderL, adjBorderR);
448 makeBorderQuad(side, shape, x, y, width, thickness);
449 makeCornerQuad(adjBorderL, shape);
450 makeCornerQuad(adjBorderR, shape);
452 m_DrawBorders.push_back(shape);
455 if (hasInnerShape(border.Style))
457 if (side == BORDER_TOP || side == BORDER_LEFT)
459 if (border.Style == CSS_LINE_STYLE_GROOVE)
460 m_DrawBorders.back().Color = blend(border.Color, CRGBA::Black, 0.5f);
461 else if (border.Style == CSS_LINE_STYLE_RIDGE)
462 shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
464 else if (side == BORDER_BOTTOM || side == BORDER_RIGHT)
466 if (border.Style == CSS_LINE_STYLE_GROOVE)
467 shape.Color = blend(border.Color, CRGBA::Black, 0.5f);
468 else if (border.Style == CSS_LINE_STYLE_RIDGE)
469 m_DrawBorders.back().Color = blend(border.Color, CRGBA::Black, 0.5f);
472 sint32 adjWidthL, adjWidthR;
473 getAdjacentBorderWidth(side, adjWidthL, adjWidthR);
475 float iStart, iMiddle, iEnd;
476 if (border.Style == CSS_LINE_STYLE_DOUBLE)
478 iStart = 2 * adjWidthL / 3.f;
479 iMiddle = 2 * thickness / 3.f;
480 iEnd = 2 * adjWidthR / 3.f;
481 } else {
482 iStart = adjWidthL / 2.f;
483 iMiddle = thickness / 2.f;
484 iEnd = adjWidthR / 2.f;
487 // create inner shape and remove overlapping from outer shape
488 switch(side)
490 case BORDER_TOP:
491 m_DrawBorders.back().Quad.V0.x -= iStart; m_DrawBorders.back().Quad.V0.y += iMiddle;
492 m_DrawBorders.back().Quad.V1.x += iEnd; m_DrawBorders.back().Quad.V1.y += iMiddle;
493 shape.Quad.V3.x += iStart; shape.Quad.V3.y -= iMiddle;
494 shape.Quad.V2.x -= iEnd; shape.Quad.V2.y -= iMiddle;
495 break;
496 case BORDER_BOTTOM:
497 m_DrawBorders.back().Quad.V2.x += iEnd; m_DrawBorders.back().Quad.V2.y -= iMiddle;
498 m_DrawBorders.back().Quad.V3.x -= iStart; m_DrawBorders.back().Quad.V3.y -= iMiddle;
499 shape.Quad.V1.x -= iEnd; shape.Quad.V1.y += iMiddle;
500 shape.Quad.V0.x += iStart; shape.Quad.V0.y += iMiddle;
501 break;
502 case BORDER_RIGHT:
503 m_DrawBorders.back().Quad.V3.x += iMiddle; m_DrawBorders.back().Quad.V3.y += iEnd;
504 m_DrawBorders.back().Quad.V0.x += iMiddle; m_DrawBorders.back().Quad.V0.y -= iStart;
505 shape.Quad.V2.x -= iMiddle; shape.Quad.V2.y -= iEnd;
506 shape.Quad.V1.x -= iMiddle; shape.Quad.V1.y += iStart;
507 break;
508 case BORDER_LEFT:
509 m_DrawBorders.back().Quad.V2.x -= iMiddle; m_DrawBorders.back().Quad.V2.y += iEnd;
510 m_DrawBorders.back().Quad.V1.x -= iMiddle; m_DrawBorders.back().Quad.V1.y -= iStart;
511 shape.Quad.V3.x += iMiddle; shape.Quad.V3.y -= iEnd;
512 shape.Quad.V0.x += iMiddle; shape.Quad.V0.y += iStart;
513 break;
515 m_DrawBorders.push_back(shape);
519 // ----------------------------------------------------------------------------
520 void CSSBorderRenderer::makeBorderQuad(EBorderSide side, SDrawBorder &shape, float x, float y, float width, float thickness) const
522 float quadW, quadH;
523 switch(side)
525 case BORDER_TOP: quadW = width; quadH = thickness; break;
526 case BORDER_BOTTOM:quadW = width; quadH = thickness; break;
527 case BORDER_LEFT: quadW = thickness; quadH = width; break;
528 case BORDER_RIGHT: quadW = thickness; quadH = width; break;
529 default: return;
531 shape.Quad.V3.x = x; shape.Quad.V3.y = y + quadH;
532 shape.Quad.V2.x = x + quadW; shape.Quad.V2.y = y + quadH;
533 shape.Quad.V1.x = x + quadW; shape.Quad.V1.y = y;
534 shape.Quad.V0.x = x; shape.Quad.V0.y = y;
537 // ----------------------------------------------------------------------------
538 void CSSBorderRenderer::makeCornerQuad(EBorderSide side, SDrawBorder &shape) const
540 switch(side)
542 case BORDER_TOP_LEFT: shape.Quad.V0.x += m_Computed.Left; break;
543 case BORDER_TOP_RIGHT: shape.Quad.V1.x -= m_Computed.Right; break;
544 case BORDER_RIGHT_TOP: shape.Quad.V3.y -= m_Computed.Top; break;
545 case BORDER_RIGHT_BOTTOM: shape.Quad.V0.y += m_Computed.Bottom; break;
546 case BORDER_BOTTOM_LEFT: shape.Quad.V3.x += m_Computed.Left; break;
547 case BORDER_BOTTOM_RIGHT: shape.Quad.V2.x -= m_Computed.Right; break;
548 case BORDER_LEFT_TOP: shape.Quad.V2.y -= m_Computed.Top; break;
549 case BORDER_LEFT_BOTTOM: shape.Quad.V1.y += m_Computed.Bottom; break;
553 // ----------------------------------------------------------------------------
554 static bool getCircleLineIntersection(float x, float y, float r, const NLMISC::CLine &line, NLMISC::CLine &result)
556 float dx = line.V0.x - line.V1.x;
557 float dy = line.V0.y - line.V1.y;
558 float rx = line.V0.x-x;
559 float ry = line.V0.y-y;
560 float a = dx*dx + dy*dy;
561 float b = 2*(dx * rx + dy * ry);
562 float c = rx * rx + ry * ry - r*r;
563 float d = b*b - 4 * a * c;
565 if (d < 0)
566 return false;
568 if (d == 0)
570 // single intersection
571 //float t = -b / (2*a);
572 //result.V0.x = result.V1.x = line.V0.x + t * dx;
573 //result.V0.y = result.V1.y = line.V0.y + t * dy;
574 return false;
577 float t;
578 t = (-b + sqrt(d)) / (2 * a);
579 result.V0.x = line.V0.x + t * dx;
580 result.V0.y = line.V0.y + t * dy;
582 t = (-b - sqrt(d)) / (2 * a);
583 result.V1.x = line.V0.x + t * dx;
584 result.V1.y = line.V0.y + t * dy;
586 return true;
589 // ----------------------------------------------------------------------------
590 void CSSBorderRenderer::buildDotCorner(SDrawBorder shape, float cX, float cY, float cR, const NLMISC::CLine &line)
592 static const float twopi = 2 * NLMISC::Pi;
593 NLMISC::CLine out;
594 if (getCircleLineIntersection(cX, cY, cR, line, out))
596 float fromAngle = std::atan2(out.V0.y - cY, out.V0.x - cX);
597 float toAngle = std::atan2(out.V1.y - cY, out.V1.x - cX);
598 if (fromAngle < 0) fromAngle += twopi;
599 if (toAngle < 0) toAngle += twopi;
600 fromAngle /= twopi;
601 toAngle /= twopi;
602 buildDotSegments(shape, cX, cY, cR, fromAngle, toAngle);
603 } else {
604 buildDotSegments(shape, cX, cY, cR);
608 // ----------------------------------------------------------------------------
609 void CSSBorderRenderer::buildDotSegments(SDrawBorder shape, float x, float y, float radius, float fromAngle, float toAngle)
611 static const float pi = (float)NLMISC::Pi;
612 static const float twopi = (float)(NLMISC::Pi * 2);
613 static const uint minSectors = 12;
615 // use single quad if dot is small
616 if (2 * radius * m_Scale < 4)
618 makeBorderQuad(BORDER_TOP, shape, x - radius, y - radius, radius * 2, radius * 2);
619 m_DrawBorders.push_back(shape);
620 return;
623 // number of sectors for full circle
624 uint sectors = std::max(minSectors, (uint)std::ceil(radius * m_Scale));
626 float arcLength;
627 if (toAngle < fromAngle)
628 arcLength = twopi * (1 + toAngle - fromAngle);
629 else
630 arcLength = twopi * (toAngle - fromAngle);
632 // sectors to draw
633 float arcSectors = ceil(arcLength * sectors / twopi );
634 float arcSectorLength = arcLength / arcSectors;
636 if (arcSectors <= 1)
637 return;
639 if (arcLength < pi)
641 // only small segment is visible
642 float px1 = x + radius * cosf(twopi * fromAngle);
643 float py1 = y + radius * sinf(twopi * fromAngle);
644 float px2 = x + radius * cosf(twopi * toAngle);
645 float py2 = y + radius * sinf(twopi * toAngle);
646 float cx = (px1 + px2) / 2.f;
647 float cy = (py1 + py2) / 2.f;
648 shape.Quad.V0.x = cx; shape.Quad.V0.y = cy;
649 shape.Quad.V1.x = cx; shape.Quad.V1.y = cy;
651 else
653 shape.Quad.V0.x = x; shape.Quad.V0.y = y;
654 shape.Quad.V1.x = x; shape.Quad.V1.y = y;
657 float a1 = fromAngle * twopi;
658 uint step;
659 for(step = 0; step < (uint)arcSectors; step++)
661 float a2 = a1 + arcSectorLength;
663 shape.Quad.V2.x = x + radius * cosf(a1); shape.Quad.V2.y = y + radius * sinf(a1);
664 shape.Quad.V3.x = x + radius * cosf(a2); shape.Quad.V3.y = y + radius * sinf(a2);
666 m_DrawBorders.push_back(shape);
668 a1 = a2;
671 // build last sector if requested range is over 180deg
672 if (arcLength > pi && arcLength < twopi)
674 float a2 = fromAngle * twopi;
675 shape.Quad.V2.x = x + radius * cosf(a1); shape.Quad.V2.y = y + radius * sinf(a1);
676 shape.Quad.V3.x = x + radius * cosf(a2); shape.Quad.V3.y = y + radius * sinf(a2);
677 m_DrawBorders.push_back(shape);
681 // ----------------------------------------------------------------------------
682 void CSSBorderRenderer::updateCoords()
684 m_Dirty = false;
685 m_DrawBorders.clear();
687 if (m_MustComputeValues)
688 computeValues();
690 if (m_Computed.Top > 0 && m_Border.Top.Color.A > 0)
692 if (m_Border.Top.Style == CSS_LINE_STYLE_DASHED || m_Border.Top.Style == CSS_LINE_STYLE_DOTTED)
693 buildDashedBorder(BORDER_TOP);
694 else
695 buildSolidBorder(BORDER_TOP);
698 if (m_Computed.Bottom > 0 && m_Border.Bottom.Color.A > 0)
700 if (m_Border.Bottom.Style == CSS_LINE_STYLE_DASHED || m_Border.Bottom.Style == CSS_LINE_STYLE_DOTTED)
701 buildDashedBorder(BORDER_BOTTOM);
702 else
703 buildSolidBorder(BORDER_BOTTOM);
706 if (m_Computed.Right > 0 && m_Border.Right.Color.A > 0)
708 if (m_Border.Right.Style == CSS_LINE_STYLE_DASHED || m_Border.Right.Style == CSS_LINE_STYLE_DOTTED)
709 buildDashedBorder(BORDER_RIGHT);
710 else
711 buildSolidBorder(BORDER_RIGHT);
714 if (m_Computed.Left > 0 && m_Border.Left.Color.A > 0)
716 if (m_Border.Left.Style == CSS_LINE_STYLE_DASHED || m_Border.Left.Style == CSS_LINE_STYLE_DOTTED)
717 buildDashedBorder(BORDER_LEFT);
718 else
719 buildSolidBorder(BORDER_LEFT);
724 // ----------------------------------------------------------------------------
725 void CSSBorderRenderer::draw() {
726 if (m_Dirty) updateCoords();
727 if (m_DrawBorders.empty()) return;
729 CViewRenderer &rVR = *CViewRenderer::getInstance();
731 CRGBA globalColor;
732 if (m_ModulateGlobalColor)
733 globalColor = CWidgetManager::getInstance()->getGlobalColor();
735 sint32 texId = rVR.getBlankTextureId();
736 for(uint i = 0; i < m_DrawBorders.size(); ++i)
738 CRGBA color = m_DrawBorders[i].Color;
739 if (m_ModulateGlobalColor)
740 color.modulateFromColor (color, globalColor);
742 color.A = (uint8) (((uint16) CurrentAlpha * (uint16) color.A) >> 8);
743 rVR.drawQuad(m_RenderLayer, m_DrawBorders[i].Quad, texId, color, false);
747 }//namespace