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 /** Canvas Management (Canvas) */
18 /** */
19 /**************************************************************************/
20
21 #define GX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "gx_api.h"
27 #include "gx_system.h"
28 #include "gx_utility.h"
29 #include "gx_display.h"
30 #include "gx_canvas.h"
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _gx_canvas_rotated_pixelmap_bound_calculate PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* Kenneth Maxwell, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function calcuates the bounding rectangle of a rotated */
45 /* pixelmap. */
46 /* */
47 /* INPUT */
48 /* */
49 /* rect Rectangle of source pixelmao. */
50 /* angle Angle of rotation in degrees. */
51 /* rot_cx x-coord of rotating center */
52 /* rot_cy y-coord of rotating center */
53 /* */
54 /* OUTPUT */
55 /* */
56 /* status Completion status */
57 /* */
58 /* CALLS */
59 /* */
60 /* None */
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_canvas_rotated_pixelmap_bound_calculate(GX_RECTANGLE * rect,INT angle,INT rot_cx,INT rot_cy)75 static UINT _gx_canvas_rotated_pixelmap_bound_calculate(GX_RECTANGLE *rect, INT angle, INT rot_cx, INT rot_cy)
76 {
77 INT mx[4] = {-1, 1, 1, -1};
78 INT my[4] = {1, 1, -1, -1};
79 INT idxminx;
80 INT idxmaxx;
81 INT idxmaxy;
82 INT srcxres;
83 INT srcyres;
84 INT cosv;
85 INT sinv;
86 INT xres;
87 INT yres;
88 INT width;
89 INT height;
90 INT x;
91 INT y;
92
93 angle %= 360;
94
95 if (angle < 0)
96 {
97 angle += 360;
98 }
99
100 /* Calculate rectangle width and height. */
101 width = (GX_VALUE)(rect -> gx_rectangle_right - rect -> gx_rectangle_left + 1);
102 height = (GX_VALUE)(rect -> gx_rectangle_bottom - rect -> gx_rectangle_top + 1);
103
104 if (angle == 0)
105 {
106 return GX_SUCCESS;
107 }
108 if (angle == 90)
109 {
110 GX_SWAP_VALS(width, height);
111
112 rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - (width - 1 - rot_cy));
113 rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - rot_cx);
114 }
115 else if (angle == 180)
116 {
117 rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - (width - 1 - rot_cx));
118 rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - (height - 1 - rot_cy));
119 }
120 else if (angle == 270)
121 {
122 GX_SWAP_VALS(width, height);
123 rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - rot_cy);
124 rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - (height - 1 - rot_cx));
125 }
126 else
127 {
128 idxminx = (angle / 90) & 0x3;
129 idxmaxx = (idxminx + 2) & 0x3;
130 idxmaxy = (idxminx + 1) & 0x3;
131
132 /* Calculate the source x and y center. */
133 srcxres = width >> 1;
134 srcyres = height >> 1;
135
136 cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
137 sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
138
139 xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
140 yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
141
142 xres = GX_FIXED_VAL_TO_INT(xres);
143 yres = GX_FIXED_VAL_TO_INT(yres);
144
145 /* Calculate destination width and height. */
146 width = (xres << 1);
147 height = (yres << 1);
148
149 /* Calculate the new rotation axis. */
150 x = GX_FIXED_VAL_TO_INT((rot_cx - srcxres) * cosv - (rot_cy - srcyres) * sinv);
151 y = GX_FIXED_VAL_TO_INT((rot_cy - srcyres) * cosv + (rot_cx - srcxres) * sinv);
152
153 x += xres;
154 y += yres;
155
156 rect -> gx_rectangle_left = (GX_VALUE)(rect -> gx_rectangle_left + rot_cx - x);
157 rect -> gx_rectangle_top = (GX_VALUE)(rect -> gx_rectangle_top + rot_cy - y);
158 }
159 rect -> gx_rectangle_right = (GX_VALUE)(rect -> gx_rectangle_left + width - 1);
160 rect -> gx_rectangle_bottom = (GX_VALUE)(rect -> gx_rectangle_top + height - 1);
161
162 return(GX_SUCCESS);
163 }
164
165 /**************************************************************************/
166 /* */
167 /* FUNCTION RELEASE */
168 /* */
169 /* _gx_canvas_pixelmap_rotate PORTABLE C */
170 /* 6.1.7 */
171 /* AUTHOR */
172 /* */
173 /* Kenneth Maxwell, Microsoft Corporation */
174 /* */
175 /* DESCRIPTION */
176 /* */
177 /* This function prepares to draw the specified pixelmap at the */
178 /* requested position. */
179 /* */
180 /* INPUT */
181 /* */
182 /* x_position Top-left x-coord to place */
183 /* pixelmap */
184 /* y_position Top-left y-coord to place */
185 /* pixelmap */
186 /* pixelmap Pointer to actual pixelmap */
187 /* to draw */
188 /* angle The angle to rotate */
189 /* rot_cx x-coord of rotating center, if*/
190 /* -1 is set, default it to */
191 /* image center. */
192 /* rot_cy y-coord of rotationg center. */
193 /* -1 is set, default it to */
194 /* image center. */
195 /* */
196 /* OUTPUT */
197 /* */
198 /* status Completion status */
199 /* */
200 /* CALLS */
201 /* */
202 /* _gx_utility_rectangle_define */
203 /* _gx_utility_rectangle_overlap_detect */
204 /* _gx_canvas_rotated_pixelmap_bound_calculate */
205 /* [gx_display_driver_pixelmap_rotate] */
206 /* */
207 /* CALLED BY */
208 /* */
209 /* Application code */
210 /* */
211 /* RELEASE HISTORY */
212 /* */
213 /* DATE NAME DESCRIPTION */
214 /* */
215 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
216 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
217 /* resulting in version 6.1 */
218 /* 06-02-2021 Kenneth Maxwell Modified comment(s), */
219 /* removed duplicate variable */
220 /* assignment, */
221 /* resulting in version 6.1.7 */
222 /* */
223 /**************************************************************************/
_gx_canvas_pixelmap_rotate(GX_VALUE x_position,GX_VALUE y_position,GX_PIXELMAP * pixelmap,INT angle,INT rot_cx,INT rot_cy)224 UINT _gx_canvas_pixelmap_rotate(GX_VALUE x_position, GX_VALUE y_position, GX_PIXELMAP *pixelmap,
225 INT angle, INT rot_cx, INT rot_cy)
226 {
227 GX_DRAW_CONTEXT *context;
228 GX_DISPLAY *display;
229 GX_RECTANGLE clip_rect;
230 GX_RECTANGLE bound;
231 GX_VIEW *view;
232 VOID (*pmp_function)(GX_DRAW_CONTEXT *, INT, INT, GX_PIXELMAP *, INT, INT, INT);
233 INT cx;
234 INT cy;
235
236 /* pick up the current drawing context */
237 context = _gx_system_current_draw_context;
238
239 /* pick up current display driver */
240 display = context -> gx_draw_context_display;
241
242 /* calculate rectangle that bounds the pixelmap */
243 _gx_utility_rectangle_define(&bound, x_position, y_position,
244 (GX_VALUE)(x_position + pixelmap -> gx_pixelmap_width - 1),
245 (GX_VALUE)(y_position + pixelmap -> gx_pixelmap_height - 1));
246
247 if (rot_cx == -1)
248 {
249 cx = pixelmap -> gx_pixelmap_width >> 1;
250 }
251 else
252 {
253 cx = rot_cx;
254 }
255
256 if (rot_cy == -1)
257 {
258 cy = pixelmap -> gx_pixelmap_height >> 1;
259 }
260 else
261 {
262 cy = rot_cy;
263 }
264
265 /* calculate rectangle that bounds the rotated pixelmap */
266 _gx_canvas_rotated_pixelmap_bound_calculate(&bound, angle, cx, cy);
267
268 /* clip the line bounding box to the dirty rectangle */
269 if (!_gx_utility_rectangle_overlap_detect(&bound, &context -> gx_draw_context_dirty, &bound))
270 {
271 /* nothing to draw, return */
272 return GX_SUCCESS;
273 }
274
275 /* Range angle to [0, 360). */
276 angle = angle % 360;
277
278 if (angle < 0)
279 {
280 angle += 360;
281 }
282
283 if (angle == 0)
284 {
285 if (!display->gx_display_driver_pixelmap_draw)
286 {
287 return GX_FAILURE;
288 }
289 }
290
291 if (pixelmap->gx_pixelmap_flags & GX_PIXELMAP_COMPRESSED)
292 {
293 return GX_NOT_SUPPORTED;
294 }
295
296 /* pickup pointer to correct pixelmap drawing function */
297 pmp_function = display -> gx_display_driver_pixelmap_rotate;
298
299 if (!pmp_function)
300 {
301 /* display driver does not support requested action */
302 return GX_FAILURE;
303 }
304
305 /* test to determine if the bounding rectangle overlaps the region we are allowed to draw
306 into. For each view that overlaps the bounding rectangle, do some drawing.
307 */
308 view = context -> gx_draw_context_view_head;
309
310 while (view)
311 {
312 if (!_gx_utility_rectangle_overlap_detect(&view -> gx_view_rectangle, &bound, &clip_rect))
313 {
314 view = view -> gx_view_next;
315 continue;
316 }
317
318 /* we have a view into which we can draw the pixelmap, do it */
319
320 /* first, set the context clip rectangle */
321 context -> gx_draw_context_clip = &clip_rect;
322
323 if (angle == 0)
324 {
325 display->gx_display_driver_pixelmap_draw(context, x_position, y_position, pixelmap);
326 }
327 else
328 {
329 /* now pass the context and drawing params to driver level function */
330 pmp_function(context, x_position, y_position, pixelmap, angle, cx, cy);
331 }
332
333 /* go to the next view */
334 view = view -> gx_view_next;
335 }
336
337 /* Return successful completion. */
338 return(GX_SUCCESS);
339 }
340
341