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