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