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