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 GX_SOURCE_CODE
22
23
24 /* Include necessary system files. */
25
26 #include "gx_api.h"
27 #include "gx_display.h"
28 #include "gx_context.h"
29 #include "gx_utility.h"
30 #include "gx_system.h"
31
32 /**************************************************************************/
33 /* */
34 /* FUNCTION RELEASE */
35 /* */
36 /* _gx_utility_8bpp_pixelmap_rotate PORTABLE C */
37 /* 6.1 */
38 /* AUTHOR */
39 /* */
40 /* Kenneth Maxwell, Microsoft Corporation */
41 /* */
42 /* DESCRIPTION */
43 /* */
44 /* This function rotates an 8bpp format uncompressed pixelmap with or */
45 /* without alpha channel. */
46 /* */
47 /* INPUT */
48 /* */
49 /* src The pixelmap to be rotated */
50 /* angle The angle to be rotated */
51 /* destination The rotated bitmap to be */
52 /* returned */
53 /* rot_cx X coordinate of rotation */
54 /* center */
55 /* rot_cy Y coordinate of rotation */
56 /* center */
57 /* */
58 /* OUTPUT */
59 /* */
60 /* Completion Status */
61 /* */
62 /* CALLS */
63 /* */
64 /* _gx_system_memory_allocator Memory Allocation routine */
65 /* _gx_utility_math_cos Compute the cosine value */
66 /* _gx_utility_math_sin Compute the sine value */
67 /* */
68 /* CALLED BY */
69 /* */
70 /* GUIX Internal Code */
71 /* */
72 /* RELEASE HISTORY */
73 /* */
74 /* DATE NAME DESCRIPTION */
75 /* */
76 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
77 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
78 /* resulting in version 6.1 */
79 /* */
80 /**************************************************************************/
_gx_utility_8bpp_pixelmap_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)81 UINT _gx_utility_8bpp_pixelmap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
82 {
83 GX_UBYTE *putrow;
84 GX_UBYTE *put;
85 GX_UBYTE *get;
86 INT srcxres;
87 INT srcyres;
88 INT cosv;
89 INT sinv;
90 INT idxminx, idxmaxx, idxmaxy;
91 INT mx[] = {-1, 1, 1, -1};
92 INT my[] = {1, 1, -1, -1};
93 INT xres;
94 INT yres;
95 INT width, height;
96 INT x, y;
97 INT xx, yy;
98
99 /* Set transparent color. */
100 if (src -> gx_pixelmap_flags & GX_PIXELMAP_TRANSPARENT)
101 {
102 destination -> gx_pixelmap_transparent_color = src -> gx_pixelmap_transparent_color;
103 }
104 else
105 {
106 destination -> gx_pixelmap_transparent_color = 0xff;
107 }
108
109 idxminx = (angle / 90) & 0x3;
110 idxmaxx = (idxminx + 2) & 0x3;
111 idxmaxy = (idxminx + 1) & 0x3;
112
113 /* Calculate the source x and y center. */
114 srcxres = src -> gx_pixelmap_width >> 1;
115 srcyres = src -> gx_pixelmap_height >> 1;
116
117 cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
118 sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
119
120 xres = GX_FIXED_VAL_TO_INT((mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv));
121 yres = GX_FIXED_VAL_TO_INT((my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv));
122
123 /* Calculate destination width and height. */
124 width = (xres << 1);
125 height = (yres << 1);
126
127 if (rot_cx && rot_cy)
128 {
129 /* Calculate the new rotation axis. */
130 x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
131 y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
132
133 x = GX_FIXED_VAL_TO_INT(x) + xres;
134 y = GX_FIXED_VAL_TO_INT(y) + yres;
135
136 srcxres = *rot_cx;
137 srcyres = *rot_cy;
138
139 *rot_cx = x;
140 *rot_cy = y;
141
142 xres = *rot_cx;
143 yres = *rot_cy;
144 }
145
146 /* Set width and height of destination pixelmap. */
147 destination -> gx_pixelmap_width = (GX_VALUE)width;
148 destination -> gx_pixelmap_height = (GX_VALUE)height;
149 destination -> gx_pixelmap_flags |= GX_PIXELMAP_TRANSPARENT;
150
151 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
152 overflow cannot occur. */
153 destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(GX_UBYTE);
154
155 /* Allocate memory for destination pixelmap to load pixel information. */
156 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
157
158 if (destination -> gx_pixelmap_data == GX_NULL)
159 {
160 return GX_SYSTEM_MEMORY_ERROR;
161 }
162
163 putrow = (GX_UBYTE *)destination -> gx_pixelmap_data;
164
165 /* For every pixel in destination bitmap, find its position in source bitmap,
166 and set the pixel with the value in source bitmap. */
167 for (y = 0; y < height; y++)
168 {
169 put = putrow;
170
171 for (x = 0; x < width; x++)
172 {
173 xx = (x - xres) * cosv + (y - yres) * sinv;
174 yy = (y - yres) * cosv - (x - xres) * sinv;
175
176 xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
177 yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
178
179 if ((xx >= 0) && (xx < src -> gx_pixelmap_width) &&
180 (yy >= 0) && (yy < src -> gx_pixelmap_height))
181 {
182 get = (GX_UBYTE *)src -> gx_pixelmap_data;
183 get += yy * src -> gx_pixelmap_width;
184 get += xx;
185
186 *put++ = *get;
187 }
188 else
189 {
190 *put++ = (GX_UBYTE)destination -> gx_pixelmap_transparent_color;
191 }
192 }
193 putrow += destination -> gx_pixelmap_width;
194 }
195
196 return GX_SUCCESS;
197 }
198
199 /**************************************************************************/
200 /* */
201 /* FUNCTION RELEASE */
202 /* */
203 /* _gx_utility_8bpp_pixelmap_simple_rotate PORTABLE C */
204 /* 6.1 */
205 /* AUTHOR */
206 /* */
207 /* Kenneth Maxwell, Microsoft Corporation */
208 /* */
209 /* DESCRIPTION */
210 /* */
211 /* This function rotates an 8bpp format uncompressed pixelmap with */
212 /* special rotation angle 90, 180 or 270 degree. */
213 /* */
214 /* INPUT */
215 /* */
216 /* src The pixelmap to be rotated */
217 /* angle The angle to be rotated */
218 /* destination The rotated bitmap to be */
219 /* returned */
220 /* rot_cx X coordinate of rotation */
221 /* center */
222 /* rot_cy Y coordinate of rotation */
223 /* center */
224 /* */
225 /* OUTPUT */
226 /* */
227 /* Completion Status */
228 /* */
229 /* CALLS */
230 /* */
231 /* _gx_system_memory_allocator Memory Allocation routine */
232 /* */
233 /* CALLED BY */
234 /* */
235 /* GUIX Internal Code */
236 /* */
237 /* RELEASE HISTORY */
238 /* */
239 /* DATE NAME DESCRIPTION */
240 /* */
241 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
242 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
243 /* resulting in version 6.1 */
244 /* */
245 /**************************************************************************/
_gx_utility_8bpp_pixelmap_simple_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)246 UINT _gx_utility_8bpp_pixelmap_simple_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
247 {
248 GX_UBYTE *put;
249 GX_UBYTE *get;
250 INT width, height;
251 INT x, y;
252
253 destination -> gx_pixelmap_transparent_color = src -> gx_pixelmap_transparent_color;
254
255 width = src -> gx_pixelmap_height;
256 height = src -> gx_pixelmap_width;
257
258 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
259 overflow cannot occur. */
260 destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(GX_UBYTE);
261 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
262
263 if (destination -> gx_pixelmap_data == GX_NULL)
264 {
265 return GX_SYSTEM_MEMORY_ERROR;
266 }
267
268 if (angle == 90)
269 {
270 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
271
272 for (y = 0; y < height; y++)
273 {
274 for (x = 0; x < width; x++)
275 {
276 get = (GX_UBYTE *)src -> gx_pixelmap_data;
277 get += (width - 1 - x) * height;
278 get += y;
279
280 *put++ = *get;
281 }
282 }
283
284 if (rot_cx && rot_cy)
285 {
286 x = *rot_cx;
287 y = *rot_cy;
288
289 *rot_cx = (width - 1 - y);
290 *rot_cy = x;
291 }
292 }
293 else if (angle == 180)
294 {
295 GX_SWAP_VALS(width, height);
296
297 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
298
299 for (y = 0; y < height; y++)
300 {
301 for (x = 0; x < width; x++)
302 {
303 get = (GX_UBYTE *)src -> gx_pixelmap_data;
304 get += (height - 1 - y) * width;
305 get += width - 1 - x;
306
307 *put++ = *get;
308 }
309 }
310
311 if (rot_cx && rot_cy)
312 {
313 x = *rot_cx;
314 y = *rot_cy;
315
316 *rot_cx = (width - 1 - x);
317 *rot_cy = (height - 1 - y);
318 }
319 }
320 else
321 {
322 /* angle = 270. */
323 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
324
325 for (y = 0; y < height; y++)
326 {
327 for (x = 0; x < width; x++)
328 {
329 get = (GX_UBYTE *)src -> gx_pixelmap_data;
330 get += x * height;
331 get += height - 1 - y;
332
333 *put++ = *get;
334 }
335 }
336
337 if (rot_cx && rot_cy)
338 {
339 x = *rot_cx;
340 y = *rot_cy;
341
342 *rot_cx = y;
343 *rot_cy = (height - 1 - x);
344 }
345 }
346
347 destination -> gx_pixelmap_height = (GX_VALUE)height;
348 destination -> gx_pixelmap_width = (GX_VALUE)width;
349
350 return GX_SUCCESS;
351 }
352
353 /**************************************************************************/
354 /* */
355 /* FUNCTION RELEASE */
356 /* */
357 /* _gx_utility_8bit_alphamap_rotate PORTABLE C */
358 /* 6.1 */
359 /* AUTHOR */
360 /* */
361 /* Kenneth Maxwell, Microsoft Corporation */
362 /* */
363 /* DESCRIPTION */
364 /* */
365 /* This function rotates an 8bit alphamap. */
366 /* */
367 /* INPUT */
368 /* */
369 /* src The pixelmap to be rotated */
370 /* angle The angle to be rotated */
371 /* destination The rotated bitmap to be */
372 /* returned */
373 /* rot_cx X coordinate of rotation */
374 /* center */
375 /* rot_cy Y coordinate of rotation */
376 /* center */
377 /* */
378 /* OUTPUT */
379 /* */
380 /* Completion Status */
381 /* */
382 /* CALLS */
383 /* */
384 /* _gx_system_memory_allocator Memory Allocation routine */
385 /* _gx_utility_math_cos Compute the cosine value */
386 /* _gx_utility_math_sin Compute the sine value */
387 /* */
388 /* CALLED BY */
389 /* */
390 /* GUIX Internal Code */
391 /* */
392 /* RELEASE HISTORY */
393 /* */
394 /* DATE NAME DESCRIPTION */
395 /* */
396 /* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
397 /* 09-30-2020 Kenneth Maxwell Modified comment(s), */
398 /* resulting in version 6.1 */
399 /* */
400 /**************************************************************************/
_gx_utility_8bit_alphamap_rotate(GX_PIXELMAP * src,INT angle,GX_PIXELMAP * destination,INT * rot_cx,INT * rot_cy)401 UINT _gx_utility_8bit_alphamap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
402 {
403 GX_UBYTE *put;
404 GX_CONST GX_UBYTE *get;
405 INT srcxres;
406 INT srcyres;
407 INT cosv;
408 INT sinv;
409 INT alpha;
410 INT idxminx;
411 INT idxmaxx;
412 INT idxmaxy;
413 INT *mx;
414 INT *my;
415 INT xres;
416 INT yres;
417 INT width;
418 INT height;
419 INT x;
420 INT y;
421 INT xx;
422 INT yy;
423 GX_UBYTE a;
424 GX_UBYTE b;
425 GX_UBYTE c;
426 GX_UBYTE d;
427 INT xdiff;
428 INT ydiff;
429
430 mx = _gx_system_scratchpad;
431 my = mx + 4;
432
433 mx[0] = mx[3] = -1;
434 mx[1] = mx[2] = 1;
435
436 my[0] = my[1] = 1;
437 my[2] = my[3] = -1;
438
439 idxminx = (angle / 90) & 0x3;
440 idxmaxx = (idxminx + 2) & 0x3;
441 idxmaxy = (idxminx + 1) & 0x3;
442
443 /* Calculate the source x and y center. */
444 srcxres = src -> gx_pixelmap_width >> 1;
445 srcyres = src -> gx_pixelmap_height >> 1;
446
447 cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
448 sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
449
450 xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
451 yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
452
453 xres = GX_FIXED_VAL_TO_INT(xres);
454 yres = GX_FIXED_VAL_TO_INT(yres);
455
456 /* Calculate destination width and height. */
457 width = (xres << 1);
458 height = (yres << 1);
459
460 /* Calculate the new rotation axis. */
461 if (rot_cx && rot_cy)
462 {
463 x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
464 y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
465
466 srcxres = *rot_cx;
467 srcyres = *rot_cy;
468
469 x = GX_FIXED_VAL_TO_INT(x) + xres;
470 y = GX_FIXED_VAL_TO_INT(y) + yres;
471
472 *rot_cx = x;
473 *rot_cy = y;
474
475 xres = *rot_cx;
476 yres = *rot_cy;
477 }
478
479 destination -> gx_pixelmap_height = (GX_VALUE)height;
480 destination -> gx_pixelmap_width = (GX_VALUE)width;
481 destination -> gx_pixelmap_flags |= GX_PIXELMAP_TRANSPARENT;
482 destination -> gx_pixelmap_transparent_color = 0;
483 destination -> gx_pixelmap_format = GX_COLOR_FORMAT_8BIT_ALPHAMAP;
484
485 /* Safe int math is not required here, calling function limits max width, height to 14 bits so
486 overflow cannot occur. */
487 destination -> gx_pixelmap_data_size = (UINT)(height * width);
488 destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
489
490 if (destination -> gx_pixelmap_data == GX_NULL)
491 {
492 return GX_SYSTEM_MEMORY_ERROR;
493 }
494
495 put = (GX_UBYTE *)destination -> gx_pixelmap_data;
496
497 /* Loop through the source's pixels. */
498 for (y = 0; y < height; y++)
499 {
500 for (x = 0; x < width; x++)
501 {
502 xx = (x - xres) * cosv + (y - yres) * sinv;
503 yy = (y - yres) * cosv - (x - xres) * sinv;
504
505 xdiff = GX_FIXED_VAL_TO_INT(xx << 8) & 0xff;
506 ydiff = GX_FIXED_VAL_TO_INT(yy << 8) & 0xff;
507
508 xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
509 yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
510
511 if ((xx >= -1) && (xx < src -> gx_pixelmap_width) &&
512 (yy >= -1) && (yy < src -> gx_pixelmap_height))
513 {
514 if ((xx >= 0) && (xx < src -> gx_pixelmap_width - 1) && \
515 (yy >= 0) && (yy < src -> gx_pixelmap_height - 1))
516 {
517 get = src -> gx_pixelmap_data;
518 get += yy * src -> gx_pixelmap_width;
519 get += xx;
520
521 a = *get;
522 b = *(get + 1);
523 c = *(get + src -> gx_pixelmap_width);
524 d = *(get + src -> gx_pixelmap_width + 1);
525 }
526 else
527 {
528 get = src -> gx_pixelmap_data;
529
530 a = 0;
531 b = a;
532 c = a;
533 d = a;
534
535 if (xx == -1)
536 {
537 /* handle left edge. */
538 if (yy >= 0)
539 {
540 b = *(get + yy * src -> gx_pixelmap_width);
541 }
542
543 if (yy < src -> gx_pixelmap_height - 1)
544 {
545 d = *(get + (yy + 1) * src -> gx_pixelmap_width);
546 }
547 }
548 else if (yy == -1)
549 {
550 /* handle top edge. */
551 c = *(get + xx);
552
553 if (xx < src -> gx_pixelmap_width - 1)
554 {
555 d = *(get + xx + 1);
556 }
557 }
558 else if (xx == src -> gx_pixelmap_width - 1)
559 {
560 /* handle right edget. */
561 a = *(get + yy * src -> gx_pixelmap_width + xx);
562
563 if (yy < src -> gx_pixelmap_height - 1)
564 {
565 c = *(get + (yy + 1) * src -> gx_pixelmap_width + xx);
566 }
567 }
568 else
569 {
570 /* handle bottom edge. */
571 a = *(get + yy * src -> gx_pixelmap_width + xx);
572 b = *(get + yy * src -> gx_pixelmap_width + xx + 1);
573 }
574 }
575
576 alpha = (INT)((a * (256 - (ULONG)xdiff) * (256 - (ULONG)ydiff) + \
577 b * (ULONG)xdiff * (256 - (ULONG)ydiff) + \
578 c * (ULONG)ydiff * (256 - (ULONG)xdiff) + \
579 d * (ULONG)xdiff * (ULONG)ydiff) >> 16);
580
581 *put++ = (GX_UBYTE)alpha;
582 }
583 else
584 {
585 *put++ = 0;
586 }
587 }
588 }
589
590 return GX_SUCCESS;
591 }
592
593