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