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_system.h"
28 #include "gx_utility.h"
29 #include "gx_display.h"
30 /**************************************************************************/
31 /* */
32 /* FUNCTION RELEASE */
33 /* */
34 /* _gx_display_driver_generic_simple_pie_fill PORTABLE C */
35 /* 6.1 */
36 /* AUTHOR */
37 /* */
38 /* Kenneth Maxwell, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* Display driver to fill a pie chart. */
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 /* start_angle Starting angle */
51 /* end_angle Ending angle */
52 /* */
53 /* OUTPUT */
54 /* */
55 /* None */
56 /* */
57 /* CALLS */
58 /* */
59 /* _gx_display_driver_arc_clipping_get Get an arc clipping. */
60 /* _gx_utility_rectangle_overlap_detect Detects two rectangles being */
61 /* overlap */
62 /* _gx_utility_rectangle_point_detect Detect whether a pixel is */
63 /* inside rectangle */
64 /* _gx_utility_circle_point_get Get point coord on a circle */
65 /* [gx_display_driver_horizontal_pixelmap_line_draw] */
66 /* Basic display driver */
67 /* horizontal pixelmap line */
68 /* draw function */
69 /* [gx_display_driver_horizontal_line_draw] */
70 /* Basic display driver */
71 /* horizontal line draw routine*/
72 /* */
73 /* CALLED BY */
74 /* */
75 /* GUIX Internal Code */
76 /* */
77 /* RELEASE HISTORY */
78 /* */
79 /* DATE NAME DESCRIPTION */
80 /* */
81 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
82 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
83 /* resulting in version 6.1 */
84 /* */
85 /**************************************************************************/
86 #if defined(GX_ARC_DRAWING_SUPPORT)
87
_gx_display_driver_generic_simple_pie_fill(GX_DRAW_CONTEXT * context,INT xcenter,INT ycenter,UINT r,INT start_angle,INT end_angle,GX_BOOL skip_end)88 VOID _gx_display_driver_generic_simple_pie_fill(GX_DRAW_CONTEXT *context, INT xcenter, INT ycenter,
89 UINT r, INT start_angle, INT end_angle, GX_BOOL skip_end)
90 {
91 /* The function will only fill a pie with both start angle and end angle are
92 between 0 and 180 or beween 180 and 360.*/
93
94 GX_DISPLAY *display;
95 GX_BRUSH *brush;
96 GX_RECTANGLE *clip;
97 GX_RECTANGLE arc_clip[4];
98 GX_POINT point;
99 GX_POINT points[3];
100 INT sign[4][2] = {{1, 1}, {-1, 1}, {1, -1}, {-1, -1}};
101 INT *pLineEnds;
102 GX_POINT *pGet;
103 INT ymin;
104 INT ymax;
105 INT xstart;
106 INT xend;
107 INT ystart;
108 INT yend;
109 INT curx;
110 INT cury;
111 INT nextx;
112 INT nexty;
113 INT dx;
114 INT dy;
115 INT Index;
116 INT loop;
117 INT height;
118 INT xsign;
119 INT ysign;
120 INT decision;
121 int fillingwards;
122 VOID (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
123 INT xpos = 0;
124 GX_PIXELMAP *pixelmap = GX_NULL;
125 GX_VALUE format;
126 INT skip_line;
127 GX_FILL_PIXELMAP_INFO info;
128
129 display = context -> gx_draw_context_display;
130 brush = &context -> gx_draw_context_brush;
131 line_draw = display -> gx_display_driver_horizontal_line_draw;
132
133 if (brush -> gx_brush_style & GX_BRUSH_PIXELMAP_FILL)
134 {
135 /* Pick up pixelmap. */
136 pixelmap = brush -> gx_brush_pixelmap;
137 if (pixelmap == GX_NULL)
138 {
139 return;
140 }
141 if (pixelmap -> gx_pixelmap_height <= 0 ||
142 pixelmap -> gx_pixelmap_width <= 0)
143 {
144 return;
145 }
146
147 memset(&info, 0, sizeof(GX_FILL_PIXELMAP_INFO));
148 format = display -> gx_display_color_format;
149
150 /*Check the pixelmap format is supported in this driver or not.*/
151 if (format >= GX_COLOR_FORMAT_24XRGB)
152 {
153 /*32ARGB FORMAT use 24xrgb driver for now. So this is a special case.*/
154 if (pixelmap -> gx_pixelmap_format < GX_COLOR_FORMAT_24XRGB)
155 {
156 /* Display driver only support its native format pixelmap. */
157 /* Nothing should be drawn if pixelmap format isn't support. */
158 return;
159 }
160 }
161 else
162 {
163 if (pixelmap -> gx_pixelmap_format != format)
164 {
165 /* Display driver only support its native format pixelmap. */
166 /* Nothing should be drawn if pixelmap format isn't support. */
167 return;
168 }
169 else if (pixelmap -> gx_pixelmap_format == GX_COLOR_FORMAT_4BIT_GRAY)
170 {
171 info.mask = 0xf0;
172 }
173 }
174
175 info.pixelmap = pixelmap;
176 info.current_pixel_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_data;
177 if (pixelmap -> gx_pixelmap_aux_data_size)
178 {
179 info.current_aux_ptr = (GX_UBYTE *)pixelmap -> gx_pixelmap_aux_data;
180 }
181 }
182
183 pGet = points;
184
185 _gx_display_driver_arc_clipping_get(xcenter, ycenter, r, start_angle, end_angle,
186 &arc_clip[0], &arc_clip[1], &arc_clip[2], &arc_clip[3]);
187
188 if ((start_angle <= 180) && (end_angle <= 180))
189 {
190 /* Pie is in upper side. */
191 ymin = ycenter - (INT)r;
192 ymax = ycenter;
193
194 if (skip_end)
195 {
196 ymax--;
197 }
198 }
199 else
200 {
201 /* Pie is in lower side. */
202 ymin = ycenter;
203 ymax = ycenter + (INT)r;
204 }
205
206 clip = context -> gx_draw_context_clip;
207
208 if (clip -> gx_rectangle_top > ymin)
209 {
210 ymin = clip -> gx_rectangle_top;
211 }
212 skip_line = ymin - (ycenter - (INT)r);
213
214 if (clip -> gx_rectangle_bottom < ymax)
215 {
216 ymax = clip -> gx_rectangle_bottom;
217 }
218
219 height = ymax - ymin + 1;
220
221 pLineEnds = _gx_system_scratchpad;
222
223 /* default the point array to being off the screen on both sides: */
224
225 for (loop = 0; loop < height * 2; loop += 2)
226 {
227 pLineEnds[loop] = 2000;
228 pLineEnds[loop + 1] = 0;
229 }
230
231 curx = 0;
232 cury = (INT)r;
233 decision = 5 - (INT)(4 * r);
234
235 while (curx <= cury)
236 {
237 for (loop = 0; loop < 4; loop++)
238 {
239 point.gx_point_x = (GX_VALUE)(curx * sign[loop][0] + xcenter);
240 point.gx_point_y = (GX_VALUE)(cury * sign[loop][1] + ycenter);
241
242 if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
243 {
244 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
245 _gx_utility_rectangle_point_detect(&arc_clip[1], point))
246 {
247 Index = (point.gx_point_y - ymin) << 1;
248 if (point.gx_point_x < pLineEnds[Index])
249 {
250 pLineEnds[Index] = point.gx_point_x;
251 }
252
253 if (point.gx_point_x > pLineEnds[Index + 1])
254 {
255 pLineEnds[Index + 1] = point.gx_point_x;
256 }
257 }
258 }
259
260 point.gx_point_x = (GX_VALUE)(cury * sign[loop][0] + xcenter);
261 point.gx_point_y = (GX_VALUE)(curx * sign[loop][1] + ycenter);
262
263 if ((point.gx_point_y >= ymin) && (point.gx_point_y <= ymax))
264 {
265 if (_gx_utility_rectangle_point_detect(&arc_clip[0], point) ||
266 _gx_utility_rectangle_point_detect(&arc_clip[1], point))
267 {
268 Index = (point.gx_point_y - ymin) << 1;
269 if (point.gx_point_x < pLineEnds[Index])
270 {
271 pLineEnds[Index] = point.gx_point_x;
272 }
273
274 if (point.gx_point_x > pLineEnds[Index + 1])
275 {
276 pLineEnds[Index + 1] = point.gx_point_x;
277 }
278 }
279 }
280 }
281
282 if (decision < 0)
283 {
284 decision += 8 * curx + 12;
285 }
286 else
287 {
288 decision += 8 * (curx - cury) + 20;
289 cury--;
290 }
291 curx++;
292 }
293
294 /* Fill in the point array by using Breshenhams line for
295 2 lines of circle sector
296 */
297
298 points[1].gx_point_x = (GX_VALUE)xcenter;
299 points[1].gx_point_y = (GX_VALUE)ycenter;
300
301 _gx_utility_circle_point_get(xcenter, ycenter, r, start_angle, &points[0]);
302 _gx_utility_circle_point_get(xcenter, ycenter, r, end_angle, &points[2]);
303
304 for (loop = 0; loop < 2; loop++)
305 {
306 xstart = pGet -> gx_point_x;
307 ystart = pGet -> gx_point_y;
308 pGet++;
309 xend = pGet -> gx_point_x;
310 yend = pGet -> gx_point_y;
311 dx = GX_ABS(xend - xstart);
312 dy = GX_ABS(yend - ystart);
313
314 /* Horizontal Line. */
315 if (ystart == yend)
316 {
317 continue;
318 }
319
320 /* Vertical Line. */
321 if (xstart == xend)
322 {
323 if (ystart > yend)
324 {
325 GX_SWAP_VALS(xstart, xend);
326 GX_SWAP_VALS(ystart, yend);
327 }
328
329 for (cury = ystart; cury <= yend; cury++)
330 {
331 if ((cury >= ymin) && (cury <= ymax))
332 {
333 Index = (cury - ymin) << 1;
334 if (xstart <= pLineEnds[Index])
335 {
336 pLineEnds[Index] = xstart;
337 }
338
339 if (xstart > pLineEnds[Index + 1])
340 {
341 pLineEnds[Index + 1] = xstart;
342 }
343 }
344 }
345 continue;
346 }
347
348 /* Simple Line. */
349 if (((dx >= dy && (xstart > xend)) ||
350 ((dy > dx) && ystart > yend)))
351 {
352 GX_SWAP_VALS(xend, xstart);
353 GX_SWAP_VALS(yend, ystart);
354 }
355
356 xsign = (xend - xstart) / dx;
357 ysign = (yend - ystart) / dy;
358
359 if (start_angle < 180)
360 {
361 if (loop == 0)
362 {
363 fillingwards = (1 + ysign) >> 1;
364 }
365 else
366 {
367 fillingwards = (1 - ysign) >> 1;
368 }
369 }
370 else
371 {
372 if (loop == 0)
373 {
374 fillingwards = (1 - ysign) >> 1;
375 }
376 else
377 {
378 fillingwards = (1 + ysign) >> 1;
379 }
380 }
381
382 if (dx >= dy)
383 {
384 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
385 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
386 decision += dy)
387 {
388 if (decision >= dx)
389 {
390 decision -= dx;
391 cury += ysign;
392 nexty -= ysign;
393 }
394
395 if ((cury - 1 + fillingwards >= ymin) && (cury - 1 + fillingwards <= ymax))
396 {
397 Index = (cury - 1 + fillingwards - ymin) << 1;
398
399 if (curx < pLineEnds[Index])
400 {
401 pLineEnds[Index] = curx;
402 }
403
404 if (curx > pLineEnds[Index + 1])
405 {
406 pLineEnds[Index + 1] = curx;
407 }
408 }
409
410 if ((nexty - 1 + fillingwards >= ymin) && (nexty - 1 + fillingwards <= ymax))
411 {
412 Index = (nexty - 1 + fillingwards - ymin) << 1;
413
414 if (nextx < pLineEnds[Index])
415 {
416 pLineEnds[Index] = nextx;
417 }
418
419 if (nextx > pLineEnds[Index + 1])
420 {
421 pLineEnds[Index + 1] = nextx;
422 }
423 }
424 }
425 }
426 else
427 {
428 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
429 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
430 decision += dx)
431 {
432 if (decision >= dy)
433 {
434 decision -= dy;
435 curx += xsign;
436 nextx -= xsign;
437 }
438
439 if ((cury >= ymin) && (cury <= ymax))
440 {
441 Index = (cury - ymin) << 1;
442
443 if (curx < pLineEnds[Index])
444 {
445 pLineEnds[Index] = curx;
446 }
447
448 if (curx - 1 > pLineEnds[Index + 1])
449 {
450 pLineEnds[Index + 1] = curx - 1;
451 }
452 }
453
454 if ((nexty >= ymin) && (nexty <= ymax))
455 {
456 Index = (nexty - ymin) << 1;
457
458 if (nextx < pLineEnds[Index])
459 {
460 pLineEnds[Index] = nextx;
461 }
462
463 if (nextx - 1 > pLineEnds[Index + 1])
464 {
465 pLineEnds[Index + 1] = nextx - 1;
466 }
467 }
468 }
469 }
470 }
471
472 if (pixelmap != NULL)
473 {
474 /* Calculate the draw_start position and skip line to fill the pie area. */
475 xpos = xcenter - (INT)r;
476
477 /*Skip the un-draw line.*/
478 if (skip_line > 0)
479 {
480 skip_line %= info.pixelmap -> gx_pixelmap_height;
481 info.draw = GX_FALSE;
482 while (skip_line--)
483 {
484 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, cury, &info);
485 }
486 }
487 }
488
489 /* Filling circle sector with horizontal line. */
490 Index = 0;
491 for (cury = ymin; cury <= ymax; cury++)
492 {
493 if (pLineEnds[Index] <= pLineEnds[Index + 1])
494 {
495 if (pLineEnds[Index] < clip -> gx_rectangle_left)
496 {
497 pLineEnds[Index] = clip -> gx_rectangle_left;
498 }
499
500 if (pLineEnds[Index + 1] > clip -> gx_rectangle_right)
501 {
502 pLineEnds[Index + 1] = clip -> gx_rectangle_right;
503 }
504
505 if (pixelmap)
506 {
507 info.draw = GX_TRUE;
508 info.x_offset = pLineEnds[Index] - xpos;
509 /* Filling pie area with pixelmap. */
510 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], cury, &info);
511 }
512 else
513 {
514 line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], cury, 1,
515 brush -> gx_brush_fill_color);
516 }
517 }
518 else
519 {
520 if (pixelmap != GX_NULL)
521 {
522 info.draw = GX_FALSE;
523 display -> gx_display_driver_horizontal_pixelmap_line_draw(context, 0, 0, cury, &info);
524 }
525 }
526
527 Index += 2;
528 }
529 }
530
531 #endif
532
533