1 /***************************************************************************
2  * Copyright (c) 2024 Microsoft Corporation
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the MIT License which is available at
6  * https://opensource.org/licenses/MIT.
7  *
8  * SPDX-License-Identifier: MIT
9  **************************************************************************/
10 
11 
12 /**************************************************************************/
13 /**************************************************************************/
14 /**                                                                       */
15 /** GUIX Component                                                        */
16 /**                                                                       */
17 /**   Display Management (Display)                                        */
18 /**                                                                       */
19 /**************************************************************************/
20 
21 #define GX_SOURCE_CODE
22 
23 
24 /* Include necessary system files.  */
25 
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_utility.h"
29 #include "gx_display.h"
30 
31 
32 /**************************************************************************/
33 /*                                                                        */
34 /*  FUNCTION                                               RELEASE        */
35 /*                                                                        */
36 /*    _gx_display_driver_generic_rotated_arc_fill         PORTABLE C      */
37 /*                                                           6.1.3        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Kenneth Maxwell, Microsoft Corporation                              */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    Display driver to fill circle sector.                               */
45 /*                                                                        */
46 /*  INPUT                                                                 */
47 /*                                                                        */
48 /*    context                               Drawing context               */
49 /*    xcenter                               x-coord of center of circle   */
50 /*    ycenter                               y-coord of center of circle   */
51 /*    r                                     Radius of circle              */
52 /*    start_angle                           The start angle of circle arc */
53 /*    end_angle                             The end angle of circle arc   */
54 /*                                                                        */
55 /*  OUTPUT                                                                */
56 /*                                                                        */
57 /*    None                                                                */
58 /*                                                                        */
59 /*  CALLS                                                                 */
60 /*                                                                        */
61 /*    [gx_display_driver_horizontal_line_draw]                            */
62 /*                                          Basic display driver          */
63 /*                                            horizontal line draw routine*/
64 /*    _gx_display_driver_arc_clipping_get   Get an arc clipping.          */
65 /*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
66 /*                                            inside rectangle            */
67 /*    _gx_display_driver_circle_point_get   Get point coord on a circle   */
68 /*    [gx_display_driver_horizontal_pixelmap_line_draw]                   */
69 /*                                          Basic display driver          */
70 /*                                            horizontal pixelmap line    */
71 /*                                            draw function               */
72 /*                                                                        */
73 /*  CALLED BY                                                             */
74 /*                                                                        */
75 /*    _gx_display_driver_generic_arc_draw                                 */
76 /*                                                                        */
77 /*  RELEASE HISTORY                                                       */
78 /*                                                                        */
79 /*    DATE              NAME                      DESCRIPTION             */
80 /*                                                                        */
81 /*  12-31-2020     Kenneth Maxwell          Initial Version 6.1.3         */
82 /*                                                                        */
83 /**************************************************************************/
84 #if defined(GX_ARC_DRAWING_SUPPORT)
_gx_display_driver_generic_rotated_arc_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle)85 VOID _gx_display_driver_generic_rotated_arc_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, UINT r, INT start_angle, INT end_angle)
86 {
87 
88 GX_DISPLAY           *display;
89 GX_RECTANGLE         *clip;
90 GX_RECTANGLE          arc_clip[4];
91 GX_BRUSH             *brush;
92 GX_POINT              point;
93 INT                   sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
94 INT                  *pLineEnds;
95 INT                   xmin;
96 INT                   xmax;
97 INT                   xstart;
98 INT                   xend;
99 INT                   ystart;
100 INT                   yend;
101 INT                   curx;
102 INT                   cury;
103 INT                   nextx;
104 INT                   nexty;
105 INT                   dx;
106 INT                   dy;
107 INT                   Index;
108 INT                   Index1;
109 INT                   width;
110 INT                   xsign;
111 INT                   ysign;
112 INT                   decision;
113 VOID                  (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
114 GX_PIXELMAP          *pixelmap = GX_NULL;
115 INT                   ypos;
116 INT                   skip_line;
117 GX_FILL_PIXELMAP_INFO info;
118 INT                   inner_offset;
119 
120     display = context -> gx_draw_context_display;
121     brush = &context -> gx_draw_context_brush;
122     inner_offset = brush -> gx_brush_width;
123     line_draw = display -> gx_display_driver_vertical_line_draw;
124     clip = context -> gx_draw_context_clip;
125 
126     if (inner_offset)
127     {
128         inner_offset -= 1;
129         inner_offset >>= 1;
130     }
131 
132     if (r <= (UINT)inner_offset)
133     {
134         return;
135     }
136 
137     if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
138     {
139         if (brush -> gx_brush_pixelmap == GX_NULL)
140         {
141             return;
142         }
143 
144         /* Pick up brush pixelmap. */
145         pixelmap = brush -> gx_brush_pixelmap;
146 
147         if (pixelmap -> gx_pixelmap_format != display -> gx_display_color_format)
148         {
149             /* Display driver only support its native format pixelmap.*/
150             /* Nothing should be drawn if pixelmap format isn't support. */
151             return;
152         }
153 
154         memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
155 
156         info.pixelmap = brush -> gx_brush_pixelmap;
157         info.current_pixel_ptr = (GX_UBYTE *)info.pixelmap -> gx_pixelmap_data;
158 
159         if (pixelmap -> gx_pixelmap_aux_data_size)
160         {
161             info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
162         }
163     }
164 
165     r = (UINT)(r - (UINT)(inner_offset >> 1));
166 
167     xmax = xcenter + (INT)r;
168     xmin = xcenter - (INT)r;
169 
170     /* Get two endpoint of the arc. */
171     _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &point);
172 
173     xstart = point.gx_point_x;
174     ystart = point.gx_point_y;
175 
176     _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &point);
177 
178     xend = point.gx_point_x;
179     yend = point.gx_point_y;
180 
181     skip_line = 0;
182 
183     /* Calculate minimum y line. */
184     if (((start_angle < 180) && (end_angle < 180)) ||
185         ((start_angle > 180) && (end_angle < 540)))
186     {
187         if (xstart > xend)
188         {
189             xmin = xend;
190         }
191         else
192         {
193             xmin = xstart;
194         }
195     }
196 
197     if (clip -> gx_rectangle_left > xmin)
198     {
199         xmin = clip -> gx_rectangle_left;
200     }
201 
202     /* Calculate maximum y line. */
203     if (end_angle < 360)
204     {
205         if (xstart > xend)
206         {
207             xmax = xstart;
208         }
209         else
210         {
211             xmax = xend;
212         }
213     }
214 
215     if (clip -> gx_rectangle_right < xmax)
216     {
217         xmax = clip -> gx_rectangle_right;
218     }
219 
220     width = xmax - xmin + 1;
221 
222     /* default the point array to being off the screen on both sides: */
223     pLineEnds = _gx_system_scratchpad;
224 
225     for (Index = 0; Index < width * 2; Index += 2)
226     {
227         pLineEnds[Index] = 2000;
228         pLineEnds[Index + 1] = 0;
229     }
230 
231     /* Get the clipping rectangles of the circle arc. */
232     _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle, &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
233 
234     curx = 0;
235     cury = (INT)r;
236     decision = (INT)(5 - 4 * r);
237 
238     while (curx <= cury)
239     {
240         for (Index = 0; Index < 4; Index++)
241         {
242             point.gx_point_x = (GX_VALUE)(curx * sign[Index][0] + xcenter);
243             point.gx_point_y = (GX_VALUE)(cury * sign[Index][1] + ycenter);
244 
245             if ((point.gx_point_x >= xmin) &&
246                 (point.gx_point_x <= xmax))
247             {
248                 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
249                     _gx_utility_rectangle_point_detect(&arc_clip[1], point) ||
250                     _gx_utility_rectangle_point_detect(&arc_clip[2], point) ||
251                     _gx_utility_rectangle_point_detect(&arc_clip[3], point))
252                 {
253                     Index1 = (point.gx_point_x - xmin) << 1;
254                     if (point.gx_point_y < pLineEnds[Index1])
255                     {
256                         pLineEnds[Index1] = point.gx_point_y;
257                     }
258 
259                     if (point.gx_point_y > pLineEnds[Index1 + 1])
260                     {
261                         pLineEnds[Index1 + 1] = point.gx_point_y;
262                     }
263                 }
264             }
265 
266             point.gx_point_x = (GX_VALUE)(cury * sign[Index][0] + xcenter);
267             point.gx_point_y = (GX_VALUE)(curx * sign[Index][1] + ycenter);
268 
269             if ((point.gx_point_x >= xmin) &&
270                 (point.gx_point_x <= xmax))
271             {
272                 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
273                     _gx_utility_rectangle_point_detect(&arc_clip[1], point) ||
274                     _gx_utility_rectangle_point_detect(&arc_clip[2], point) ||
275                     _gx_utility_rectangle_point_detect(&arc_clip[3], point))
276                 {
277                     Index1 = (point.gx_point_x - xmin) << 1;
278                     if (point.gx_point_y < pLineEnds[Index1])
279                     {
280                         pLineEnds[Index1] = point.gx_point_y;
281                     }
282 
283                     if (point.gx_point_y > pLineEnds[Index1 + 1])
284                     {
285                         pLineEnds[Index1 + 1] = point.gx_point_y;
286                     }
287                 }
288             }
289         }
290 
291         if (decision < 0)
292         {
293             decision += 8 * curx + 12;
294         }
295         else
296         {
297             decision += 8 * (curx - cury) + 20;
298             cury--;
299         }
300         curx++;
301     }
302 
303     /* Fill in the point array by using Breshenhams line for
304        the line that connect two endpoints of the arc. */
305 
306     dx = GX_ABS(xend - xstart);
307     dy = GX_ABS(yend - ystart);
308 
309     if (xstart != xend)
310     {
311         /* Horizontal Line. */
312         if (ystart == yend)
313         {
314             if (xstart > xend)
315             {
316                 GX_SWAP_VALS(xstart, xend);
317                 GX_SWAP_VALS(ystart, yend);
318             }
319 
320             for (curx = xstart; curx <= xend; curx++)
321             {
322                 if ((curx >= xmin) &&
323                     (curx <= xmax))
324                 {
325                     Index = (curx - xmin) << 1;
326                     if (ystart <= pLineEnds[Index])
327                     {
328                         pLineEnds[Index] = ystart;
329                     }
330 
331                     if (ystart > pLineEnds[Index + 1])
332                     {
333                         pLineEnds[Index + 1] = ystart;
334                     }
335                 }
336             }
337         }
338         else
339         {
340             /* Simple Line. */
341             if (((dx >= dy && (xstart > xend)) ||
342                  ((dy > dx) && ystart > yend)))
343             {
344                 GX_SWAP_VALS(xend, xstart);
345                 GX_SWAP_VALS(yend, ystart);
346             }
347 
348             xsign = (xend - xstart) / dx;
349             ysign = (yend - ystart) / dy;
350 
351             if (dx >= dy)
352             {
353                 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
354                      decision = (dx >> 1); curx <= nextx; curx++, nextx--,
355                      decision += dy)
356                 {
357                     if (decision >= dx)
358                     {
359                         decision -= dx;
360                         cury += ysign;
361                         nexty -= ysign;
362                     }
363 
364                     if ((curx >= xmin) && (curx <= xmax))
365                     {
366                         Index = (curx - xmin) << 1;
367 
368                         if (cury < pLineEnds[Index])
369                         {
370                             pLineEnds[Index] = cury;
371                         }
372 
373                         if (cury > pLineEnds[Index + 1])
374                         {
375                             pLineEnds[Index + 1] = cury;
376                         }
377                     }
378 
379                     if ((nextx >= xmin) && (nextx <= xmax))
380                     {
381                         Index1 = (nextx - xmin) << 1;
382 
383                         if (nexty < pLineEnds[Index1])
384                         {
385                             pLineEnds[Index1] = nexty;
386                         }
387 
388                         if (nexty > pLineEnds[Index1 + 1])
389                         {
390                             pLineEnds[Index1 + 1] = nexty;
391                         }
392                     }
393                 }
394             }
395             else
396             {
397                 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
398                      decision = (dy >> 1); cury <= nexty; cury++, nexty--,
399                      decision += dx)
400                 {
401                     if (decision >= dy)
402                     {
403                         decision -= dy;
404                         curx += xsign;
405                         nextx -= xsign;
406                     }
407 
408                     if ((curx >= xmin) && (curx <= xmax))
409                     {
410                         Index = (curx - xmin) << 1;
411                         if (cury < pLineEnds[Index])
412                         {
413                             pLineEnds[Index] = cury;
414                         }
415 
416                         if (cury > pLineEnds[Index + 1])
417                         {
418                             pLineEnds[Index + 1] = cury;
419                         }
420                     }
421 
422                     if ((nextx >= xmin) && (nextx <= xmax))
423                     {
424                         Index1 = (nextx - xmin) << 1;
425 
426                         if (nexty < pLineEnds[Index1])
427                         {
428                             pLineEnds[Index1] = nexty;
429                         }
430 
431                         if (nexty > pLineEnds[Index1 + 1])
432                         {
433                             pLineEnds[Index1 + 1] = nexty;
434                         }
435                     }
436                 }
437             }
438         }
439     }
440 
441     if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
442     {
443         if (context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_CW)
444         {
445             skip_line = (xmax - (xcenter - (INT)r) + 1) % pixelmap -> gx_pixelmap_width;
446 
447             /* Skip the un-draw line.*/
448             if (skip_line)
449             {
450                 skip_line = pixelmap -> gx_pixelmap_width - skip_line;
451             }
452 
453             xstart = xmax;
454             Index = (width - 1) * 2;
455             xsign = -1;
456         }
457         else
458         {
459             skip_line = (xmin - clip -> gx_rectangle_left);
460 
461             xstart = xmin;
462             Index = 0;
463             xsign = 1;
464         }
465 
466         /* Skip the un-draw line.*/
467         if (skip_line)
468         {
469             info.draw = GX_FALSE;
470             while (skip_line--)
471             {
472                 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, cury, &info);
473             }
474         }
475 
476         info.draw = GX_TRUE;
477         ypos = ycenter - (INT)r;
478 
479         for (curx = xmin; curx <= xmax; curx++)
480         {
481             if (pLineEnds[Index] < clip -> gx_rectangle_top)
482             {
483                 pLineEnds[Index] = clip -> gx_rectangle_top;
484             }
485 
486             if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
487             {
488                 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
489             }
490 
491             /* Filling arc area with pixelmap. */
492             info.x_offset = pLineEnds[Index] - ypos;
493             display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], xstart, &info);
494 
495             xstart += xsign;
496             Index += xsign;
497             Index += xsign;
498         }
499     }
500     else
501     {
502         Index = 0;
503 
504         for (curx = xmin; curx <= xmax; curx++)
505         {
506             if (pLineEnds[Index] < clip -> gx_rectangle_top)
507             {
508                 pLineEnds[Index] = clip -> gx_rectangle_top;
509             }
510 
511             if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
512             {
513                 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
514             }
515 
516             /* Fill arc with horizontal lines. */
517             line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], curx, 1, brush -> gx_brush_fill_color);
518 
519             Index += 2;
520         }
521     }
522 }
523 
524 #endif
525 
526