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