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