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_display.h"
29
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _gx_display_driver_generic_aliased_ellipse_draw PORTABLE C */
35 /* 6.1 */
36 /* AUTHOR */
37 /* */
38 /* Kenneth Maxwell, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* Display driver to draw anti-alised ellipse. */
43 /* */
44 /* INPUT */
45 /* */
46 /* context Drawing context */
47 /* xcenter x-coord of center of ellipse */
48 /* ycenter y-coord of center of ellipse */
49 /* a Length of the Semi-major Axis */
50 /* b Length of the Semi-minor Axis */
51 /* */
52 /* OUTPUT */
53 /* */
54 /* None */
55 /* */
56 /* CALLS */
57 /* */
58 /* _gx_utility_rectangle_overlap_detect Detect two rectangles being */
59 /* overlap to each other */
60 /* _gx_utility_math_sqrt Compute the square root value */
61 /* [gx_display_driver_pixel_blend] Basic display driver pixel */
62 /* blend function */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* GUIX Internal Code */
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 /* */
76 /**************************************************************************/
_gx_display_driver_generic_aliased_ellipse_draw(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,INT a,INT b)77 VOID _gx_display_driver_generic_aliased_ellipse_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, INT a, INT b)
78 {
79 /* The ellipse draw function is implemented from midpoint ellipse algorithm. */
80
81 GX_DISPLAY *display;
82 GX_RECTANGLE *clip;
83 GX_BRUSH *brush;
84 INT x;
85 INT y;
86 GX_POINT point;
87 INT sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
88 INT index;
89 INT aa;
90 INT bb;
91 INT realval;
92 INT error;
93 GX_UBYTE alpha1;
94 GX_UBYTE alpha2;
95
96 VOID (*blend_func)(GX_DRAW_CONTEXT *context,
97 INT x, INT y, GX_COLOR color, GX_UBYTE alpha);
98
99 #if defined(GX_BRUSH_ALPHA_SUPPORT)
100 GX_UBYTE brush_alpha;
101
102 brush_alpha = context -> gx_draw_context_brush.gx_brush_alpha;
103
104 if (brush_alpha == 0)
105 {
106 /* Nothing to draw here. */
107 return;
108 }
109 #endif
110
111 display = context -> gx_draw_context_display;
112 clip = context -> gx_draw_context_clip;
113 brush = &context -> gx_draw_context_brush;
114
115 blend_func = display -> gx_display_driver_pixel_blend;
116
117 if (blend_func == GX_NULL)
118 {
119 return;
120 }
121
122 aa = a * a;
123 bb = b * b;
124 x = 0;
125 y = b;
126 error = 0;
127
128 /* Region I of the first quarter of the ellipse. */
129 while (2 * bb * (x + 1) < aa * (2 * y - 1))
130 {
131 alpha1 = (GX_UBYTE)(255 - error);
132 alpha2 = (GX_UBYTE)error;
133 #if defined(GX_BRUSH_ALPHA_SUPPORT)
134 alpha1 = (GX_UBYTE)(alpha1 * brush_alpha / 255);
135 alpha2 = (GX_UBYTE)(alpha2 * brush_alpha / 255);
136 #endif
137 /* calculate error of next pixel. */
138 realval = bb - bb * (x + 1) * (x + 1) / aa;
139 error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3);
140
141 if (error >= 510)
142 {
143 /* The slope in point(x + 1, y) is greater than -1,
144 make point(x, y) the delimit pixel, break here. */
145 realval = bb - bb * x * x / aa;
146 error = (y << 8) - (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3);
147 break;
148 }
149
150 for (index = 0; index < 4; index++)
151 {
152 point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
153 point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
154
155 if (_gx_utility_rectangle_point_detect(clip, point))
156 {
157 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
158 }
159
160 point.gx_point_y = (GX_VALUE)((y - 1) * sign[index][1] + ycenter);
161
162 if (_gx_utility_rectangle_point_detect(clip, point))
163 {
164 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha2);
165 }
166 }
167
168 if (error >= 255)
169 {
170 error -= 255;
171 y--;
172 }
173
174 x++;
175 }
176
177 alpha1 = (GX_UBYTE)(255 - error);
178 #if defined(GX_BRUSH_ALPHA_SUPPORT)
179 alpha1 = (GX_UBYTE)(alpha1 * brush_alpha / 255);
180 #endif
181
182 /* Draw delimit pixel where delta x equals to delta y. */
183 for (index = 0; index < 4; index++)
184 {
185 point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
186 point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
187
188 if (_gx_utility_rectangle_point_detect(clip, point))
189 {
190 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
191 }
192 }
193
194 /* Region II of the first quarter of the ellipse. */
195 while (y > 0)
196 {
197 y--;
198
199 realval = aa - aa * y * y / bb;
200 error = (INT)(_gx_utility_math_sqrt((UINT)(realval << 10)) << 3) - (x << 8);
201
202 while (error >= 255)
203 {
204 error -= 255;
205 x++;
206 }
207 alpha1 = (GX_UBYTE)(255 - error);
208 alpha2 = (GX_UBYTE)error;
209 #if defined(GX_BRUSH_ALPHA_SUPPORT)
210 alpha1 = (GX_UBYTE)(alpha1 * brush_alpha / 255);
211 alpha2 = (GX_UBYTE)(alpha2 * brush_alpha / 255);
212 #endif
213
214 for (index = 0; index < 4; index++)
215 {
216 point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
217 point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
218
219
220 if (_gx_utility_rectangle_point_detect(clip, point))
221 {
222 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha1);
223 }
224
225 point.gx_point_x = (GX_VALUE)((x + 1) * sign[index][0] + xcenter);
226
227 if (_gx_utility_rectangle_point_detect(clip, point))
228 {
229 blend_func(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, alpha2);
230 }
231 }
232 }
233 }
234
235