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