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 #define GX_SOURCE_CODE
22
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_1bpp_simple_line_draw PORTABLE C */
35 /* 6.1 */
36 /* AUTHOR */
37 /* */
38 /* Kenneth Maxwell, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* Simple line draw function for the 1bpp display driver. */
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_ABS Compute the absolute value */
59 /* GX_SWAP_VALUE Swap two values */
60 /* */
61 /* CALLED BY */
62 /* */
63 /* GUIX Internal Code */
64 /* */
65 /* RELEASE HISTORY */
66 /* */
67 /* DATE NAME DESCRIPTION */
68 /* */
69 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
70 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
71 /* resulting in version 6.1 */
72 /* */
73 /**************************************************************************/
_gx_display_driver_1bpp_simple_line_draw(GX_DRAW_CONTEXT * context,INT xstart,INT ystart,INT xend,INT yend)74 VOID _gx_display_driver_1bpp_simple_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
75 {
76
77 /**************************************************************************/
78 /* Integer non-aliased line draw. This algorithm is taken directly from */
79 /* Roger Stevens "The C++ graphics programming handbook" pages 281-282. */
80 /* Removed the pattern test and renamed the variables and converted from */
81 /* C++ to C. Also modified the algorithm to draw from both ends in to */
82 /* the middle, instead of drawing from one end to the other. */
83 /**************************************************************************/
84
85 INT curx;
86 INT cury;
87 INT x_sign;
88 INT y_sign;
89 INT decision;
90 INT nextx;
91 INT nexty;
92 INT y_increment;
93 GX_POINT end_point;
94 GX_POINT mid_point;
95 GX_RECTANGLE half_rectangle;
96 GX_RECTANGLE half_over;
97 INT sign;
98 INT steps;
99 INT pos_start;
100 INT pos_end;
101 GX_UBYTE start_mask;
102 GX_UBYTE end_mask;
103
104 GX_UBYTE *start_address;
105 GX_UBYTE *put;
106 GX_UBYTE *next_put;
107
108 GX_BOOL clipped = GX_TRUE;
109 INT dx = GX_ABS(xend - xstart);
110 INT dy = GX_ABS(yend - ystart);
111
112 GX_RECTANGLE *clip = context -> gx_draw_context_clip;
113 GX_UBYTE linecolor = context -> gx_draw_context_brush.gx_brush_line_color & 0x01;
114 INT stride;
115
116 if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
117 {
118 GX_SWAP_VALS(xend, xstart);
119 GX_SWAP_VALS(yend, ystart);
120 }
121 x_sign = (xend - xstart) / dx;
122 y_sign = (yend - ystart) / dy;
123
124 if (y_sign > 0)
125 {
126 y_increment = context -> gx_draw_context_pitch;
127 }
128 else
129 {
130 y_increment = 0 - context -> gx_draw_context_pitch;
131 }
132
133 stride = (context -> gx_draw_context_pitch + 7) >> 3;
134
135 start_address = (GX_UBYTE *)(context -> gx_draw_context_memory);
136 pos_start = ystart * (stride << 3) + xstart;
137 pos_end = yend * (stride << 3) + xend;
138
139 end_point.gx_point_x = (GX_VALUE)xstart;
140 end_point.gx_point_y = (GX_VALUE)ystart;
141
142 if (_gx_utility_rectangle_point_detect(clip, end_point))
143 {
144 end_point.gx_point_x = (GX_VALUE)xend;
145 end_point.gx_point_y = (GX_VALUE)yend;
146
147 if (_gx_utility_rectangle_point_detect(clip, end_point))
148 {
149 clipped = GX_FALSE;
150 }
151 }
152
153 if (clipped)
154 {
155 /* here if we must do clipping in the inner loop, because one
156 or both of the end points are outside clipping rectangle */
157
158 /* Calculate the middle point of the line. */
159 mid_point.gx_point_x = (GX_VALUE)((xend + xstart) >> 1);
160 mid_point.gx_point_y = (GX_VALUE)((yend + ystart) >> 1);
161
162 /* Judge the clip in which side. */
163 if (_gx_utility_rectangle_point_detect(clip, mid_point))
164 {
165
166 /* the clip in two sides. */
167 if (dx >= dy)
168 {
169 /* walk out the clipping point. */
170 for (curx = xstart, cury = ystart, decision = (dx >> 1); curx < mid_point.gx_point_x;
171 curx++, decision += dy)
172 {
173 if (decision >= dx)
174 {
175 decision -= dx;
176 cury += y_sign;
177
178 pos_start += y_increment;
179 }
180
181 if (curx >= clip -> gx_rectangle_left &&
182 cury >= clip -> gx_rectangle_top &&
183 cury <= clip -> gx_rectangle_bottom)
184 {
185 break;
186 }
187 pos_start++;
188 }
189 for (; curx <= mid_point.gx_point_x;
190 curx++, decision += dy)
191 {
192 if (decision >= dx)
193 {
194 decision -= dx;
195 cury += y_sign;
196 pos_start += y_increment;
197 }
198 put = start_address;
199 put += pos_start >> 3;
200 start_mask = (GX_UBYTE)(0x80 >> (pos_start & 0x07));
201 if (linecolor == 0x00)
202 {
203 *put = (GX_UBYTE)((*put) & (~start_mask));
204 }
205 else
206 {
207 *put |= start_mask;
208 }
209 pos_start++;
210 }
211 for (nextx = xend, nexty = yend, decision = (dx >> 1); nextx > mid_point.gx_point_x;
212 nextx--, decision += dy)
213 {
214 if (decision >= dx)
215 {
216 decision -= dx;
217 nexty -= y_sign;
218 pos_end -= y_increment;
219 }
220 if (nextx <= clip -> gx_rectangle_right &&
221 nexty >= clip -> gx_rectangle_top &&
222 nexty <= clip -> gx_rectangle_bottom)
223 {
224 break;
225 }
226 pos_end--;
227 }
228
229 for (; nextx > mid_point.gx_point_x;
230 nextx--, decision += dy)
231 {
232 if (decision >= dx)
233 {
234 decision -= dx;
235 nexty -= y_sign;
236 pos_end -= y_increment;
237 }
238 next_put = start_address;
239 next_put += pos_end >> 3;
240 end_mask = (GX_UBYTE)(0x80 >> (pos_end & 0x07));
241 if (linecolor == 0x00)
242 {
243 *next_put = (GX_UBYTE)((*next_put) & (~end_mask));
244 }
245 else
246 {
247 *next_put |= end_mask;
248 }
249 pos_end--;
250 }
251 }
252 else
253 {
254 for (nextx = xend, nexty = yend, decision = (dy >> 1); nexty > mid_point.gx_point_y;
255 nexty--, decision += dx)
256 {
257 if (decision >= dy)
258 {
259 decision -= dy;
260 nextx -= x_sign;
261 pos_end -= x_sign;
262 }
263 if (nextx >= clip -> gx_rectangle_left &&
264 nextx <= clip -> gx_rectangle_right &&
265 nexty <= clip -> gx_rectangle_bottom)
266 {
267 break;
268 }
269 pos_end -= context -> gx_draw_context_pitch;
270 }
271
272 for (; nexty > mid_point.gx_point_y;
273 nexty--, decision += dx)
274 {
275 if (decision >= dy)
276 {
277 decision -= dy;
278 nextx -= x_sign;
279 pos_end -= x_sign;
280 }
281 next_put = start_address;
282 next_put += pos_end >> 3;
283 end_mask = (GX_UBYTE)(0x80 >> (pos_end & 0x07));
284 if (linecolor == 0x00)
285 {
286 *next_put = (GX_UBYTE)((*next_put) & (~end_mask));
287 }
288 else
289 {
290 *next_put |= end_mask;
291 }
292 pos_end -= context -> gx_draw_context_pitch;
293 }
294
295 /* walk out the clipping point. */
296 for (curx = xstart, cury = ystart, decision = (dy >> 1); cury < mid_point.gx_point_y;
297 cury++, decision += dx)
298 {
299 if (decision >= dy)
300 {
301 decision -= dy;
302 curx += x_sign;
303 pos_start += x_sign;
304 }
305
306 if (curx >= clip -> gx_rectangle_left &&
307 curx <= clip -> gx_rectangle_right &&
308 cury >= clip -> gx_rectangle_top)
309 {
310 break;
311 }
312 pos_start += context -> gx_draw_context_pitch;
313 }
314 for (; cury <= mid_point.gx_point_y;
315 cury++, decision += dx)
316 {
317 if (decision >= dy)
318 {
319 decision -= dy;
320 curx += x_sign;
321 pos_start += x_sign;
322 }
323 put = start_address;
324 put += pos_start >> 3;
325 start_mask = (GX_UBYTE)(0x80 >> (pos_start & 0x07));
326 if (linecolor == 0x00)
327 {
328 *put = (GX_UBYTE)((*put) & (~start_mask));
329 }
330 else
331 {
332 *put |= start_mask;
333 }
334 pos_start += context -> gx_draw_context_pitch;
335 }
336 }
337 }
338 else
339 {
340 /* The clip stay at one side. */
341 if (dx >= dy)
342 {
343 half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
344 half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
345 if (y_sign == 1)
346 {
347 half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
348 half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
349 }
350 else
351 {
352 half_rectangle.gx_rectangle_top = mid_point.gx_point_y;
353 half_rectangle.gx_rectangle_bottom = (GX_VALUE)ystart;
354 }
355
356 if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
357 {
358 curx = xstart;
359 cury = ystart;
360 steps = mid_point.gx_point_x - curx + 1;
361 sign = 1;
362 }
363 else
364 {
365 curx = xend;
366 cury = yend;
367 steps = xend - mid_point.gx_point_x;
368 sign = -1;
369 y_increment = 0 - y_increment;
370 y_sign = 0 - y_sign;
371 pos_start = pos_end;
372 }
373 for (decision = (dx >> 1); steps > 0; curx += sign, decision += dy, steps--)
374 {
375 if (decision >= dx)
376 {
377 decision -= dx;
378 cury += y_sign;
379 pos_start += y_increment;
380 }
381
382 if (curx >= clip -> gx_rectangle_left &&
383 curx <= clip -> gx_rectangle_right &&
384 cury >= clip -> gx_rectangle_top &&
385 cury <= clip -> gx_rectangle_bottom)
386 {
387 put = start_address;
388 put += pos_start >> 3;
389 start_mask = (GX_UBYTE)(0x80 >> (pos_start & 0x07));
390 if (linecolor == 0x00)
391 {
392 *put = (GX_UBYTE)((*put) & (~start_mask));
393 }
394 else
395 {
396 *put |= start_mask;
397 }
398 }
399 pos_start += sign;
400 }
401 }
402 else
403 {
404 half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
405 half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
406 if (x_sign == 1)
407 {
408 half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
409 half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
410 }
411 else
412 {
413 half_rectangle.gx_rectangle_right = (GX_VALUE)xstart;
414 half_rectangle.gx_rectangle_left = mid_point.gx_point_x;
415 }
416
417 if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
418 {
419 curx = xstart;
420 cury = ystart;
421 steps = mid_point.gx_point_y - cury + 1;
422 y_increment = context -> gx_draw_context_pitch;
423 sign = 1;
424 }
425 else
426 {
427 curx = xend;
428 cury = yend;
429 steps = yend - mid_point.gx_point_y;
430 sign = -1;
431 y_increment = 0 - context -> gx_draw_context_pitch;
432 x_sign = 0 - x_sign;
433 pos_start = pos_end;
434 }
435
436 for (decision = (dy >> 1); steps > 0; cury += sign, decision += dx, steps--)
437 {
438 if (decision >= dy)
439 {
440 decision -= dy;
441 curx += x_sign;
442 pos_start += x_sign;
443 }
444 if (curx >= clip -> gx_rectangle_left &&
445 curx <= clip -> gx_rectangle_right &&
446 cury >= clip -> gx_rectangle_top &&
447 cury <= clip -> gx_rectangle_bottom)
448 {
449 put = start_address;
450 put += pos_start >> 3;
451 start_mask = (GX_UBYTE)(0x80 >> (pos_start & 0x07));
452 if (linecolor == 0x00)
453 {
454 *put = (GX_UBYTE)((*put) & (~start_mask));
455 }
456 else
457 {
458 *put |= start_mask;
459 }
460 }
461 pos_start += y_increment;
462 }
463 }
464 }
465 }
466 else
467 {
468 /* here if both line ends lie within clipping rectangle, we can
469 run a faster inner loop */
470 if (dx >= dy)
471 {
472 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
473 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
474 decision += dy)
475 {
476
477 if (decision >= dx)
478 {
479 decision -= dx;
480 cury += y_sign;
481 nexty -= y_sign;
482
483 pos_start += y_increment;
484 pos_end -= y_increment;
485 }
486 put = start_address;
487 put += pos_start >> 3;
488 start_mask = (GX_UBYTE)(0x80 >> (pos_start & 0x07));
489 next_put = start_address;
490 next_put += pos_end >> 3;
491 end_mask = (GX_UBYTE)(0x80 >> (pos_end & 0x07));
492 if (linecolor == 0x00)
493 {
494 *put = (GX_UBYTE)((*put) & (~start_mask));
495 *next_put = (GX_UBYTE)((*next_put) & (~end_mask));
496 }
497 else
498 {
499 *put |= start_mask;
500 *next_put |= end_mask;
501 }
502
503 pos_start++;
504 pos_end--;
505 }
506 }
507 else
508 {
509 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
510 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
511 decision += dx)
512 {
513 if (decision >= dy)
514 {
515 decision -= dy;
516 curx += x_sign;
517 nextx -= x_sign;
518
519 pos_start += x_sign;
520 pos_end -= x_sign;
521 }
522 put = start_address;
523 put += pos_start >> 3;
524 start_mask = (GX_UBYTE)(0x80 >> (pos_start & 0x07));
525 next_put = start_address;
526 next_put += pos_end >> 3;
527 end_mask = (GX_UBYTE)(0x80 >> (pos_end & 0x07));
528 if (linecolor == 0x00)
529 {
530 *put = (GX_UBYTE)((*put) & (~start_mask));
531 *next_put = (GX_UBYTE)((*next_put) & (~end_mask));
532 }
533 else
534 {
535 *put |= start_mask;
536 *next_put |= end_mask;
537 }
538
539 pos_start += context -> gx_draw_context_pitch;
540 pos_end -= context -> gx_draw_context_pitch;
541 }
542 }
543 }
544 }
545
546