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_display.h"
28 
29 
30 /**************************************************************************/
31 /*                                                                        */
32 /*  FUNCTION                                               RELEASE        */
33 /*                                                                        */
34 /*    _gx_display_driver_generic_filled_circle_draw       PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Kenneth Maxwell, Microsoft Corporation                              */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    Display driver to draw filled circals.                              */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    context                               Drawing context               */
47 /*    xcenter                               x-coord of center of circle   */
48 /*    ycenter                               y-coord of center of circle   */
49 /*    r                                     Radius of circle              */
50 /*                                                                        */
51 /*  OUTPUT                                                                */
52 /*                                                                        */
53 /*    None                                                                */
54 /*                                                                        */
55 /*  CALLS                                                                 */
56 /*                                                                        */
57 /*    [gx_display_driver_horizontal_line_draw]                            */
58 /*                                          Driver-level horizontal line  */
59 /*                                            draw function               */
60 /*                                                                        */
61 /*  CALLED BY                                                             */
62 /*                                                                        */
63 /*    _gx_display_driver_generic_simple_wide_line_draw                    */
64 /*                                                                        */
65 /*  RELEASE HISTORY                                                       */
66 /*                                                                        */
67 /*    DATE              NAME                      DESCRIPTION             */
68 /*                                                                        */
69 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
70 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
71 /*                                            resulting in version 6.1    */
72 /*                                                                        */
73 /**************************************************************************/
_gx_display_driver_generic_filled_circle_draw(GX_DRAW_CONTEXT * context,GX_FIXED_VAL xcenter,GX_FIXED_VAL ycenter,GX_FIXED_VAL r)74 VOID _gx_display_driver_generic_filled_circle_draw(GX_DRAW_CONTEXT *context, GX_FIXED_VAL xcenter, GX_FIXED_VAL ycenter, GX_FIXED_VAL r)
75 {
76 /* The circle draw function is implemented from midpoint circle algorithm. */
77 
78 GX_DISPLAY   *display;
79 GX_RECTANGLE *clip;
80 GX_BRUSH     *brush;
81 INT           x;
82 INT           y;
83 GX_BYTE       ysign[2] = {1, -1};
84 INT           index;
85 INT           yi;
86 GX_VALUE      xstart;
87 GX_VALUE      xend;
88 GX_FIXED_VAL  xfraction;
89 GX_FIXED_VAL  yfraction;
90 INT           decision;
91 INT           half_shift;
92 
93     display = context -> gx_draw_context_display;
94     clip = context -> gx_draw_context_clip;
95     brush = &context -> gx_draw_context_brush;
96 
97     xfraction = (xcenter & GX_FIXED_VAL_FRACTION_MASK);
98     yfraction = (ycenter & GX_FIXED_VAL_FRACTION_MASK);
99 
100     r -= GX_FIXED_VAL_HALF;
101 
102     if (xfraction)
103     {
104         x = GX_FIXED_VAL_ONE - xfraction;
105     }
106     else
107     {
108         x = 0;
109     }
110     y = GX_FIXED_VAL_RND_UP(r + yfraction);
111     y = GX_FIXED_VAL_MAKE(y) - yfraction;
112 
113     half_shift = GX_FIXED_VAL_SHIFT >> 1;
114 
115     if ((x == 0) && (y == r))
116     {
117         decision = 256 - r;
118     }
119     else
120     {
121         decision = (x >> half_shift) * (x >> half_shift);
122         decision += ((y - GX_FIXED_VAL_HALF) >> half_shift) * ((y - GX_FIXED_VAL_HALF) >> half_shift);
123         decision -= ((r >> half_shift) * (r >> half_shift));
124     }
125 
126     while (1)
127     {
128         if (decision < 0)
129         {
130             decision += 2 * x + GX_FIXED_VAL_ONE;
131         }
132         else
133         {
134             decision += 2 * (x - y) + GX_FIXED_VAL_MAKE(3);
135             y -= GX_FIXED_VAL_ONE;
136         }
137 
138         if (x > y)
139         {
140             break;
141         }
142 
143         for (index = 0; index < 2; index++)
144         {
145             xstart = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter - x);
146             xend = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter + x);
147             yi = (GX_VALUE)GX_FIXED_VAL_TO_INT(ycenter + y * ysign[index]);
148 
149             if (xstart < clip -> gx_rectangle_left)
150             {
151                 xstart = clip -> gx_rectangle_left;
152             }
153 
154             if (xend > clip -> gx_rectangle_right)
155             {
156                 xend = clip -> gx_rectangle_right;
157             }
158 
159             if (xstart <= xend &&
160                 yi >= clip -> gx_rectangle_top &&
161                 yi <= clip -> gx_rectangle_bottom)
162             {
163                 display -> gx_display_driver_horizontal_line_draw(context, xstart, xend, yi, 1, brush -> gx_brush_line_color);
164             }
165         }
166 
167         x += GX_FIXED_VAL_ONE;
168     }
169 
170     x = GX_FIXED_VAL_RND_UP(r + xfraction);
171     x = GX_FIXED_VAL_MAKE(x) - xfraction;
172 
173     if (yfraction)
174     {
175         y = yfraction;
176     }
177     else
178     {
179         y = 0;
180     }
181 
182     if ((y == 0) && (x == r))
183     {
184         decision = 256 - r;
185     }
186     else
187     {
188         decision = (((x - GX_FIXED_VAL_HALF) >> half_shift) * ((x - GX_FIXED_VAL_HALF) >> half_shift));
189         decision += ((y >> half_shift) * (y >> half_shift));
190         decision -=  ((r >> half_shift) * (r >> half_shift));
191     }
192 
193     while (1)
194     {
195         if (decision < 0)
196         {
197             decision += 2 * y + GX_FIXED_VAL_ONE;
198         }
199         else
200         {
201             decision += 2 * (y - x) + GX_FIXED_VAL_MAKE(3);
202             x -= GX_FIXED_VAL_ONE;
203         }
204 
205         if (x <= y)
206         {
207             break;
208         }
209 
210         for (index = 0; index < 2; index++)
211         {
212             xstart = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter - x);
213             xend  = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter + x);
214             yi = (GX_VALUE)GX_FIXED_VAL_TO_INT(ycenter + y * ysign[index]);
215 
216             if (xstart < clip -> gx_rectangle_left)
217             {
218                 xstart = clip -> gx_rectangle_left;
219             }
220 
221             if (xend > clip -> gx_rectangle_right)
222             {
223                 xend = clip -> gx_rectangle_right;
224             }
225 
226             if (xstart <= xend &&
227                 yi >= clip -> gx_rectangle_top &&
228                 yi <= clip -> gx_rectangle_bottom)
229             {
230                 display -> gx_display_driver_horizontal_line_draw(context, xstart, xend, yi, 1, brush -> gx_brush_line_color);
231             }
232         }
233 
234         y += GX_FIXED_VAL_ONE;
235     }
236 }
237 
238