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