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
23 #define GX_SOURCE_CODE
24
25
26 /* Include necessary system files. */
27
28 #include "gx_api.h"
29 #include "gx_utility.h"
30 #include "gx_display.h"
31 #include "gx_system.h"
32
33 /**************************************************************************/
34 /* */
35 /* FUNCTION RELEASE */
36 /* */
37 /* _gx_display_driver_generic_rotated_wide_line_fill PORTABLE C */
38 /* 6.1.3 */
39 /* AUTHOR */
40 /* */
41 /* Kenneth Maxwell, Microsoft Corporation */
42 /* */
43 /* DESCRIPTION */
44 /* */
45 /* Fill a wide line after the four corner points have been calculated. */
46 /* */
47 /* INPUT */
48 /* */
49 /* context Drawing context */
50 /* pPoints Pre-computed end points */
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 /* [_gx_display_driver_horizontal_line_draw] */
61 /* Driver for horizontal line */
62 /* draw */
63 /* */
64 /* CALLED BY */
65 /* */
66 /* _gx_display_driver_generic_simple_wide_line_draw */
67 /* _gx_display_driver_generic_aliased_wide_line_draw */
68 /* */
69 /* RELEASE HISTORY */
70 /* */
71 /* DATE NAME DESCRIPTION */
72 /* */
73 /* 12-31-2020 Kenneth Maxwell Initial Version 6.1.3 */
74 /* */
75 /**************************************************************************/
_gx_display_driver_generic_rotated_wide_line_fill(GX_DRAW_CONTEXT * context,GX_FIXED_POINT * pPoints)76 VOID _gx_display_driver_generic_rotated_wide_line_fill(GX_DRAW_CONTEXT *context, GX_FIXED_POINT *pPoints)
77 {
78 /*
79 Use Breshenham's line to compute the points along each line that bounds
80 the wide line and save the points to an array. Then draw horizontal lines
81 to connect the points.
82 */
83
84 GX_FIXED_POINT *pGet = pPoints;
85 INT *pLineEnds;
86 INT xmin;
87 INT xmax;
88 INT xstart;
89 INT xend;
90 INT ystart;
91 INT yend;
92 INT curx;
93 INT cury;
94 INT test;
95 GX_FIXED_VAL dx;
96 GX_FIXED_VAL dy;
97 INT Index;
98 INT loop;
99 INT width;
100 INT xsign;
101 INT ysign;
102 INT decision;
103 INT shift;
104 VOID (*line_draw)(GX_DRAW_CONTEXT *context, INT x1, INT x2, INT ypos, INT width, GX_COLOR color);
105 GX_RECTANGLE *clip = context -> gx_draw_context_clip;
106 GX_COLOR linecolor = context -> gx_draw_context_brush.gx_brush_line_color;
107 GX_BOOL aliased = GX_FALSE;
108 INT x_fraction;
109 INT y_fraction;
110
111 if ((context -> gx_draw_context_brush.gx_brush_style & GX_BRUSH_ALIAS) &&
112 context -> gx_draw_context_display -> gx_display_driver_pixel_blend)
113 {
114 aliased = GX_TRUE;
115 }
116
117 xmin = GX_FIXED_VAL_TO_INT(pPoints[0].x);
118 xmax = GX_FIXED_VAL_RND_UP(pPoints[2].x);
119
120 if (xmin < clip -> gx_rectangle_left)
121 {
122 xmin = clip -> gx_rectangle_left;
123 }
124
125 if (xmax > clip -> gx_rectangle_right)
126 {
127 xmax = clip -> gx_rectangle_right;
128 }
129
130 width = xmax - xmin + 1;
131
132 pLineEnds = _gx_system_scratchpad;
133
134 /* default the point array to being off the screen on both sides: */
135
136 for (loop = 0; loop < width * 2; loop += 2)
137 {
138 pLineEnds[loop] = 2000;
139 pLineEnds[loop + 1] = 0;
140 }
141
142 /* Fill in the point array by using Breshenhams line for
143 all 4 sides of the bounding rectangle
144 */
145
146 for (loop = 0; loop < 4; loop++)
147 {
148 xstart = pGet -> x;
149 ystart = pGet -> y;
150 pGet++;
151 xend = pGet -> x;
152 yend = pGet -> y;
153 dx = GX_ABS(xend - xstart);
154 dy = GX_ABS(yend - ystart);
155
156 xsign = ysign = 1;
157
158 if (((dx >= dy && (xstart > xend)) ||
159 ((dy > dx) && ystart > yend)))
160 {
161 GX_SWAP_VALS(xend, xstart);
162 GX_SWAP_VALS(yend, ystart);
163 }
164 if (dx)
165 {
166 xsign = (xend - xstart) / dx;
167 }
168 if (dy)
169 {
170 ysign = (yend - ystart) / dy;
171 }
172
173 x_fraction = (xstart & GX_FIXED_VAL_FRACTION_MASK);
174 y_fraction = (ystart & GX_FIXED_VAL_FRACTION_MASK);
175
176 shift = 0;
177
178 if (dx >= dy)
179 {
180 if (ysign < 0)
181 {
182 cury = GX_FIXED_VAL_RND_UP(ystart);
183
184 if (y_fraction)
185 {
186 y_fraction = GX_FIXED_VAL_ONE - y_fraction;
187 }
188 }
189 else
190 {
191 cury = GX_FIXED_VAL_TO_INT(ystart);
192 }
193
194 decision = (y_fraction * dx - x_fraction * dy) / GX_FIXED_VAL_ONE;
195
196 if (decision < 0)
197 {
198 decision += dx;
199 cury -= ysign;
200 }
201
202 xstart = GX_FIXED_VAL_TO_INT(xstart);
203
204 if (aliased)
205 {
206 xend = GX_FIXED_VAL_TO_INT(xend);
207
208 if (x_fraction)
209 {
210 xstart++;
211 decision += dy;
212 }
213
214 if (dy)
215 {
216 if ((loop == 1) || (loop == 2))
217 {
218 shift = ysign;
219 }
220 }
221 }
222 else
223 {
224 xend = GX_FIXED_VAL_RND(xend);
225
226 if (x_fraction >= GX_FIXED_VAL_HALF)
227 {
228 xstart++;
229 decision += dy;
230 }
231
232 decision += (dx >> 1);
233 if (decision >= dx)
234 {
235 decision -= dx;
236 cury += ysign;
237 }
238 }
239
240 for (curx = xstart; curx <= xend; curx++, decision += dy)
241 {
242 if (decision >= dx)
243 {
244 decision -= dx;
245 cury += ysign;
246 }
247
248 if ((curx >= xmin) && (curx <= xmax))
249 {
250 Index = (curx - xmin) << 1;
251
252 test = cury + shift;
253 if (test < pLineEnds[Index])
254 {
255 pLineEnds[Index] = test;
256 }
257
258 if (test > pLineEnds[Index + 1])
259 {
260 pLineEnds[Index + 1] = test;
261 }
262 }
263 }
264 }
265 else
266 {
267 if (xsign < 0)
268 {
269 curx = GX_FIXED_VAL_RND_UP(xstart);
270
271 if (x_fraction)
272 {
273 x_fraction = GX_FIXED_VAL_FRACTION_MASK - x_fraction;
274 }
275 }
276 else
277 {
278 curx = GX_FIXED_VAL_TO_INT(xstart);
279 }
280
281 decision = (x_fraction * dy - y_fraction * dx) / GX_FIXED_VAL_ONE;
282
283 if (decision < 0)
284 {
285 decision += dy;
286 curx -= xsign;
287 }
288
289 ystart = GX_FIXED_VAL_TO_INT(ystart);
290
291 if (aliased)
292 {
293 yend = GX_FIXED_VAL_TO_INT(yend);
294
295 if (y_fraction)
296 {
297 ystart++;
298 decision += dx;
299 }
300
301 if (dx)
302 {
303 if (loop == 2 || loop == 3)
304 {
305 shift = xsign;
306 }
307 }
308 }
309 else
310 {
311 yend = GX_FIXED_VAL_RND(yend);
312
313 if (y_fraction >= GX_FIXED_VAL_HALF)
314 {
315 ystart++;
316 decision += dx;
317 }
318
319 decision += (dy >> 1);
320
321 if (decision >= dy)
322 {
323 decision -= dy;
324 curx += xsign;
325 }
326 }
327
328 for (cury = ystart; cury <= yend; cury++, decision += dx)
329 {
330 if (decision >= dy)
331 {
332 decision -= dy;
333 curx += xsign;
334 }
335
336 test = curx + shift;
337
338 if ((test >= xmin) && (test <= xmax))
339 {
340 Index = (test - xmin) << 1;
341
342 if (cury < pLineEnds[Index])
343 {
344 pLineEnds[Index] = cury;
345 }
346
347 if (cury > pLineEnds[Index + 1])
348 {
349 pLineEnds[Index + 1] = cury;
350 }
351 }
352 }
353 }
354 }
355
356 Index = 0;
357 line_draw = context -> gx_draw_context_display -> gx_display_driver_vertical_line_draw;
358
359 for (curx = xmin; curx <= xmax; curx++)
360 {
361 if (pLineEnds[Index] < clip -> gx_rectangle_top)
362 {
363 pLineEnds[Index] = clip -> gx_rectangle_top;
364 }
365
366 if (pLineEnds[Index + 1] > clip -> gx_rectangle_bottom)
367 {
368 pLineEnds[Index + 1] = clip -> gx_rectangle_bottom;
369 }
370
371 if (pLineEnds[Index] <= pLineEnds[Index + 1])
372 {
373 line_draw(context, pLineEnds[Index], pLineEnds[Index + 1], curx, 1, linecolor);
374 }
375 Index += 2;
376 }
377 }
378
379