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_simple_line_draw PORTABLE C */
35 /* 6.1 */
36 /* AUTHOR */
37 /* */
38 /* Kenneth Maxwell, Microsoft Corporation */
39 /* */
40 /* DESCRIPTION */
41 /* */
42 /* Generic 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 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
71 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
72 /* resulting in version 6.1 */
73 /* */
74 /**************************************************************************/
_gx_display_driver_32bpp_simple_line_draw(GX_DRAW_CONTEXT * context,INT xstart,INT ystart,INT xend,INT yend)75 VOID _gx_display_driver_32bpp_simple_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend)
76 {
77 INT curx;
78 INT cury;
79 INT x_sign;
80 INT y_sign;
81 INT decision;
82 INT nextx;
83 INT nexty;
84 INT y_increment;
85 GX_POINT end_point;
86 GX_POINT mid_point;
87 GX_RECTANGLE half_rectangle;
88 GX_RECTANGLE half_over;
89 INT sign;
90 INT steps;
91
92 ULONG *put;
93 ULONG *next_put;
94
95 GX_BOOL clipped = GX_TRUE;
96 INT dx = GX_ABS(xend - xstart);
97 INT dy = GX_ABS(yend - ystart);
98
99 GX_RECTANGLE *clip = context -> gx_draw_context_clip;
100 GX_COLOR linecolor = context -> gx_draw_context_brush.gx_brush_line_color;
101 #if defined GX_BRUSH_ALPHA_SUPPORT
102 GX_UBYTE alpha;
103
104 alpha = context -> gx_draw_context_brush.gx_brush_alpha;
105 if (alpha == 0)
106 {
107 /* Nothing to drawn. Just return. */
108 return;
109 }
110 if (alpha != 0xff)
111 {
112 _gx_display_driver_simple_line_alpha_draw(context, xstart, ystart, xend, yend, alpha);
113 return;
114 }
115 #endif
116
117 if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend)))
118 {
119 GX_SWAP_VALS(xend, xstart);
120 GX_SWAP_VALS(yend, ystart);
121 }
122 x_sign = (xend - xstart) / dx;
123 y_sign = (yend - ystart) / dy;
124
125 if (y_sign > 0)
126 {
127 y_increment = context -> gx_draw_context_pitch;
128 }
129 else
130 {
131 y_increment = 0 - context -> gx_draw_context_pitch;
132 }
133
134 put = (ULONG *)(context -> gx_draw_context_memory) + ystart * context -> gx_draw_context_pitch + xstart;
135 next_put = (ULONG *)(context -> gx_draw_context_memory) + yend * context -> gx_draw_context_pitch + xend;
136
137
138 end_point.gx_point_x = (GX_VALUE)xstart;
139 end_point.gx_point_y = (GX_VALUE)ystart;
140
141 if (_gx_utility_rectangle_point_detect(clip, end_point))
142 {
143 end_point.gx_point_x = (GX_VALUE)xend;
144 end_point.gx_point_y = (GX_VALUE)yend;
145
146 if (_gx_utility_rectangle_point_detect(clip, end_point))
147 {
148 clipped = GX_FALSE;
149 }
150 }
151
152 if (clipped)
153 {
154 /* here if we must do clipping in the inner loop, because one
155 or both of the end points are outside clipping rectangle */
156
157 /* Calculate the middle point of the line. */
158 mid_point.gx_point_x = (GX_VALUE)(xend + xstart) >> 1;
159 mid_point.gx_point_y = (GX_VALUE)(yend + ystart) >> 1;
160
161 /* Judge the clip in which side. */
162 if (_gx_utility_rectangle_point_detect(clip, mid_point))
163 {
164
165 /* the clip in two sides. */
166 if (dx >= dy)
167 {
168 /* walk out the clipping point. */
169 for (curx = xstart, cury = ystart, decision = (dx >> 1); curx < mid_point.gx_point_x;
170 curx++, decision += dy)
171 {
172 if (decision >= dx)
173 {
174 decision -= dx;
175 cury += y_sign;
176 put += y_increment;
177 }
178
179 if (curx >= clip -> gx_rectangle_left &&
180 cury >= clip -> gx_rectangle_top &&
181 cury <= clip -> gx_rectangle_bottom)
182 {
183 break;
184 }
185 put++;
186 }
187 for (; curx <= mid_point.gx_point_x;
188 curx++, decision += dy)
189 {
190 if (decision >= dx)
191 {
192 decision -= dx;
193 cury += y_sign;
194 put += y_increment;
195 }
196 PIXEL_WRITE(put, linecolor);
197 put++;
198 }
199 for (nextx = xend, nexty = yend, decision = (dx >> 1); nextx > mid_point.gx_point_x;
200 nextx--, decision += dy)
201 {
202 if (decision >= dx)
203 {
204 decision -= dx;
205 nexty -= y_sign;
206 next_put -= y_increment;
207 }
208 if (nextx <= clip -> gx_rectangle_right &&
209 nexty >= clip -> gx_rectangle_top &&
210 nexty <= clip -> gx_rectangle_bottom)
211 {
212 break;
213 }
214 next_put--;
215 }
216
217 for (; nextx > mid_point.gx_point_x;
218 nextx--, decision += dy)
219 {
220 if (decision >= dx)
221 {
222 decision -= dx;
223 nexty -= y_sign;
224 next_put -= y_increment;
225 }
226 PIXEL_WRITE(next_put, linecolor);
227 next_put--;
228 }
229 }
230 else
231 {
232 for (nextx = xend, nexty = yend, decision = (dy >> 1); nexty > mid_point.gx_point_y;
233 nexty--, decision += dx)
234 {
235 if (decision >= dy)
236 {
237 decision -= dy;
238 nextx -= x_sign;
239 next_put -= x_sign;
240 }
241 if (nextx >= clip -> gx_rectangle_left &&
242 nextx <= clip -> gx_rectangle_right &&
243 nexty <= clip -> gx_rectangle_bottom)
244 {
245 break;
246 }
247 next_put -= context -> gx_draw_context_pitch;
248 }
249
250 for (; nexty > mid_point.gx_point_y;
251 nexty--, decision += dx)
252 {
253 if (decision >= dy)
254 {
255 decision -= dy;
256 nextx -= x_sign;
257 next_put -= x_sign;
258 }
259 PIXEL_WRITE(next_put, linecolor);
260 next_put -= context -> gx_draw_context_pitch;
261 }
262
263 /* walk out the clipping point. */
264 for (curx = xstart, cury = ystart, decision = (dy >> 1); cury < mid_point.gx_point_y;
265 cury++, decision += dx)
266 {
267 if (decision >= dy)
268 {
269 decision -= dy;
270 curx += x_sign;
271 put += x_sign;
272 }
273
274 if (curx >= clip -> gx_rectangle_left &&
275 curx <= clip -> gx_rectangle_right &&
276 cury >= clip -> gx_rectangle_top)
277 {
278 break;
279 }
280 put += context -> gx_draw_context_pitch;
281 }
282 for (; cury <= mid_point.gx_point_y;
283 cury++, decision += dx)
284 {
285 if (decision >= dy)
286 {
287 decision -= dy;
288 curx += x_sign;
289 put += x_sign;
290 }
291 PIXEL_WRITE(put, linecolor);
292 put += context -> gx_draw_context_pitch;
293 }
294 } /**/
295 /*context -> gx_draw_context_display -> gx_display_driver_pixel_write(context, mid_point.gx_point_x,mid_point.gx_point_y, GX_COLOR_RED);*/
296 }
297 else
298 {
299 /* The clip stay at one side. */
300 if (dx >= dy)
301 {
302 half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
303 half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
304 if (y_sign == 1)
305 {
306 half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
307 half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
308 }
309 else
310 {
311 half_rectangle.gx_rectangle_top = mid_point.gx_point_y;
312 half_rectangle.gx_rectangle_bottom = (GX_VALUE)ystart;
313 }
314
315 if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
316 {
317 curx = xstart;
318 cury = ystart;
319 steps = mid_point.gx_point_x - curx + 1;
320 sign = 1;
321 }
322 else
323 {
324 curx = xend;
325 cury = yend;
326 steps = xend - mid_point.gx_point_x;
327 sign = -1;
328 y_increment = 0 - y_increment;
329 y_sign = 0 - y_sign;
330 put = next_put;
331 }
332 for (decision = (dx >> 1); steps > 0; curx += sign, decision += dy, steps--)
333 {
334 if (decision >= dx)
335 {
336 decision -= dx;
337 cury += y_sign;
338 put += y_increment;
339 }
340
341 if (curx >= clip -> gx_rectangle_left &&
342 curx <= clip -> gx_rectangle_right &&
343 cury >= clip -> gx_rectangle_top &&
344 cury <= clip -> gx_rectangle_bottom)
345 {
346 PIXEL_WRITE(put, linecolor);
347 }
348 put += sign;
349 }
350 }
351 else
352 {
353 half_rectangle.gx_rectangle_top = (GX_VALUE)ystart;
354 half_rectangle.gx_rectangle_bottom = mid_point.gx_point_y;
355 if (x_sign == 1)
356 {
357 half_rectangle.gx_rectangle_right = mid_point.gx_point_x;
358 half_rectangle.gx_rectangle_left = (GX_VALUE)xstart;
359 }
360 else
361 {
362 half_rectangle.gx_rectangle_right = (GX_VALUE)xstart;
363 half_rectangle.gx_rectangle_left = mid_point.gx_point_x;
364 }
365
366 if (_gx_utility_rectangle_overlap_detect(clip, &half_rectangle, &half_over))
367 {
368 curx = xstart;
369 cury = ystart;
370 steps = mid_point.gx_point_y - cury + 1;
371 y_increment = context -> gx_draw_context_pitch;
372 sign = 1;
373 }
374 else
375 {
376 curx = xend;
377 cury = yend;
378 steps = yend - mid_point.gx_point_y;
379 sign = -1;
380 y_increment = 0 - context -> gx_draw_context_pitch;
381 x_sign = 0 - x_sign;
382 put = next_put;
383 }
384
385 for (decision = (dy >> 1); steps > 0; cury += sign, decision += dx, steps--)
386 {
387 if (decision >= dy)
388 {
389 decision -= dy;
390 curx += x_sign;
391 put += x_sign;
392 }
393 if (curx >= clip -> gx_rectangle_left &&
394 curx <= clip -> gx_rectangle_right &&
395 cury >= clip -> gx_rectangle_top &&
396 cury <= clip -> gx_rectangle_bottom)
397 {
398 PIXEL_WRITE(put, linecolor);
399 }
400 put += y_increment;
401 }
402 }
403 }
404 }
405 else
406 {
407 /* here if both line ends lie within clipping rectangle, we can
408 run a faster inner loop */
409 if (dx >= dy)
410 {
411 put = (ULONG *)(context -> gx_draw_context_memory) + ystart * context -> gx_draw_context_pitch + xstart;
412 next_put = (ULONG *)(context -> gx_draw_context_memory) + yend * context -> gx_draw_context_pitch + xend;
413
414 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
415 decision = (dx >> 1); curx <= nextx; curx++, nextx--,
416 decision += dy)
417 {
418
419 if (decision >= dx)
420 {
421 decision -= dx;
422 cury += y_sign;
423 nexty -= y_sign;
424
425 put += y_increment;
426 next_put -= y_increment;
427 }
428 PIXEL_WRITE(put, linecolor);
429 PIXEL_WRITE(next_put, linecolor);
430
431 put++;
432 next_put--;
433 }
434 }
435 else
436 {
437
438 for (curx = xstart, cury = ystart, nextx = xend, nexty = yend,
439 decision = (dy >> 1); cury <= nexty; cury++, nexty--,
440 decision += dx)
441 {
442 if (decision >= dy)
443 {
444 decision -= dy;
445 curx += x_sign;
446 nextx -= x_sign;
447
448 put += x_sign;
449 next_put -= x_sign;
450 }
451 PIXEL_WRITE(put, linecolor);
452 PIXEL_WRITE(next_put, linecolor);
453
454 put += context -> gx_draw_context_pitch;
455 next_put -= context -> gx_draw_context_pitch;
456 }
457 }
458 }
459 }
460