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_display.h" |
28 |
|
|
#include "gx_utility.h" |
29 |
|
|
|
30 |
|
|
|
31 |
|
|
/**************************************************************************/ |
32 |
|
|
/* */ |
33 |
|
|
/* FUNCTION RELEASE */ |
34 |
|
|
/* */ |
35 |
|
|
/* _gx_display_driver_generic_aliased_line_draw PORTABLE C */ |
36 |
|
|
/* 6.1 */ |
37 |
|
|
/* AUTHOR */ |
38 |
|
|
/* */ |
39 |
|
|
/* Kenneth Maxwell, Microsoft Corporation */ |
40 |
|
|
/* */ |
41 |
|
|
/* DESCRIPTION */ |
42 |
|
|
/* */ |
43 |
|
|
/* General anti-aliasing line drawing function. */ |
44 |
|
|
/* */ |
45 |
|
|
/* INPUT */ |
46 |
|
|
/* */ |
47 |
|
|
/* context Drawing context */ |
48 |
|
|
/* xstart x-coord of endpoint */ |
49 |
|
|
/* ystart y-coord of endpoint */ |
50 |
|
|
/* xend x-coord of endpoint */ |
51 |
|
|
/* yend y-coord of endpoint */ |
52 |
|
|
/* */ |
53 |
|
|
/* OUTPUT */ |
54 |
|
|
/* */ |
55 |
|
|
/* None */ |
56 |
|
|
/* */ |
57 |
|
|
/* CALLS */ |
58 |
|
|
/* */ |
59 |
|
|
/* [gx_display_driver_pixel_blend] Display driver blend function */ |
60 |
|
|
/* _gx_utility_rectangle_point_detect Detect whether a pixel is */ |
61 |
|
|
/* inside rectangle */ |
62 |
|
|
/* GX_SWAP_VALS Swap two values */ |
63 |
|
|
/* [gx_display_driver_simple_line_draw] Basic display driver simple */ |
64 |
|
|
/* line draw function */ |
65 |
|
|
/* */ |
66 |
|
|
/* CALLED BY */ |
67 |
|
|
/* */ |
68 |
|
|
/* GUIX Internal Code */ |
69 |
|
|
/* */ |
70 |
|
|
/* RELEASE HISTORY */ |
71 |
|
|
/* */ |
72 |
|
|
/* DATE NAME DESCRIPTION */ |
73 |
|
|
/* */ |
74 |
|
|
/* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */ |
75 |
|
|
/* 09-30-2020 Kenneth Maxwell Modified comment(s), */ |
76 |
|
|
/* resulting in version 6.1 */ |
77 |
|
|
/* */ |
78 |
|
|
/**************************************************************************/ |
79 |
|
2446 |
VOID _gx_display_driver_generic_aliased_line_draw(GX_DRAW_CONTEXT *context, INT xstart, INT ystart, INT xend, INT yend) |
80 |
|
|
{ |
81 |
|
2446 |
GX_BRUSH *brush = &context -> gx_draw_context_brush; |
82 |
|
2446 |
GX_COLOR line_color = brush -> gx_brush_line_color; |
83 |
|
2446 |
GX_RECTANGLE *clip = context -> gx_draw_context_clip; |
84 |
|
|
|
85 |
|
|
VOID (*blend_func)(GX_DRAW_CONTEXT *context, |
86 |
|
|
INT x, INT y, GX_COLOR color, GX_UBYTE alpha); |
87 |
|
|
|
88 |
|
2446 |
INT dx = GX_ABS(xend - xstart); |
89 |
|
2446 |
INT dy = GX_ABS(yend - ystart); |
90 |
|
|
GX_POINT point; |
91 |
|
|
GX_POINT point2; |
92 |
|
|
INT curx; |
93 |
|
|
INT cury; |
94 |
|
|
INT decision; |
95 |
|
|
INT nextx; |
96 |
|
|
INT nexty; |
97 |
|
|
INT back_alpha; |
98 |
|
|
INT fore_alpha; |
99 |
|
|
INT x_sign; |
100 |
|
|
INT y_sign; |
101 |
|
|
GX_UBYTE alpha; |
102 |
|
|
|
103 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
104 |
|
|
GX_UBYTE brush_alpha; |
105 |
|
|
|
106 |
|
2446 |
brush_alpha = context -> gx_draw_context_brush.gx_brush_alpha; |
107 |
|
|
|
108 |
✓✓ |
2446 |
if (brush_alpha == 0) |
109 |
|
|
{ |
110 |
|
|
/* Nothing to draw here. */ |
111 |
|
227 |
return; |
112 |
|
|
} |
113 |
|
|
#endif |
114 |
|
|
|
115 |
✓✓✓✓
|
2403 |
if (!dx || !dy) |
116 |
|
|
{ |
117 |
|
143 |
return; |
118 |
|
|
} |
119 |
|
|
|
120 |
✓✓ |
2260 |
if (!(context -> gx_draw_context_display -> gx_display_driver_pixel_blend)) |
121 |
|
|
{ |
122 |
|
1 |
context -> gx_draw_context_display -> gx_display_driver_simple_line_draw(context, xstart, ystart, xend, yend); |
123 |
|
1 |
return; |
124 |
|
|
} |
125 |
|
2259 |
blend_func = context -> gx_draw_context_display -> gx_display_driver_pixel_blend; |
126 |
|
|
|
127 |
|
|
/* special case of 1x1 pixel line:*/ |
128 |
|
|
|
129 |
✓✓✓✓
|
2259 |
if (dx == 1 && dy == 1) |
130 |
|
|
{ |
131 |
|
40 |
point.gx_point_x = (GX_VALUE)xstart; |
132 |
|
40 |
point.gx_point_y = (GX_VALUE)ystart; |
133 |
|
|
|
134 |
✓✓ |
40 |
if (_gx_utility_rectangle_point_detect(clip, point)) |
135 |
|
|
{ |
136 |
|
39 |
alpha = 0xc0; |
137 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
138 |
|
39 |
alpha = (GX_UBYTE)(brush_alpha * alpha / 255); |
139 |
|
|
#endif |
140 |
|
39 |
blend_func(context, xstart, ystart, line_color, alpha); |
141 |
|
|
} |
142 |
|
40 |
point.gx_point_x = (GX_VALUE)xend; |
143 |
|
40 |
point.gx_point_y = (GX_VALUE)yend; |
144 |
|
|
|
145 |
✓✓ |
40 |
if (_gx_utility_rectangle_point_detect(clip, point)) |
146 |
|
|
{ |
147 |
|
39 |
alpha = 0x40; |
148 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
149 |
|
39 |
alpha = (GX_UBYTE)(brush_alpha * alpha / 255); |
150 |
|
|
#endif |
151 |
|
39 |
blend_func(context, xend, yend, line_color, alpha); |
152 |
|
|
} |
153 |
|
40 |
point.gx_point_x = (GX_VALUE)xstart; |
154 |
|
40 |
point.gx_point_y = (GX_VALUE)yend; |
155 |
|
|
|
156 |
✓✓ |
40 |
if (_gx_utility_rectangle_point_detect(clip, point)) |
157 |
|
|
{ |
158 |
|
39 |
alpha = 0x40; |
159 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
160 |
|
39 |
alpha = (GX_UBYTE)(brush_alpha * alpha / 255); |
161 |
|
|
#endif |
162 |
|
39 |
blend_func(context, xstart, yend, line_color, alpha); |
163 |
|
|
} |
164 |
|
40 |
point.gx_point_x = (GX_VALUE)xend; |
165 |
|
40 |
point.gx_point_y = (GX_VALUE)ystart; |
166 |
|
|
|
167 |
✓✓ |
40 |
if (_gx_utility_rectangle_point_detect(clip, point)) |
168 |
|
|
{ |
169 |
|
39 |
alpha = 0xc0; |
170 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
171 |
|
39 |
alpha = (GX_UBYTE)(brush_alpha * alpha / 255); |
172 |
|
|
#endif |
173 |
|
39 |
blend_func(context, xend, ystart, line_color, alpha); |
174 |
|
|
} |
175 |
|
40 |
return; |
176 |
|
|
} |
177 |
|
|
|
178 |
✓✓✓✓ ✓✓✓✓
|
2219 |
if (((dx >= dy && (xstart > xend)) || ((dy > dx) && ystart > yend))) |
179 |
|
|
{ |
180 |
|
852 |
GX_SWAP_VALS(xend, xstart); |
181 |
|
852 |
GX_SWAP_VALS(yend, ystart); |
182 |
|
|
} |
183 |
|
|
|
184 |
|
2219 |
x_sign = ((INT)xend - (INT)xstart) / dx; |
185 |
|
2219 |
y_sign = ((INT)yend - (INT)ystart) / dy; |
186 |
|
|
|
187 |
|
2219 |
point.gx_point_x = (GX_VALUE)xstart; |
188 |
|
2219 |
point.gx_point_y = (GX_VALUE)ystart; |
189 |
|
2219 |
point2.gx_point_x = (GX_VALUE)xend; |
190 |
|
2219 |
point2.gx_point_y = (GX_VALUE)yend; |
191 |
|
|
|
192 |
✓✓✓✓
|
4299 |
if (_gx_utility_rectangle_point_detect(clip, point) && |
193 |
|
2080 |
_gx_utility_rectangle_point_detect(clip, point2)) |
194 |
|
|
{ |
195 |
|
|
/* both endpoints are inside clip rectangle. We don't need to clip |
196 |
|
|
inside the inner loop */ |
197 |
|
|
|
198 |
✓✓ |
1954 |
if (dx >= dy) |
199 |
|
|
{ |
200 |
|
|
/* draw anti-aliased line along x axis, no clipping */ |
201 |
|
1220 |
for (curx = xstart, cury = ystart, nextx = xend, nexty = yend, |
202 |
✓✓ |
14421 |
decision = 0; curx <= nextx; curx++, nextx--, |
203 |
|
13201 |
decision += dy) |
204 |
|
|
{ |
205 |
✓✓ |
13201 |
if (decision >= dx) |
206 |
|
|
{ |
207 |
|
6118 |
decision -= dx; |
208 |
|
6118 |
cury += y_sign; |
209 |
|
6118 |
nexty -= y_sign; |
210 |
|
|
} |
211 |
|
|
|
212 |
|
13201 |
back_alpha = ((decision << 8) / dx); |
213 |
|
13201 |
fore_alpha = 255 - back_alpha; |
214 |
|
|
|
215 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
216 |
|
13201 |
fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255); |
217 |
|
13201 |
back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255); |
218 |
|
|
#endif |
219 |
|
13201 |
blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha); |
220 |
|
13201 |
blend_func(context, curx, cury + y_sign, line_color, (GX_UBYTE)back_alpha); |
221 |
✓✓ |
13201 |
if (curx != nextx) |
222 |
|
|
{ |
223 |
|
12402 |
blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha); |
224 |
|
12402 |
blend_func(context, nextx, nexty - y_sign, line_color, (GX_UBYTE)back_alpha); |
225 |
|
|
} |
226 |
|
|
} |
227 |
|
|
} |
228 |
|
|
else |
229 |
|
|
{ |
230 |
|
|
/* draw anti-aliased line along y axis, no clipping */ |
231 |
|
734 |
for (curx = xstart, cury = ystart, nextx = xend, nexty = yend, |
232 |
✓✓ |
12725 |
decision = 0; cury <= nexty; cury++, nexty--, |
233 |
|
11991 |
decision += dx) |
234 |
|
|
{ |
235 |
✓✓ |
11991 |
if (decision >= dy) |
236 |
|
|
{ |
237 |
|
4036 |
decision -= dy; |
238 |
|
4036 |
curx += x_sign; |
239 |
|
4036 |
nextx -= x_sign; |
240 |
|
|
} |
241 |
|
|
|
242 |
|
11991 |
back_alpha = ((decision << 8) / dy); |
243 |
|
11991 |
fore_alpha = 255 - back_alpha; |
244 |
|
|
|
245 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
246 |
|
11991 |
fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255); |
247 |
|
11991 |
back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255); |
248 |
|
|
#endif |
249 |
|
11991 |
blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha); |
250 |
|
11991 |
blend_func(context, curx + x_sign, cury, line_color, (GX_UBYTE)back_alpha); |
251 |
✓✓ |
11991 |
if (cury != nexty) |
252 |
|
|
{ |
253 |
|
11552 |
blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha); |
254 |
|
11552 |
blend_func(context, nextx - x_sign, nexty, line_color, (GX_UBYTE)back_alpha); |
255 |
|
|
} |
256 |
|
|
} |
257 |
|
|
} |
258 |
|
|
} |
259 |
|
|
else |
260 |
|
|
{ |
261 |
|
|
|
262 |
✓✓ |
265 |
if (dx >= dy) |
263 |
|
|
{ |
264 |
|
|
/* draw anti-aliased line along x axis, clipping in the inner loop */ |
265 |
|
141 |
for (curx = xstart, cury = ystart, nextx = xend, nexty = yend, |
266 |
✓✓ |
11400 |
decision = 0; curx <= nextx; curx++, nextx--, |
267 |
|
11259 |
decision += dy) |
268 |
|
|
{ |
269 |
✓✓ |
11259 |
if (decision >= dx) |
270 |
|
|
{ |
271 |
|
6514 |
decision -= dx; |
272 |
|
6514 |
cury += y_sign; |
273 |
|
6514 |
nexty -= y_sign; |
274 |
|
|
} |
275 |
|
|
|
276 |
|
11259 |
back_alpha = ((decision << 8) / dx); |
277 |
|
11259 |
fore_alpha = 255 - back_alpha; |
278 |
|
|
|
279 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
280 |
|
11259 |
fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255); |
281 |
|
11259 |
back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255); |
282 |
|
|
#endif |
283 |
✓✓ |
11259 |
if (curx >= clip -> gx_rectangle_left && |
284 |
✓✓ |
6096 |
curx <= clip -> gx_rectangle_right && |
285 |
✓✓ |
5243 |
cury >= clip -> gx_rectangle_top && |
286 |
✓✓ |
5104 |
cury <= clip -> gx_rectangle_bottom) |
287 |
|
|
{ |
288 |
|
4991 |
blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha); |
289 |
|
|
} |
290 |
✓✓ |
11259 |
if (curx >= clip -> gx_rectangle_left && |
291 |
✓✓ |
6096 |
curx <= clip -> gx_rectangle_right && |
292 |
✓✓ |
5243 |
(cury + y_sign) >= clip -> gx_rectangle_top && |
293 |
✓✓ |
5111 |
(cury + y_sign) <= clip -> gx_rectangle_bottom) |
294 |
|
|
{ |
295 |
|
4993 |
blend_func(context, curx, cury + y_sign, line_color, (GX_UBYTE)back_alpha); |
296 |
|
|
} |
297 |
✓✓ |
11259 |
if (curx == nextx) |
298 |
|
|
{ |
299 |
|
108 |
continue; |
300 |
|
|
} |
301 |
✓✓ |
11151 |
if (nextx >= clip -> gx_rectangle_left && |
302 |
✓✓ |
10945 |
nextx <= clip -> gx_rectangle_right && |
303 |
✓✓ |
5767 |
nexty >= clip -> gx_rectangle_top && |
304 |
✓✓ |
5653 |
nexty <= clip -> gx_rectangle_bottom) |
305 |
|
|
{ |
306 |
|
5544 |
blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha); |
307 |
|
|
} |
308 |
✓✓ |
11151 |
if (nextx >= clip -> gx_rectangle_left && |
309 |
✓✓ |
10945 |
nextx <= clip -> gx_rectangle_right && |
310 |
✓✓ |
5767 |
(nexty - y_sign) >= clip -> gx_rectangle_top && |
311 |
✓✓ |
5654 |
(nexty - y_sign) <= clip -> gx_rectangle_bottom) |
312 |
|
|
{ |
313 |
|
5540 |
blend_func(context, nextx, nexty - y_sign, line_color, (GX_UBYTE)back_alpha); |
314 |
|
|
} |
315 |
|
|
} |
316 |
|
|
} |
317 |
|
|
else |
318 |
|
|
{ |
319 |
|
|
/* draw anti-aliased line along y axis, clipping in the inner loop */ |
320 |
|
124 |
for (curx = xstart, cury = ystart, nextx = xend, nexty = yend, |
321 |
✓✓ |
10903 |
decision = 0; cury <= nexty; cury++, nexty--, |
322 |
|
10779 |
decision += dx) |
323 |
|
|
{ |
324 |
✓✓ |
10779 |
if (decision >= dy) |
325 |
|
|
{ |
326 |
|
6278 |
decision -= dy; |
327 |
|
6278 |
curx += x_sign; |
328 |
|
6278 |
nextx -= x_sign; |
329 |
|
|
} |
330 |
|
|
|
331 |
|
10779 |
back_alpha = ((decision << 8) / dy); |
332 |
|
10779 |
fore_alpha = 255 - back_alpha; |
333 |
|
|
|
334 |
|
|
#if defined(GX_BRUSH_ALPHA_SUPPORT) |
335 |
|
10779 |
fore_alpha = (GX_UBYTE)(brush_alpha * fore_alpha / 255); |
336 |
|
10779 |
back_alpha = (GX_UBYTE)(brush_alpha * back_alpha / 255); |
337 |
|
|
#endif |
338 |
✓✓ |
10779 |
if (curx >= clip -> gx_rectangle_left && |
339 |
✓✓ |
8643 |
curx <= clip -> gx_rectangle_right && |
340 |
✓✓ |
7926 |
cury >= clip -> gx_rectangle_top && |
341 |
✓✓ |
7340 |
cury <= clip -> gx_rectangle_bottom) |
342 |
|
|
{ |
343 |
|
6600 |
blend_func(context, curx, cury, line_color, (GX_UBYTE)fore_alpha); |
344 |
|
|
} |
345 |
|
|
|
346 |
✓✓ |
10779 |
if ((curx + x_sign) >= clip -> gx_rectangle_left && |
347 |
✓✓ |
8695 |
(curx + x_sign) <= clip -> gx_rectangle_right && |
348 |
✓✓ |
7966 |
cury >= clip -> gx_rectangle_top && |
349 |
✓✓ |
7374 |
cury <= clip -> gx_rectangle_bottom) |
350 |
|
|
{ |
351 |
|
6639 |
blend_func(context, curx + x_sign, cury, line_color, (GX_UBYTE)back_alpha); |
352 |
|
|
} |
353 |
|
|
|
354 |
✓✓ |
10779 |
if (cury == nexty) |
355 |
|
|
{ |
356 |
|
110 |
continue; |
357 |
|
|
} |
358 |
✓✓ |
10669 |
if (nextx >= clip -> gx_rectangle_left && |
359 |
✓✓ |
9958 |
nextx <= clip -> gx_rectangle_right && |
360 |
✓✓ |
6989 |
nexty >= clip -> gx_rectangle_top && |
361 |
✓✓ |
6426 |
nexty <= clip -> gx_rectangle_bottom) |
362 |
|
|
{ |
363 |
|
3882 |
blend_func(context, nextx, nexty, line_color, (GX_UBYTE)fore_alpha); |
364 |
|
|
} |
365 |
✓✓ |
10669 |
if ((nextx - x_sign) >= clip -> gx_rectangle_left && |
366 |
✓✓ |
9958 |
(nextx - x_sign) <= clip -> gx_rectangle_right && |
367 |
✓✓ |
7424 |
nexty >= clip -> gx_rectangle_top && |
368 |
✓✓ |
6863 |
nexty <= clip -> gx_rectangle_bottom) |
369 |
|
|
{ |
370 |
|
4319 |
blend_func(context, nextx - x_sign, nexty, line_color, (GX_UBYTE)back_alpha); |
371 |
|
|
} |
372 |
|
|
} |
373 |
|
|
} |
374 |
|
|
} |
375 |
|
|
} |
376 |
|
|
|