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 
22 
23 #define GX_SOURCE_CODE
24 
25 
26 /* Include necessary system files.  */
27 
28 #include "gx_api.h"
29 #include "gx_utility.h"
30 #include "gx_display.h"
31 #include "gx_system.h"
32 
33 /**************************************************************************/
34 /*                                                                        */
35 /*  FUNCTION                                               RELEASE        */
36 /*                                                                        */
37 /*    _gx_display_driver_generic_rotated_wide_line_fill   PORTABLE C      */
38 /*                                                           6.1.3        */
39 /*  AUTHOR                                                                */
40 /*                                                                        */
41 /*    Kenneth Maxwell, Microsoft Corporation                              */
42 /*                                                                        */
43 /*  DESCRIPTION                                                           */
44 /*                                                                        */
45 /*   Fill a wide line after the four corner points have been calculated.  */
46 /*                                                                        */
47 /*  INPUT                                                                 */
48 /*                                                                        */
49 /*    context                               Drawing context               */
50 /*    pPoints                               Pre-computed end points       */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    GX_ABS                                Compute the absolute value    */
59 /*    GX_SWAP_VALUE                         Swap two values               */
60 /*    [_gx_display_driver_horizontal_line_draw]                           */
61 /*                                          Driver for horizontal line    */
62 /*                                            draw                        */
63 /*                                                                        */
64 /*  CALLED BY                                                             */
65 /*                                                                        */
66 /*    _gx_display_driver_generic_simple_wide_line_draw                    */
67 /*    _gx_display_driver_generic_aliased_wide_line_draw                   */
68 /*                                                                        */
69 /*  RELEASE HISTORY                                                       */
70 /*                                                                        */
71 /*    DATE              NAME                      DESCRIPTION             */
72 /*                                                                        */
73 /*  12-31-2020     Kenneth Maxwell          Initial Version 6.1.3         */
74 /*                                                                        */
75 /**************************************************************************/
_gx_display_driver_generic_rotated_wide_line_fill(GX_DRAW_CONTEXT * context,GX_FIXED_POINT * pPoints)76 VOID _gx_display_driver_generic_rotated_wide_line_fill(GX_DRAW_CONTEXT *context, GX_FIXED_POINT *pPoints)
77 {
78 /*
79    Use Breshenham's line to compute the points along each line that bounds
80    the wide line and save the points to an array. Then draw horizontal lines
81    to connect the points.
82  */
83 
84 GX_FIXED_POINT *pGet = pPoints;
85 INT            *pLineEnds;
86 INT             xmin;
87 INT             xmax;
88 INT             xstart;
89 INT             xend;
90 INT             ystart;
91 INT             yend;
92 INT             curx;
93 INT             cury;
94 INT             test;
95 GX_FIXED_VAL    dx;
96 GX_FIXED_VAL    dy;
97 INT             Index;
98 INT             loop;
99 INT             width;
100 INT             xsign;
101 INT             ysign;
102 INT             decision;
103 INT             shift;
104 VOID            (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
105 GX_RECTANGLE   *clip = context -> gx_draw_context_clip;
106 GX_COLOR        linecolor = context -> gx_draw_context_brush.gx_brush_line_color;
107 GX_BOOL         aliased = GX_FALSE;
108 INT             x_fraction;
109 INT             y_fraction;
110 
111     if ((context -> gx_draw_context_brush.gx_brush_style & GX_BRUSH_ALIAS) &&
112         context -> gx_draw_context_display -> gx_display_driver_pixel_blend)
113     {
114         aliased = GX_TRUE;
115     }
116 
117     xmin = GX_FIXED_VAL_TO_INT(pPoints[0].x);
118     xmax = GX_FIXED_VAL_RND_UP(pPoints[2].x);
119 
120     if (xmin < clip -> gx_rectangle_left)
121     {
122         xmin = clip -> gx_rectangle_left;
123     }
124 
125     if (xmax > clip -> gx_rectangle_right)
126     {
127         xmax = clip -> gx_rectangle_right;
128     }
129 
130     width = xmax - xmin + 1;
131 
132     pLineEnds = _gx_system_scratchpad;
133 
134     /* default the point array to being off the screen on both sides: */
135 
136     for (loop = 0; loop < width * 2; loop += 2)
137     {
138         pLineEnds[loop] = 2000;
139         pLineEnds[loop + 1] = 0;
140     }
141 
142     /* Fill in the point array by using Breshenhams line for
143        all 4 sides of the bounding rectangle
144      */
145 
146     for (loop = 0; loop < 4; loop++)
147     {
148         xstart = pGet -> x;
149         ystart = pGet -> y;
150         pGet++;
151         xend = pGet -> x;
152         yend = pGet -> y;
153         dx = GX_ABS(xend - xstart);
154         dy = GX_ABS(yend - ystart);
155 
156         xsign = ysign = 1;
157 
158         if (((dx >= dy && (xstart > xend)) ||
159              ((dy > dx) && ystart > yend)))
160         {
161             GX_SWAP_VALS(xend, xstart);
162             GX_SWAP_VALS(yend, ystart);
163         }
164         if (dx)
165         {
166             xsign = (xend - xstart) / dx;
167         }
168         if (dy)
169         {
170             ysign = (yend - ystart) / dy;
171         }
172 
173         x_fraction = (xstart & GX_FIXED_VAL_FRACTION_MASK);
174         y_fraction = (ystart & GX_FIXED_VAL_FRACTION_MASK);
175 
176         shift = 0;
177 
178         if (dx >= dy)
179         {
180             if (ysign < 0)
181             {
182                 cury = GX_FIXED_VAL_RND_UP(ystart);
183 
184                 if (y_fraction)
185                 {
186                     y_fraction = GX_FIXED_VAL_ONE - y_fraction;
187                 }
188             }
189             else
190             {
191                 cury = GX_FIXED_VAL_TO_INT(ystart);
192             }
193 
194             decision = (y_fraction * dx - x_fraction * dy) / GX_FIXED_VAL_ONE;
195 
196             if (decision < 0)
197             {
198                 decision += dx;
199                 cury -= ysign;
200             }
201 
202             xstart = GX_FIXED_VAL_TO_INT(xstart);
203 
204             if (aliased)
205             {
206                 xend = GX_FIXED_VAL_TO_INT(xend);
207 
208                 if (x_fraction)
209                 {
210                     xstart++;
211                     decision += dy;
212                 }
213 
214                 if (dy)
215                 {
216                     if ((loop == 1) || (loop == 2))
217                     {
218                         shift = ysign;
219                     }
220                 }
221             }
222             else
223             {
224                 xend = GX_FIXED_VAL_RND(xend);
225 
226                 if (x_fraction >= GX_FIXED_VAL_HALF)
227                 {
228                     xstart++;
229                     decision += dy;
230                 }
231 
232                 decision += (dx >> 1);
233                 if (decision >= dx)
234                 {
235                     decision -= dx;
236                     cury += ysign;
237                 }
238             }
239 
240             for (curx = xstart; curx <= xend; curx++, decision += dy)
241             {
242                 if (decision >= dx)
243                 {
244                     decision -= dx;
245                     cury += ysign;
246                 }
247 
248                 if ((curx >= xmin) && (curx <= xmax))
249                 {
250                     Index = (curx - xmin) << 1;
251 
252                     test = cury + shift;
253                     if (test < pLineEnds[Index])
254                     {
255                         pLineEnds[Index] = test;
256                     }
257 
258                     if (test > pLineEnds[Index + 1])
259                     {
260                         pLineEnds[Index + 1] = test;
261                     }
262                 }
263             }
264         }
265         else
266         {
267             if (xsign < 0)
268             {
269                 curx = GX_FIXED_VAL_RND_UP(xstart);
270 
271                 if (x_fraction)
272                 {
273                     x_fraction = GX_FIXED_VAL_FRACTION_MASK - x_fraction;
274                 }
275             }
276             else
277             {
278                 curx = GX_FIXED_VAL_TO_INT(xstart);
279             }
280 
281             decision = (x_fraction * dy - y_fraction * dx) / GX_FIXED_VAL_ONE;
282 
283             if (decision < 0)
284             {
285                 decision += dy;
286                 curx -= xsign;
287             }
288 
289             ystart = GX_FIXED_VAL_TO_INT(ystart);
290 
291             if (aliased)
292             {
293                 yend = GX_FIXED_VAL_TO_INT(yend);
294 
295                 if (y_fraction)
296                 {
297                     ystart++;
298                     decision += dx;
299                 }
300 
301                 if (dx)
302                 {
303                     if (loop == 2 || loop == 3)
304                     {
305                         shift = xsign;
306                     }
307                 }
308             }
309             else
310             {
311                 yend = GX_FIXED_VAL_RND(yend);
312 
313                 if (y_fraction >= GX_FIXED_VAL_HALF)
314                 {
315                     ystart++;
316                     decision += dx;
317                 }
318 
319                 decision += (dy >> 1);
320 
321                 if (decision >= dy)
322                 {
323                     decision -= dy;
324                     curx += xsign;
325                 }
326             }
327 
328             for (cury = ystart; cury <= yend; cury++, decision += dx)
329             {
330                 if (decision >= dy)
331                 {
332                     decision -= dy;
333                     curx += xsign;
334                 }
335 
336                 test = curx + shift;
337 
338                 if ((test >= xmin) && (test <= xmax))
339                 {
340                     Index = (test - xmin) << 1;
341 
342                     if (cury < pLineEnds[Index])
343                     {
344                         pLineEnds[Index] = cury;
345                     }
346 
347                     if (cury > pLineEnds[Index + 1])
348                     {
349                         pLineEnds[Index + 1] = cury;
350                     }
351                 }
352             }
353         }
354     }
355 
356     Index = 0;
357     line_draw = context -> gx_draw_context_display -> gx_display_driver_vertical_line_draw;
358 
359     for (curx = xmin; curx <= xmax; curx++)
360     {
361         if (pLineEnds[Index] < clip -> gx_rectangle_top)
362         {
363             pLineEnds[Index] = clip -> gx_rectangle_top;
364         }
365 
366         if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
367         {
368             pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
369         }
370 
371         if (pLineEnds[Index] <= pLineEnds[Index + 1])
372         {
373             line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], curx, 1, linecolor);
374         }
375         Index += 2;
376     }
377 }
378 
379