1 /**************************************************************************/
2 /*                                                                        */
3 /*       Copyright (c) Microsoft Corporation. All rights reserved.        */
4 /*                                                                        */
5 /*       This software is licensed under the Microsoft Software License   */
6 /*       Terms for Microsoft Azure RTOS. Full text of the license can be  */
7 /*       found in the LICENSE file at https://aka.ms/AzureRTOS_EULA       */
8 /*       and in the root directory of this software.                      */
9 /*                                                                        */
10 /**************************************************************************/
11 
12 
13 /**************************************************************************/
14 /**************************************************************************/
15 /**                                                                       */
16 /** GUIX Component                                                        */
17 /**                                                                       */
18 /**   Display Management (Display)                                        */
19 /**                                                                       */
20 /**************************************************************************/
21 
22 #define GX_SOURCE_CODE
23 
24 
25 /* Include necessary system files.  */
26 
27 #include "gx_api.h"
28 #include "gx_display.h"
29 #include "gx_utility.h"
30 
31 /**************************************************************************/
32 /*                                                                        */
33 /*  FUNCTION                                               RELEASE        */
34 /*                                                                        */
35 /*    _gx_display_driver_generic_aliased_filled_circle_draw               */
36 /*                                                        PORTABLE C      */
37 /*                                                           6.1.7        */
38 /*  AUTHOR                                                                */
39 /*                                                                        */
40 /*    Kenneth Maxwell, Microsoft Corporation                              */
41 /*                                                                        */
42 /*  DESCRIPTION                                                           */
43 /*                                                                        */
44 /*    Display driver to draw filled circals with anti-aliased edge.       */
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 /*                                                                        */
53 /*  OUTPUT                                                                */
54 /*                                                                        */
55 /*    None                                                                */
56 /*                                                                        */
57 /*  CALLS                                                                 */
58 /*                                                                        */
59 /*    [gx_display_driver_pixel_blend]       Driver-level pixel blend      */
60 /*    [gx_display_driver_horizontal_line_draw]                            */
61 /*                                          Driver-level horizontal line  */
62 /*                                            draw function               */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _gx_display_driver_generic_aliased_wide_line_draw                   */
67 /*                                                                        */
68 /*  RELEASE HISTORY                                                       */
69 /*                                                                        */
70 /*    DATE              NAME                      DESCRIPTION             */
71 /*                                                                        */
72 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
73 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
74 /*                                            resulting in version 6.1    */
75 /*  06-02-2021     Kenneth Maxwell          Modified comment(s),          */
76 /*                                            removed unused variable     */
77 /*                                            assignment,                 */
78 /*                                            resulting in version 6.1.7  */
79 /*                                                                        */
80 /**************************************************************************/
_gx_display_driver_generic_aliased_filled_circle_draw(GX_DRAW_CONTEXT * context,GX_FIXED_VAL xcenter,GX_FIXED_VAL ycenter,GX_FIXED_VAL r)81 VOID _gx_display_driver_generic_aliased_filled_circle_draw(GX_DRAW_CONTEXT *context, GX_FIXED_VAL xcenter, GX_FIXED_VAL ycenter, GX_FIXED_VAL r)
82 {
83 /* The circle draw function is implemented from midpoint circle algorithm. */
84 
85 GX_DISPLAY   *display;
86 GX_RECTANGLE *clip;
87 GX_BRUSH     *brush;
88 INT           x;
89 INT           y;
90 GX_POINT      point;
91 GX_BYTE       ysign[2] = {1, -1};
92 INT           index;
93 INT           error;
94 INT           yi;
95 GX_VALUE      xstart;
96 GX_VALUE      xend;
97 GX_UBYTE      alpha1;
98 GX_FIXED_VAL  xfraction;
99 GX_FIXED_VAL  yfraction;
100 INT           rr;
101 INT           half_shift;
102 VOID          (*blend_func)(GX_DRAW_CONTEXT *context,
103                             INT x, INT y, GX_COLOR color, GX_UBYTE alpha);
104 
105 #if defined(GX_BRUSH_ALPHA_SUPPORT)
106 GX_UBYTE brush_alpha;
107 
108     brush_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
109 
110     if (brush_alpha == 0)
111     {
112         /* Nothing to draw here. */
113         return;
114     }
115 #endif
116 
117     display = context -> gx_draw_context_display;
118     clip = context -> gx_draw_context_clip;
119     brush = &context -> gx_draw_context_brush;
120 
121     blend_func = display -> gx_display_driver_pixel_blend;
122 
123     if (blend_func == GX_NULL)
124     {
125         return;
126     }
127 
128     xfraction = (xcenter & GX_FIXED_VAL_FRACTION_MASK);
129     yfraction = (ycenter & GX_FIXED_VAL_FRACTION_MASK);
130 
131     r -= GX_FIXED_VAL_HALF;
132 
133     if (xfraction)
134     {
135         x = GX_FIXED_VAL_ONE - xfraction;
136     }
137     else
138     {
139         x = 0;
140     }
141     y = GX_FIXED_VAL_RND_UP(r + yfraction);
142     y = GX_FIXED_VAL_MAKE(y) - yfraction;
143 
144     half_shift = (GX_FIXED_VAL_SHIFT >> 1);
145     rr = (r >> half_shift) * (r >> half_shift);
146 
147     while (x < y)
148     {
149         yi = rr - ((x >> half_shift) * (x >> half_shift));
150 
151         error = (INT)_gx_utility_math_sqrt((UINT)yi);
152         error <<= 8;
153         error >>= half_shift;
154         error = GX_FIXED_VAL_TO_INT((y << 8)) - error;
155 
156         while (error >= 255)
157         {
158             error -= 255;
159             y -= GX_FIXED_VAL_ONE;
160         }
161 
162         if (x > y)
163         {
164             break;
165         }
166 
167         alpha1 = (GX_UBYTE)(255 - error);
168 #if defined(GX_BRUSH_ALPHA_SUPPORT)
169         alpha1 = (GX_UBYTE)(alpha1 * brush_alpha / 255);
170 #endif
171 
172         for (index = 0; index < 2; index++)
173         {
174             point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter + x);
175             point.gx_point_y = (GX_VALUE)GX_FIXED_VAL_TO_INT(ycenter + y * ysign[index]);
176 
177             xend = point.gx_point_x;
178 
179             /* draw pixel(x, y). */
180             if (_gx_utility_rectangle_point_detect(clip, point))
181             {
182                 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
183             }
184 
185             point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter - x);
186 
187             xstart = point.gx_point_x;
188 
189             yi = GX_FIXED_VAL_TO_INT(ycenter + (y - GX_FIXED_VAL_ONE) * ysign[index]);
190 
191             if (xstart < clip -> gx_rectangle_left)
192             {
193                 xstart = clip -> gx_rectangle_left;
194             }
195 
196             if (xend > clip -> gx_rectangle_right)
197             {
198                 xend = clip -> gx_rectangle_right;
199             }
200 
201             if (xstart <= xend &&
202                 yi >= clip -> gx_rectangle_top &&
203                 yi <= clip -> gx_rectangle_bottom)
204             {
205                 display -> gx_display_driver_horizontal_line_draw(context, xstart, xend, yi, 1, brush -> gx_brush_line_color);
206             }
207 
208             if (x)
209             {
210                 /* draw pixel(-x, y). */
211                 if (_gx_utility_rectangle_point_detect(clip, point))
212                 {
213                     blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
214                 }
215             }
216         }
217 
218         x += GX_FIXED_VAL_ONE;
219     }
220 
221     x = GX_FIXED_VAL_RND_UP(r + xfraction);
222     x = GX_FIXED_VAL_MAKE(x) - xfraction;
223 
224     if (yfraction)
225     {
226         y = yfraction;
227     }
228     else
229     {
230         y = 0;
231     }
232 
233     while (x > y)
234     {
235         yi = rr - ((y >> half_shift) * (y >> half_shift));
236 
237         error = (INT)_gx_utility_math_sqrt((UINT)yi);
238         error <<= 8;
239         error >>= half_shift;
240         error = GX_FIXED_VAL_TO_INT((x << 8)) - error;
241 
242         while (error >= 255)
243         {
244             error -= 255;
245             x -= GX_FIXED_VAL_ONE;
246         }
247 
248         if (x < y)
249         {
250             break;
251         }
252 
253         alpha1 = (GX_UBYTE)(255 - error);
254 #if defined(GX_BRUSH_ALPHA_SUPPORT)
255         alpha1 = (GX_UBYTE)(alpha1 * brush_alpha / 255);
256 #endif
257 
258         for (index = 0; index < 2; index++)
259         {
260             point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter + x);
261             point.gx_point_y = (GX_VALUE)GX_FIXED_VAL_TO_INT(ycenter + y * ysign[index]);
262 
263             xend = (GX_VALUE)(point.gx_point_x - 1);
264 
265             /* draw pixel(x, y). */
266             if (_gx_utility_rectangle_point_detect(clip, point))
267             {
268                 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
269             }
270 
271 
272             point.gx_point_x = (GX_VALUE)GX_FIXED_VAL_TO_INT(xcenter - x);
273             xstart = (GX_VALUE)(point.gx_point_x + 1);
274 
275             if (xstart < clip -> gx_rectangle_left)
276             {
277                 xstart = clip -> gx_rectangle_left;
278             }
279 
280             if (xend > clip -> gx_rectangle_right)
281             {
282                 xend = clip -> gx_rectangle_right;
283             }
284 
285             if (xstart <= xend &&
286                 point.gx_point_y >= clip -> gx_rectangle_top &&
287                 point.gx_point_y <= clip -> gx_rectangle_bottom)
288             {
289                 display -> gx_display_driver_horizontal_line_draw(context, xstart, xend, point.gx_point_y, 1, brush -> gx_brush_line_color);
290             }
291 
292             /* draw pixel(-x, y). */
293             if (_gx_utility_rectangle_point_detect(clip, point))
294             {
295                 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
296             }
297         }
298 
299         y += GX_FIXED_VAL_ONE;
300     }
301 }
302 
303