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