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 /** Utility (Utility) */
18 /** */
19 /**************************************************************************/
20
21 #define ALPHAVAL(_c) (GX_UBYTE)(((_c) >> 12) & 0xf)
22 #define REDVAL(_c) (GX_UBYTE)(((_c) >> 8) & 0xf)
23 #define GREENVAL(_c) (GX_UBYTE)(((_c) >> 4) & 0xf)
24 #define BLUEVAL(_c) (GX_UBYTE)(((_c)) & 0xf)
25
26 #define ASSEMBLECOLOR(_a, _r, _g, _b) \
27 (USHORT)((((_a) & 0xf) << 12) | \
28 (((_r) & 0xf) << 8) | \
29 (((_g) & 0xf) << 4) | \
30 ((_b) & 0xf))
31
32 #define GX_SOURCE_CODE
33
34
35 /* Include necessary system files. */
36
37 #include "gx_api.h"
38 #include "gx_display.h"
39 #include "gx_context.h"
40 #include "gx_utility.h"
41 #include "gx_system.h"
42
43 /**************************************************************************/
44 /* */
45 /* FUNCTION RELEASE */
46 /* */
47 /* _gx_utility_4444argb_pixelmap_rotate PORTABLE C */
48 /* 6.1 */
49 /* AUTHOR */
50 /* */
51 /* Kenneth Maxwell, Microsoft Corporation */
52 /* */
53 /* DESCRIPTION */
54 /* */
55 /* Internal helper funciton that rotate an 4444argb format uncompressed*/
56 /* pixelmap. */
57 /* */
58 /* INPUT */
59 /* */
60 /* src The pixelmap to be rotated */
61 /* angle The angle to be rotated */
62 /* destination The rotated bitmap to be */
63 /* returned */
64 /* rot_cx X coordinate of rotation */
65 /* center */
66 /* rot_cy Y coordinate of rotation */
67 /* center */
68 /* */
69 /* OUTPUT */
70 /* */
71 /* status Completion status */
72 /* */
73 /* CALLS */
74 /* */
75 /* _gx_system_memory_allocator Application defined memory */
76 /* allocation function */
77 /* _gx_utility_math_cos Calculate cosine of supplied */
78 /* angle */
79 /* _gx_utility_math_sin Calculate sine of supplied */
80 /* angle */
81 /* */
82 /* CALLED BY */
83 /* */
84 /* GUIX Internal Code */
85 /* */
86 /* RELEASE HISTORY */
87 /* */
88 /* DATE NAME DESCRIPTION */
89 /* */
90 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
91 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
92 /* resulting in version 6.1 */
93 /* */
94 /**************************************************************************/
_gx_utility_4444argb_pixelmap_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)95 UINT _gx_utility_4444argb_pixelmap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
96 {
97 USHORT *get;
98 USHORT *put;
99 INT srcxres;
100 INT srcyres;
101 INT cosv;
102 INT sinv;
103 USHORT red, green, blue;
104 INT idxminx, idxmaxx, idxmaxy;
105 INT *mx;
106 INT *my;
107 INT xres;
108 INT yres;
109 INT width, height;
110 INT x, y;
111 INT xx, yy;
112 USHORT a, b, c, d;
113 USHORT alpha[4];
114 INT xdiff, ydiff;
115
116 mx = _gx_system_scratchpad;
117 my = mx + 4;
118
119 mx[0] = mx[3] = -1;
120 mx[1] = mx[2] = 1;
121
122 my[0] = my[1] = 1;
123 my[2] = my[3] = -1;
124
125 idxminx = (angle / 90) & 0x3;
126 idxmaxx = (idxminx + 2) & 0x3;
127 idxmaxy = (idxminx + 1) & 0x3;
128
129 /* Calculate the source x and y center. */
130 srcxres = src -> gx_pixelmap_width >> 1;
131 srcyres = src -> gx_pixelmap_height >> 1;
132
133 cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
134 sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
135
136 xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
137 yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
138
139 xres = GX_FIXED_VAL_TO_INT(xres);
140 yres = GX_FIXED_VAL_TO_INT(yres);
141
142 /* Calculate destination width and height. */
143 width = (xres << 1);
144 height = (yres << 1);
145
146 /* Calculate the new rotation axis. */
147 if (rot_cx && rot_cy)
148 {
149 x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
150 y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
151
152 srcxres = *rot_cx;
153 srcyres = *rot_cy;
154
155 x = GX_FIXED_VAL_TO_INT(x) + xres;
156 y = GX_FIXED_VAL_TO_INT(y) + yres;
157
158 *rot_cx = x;
159 *rot_cy = y;
160
161 xres = *rot_cx;
162 yres = *rot_cy;
163 }
164
165 destination -> gx_pixelmap_height = (GX_VALUE)height;
166 destination -> gx_pixelmap_width = (GX_VALUE)width;
167 destination -> gx_pixelmap_flags |= GX_PIXELMAP_ALPHA;
168
169 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
170 overflow cannot occur. */
171 destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(USHORT);
172 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
173
174 if (destination -> gx_pixelmap_data == GX_NULL)
175 {
176 return GX_SYSTEM_MEMORY_ERROR;
177 }
178
179 put = (USHORT *)destination -> gx_pixelmap_data;
180
181 /* Loop through the destination's pixels. */
182 for (y = 0; y < height; y++)
183 {
184 for (x = 0; x < width; x++)
185 {
186 xx = (x - xres) * cosv + (y - yres) * sinv;
187 yy = (y - yres) * cosv - (x - xres) * sinv;
188
189 xdiff = GX_FIXED_VAL_TO_INT(xx << 8) & 0xff;
190 ydiff = GX_FIXED_VAL_TO_INT(yy << 8) & 0xff;
191
192 xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
193 yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
194
195 if ((xx >= -1) && (xx < src -> gx_pixelmap_width) &&
196 (yy >= -1) && (yy < src -> gx_pixelmap_height))
197 {
198
199 if ((xx >= 0) && (xx < src -> gx_pixelmap_width - 1) &&
200 (yy >= 0) && (yy < src -> gx_pixelmap_height - 1))
201 {
202 get = (USHORT *)src -> gx_pixelmap_data;
203 get += yy * src -> gx_pixelmap_width;
204 get += xx;
205
206 a = *get;
207 b = *(get + 1);
208 c = *(get + src -> gx_pixelmap_width);
209 d = *(get + src -> gx_pixelmap_width + 1);
210 alpha[0] = ALPHAVAL(a);
211 alpha[1] = ALPHAVAL(b);
212 alpha[2] = ALPHAVAL(c);
213 alpha[3] = ALPHAVAL(d);
214 }
215 else
216 {
217 get = (USHORT *)src -> gx_pixelmap_data;
218
219 a = 0;
220 b = 0;
221 c = 0;
222 d = 0;
223
224 if (xx == -1)
225 {
226 /* handle left edge. */
227 if (yy >= 0)
228 {
229 b = *(get + yy * src -> gx_pixelmap_width);
230 alpha[1] = ALPHAVAL(b);
231 }
232
233 if (yy < src -> gx_pixelmap_height - 1)
234 {
235 d = *(get + (yy + 1) * src -> gx_pixelmap_width);
236 alpha[3] = ALPHAVAL(d);
237 }
238 }
239 else if (yy == -1)
240 {
241 /* handle top edge. */
242 c = *(get + xx);
243 alpha[2] = ALPHAVAL(c);
244
245 if (xx < src -> gx_pixelmap_width - 1)
246 {
247 d = *(get + xx + 1);
248 alpha[3] = ALPHAVAL(d);
249 }
250 }
251 else if (xx == src -> gx_pixelmap_width - 1)
252 {
253 /* handle right edget. */
254 a = *(get + yy * src -> gx_pixelmap_width + xx);
255 alpha[0] = ALPHAVAL(a);
256
257 if (yy < src -> gx_pixelmap_height - 1)
258 {
259 c = *(get + (yy + 1) * src -> gx_pixelmap_width + xx);
260 alpha[2] = ALPHAVAL(c);
261 }
262 }
263 else
264 {
265 /* handle bottom edge. */
266 a = *(get + yy * src -> gx_pixelmap_width + xx);
267 alpha[0] = ALPHAVAL(a);
268
269 b = *(get + yy * src -> gx_pixelmap_width + xx + 1);
270 alpha[1] = ALPHAVAL(b);
271 }
272
273 if (!a)
274 {
275 alpha[0] = 0;
276 }
277
278 if (!b)
279 {
280 alpha[1] = 0;
281 }
282
283 if (!c)
284 {
285 alpha[2] = 0;
286 }
287
288 if (!d)
289 {
290 alpha[3] = 0;
291 }
292 }
293
294 red = (USHORT)((REDVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
295 REDVAL(b) * alpha[1] * xdiff * (256 - ydiff) + \
296 REDVAL(c) * alpha[2] * ydiff * (256 - xdiff) + \
297 REDVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
298
299 green = (USHORT)((GREENVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
300 GREENVAL(b) * alpha[1] * xdiff * (256 - ydiff) + \
301 GREENVAL(c) * alpha[2] * ydiff * (256 - xdiff) + \
302 GREENVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
303
304 blue = (USHORT)((BLUEVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
305 BLUEVAL(b) * alpha[1] * xdiff * (256 - ydiff) + \
306 BLUEVAL(c) * alpha[2] * ydiff * (256 - xdiff) + \
307 BLUEVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
308
309 alpha[0] = (USHORT)((alpha[0] * (256 - xdiff) * (256 - ydiff) + \
310 alpha[1] * xdiff * (256 - ydiff) + \
311 alpha[2] * ydiff * (256 - xdiff) + \
312 alpha[3] * xdiff * ydiff) >> 16);
313
314 if (alpha[0])
315 {
316 red /= alpha[0];
317 green /= alpha[0];
318 blue /= alpha[0];
319 }
320 red = red > 15 ? 15 : red;
321 green = green > 15 ? 15 : green;
322 blue = blue > 15 ? 15 : blue;
323 alpha[0] = alpha[0] > 15 ? 15 : alpha[0];
324
325 *put++ = ASSEMBLECOLOR(alpha[0], red, green, blue);
326 }
327 else
328 {
329 *put++ = 0;
330 }
331 }
332 }
333 return GX_SUCCESS;
334 }
335
336 /**************************************************************************/
337 /* */
338 /* FUNCTION RELEASE */
339 /* */
340 /* _gx_utility_4444argb_pixelmap_simple_rotate PORTABLE C */
341 /* 6.1 */
342 /* AUTHOR */
343 /* */
344 /* Kenneth Maxwell, Microsoft Corporation */
345 /* */
346 /* DESCRIPTION */
347 /* */
348 /* 4444argb pixelmap rotation function that handles 90, 180 and 270 */
349 /* degree case. */
350 /* */
351 /* INPUT */
352 /* */
353 /* src The pixelmap to be rotated */
354 /* angle The angle to be rotated */
355 /* destination The rotated bitmap to be */
356 /* returned */
357 /* rot_cx X coordinate of rotation */
358 /* center */
359 /* rot_cy Y coordinate of rotation */
360 /* center */
361 /* */
362 /* OUTPUT */
363 /* */
364 /* status Completion status */
365 /* */
366 /* CALLS */
367 /* */
368 /* _gx_system_memory_allocator Application defined memory */
369 /* allocation function */
370 /* */
371 /* CALLED BY */
372 /* */
373 /* GUIX Internal Code */
374 /* */
375 /* RELEASE HISTORY */
376 /* */
377 /* DATE NAME DESCRIPTION */
378 /* */
379 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
380 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
381 /* resulting in version 6.1 */
382 /* */
383 /**************************************************************************/
_gx_utility_4444argb_pixelmap_simple_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)384 UINT _gx_utility_4444argb_pixelmap_simple_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
385 {
386 USHORT *put;
387 USHORT *get;
388 INT width;
389 INT height;
390 INT x;
391 INT y;
392
393 width = src -> gx_pixelmap_height;
394 height = src -> gx_pixelmap_width;
395
396 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
397 overflow cannot occur. */
398 destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(USHORT);
399 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
400
401 if (destination -> gx_pixelmap_data == GX_NULL)
402 {
403 return GX_SYSTEM_MEMORY_ERROR;
404 }
405
406 if (angle == 90)
407 {
408 put = (USHORT *)destination -> gx_pixelmap_data;
409
410 for (y = 0; y < height; y++)
411 {
412 for (x = 0; x < width; x++)
413 {
414 get = (USHORT *)src -> gx_pixelmap_data;
415 get += (width - 1 - x) * height;
416 get += y;
417
418 *put++ = *get;
419 }
420 }
421
422 if (rot_cx && rot_cy)
423 {
424 x = *rot_cx;
425 y = *rot_cy;
426
427 /* Get new rotation point. */
428 *rot_cx = (width - 1 - y);
429 *rot_cy = x;
430 }
431 }
432 else if (angle == 180)
433 {
434 GX_SWAP_VALS(width, height);
435 put = (USHORT *)destination -> gx_pixelmap_data;
436 for (y = 0; y < height; y++)
437 {
438 for (x = 0; x < width; x++)
439 {
440 get = (USHORT *)src -> gx_pixelmap_data;
441 get += (height - 1 - y) * width;
442 get += width - 1 - x;
443
444 *put++ = *get;
445 }
446 }
447
448 if (rot_cx && rot_cy)
449 {
450 x = *rot_cx;
451 y = *rot_cy;
452
453 /* Get new rotation point. */
454 *rot_cx = (width - 1 - x);
455 *rot_cy = (height - 1 - y);
456 }
457 }
458 else
459 {
460 /* angle = 270. */
461 put = (USHORT *)destination -> gx_pixelmap_data;
462
463 for (y = 0; y < height; y++)
464 {
465 for (x = 0; x < width; x++)
466 {
467 get = (USHORT *)src -> gx_pixelmap_data;
468 get += x * height;
469 get += height - 1 - y;
470
471 *put++ = *get;
472 }
473 }
474
475 if (rot_cx && rot_cy)
476 {
477 x = *rot_cx;
478 y = *rot_cy;
479
480 /* Get new rotation point. */
481 *rot_cx = y;
482 *rot_cy = (height - 1 - x);
483 }
484 }
485
486 destination -> gx_pixelmap_height = (GX_VALUE)height;
487 destination -> gx_pixelmap_width = (GX_VALUE)width;
488
489 return GX_SUCCESS;
490 }
491
492