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