GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: gx_display_driver_generic_ellipse_draw.c Lines: 62 62 100.0 %
Date: 2024-12-05 08:52:37 Branches: 38 38 100.0 %

Line Branch Exec Source
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_ellipse_draw             PORTABLE C      */
35
/*                                                           6.1.6        */
36
/*  AUTHOR                                                                */
37
/*                                                                        */
38
/*    Kenneth Maxwell, Microsoft Corporation                              */
39
/*                                                                        */
40
/*  DESCRIPTION                                                           */
41
/*                                                                        */
42
/*    Display driver to draw 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_display_driver_pixel_blend]       Basic display driver pixel    */
59
/*                                            blend function              */
60
/*    [gx_display_driver_pixel_write]       Basic display driver pixel    */
61
/*                                            write function              */
62
/*    _gx_utility_rectangle_point_detect    Detect whether a pixel is     */
63
/*                                            inside rectangle            */
64
/*                                                                        */
65
/*  CALLED BY                                                             */
66
/*                                                                        */
67
/*    GUIX Internal Code                                                  */
68
/*                                                                        */
69
/*  RELEASE HISTORY                                                       */
70
/*                                                                        */
71
/*    DATE              NAME                      DESCRIPTION             */
72
/*                                                                        */
73
/*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
74
/*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
75
/*                                            resulting in version 6.1    */
76
/*  04-02-2021     Kenneth Maxwell          Modified comment(s),          */
77
/*                                            improved precision,         */
78
/*                                            resulting in version 6.1.6  */
79
/*                                                                        */
80
/**************************************************************************/
81
432
VOID _gx_display_driver_generic_ellipse_draw(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter, INT a, INT b)
82
{
83
/* The ellipse draw function is implemented from Bresenham ellipse algorithm. */
84
INT           x;
85
INT           y;
86
INT           d;
87
GX_POINT      point;
88
432
INT           sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
89
INT           index;
90
INT           aa;
91
INT           bb;
92
432
GX_DISPLAY   *display = context -> gx_draw_context_display;
93
432
GX_BRUSH     *brush = &context -> gx_draw_context_brush;
94
432
GX_RECTANGLE *clip = context -> gx_draw_context_clip;
95
96
#if defined(GX_BRUSH_ALPHA_SUPPORT)
97
432
GX_UBYTE brush_alpha = brush -> gx_brush_alpha;
98
99
432
    if (display -> gx_display_driver_pixel_blend == GX_NULL)
100
    {
101
        /* Pixel blend function is null means alpha isn't supported in this driver.
102
           So set alpha value to 0xff to make it draw the original color in case GX_BRUSH_ALPHA_SUPPORT is defined. */
103
60
        brush_alpha = 0xff;
104
    }
105
    else
106
    {
107
372
        if (brush_alpha == 0)
108
        {
109
            /* Nothing to draw here. */
110
124
            return;
111
        }
112
    }
113
#endif
114
115
    /* The ellipse is split into 2 regions, region I with dx > dy and resion II with dx <= dy.
116
       In region I, the midpoint between (x + 1, y) and (x + 1, y - 1) is used to select next point that is closer to the ellipse,
117
       d(x + 1, y - 0.5) is the distance from the midpoint to the ellipse center,
118
       if the decision < 0, the midpoint is inside the ellipse, point (x + 1, y - 1) is closer to the ellipse, and be selected for drawing.
119
       otherwise, (x + 1, y) is selected.
120
       In region II, the midpoint between (x, y - 1) and (x + 1, y - 1) is used to select next point that is closer to the ellipse,
121
       d(x + 0.5, y - 1) is the distance from the midpoint to ellipse center,
122
       if the decision < 0, the midpoint is inside the ellipse, point(x + 1, y - 1) is closer to the ellipse, and be selected for drawing,
123
       otherwise, (x, y - 1) is selected.
124
125
       Ellipse equation is f(x, y) = sqr(b * x) + sqr(a * y) - sqr(a * b).
126
       First, we assume ellipse is centered at the origin(0, 0), and the first point is (0, b).
127
       Set initial decision value for region I as d = f(1, b - 0.5) = sqr(b) + sqr(a) * (-b + 0.25).
128
    */
129
130
308
    aa = a * a;
131
308
    bb = b * b;
132
308
    x = 0;
133
308
    y = b;
134
135
    /* Decision is enlarged by 4 to avoid floating point. */
136
308
    d = (bb << 2) + aa * (1 - (b << 2));
137
138
#if defined(GX_BRUSH_ALPHA_SUPPORT)
139
308
    if (brush_alpha != 0xff)
140
    {
141
142
        /* Region I of the first quarter of the ellipse.  */
143
8646
        while ((bb << 1) * (x + 1) < aa * (2 * y - 1))
144
        {
145
42610
            for (index = 0; index < 4; index++)
146
            {
147
34088
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
148
34088
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
149
150
34088
                if (_gx_utility_rectangle_point_detect(clip, point))
151
                {
152
34056
                    display -> gx_display_driver_pixel_blend(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, brush_alpha);
153
                }
154
            }
155
156
8522
            if (d < 0)
157
            {
158
6402
                d += (bb << 2) * ((x << 1) + 3);
159
            }
160
            else
161
            {
162
2120
                d += (bb << 2) * ((x << 1) + 3) + (aa << 3) * (1 - y);
163
2120
                y--;
164
            }
165
8522
            x++;
166
        }
167
168
124
        d = bb * ((x << 1) + 1) * ((x << 1) + 1) + (aa << 2) * (y - 1) * (y - 1) - (aa << 2) * bb;
169
170
        /* Region II of the first quarter of the ellipse.  */
171
8828
        while (y >= 0)
172
        {
173
43520
            for (index = 0; index < 4; index++)
174
            {
175
34816
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
176
34816
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
177
178
34816
                if (_gx_utility_rectangle_point_detect(clip, point))
179
                {
180
34220
                    display -> gx_display_driver_pixel_blend(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color, brush_alpha);
181
                }
182
            }
183
184
8704
            if (d < 0)
185
            {
186
2178
                d += (bb << 3) * (x + 1) + (aa << 2) * (3 - (y << 1));
187
2178
                x++;
188
            }
189
            else
190
            {
191
6526
                d += (aa << 2) * (3 - (y << 1));
192
            }
193
194
8704
            y--;
195
        }
196
    }
197
    else
198
    {
199
#endif
200
        /* Region I of the first quarter of the ellipse.  */
201
10426
        while ((bb << 1) * (x + 1) < aa * (2 * y - 1))
202
        {
203
51210
            for (index = 0; index < 4; index++)
204
            {
205
40968
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
206
40968
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
207
208
40968
                if (_gx_utility_rectangle_point_detect(clip, point))
209
                {
210
40936
                    display -> gx_display_driver_pixel_write(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color);
211
                }
212
            }
213
214
10242
            if (d < 0)
215
            {
216
7582
                d += (bb << 2) * ((x << 1) + 3);
217
            }
218
            else
219
            {
220
2660
                d += (bb << 2) * ((x << 1) + 3) + (aa << 3) * (1 - y);
221
2660
                y--;
222
            }
223
10242
            x++;
224
        }
225
226
        /* Set initial decision value for region II as d = f(x + 0.5, y - 1) = sqr(b * (x + 0.5) + sqr(a * (y - 1)) - sqr(a * b).
227
           Enlarge the decision by 4 to avoid float calculation. */
228
229
184
        d = bb * ((x << 1) + 1) * ((x << 1) + 1) + (aa << 2) * (y - 1) * (y - 1) - (aa << 2) * bb;
230
231
        /* Region II of the first quarter of the ellipse.  */
232
12128
        while (y >= 0)
233
        {
234
59720
            for (index = 0; index < 4; index++)
235
            {
236
47776
                point.gx_point_x = (GX_VALUE)(x * sign[index][0] + xcenter);
237
47776
                point.gx_point_y = (GX_VALUE)(y * sign[index][1] + ycenter);
238
239
47776
                if (_gx_utility_rectangle_point_detect(clip, point))
240
                {
241
47180
                    display -> gx_display_driver_pixel_write(context, point.gx_point_x, point.gx_point_y, brush -> gx_brush_line_color);
242
                }
243
            }
244
245
11944
            if (d < 0)
246
            {
247
2738
                d += (bb << 3) * (x + 1) + (aa << 2) * (3 - (y << 1));
248
2738
                x++;
249
            }
250
            else
251
            {
252
9206
                d += (aa << 2) * (3 - (y << 1));
253
            }
254
255
11944
            y--;
256
        }
257
#if defined(GX_BRUSH_ALPHA_SUPPORT)
258
    }
259
#endif
260
}
261