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 #define PIXEL_WRITE(loc, val) (*(loc) = (val))
21 
22 #define GX_SOURCE_CODE
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_32bpp_simple_line_draw           PORTABLE C      */
35 /*                                                           6.1          */
36 /*  AUTHOR                                                                */
37 /*                                                                        */
38 /*    Kenneth Maxwell, Microsoft Corporation                              */
39 /*                                                                        */
40 /*  DESCRIPTION                                                           */
41 /*                                                                        */
42 /*    Generic 32bpp color format line draw function.                      */
43 /*                                                                        */
44 /*  INPUT                                                                 */
45 /*                                                                        */
46 /*    context                               Drawing context               */
47 /*    xstart                                x-coord of endpoint           */
48 /*    ystart                                y-coord of endpoint           */
49 /*    xend                                  x-coord of endpoint           */
50 /*    yend                                  y-coord of endpoint           */
51 /*                                                                        */
52 /*  OUTPUT                                                                */
53 /*                                                                        */
54 /*    None                                                                */
55 /*                                                                        */
56 /*  CALLS                                                                 */
57 /*                                                                        */
58 /*    _gx_display_driver_simple_line_alpha_draw                           */
59 /*                                          Basic display driver line     */
60 /*                                            alpha draw function         */
61 /*                                                                        */
62 /*  CALLED BY                                                             */
63 /*                                                                        */
64 /*    GUIX Internal Code                                                  */
65 /*                                                                        */
66 /*  RELEASE HISTORY                                                       */
67 /*                                                                        */
68 /*    DATE              NAME                      DESCRIPTION             */
69 /*                                                                        */
70 /*  05-19-2020     Kenneth Maxwell          Initial Version 6.0           */
71 /*  09-30-2020     Kenneth Maxwell          Modified comment(s),          */
72 /*                                            resulting in version 6.1    */
73 /*                                                                        */
74 /**************************************************************************/
_gx_display_driver_32bpp_simple_line_draw(GX_DRAW_CONTEXT * context,INT xstart,INT ystart,INT xend,INT yend)75 VOID _gx_display_driver_32bpp_simple_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
76 {
77 INT           curx;
78 INT           cury;
79 INT           x_sign;
80 INT           y_sign;
81 INT           decision;
82 INT           nextx;
83 INT           nexty;
84 INT           y_increment;
85 GX_POINT      end_point;
86 GX_POINT      mid_point;
87 GX_RECTANGLE  half_rectangle;
88 GX_RECTANGLE  half_over;
89 INT           sign;
90 INT           steps;
91 
92 ULONG        *put;
93 ULONG        *next_put;
94 
95 GX_BOOL       clipped = GX_TRUE;
96 INT           dx = GX_ABS(xend - xstart);
97 INT           dy = GX_ABS(yend - ystart);
98 
99 GX_RECTANGLE *clip = context -> gx_draw_context_clip;
100 GX_COLOR      linecolor = context -> gx_draw_context_brush.gx_brush_line_color;
101 #if defined GX_BRUSH_ALPHA_SUPPORT
102 GX_UBYTE      alpha;
103 
104     alpha = context -> gx_draw_context_brush.gx_brush_alpha;
105     if (alpha == 0)
106     {
107         /* Nothing to drawn. Just return. */
108         return;
109     }
110     if (alpha != 0xff)
111     {
112         _gx_display_driver_simple_line_alpha_draw(context, xstart, ystart, xend, yend, alpha);
113         return;
114     }
115 #endif
116 
117     if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
118     {
119         GX_SWAP_VALS(xend, xstart);
120         GX_SWAP_VALS(yend, ystart);
121     }
122     x_sign = (xend - xstart) / dx;
123     y_sign = (yend - ystart) / dy;
124 
125     if (y_sign > 0)
126     {
127         y_increment = context -> gx_draw_context_pitch;
128     }
129     else
130     {
131         y_increment = 0 - context -> gx_draw_context_pitch;
132     }
133 
134     put = (ULONG *)(context -> gx_draw_context_memory) + ystart * context -> gx_draw_context_pitch + xstart;
135     next_put = (ULONG *)(context -> gx_draw_context_memory) + yend * context -> gx_draw_context_pitch + xend;
136 
137 
138     end_point.gx_point_x = (GX_VALUE)xstart;
139     end_point.gx_point_y = (GX_VALUE)ystart;
140 
141     if (_gx_utility_rectangle_point_detect(clip, end_point))
142     {
143         end_point.gx_point_x = (GX_VALUE)xend;
144         end_point.gx_point_y = (GX_VALUE)yend;
145 
146         if (_gx_utility_rectangle_point_detect(clip, end_point))
147         {
148             clipped = GX_FALSE;
149         }
150     }
151 
152     if (clipped)
153     {
154         /* here if we must do clipping in the inner loop, because one
155         or both of the end points are outside clipping rectangle */
156 
157         /* Calculate the middle point of the line.  */
158         mid_point.gx_point_x = (GX_VALUE)(xend + xstart) >> 1;
159         mid_point.gx_point_y = (GX_VALUE)(yend + ystart) >> 1;
160 
161         /* Judge the clip in which side.  */
162         if (_gx_utility_rectangle_point_detect(clip, mid_point))
163         {
164 
165             /* the clip in two sides.  */
166             if (dx >= dy)
167             {
168                 /* walk out the clipping point.  */
169                 for (curx = xstart, cury = ystart, decision = (dx >> 1); curx < mid_point.gx_point_x;
170                     curx++, decision += dy)
171                 {
172                     if (decision >= dx)
173                     {
174                         decision -= dx;
175                         cury += y_sign;
176                         put += y_increment;
177                     }
178 
179                     if (curx >= clip -> gx_rectangle_left &&
180                         cury >= clip -> gx_rectangle_top &&
181                         cury <= clip -> gx_rectangle_bottom)
182                     {
183                         break;
184                     }
185                     put++;
186                 }
187                 for (; curx <= mid_point.gx_point_x;
188                     curx++, decision += dy)
189                 {
190                     if (decision >= dx)
191                     {
192                         decision -= dx;
193                         cury += y_sign;
194                         put += y_increment;
195                     }
196                     PIXEL_WRITE(put, linecolor);
197                     put++;
198                 }
199                 for (nextx = xend, nexty = yend, decision = (dx >> 1); nextx > mid_point.gx_point_x;
200                     nextx--, decision += dy)
201                 {
202                     if (decision >= dx)
203                     {
204                         decision -= dx;
205                         nexty -= y_sign;
206                         next_put -= y_increment;
207                     }
208                     if (nextx <= clip -> gx_rectangle_right &&
209                         nexty >= clip -> gx_rectangle_top &&
210                         nexty <= clip -> gx_rectangle_bottom)
211                     {
212                         break;
213                     }
214                     next_put--;
215                 }
216 
217                 for (; nextx > mid_point.gx_point_x;
218                     nextx--, decision += dy)
219                 {
220                     if (decision >= dx)
221                     {
222                         decision -= dx;
223                         nexty -= y_sign;
224                         next_put -= y_increment;
225                     }
226                     PIXEL_WRITE(next_put, linecolor);
227                     next_put--;
228                 }
229             }
230             else
231             {
232                 for (nextx = xend, nexty = yend, decision = (dy >> 1); nexty > mid_point.gx_point_y;
233                     nexty--, decision += dx)
234                 {
235                     if (decision >= dy)
236                     {
237                         decision -= dy;
238                         nextx -= x_sign;
239                         next_put -= x_sign;
240                     }
241                     if (nextx >= clip -> gx_rectangle_left &&
242                         nextx <= clip -> gx_rectangle_right &&
243                         nexty <= clip -> gx_rectangle_bottom)
244                     {
245                         break;
246                     }
247                     next_put -= context -> gx_draw_context_pitch;
248                 }
249 
250                 for (; nexty > mid_point.gx_point_y;
251                     nexty--, decision += dx)
252                 {
253                     if (decision >= dy)
254                     {
255                         decision -= dy;
256                         nextx -= x_sign;
257                         next_put -= x_sign;
258                     }
259                     PIXEL_WRITE(next_put, linecolor);
260                     next_put -= context -> gx_draw_context_pitch;
261                 }
262 
263                 /* walk out the clipping point.  */
264                 for (curx = xstart, cury = ystart, decision = (dy >> 1); cury < mid_point.gx_point_y;
265                     cury++, decision += dx)
266                 {
267                     if (decision >= dy)
268                     {
269                         decision -= dy;
270                         curx += x_sign;
271                         put += x_sign;
272                     }
273 
274                     if (curx >= clip -> gx_rectangle_left &&
275                         curx <= clip -> gx_rectangle_right &&
276                         cury >= clip -> gx_rectangle_top)
277                     {
278                         break;
279                     }
280                     put += context -> gx_draw_context_pitch;
281                 }
282                 for (; cury <= mid_point.gx_point_y;
283                     cury++, decision += dx)
284                 {
285                     if (decision >= dy)
286                     {
287                         decision -= dy;
288                         curx += x_sign;
289                         put += x_sign;
290                     }
291                     PIXEL_WRITE(put, linecolor);
292                     put += context -> gx_draw_context_pitch;
293                 }
294             }   /**/
295                 /*context   ->  gx_draw_context_display  ->  gx_display_driver_pixel_write(context, mid_point.gx_point_x,mid_point.gx_point_y, GX_COLOR_RED);*/
296         }
297         else
298         {
299             /* The clip stay at one side.  */
300             if (dx >= dy)
301             {
302                 half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
303                 half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
304                 if (y_sign == 1)
305                 {
306                     half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
307                     half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
308                 }
309                 else
310                 {
311                     half_rectangle.gx_rectangle_top = mid_point.gx_point_y;
312                     half_rectangle.gx_rectangle_bottom = (GX_VALUE)ystart;
313                 }
314 
315                 if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
316                 {
317                     curx = xstart;
318                     cury = ystart;
319                     steps = mid_point.gx_point_x - curx + 1;
320                     sign = 1;
321                 }
322                 else
323                 {
324                     curx = xend;
325                     cury = yend;
326                     steps = xend - mid_point.gx_point_x;
327                     sign = -1;
328                     y_increment = 0 - y_increment;
329                     y_sign = 0 - y_sign;
330                     put = next_put;
331                 }
332                 for (decision = (dx >> 1); steps > 0; curx += sign, decision += dy, steps--)
333                 {
334                     if (decision >= dx)
335                     {
336                         decision -= dx;
337                         cury += y_sign;
338                         put += y_increment;
339                     }
340 
341                     if (curx >= clip -> gx_rectangle_left &&
342                         curx <= clip -> gx_rectangle_right &&
343                         cury >= clip -> gx_rectangle_top &&
344                         cury <= clip -> gx_rectangle_bottom)
345                     {
346                         PIXEL_WRITE(put, linecolor);
347                     }
348                     put += sign;
349                 }
350             }
351             else
352             {
353                 half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
354                 half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
355                 if (x_sign == 1)
356                 {
357                     half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
358                     half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
359                 }
360                 else
361                 {
362                     half_rectangle.gx_rectangle_right = (GX_VALUE)xstart;
363                     half_rectangle.gx_rectangle_left = mid_point.gx_point_x;
364                 }
365 
366                 if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
367                 {
368                     curx = xstart;
369                     cury = ystart;
370                     steps = mid_point.gx_point_y - cury + 1;
371                     y_increment = context -> gx_draw_context_pitch;
372                     sign = 1;
373                 }
374                 else
375                 {
376                     curx = xend;
377                     cury = yend;
378                     steps = yend - mid_point.gx_point_y;
379                     sign = -1;
380                     y_increment = 0 - context -> gx_draw_context_pitch;
381                     x_sign = 0 - x_sign;
382                     put = next_put;
383                 }
384 
385                 for (decision = (dy >> 1); steps > 0; cury += sign, decision += dx, steps--)
386                 {
387                     if (decision >= dy)
388                     {
389                         decision -= dy;
390                         curx += x_sign;
391                         put += x_sign;
392                     }
393                     if (curx >= clip -> gx_rectangle_left &&
394                         curx <= clip -> gx_rectangle_right &&
395                         cury >= clip -> gx_rectangle_top &&
396                         cury <= clip -> gx_rectangle_bottom)
397                     {
398                         PIXEL_WRITE(put, linecolor);
399                     }
400                     put += y_increment;
401                 }
402             }
403         }
404     }
405     else
406     {
407         /* here if both line ends lie within clipping rectangle, we can
408         run a faster inner loop */
409         if (dx >= dy)
410         {
411             put = (ULONG *)(context -> gx_draw_context_memory) + ystart * context -> gx_draw_context_pitch + xstart;
412             next_put = (ULONG *)(context -> gx_draw_context_memory) + yend * context -> gx_draw_context_pitch + xend;
413 
414             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
415                 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
416                 decision += dy)
417             {
418 
419                 if (decision >= dx)
420                 {
421                     decision -= dx;
422                     cury += y_sign;
423                     nexty -= y_sign;
424 
425                     put += y_increment;
426                     next_put -= y_increment;
427                 }
428                 PIXEL_WRITE(put, linecolor);
429                 PIXEL_WRITE(next_put, linecolor);
430 
431                 put++;
432                 next_put--;
433             }
434         }
435         else
436         {
437 
438             for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
439                 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
440                 decision += dx)
441             {
442                 if (decision >= dy)
443                 {
444                     decision -= dy;
445                     curx += x_sign;
446                     nextx -= x_sign;
447 
448                     put += x_sign;
449                     next_put -= x_sign;
450                 }
451                 PIXEL_WRITE(put, linecolor);
452                 PIXEL_WRITE(next_put, linecolor);
453 
454                 put += context -> gx_draw_context_pitch;
455                 next_put -= context -> gx_draw_context_pitch;
456             }
457         }
458     }
459 }
460