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