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_utility.h"
28 #include "gx_system.h"
29 #include "gx_display.h"
30
31 #if defined(GX_ARC_DRAWING_SUPPORT)
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_display_driver_generic_rotated_ellipse_fill PORTABLE C */
38 /* 6.1.6 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* Display driver to draw a filled ellipse. */
46 /* */
47 /* INPUT */
48 /* */
49 /* context Drawing context */
50 /* xcenter x-coord of center of ellipse */
51 /* ycenter y-coord of center of ellipse */
52 /* a Length of the Semi-major Axis */
53 /* b Length of the Semi-minor Axis */
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_horizontal_pixelmap_line_draw] */
65 /* Basic display driver */
66 /* horizontal pixelmap line */
67 /* draw function */
68 /* */
69 /* CALLED BY */
70 /* */
71 /* GUIX Internal Code */
72 /* */
73 /* RELEASE HISTORY */
74 /* */
75 /* DATE NAME DESCRIPTION */
76 /* */
77 /* 12-31-2020 Kenneth Maxwell Initial Version 6.1.3 */
78 /* 04-02-2021 Ting Zhu Modified comment(s), */
79 /* modified algorithm to make */
80 /* it fit one-width antialiaed */
81 /* ellipse outline, */
82 /* resulting in version 6.1.6 */
83 /* */
84 /**************************************************************************/
_gx_display_driver_generic_rotated_ellipse_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,INT a,INT b)85 VOID _gx_display_driver_generic_rotated_ellipse_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, INT a, INT b)
86 {
87 /* The ellipse fill function follows Bresenham ellipse algorithm while
88 connecting the two point that symmetric with respect to y-axis. */
89
90 GX_DISPLAY *display;
91 GX_RECTANGLE *clip;
92 GX_BRUSH *brush;
93 INT x1;
94 INT x;
95 INT y;
96 INT y0;
97 INT y1;
98 INT sign[2] = {1, -1};
99 INT *pLineEnds;
100 INT index;
101 INT width;
102 INT Index;
103 INT aa;
104 INT bb;
105 INT ypos;
106 INT xmin;
107 INT xmax;
108 INT skip_line;
109 GX_PIXELMAP *pixelmap = GX_NULL;
110 GX_COLOR fill_color;
111 GX_FILL_PIXELMAP_INFO info;
112 GX_BYTE xsign;
113 INT error;
114 INT realval;
115 GX_BOOL record;
116
117 display = context -> gx_draw_context_display;
118 clip = context -> gx_draw_context_clip;
119 brush = &context -> gx_draw_context_brush;
120
121 if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
122 {
123 if (brush -> gx_brush_pixelmap == GX_NULL)
124 {
125 /* Nothing should be drawn if pixelmap isn't set with GX_BRUSH_PIXELMAP_FILL style. */
126 return;
127 }
128
129 pixelmap = brush -> gx_brush_pixelmap;
130
131 if (pixelmap -> gx_pixelmap_format != display -> gx_display_color_format)
132 {
133 /* Display driver only support its native format pixelmap.*/
134 /* Nothing should be drawn if pixelmap format isn't support. */
135 return;
136 }
137
138 memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
139
140 info.pixelmap = brush -> gx_brush_pixelmap;
141 info.current_pixel_ptr = (GX_UBYTE *)info.pixelmap -> gx_pixelmap_data;
142
143 if (pixelmap -> gx_pixelmap_aux_data_size)
144 {
145 info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
146 }
147 }
148
149 xmin = xcenter - a;
150 xmax = xcenter + a;
151
152 /* Calculate minimum y line. */
153 if (clip -> gx_rectangle_left > xmin)
154 {
155 xmin = clip -> gx_rectangle_left;
156 }
157
158 /* Calculate maximum y line. */
159 if (clip -> gx_rectangle_right < xmax)
160 {
161 xmax = clip -> gx_rectangle_right;
162 }
163
164 width = (xmax - xmin + 1);
165 pLineEnds = _gx_system_scratchpad;
166
167 /* default the point array to being off the screen on both sides: */
168 for (Index = 0; Index < width * 2; Index += 2)
169 {
170 pLineEnds[Index] = 2000;
171 pLineEnds[Index + 1] = 0;
172 }
173
174 aa = a * a;
175 bb = b * b;
176 x = 0;
177 y = b;
178 error = 0;
179
180 /* Region I of the first quarter of the ellipse. */
181 while (2 * bb * (x + 1) < aa * (2 * y - 1))
182 {
183 /* calculate error of next pixel. */
184 realval = bb - bb * (x + 1) * (x + 1) / aa;
185 error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3);
186
187 if (error >= 510)
188 {
189 /* The slope in point(x + 1, y) is greater than -1,
190 make point(x, y) the delimit pixel, break here. */
191 realval = bb - bb * x * x / aa;
192 error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3);
193 break;
194 }
195
196 y0 = ycenter - (y - 1);
197 y1 = ycenter + (y - 1);
198
199 if (y0 < clip -> gx_rectangle_top)
200 {
201 y0 = clip -> gx_rectangle_top;
202 }
203
204 if (y1 > clip -> gx_rectangle_bottom)
205 {
206 y1 = clip -> gx_rectangle_bottom;
207 }
208
209 for (index = 0; index < 2; index++)
210 {
211 x1 = x * sign[index] + xcenter;
212
213 if ((x1 >= xmin) && (x1 <= xmax))
214 {
215 Index = (x1 - xmin) << 1;
216 pLineEnds[Index] = y0;
217 pLineEnds[Index + 1] = y1;
218 }
219 }
220
221 if (error >= 255)
222 {
223 y--;
224 }
225
226 x++;
227 }
228
229 record = GX_TRUE;
230
231 y0 = ycenter - y;
232 y1 = ycenter + y;
233
234 if (y0 < clip -> gx_rectangle_top)
235 {
236 y0 = clip -> gx_rectangle_top;
237 }
238
239 if (y1 > clip -> gx_rectangle_bottom)
240 {
241 y1 = clip -> gx_rectangle_bottom;
242 }
243
244 for (index = 0; index < 2; index++)
245 {
246 x1 = x * sign[index] + xcenter;
247
248 if ((x1 >= xmin) && (x1 <= xmax))
249 {
250 Index = (x1 - xmin) << 1;
251 pLineEnds[Index] = y0;
252 pLineEnds[Index + 1] = y1;
253 }
254 }
255
256 /* Region II of the first quarter of the ellipse. */
257 while (y > 0)
258 {
259 y--;
260
261 realval = aa - aa * y * y / bb;
262 error = (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3) - (x << 8);
263
264 while (error >= 255)
265 {
266 error -= 255;
267 x++;
268
269 record = GX_TRUE;
270 }
271
272 if (record)
273 {
274 record = GX_FALSE;
275
276 y0 = ycenter - y;
277 y1 = ycenter + y;
278
279 if (y0 < clip -> gx_rectangle_top)
280 {
281 y0 = clip -> gx_rectangle_top;
282 }
283
284 if (y1 > clip -> gx_rectangle_bottom)
285 {
286 y1 = clip -> gx_rectangle_bottom;
287 }
288
289 for (index = 0; index < 2; index++)
290 {
291 x1 = x * sign[index] + xcenter;
292
293 if ((x1 >= xmin) && (x1 <= xmax))
294 {
295 Index = (x1 - xmin) << 1;
296 pLineEnds[Index] = y0;
297 pLineEnds[Index + 1] = y1;
298 }
299 }
300 }
301 }
302
303 if (pixelmap != GX_NULL)
304 {
305 if (context -> gx_draw_context_display -> gx_display_rotation_angle == GX_SCREEN_ROTATION_CW)
306 {
307 skip_line = (xmax - (xcenter - a) + 1) % pixelmap -> gx_pixelmap_width;
308
309 if (skip_line)
310 {
311 skip_line = pixelmap -> gx_pixelmap_width - skip_line;
312 }
313
314 x1 = xmax;
315 xsign = -1;
316 Index = (width - 1) * 2;
317 }
318 else
319 {
320 skip_line = (xmin - clip -> gx_rectangle_left);
321
322 x1 = xmin;
323 xsign = 1;
324 Index = 0;
325 }
326
327 if (skip_line)
328 {
329 info.draw = GX_FALSE;
330 while (skip_line--)
331 {
332 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, 0, &info);
333 }
334 }
335
336 info.draw = GX_TRUE;
337 ypos = ycenter - b;
338
339 for (x = xmin; x <= xmax; x++)
340 {
341 info.x_offset = pLineEnds[Index] - ypos;
342 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], x1, &info);
343
344 x1 += xsign;
345 Index += xsign;
346 Index += xsign;
347 }
348 }
349 else
350 {
351 Index = 0;
352 fill_color = brush -> gx_brush_fill_color;
353
354 for (x = xmin; x <= xmax; x++)
355 {
356 display -> gx_display_driver_vertical_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], x, 1, fill_color);
357 Index += 2;
358 }
359 }
360 }
361 #endif
362
363