1
0
mirror of https://github.com/azure-rtos/guix.git synced 2025-02-04 07:13:17 +08:00
guix/common/src/gx_utility_4444argb_pixelmap_rotate.c
Bo Chen (from Dev Box) db360a10fa Update copyright.
2024-01-29 14:12:20 +08:00

492 lines
20 KiB
C

/***************************************************************************
* Copyright (c) 2024 Microsoft Corporation
*
* This program and the accompanying materials are made available under the
* terms of the MIT License which is available at
* https://opensource.org/licenses/MIT.
*
* SPDX-License-Identifier: MIT
**************************************************************************/
/**************************************************************************/
/**************************************************************************/
/** */
/** GUIX Component */
/** */
/** Utility (Utility) */
/** */
/**************************************************************************/
#define ALPHAVAL(_c) (GX_UBYTE)(((_c) >> 12) & 0xf)
#define REDVAL(_c) (GX_UBYTE)(((_c) >> 8) & 0xf)
#define GREENVAL(_c) (GX_UBYTE)(((_c) >> 4) & 0xf)
#define BLUEVAL(_c) (GX_UBYTE)(((_c)) & 0xf)
#define ASSEMBLECOLOR(_a, _r, _g, _b) \
(USHORT)((((_a) & 0xf) << 12) | \
(((_r) & 0xf) << 8) | \
(((_g) & 0xf) << 4) | \
((_b) & 0xf))
#define GX_SOURCE_CODE
/* Include necessary system files. */
#include "gx_api.h"
#include "gx_display.h"
#include "gx_context.h"
#include "gx_utility.h"
#include "gx_system.h"
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _gx_utility_4444argb_pixelmap_rotate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Kenneth Maxwell, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* Internal helper funciton that rotate an 4444argb format uncompressed*/
/* pixelmap. */
/* */
/* INPUT */
/* */
/* src The pixelmap to be rotated */
/* angle The angle to be rotated */
/* destination The rotated bitmap to be */
/* returned */
/* rot_cx X coordinate of rotation */
/* center */
/* rot_cy Y coordinate of rotation */
/* center */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _gx_system_memory_allocator Application defined memory */
/* allocation function */
/* _gx_utility_math_cos Calculate cosine of supplied */
/* angle */
/* _gx_utility_math_sin Calculate sine of supplied */
/* angle */
/* */
/* CALLED BY */
/* */
/* GUIX Internal Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
/* 09-30-2020 Kenneth Maxwell Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _gx_utility_4444argb_pixelmap_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
{
USHORT *get;
USHORT *put;
INT srcxres;
INT srcyres;
INT cosv;
INT sinv;
USHORT red, green, blue;
INT idxminx, idxmaxx, idxmaxy;
INT *mx;
INT *my;
INT xres;
INT yres;
INT width, height;
INT x, y;
INT xx, yy;
USHORT a, b, c, d;
USHORT alpha[4];
INT xdiff, ydiff;
mx = _gx_system_scratchpad;
my = mx + 4;
mx[0] = mx[3] = -1;
mx[1] = mx[2] = 1;
my[0] = my[1] = 1;
my[2] = my[3] = -1;
idxminx = (angle / 90) & 0x3;
idxmaxx = (idxminx + 2) & 0x3;
idxmaxy = (idxminx + 1) & 0x3;
/* Calculate the source x and y center. */
srcxres = src -> gx_pixelmap_width >> 1;
srcyres = src -> gx_pixelmap_height >> 1;
cosv = _gx_utility_math_cos(GX_FIXED_VAL_MAKE(angle));
sinv = _gx_utility_math_sin(GX_FIXED_VAL_MAKE(angle));
xres = mx[idxmaxx] * (srcxres + 2) * cosv - my[idxmaxx] * (srcyres + 2) * sinv;
yres = my[idxmaxy] * (srcyres + 2) * cosv + mx[idxmaxy] * (srcxres + 2) * sinv;
xres = GX_FIXED_VAL_TO_INT(xres);
yres = GX_FIXED_VAL_TO_INT(yres);
/* Calculate destination width and height. */
width = (xres << 1);
height = (yres << 1);
/* Calculate the new rotation axis. */
if (rot_cx && rot_cy)
{
x = ((*rot_cx) - srcxres) * cosv - ((*rot_cy) - srcyres) * sinv;
y = ((*rot_cy) - srcyres) * cosv + ((*rot_cx) - srcxres) * sinv;
srcxres = *rot_cx;
srcyres = *rot_cy;
x = GX_FIXED_VAL_TO_INT(x) + xres;
y = GX_FIXED_VAL_TO_INT(y) + yres;
*rot_cx = x;
*rot_cy = y;
xres = *rot_cx;
yres = *rot_cy;
}
destination -> gx_pixelmap_height = (GX_VALUE)height;
destination -> gx_pixelmap_width = (GX_VALUE)width;
destination -> gx_pixelmap_flags |= GX_PIXELMAP_ALPHA;
/* Safe int math is not required here, calling function limits max width, height to 14 bits so
overflow cannot occur. */
destination -> gx_pixelmap_data_size = (UINT)(height * width) * sizeof(USHORT);
destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
if (destination -> gx_pixelmap_data == GX_NULL)
{
return GX_SYSTEM_MEMORY_ERROR;
}
put = (USHORT *)destination -> gx_pixelmap_data;
/* Loop through the destination's pixels. */
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
xx = (x - xres) * cosv + (y - yres) * sinv;
yy = (y - yres) * cosv - (x - xres) * sinv;
xdiff = GX_FIXED_VAL_TO_INT(xx << 8) & 0xff;
ydiff = GX_FIXED_VAL_TO_INT(yy << 8) & 0xff;
xx = GX_FIXED_VAL_TO_INT(xx) + srcxres;
yy = GX_FIXED_VAL_TO_INT(yy) + srcyres;
if ((xx >= -1) && (xx < src -> gx_pixelmap_width) &&
(yy >= -1) && (yy < src -> gx_pixelmap_height))
{
if ((xx >= 0) && (xx < src -> gx_pixelmap_width - 1) &&
(yy >= 0) && (yy < src -> gx_pixelmap_height - 1))
{
get = (USHORT *)src -> gx_pixelmap_data;
get += yy * src -> gx_pixelmap_width;
get += xx;
a = *get;
b = *(get + 1);
c = *(get + src -> gx_pixelmap_width);
d = *(get + src -> gx_pixelmap_width + 1);
alpha[0] = ALPHAVAL(a);
alpha[1] = ALPHAVAL(b);
alpha[2] = ALPHAVAL(c);
alpha[3] = ALPHAVAL(d);
}
else
{
get = (USHORT *)src -> gx_pixelmap_data;
a = 0;
b = 0;
c = 0;
d = 0;
if (xx == -1)
{
/* handle left edge. */
if (yy >= 0)
{
b = *(get + yy * src -> gx_pixelmap_width);
alpha[1] = ALPHAVAL(b);
}
if (yy < src -> gx_pixelmap_height - 1)
{
d = *(get + (yy + 1) * src -> gx_pixelmap_width);
alpha[3] = ALPHAVAL(d);
}
}
else if (yy == -1)
{
/* handle top edge. */
c = *(get + xx);
alpha[2] = ALPHAVAL(c);
if (xx < src -> gx_pixelmap_width - 1)
{
d = *(get + xx + 1);
alpha[3] = ALPHAVAL(d);
}
}
else if (xx == src -> gx_pixelmap_width - 1)
{
/* handle right edget. */
a = *(get + yy * src -> gx_pixelmap_width + xx);
alpha[0] = ALPHAVAL(a);
if (yy < src -> gx_pixelmap_height - 1)
{
c = *(get + (yy + 1) * src -> gx_pixelmap_width + xx);
alpha[2] = ALPHAVAL(c);
}
}
else
{
/* handle bottom edge. */
a = *(get + yy * src -> gx_pixelmap_width + xx);
alpha[0] = ALPHAVAL(a);
b = *(get + yy * src -> gx_pixelmap_width + xx + 1);
alpha[1] = ALPHAVAL(b);
}
if (!a)
{
alpha[0] = 0;
}
if (!b)
{
alpha[1] = 0;
}
if (!c)
{
alpha[2] = 0;
}
if (!d)
{
alpha[3] = 0;
}
}
red = (USHORT)((REDVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
REDVAL(b) * alpha[1] * xdiff * (256 - ydiff) + \
REDVAL(c) * alpha[2] * ydiff * (256 - xdiff) + \
REDVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
green = (USHORT)((GREENVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
GREENVAL(b) * alpha[1] * xdiff * (256 - ydiff) + \
GREENVAL(c) * alpha[2] * ydiff * (256 - xdiff) + \
GREENVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
blue = (USHORT)((BLUEVAL(a) * alpha[0] * (256 - xdiff) * (256 - ydiff) + \
BLUEVAL(b) * alpha[1] * xdiff * (256 - ydiff) + \
BLUEVAL(c) * alpha[2] * ydiff * (256 - xdiff) + \
BLUEVAL(d) * alpha[3] * xdiff * ydiff) >> 16);
alpha[0] = (USHORT)((alpha[0] * (256 - xdiff) * (256 - ydiff) + \
alpha[1] * xdiff * (256 - ydiff) + \
alpha[2] * ydiff * (256 - xdiff) + \
alpha[3] * xdiff * ydiff) >> 16);
if (alpha[0])
{
red /= alpha[0];
green /= alpha[0];
blue /= alpha[0];
}
red = red > 15 ? 15 : red;
green = green > 15 ? 15 : green;
blue = blue > 15 ? 15 : blue;
alpha[0] = alpha[0] > 15 ? 15 : alpha[0];
*put++ = ASSEMBLECOLOR(alpha[0], red, green, blue);
}
else
{
*put++ = 0;
}
}
}
return GX_SUCCESS;
}
/**************************************************************************/
/* */
/* FUNCTION RELEASE */
/* */
/* _gx_utility_4444argb_pixelmap_simple_rotate PORTABLE C */
/* 6.1 */
/* AUTHOR */
/* */
/* Kenneth Maxwell, Microsoft Corporation */
/* */
/* DESCRIPTION */
/* */
/* 4444argb pixelmap rotation function that handles 90, 180 and 270 */
/* degree case. */
/* */
/* INPUT */
/* */
/* src The pixelmap to be rotated */
/* angle The angle to be rotated */
/* destination The rotated bitmap to be */
/* returned */
/* rot_cx X coordinate of rotation */
/* center */
/* rot_cy Y coordinate of rotation */
/* center */
/* */
/* OUTPUT */
/* */
/* status Completion status */
/* */
/* CALLS */
/* */
/* _gx_system_memory_allocator Application defined memory */
/* allocation function */
/* */
/* CALLED BY */
/* */
/* GUIX Internal Code */
/* */
/* RELEASE HISTORY */
/* */
/* DATE NAME DESCRIPTION */
/* */
/* 05-19-2020 Kenneth Maxwell Initial Version 6.0 */
/* 09-30-2020 Kenneth Maxwell Modified comment(s), */
/* resulting in version 6.1 */
/* */
/**************************************************************************/
UINT _gx_utility_4444argb_pixelmap_simple_rotate(GX_PIXELMAP *src, INT angle, GX_PIXELMAP *destination, INT *rot_cx, INT *rot_cy)
{
USHORT *put;
USHORT *get;
INT width;
INT height;
INT x;
INT y;
width = src -> gx_pixelmap_height;
height = src -> gx_pixelmap_width;
/* Safe int math is not required here, calling function limits max width, height to 14 bits so
overflow cannot occur. */
destination -> gx_pixelmap_data_size = (UINT)(width * height) * sizeof(USHORT);
destination -> gx_pixelmap_data = (GX_UBYTE *)_gx_system_memory_allocator(destination -> gx_pixelmap_data_size);
if (destination -> gx_pixelmap_data == GX_NULL)
{
return GX_SYSTEM_MEMORY_ERROR;
}
if (angle == 90)
{
put = (USHORT *)destination -> gx_pixelmap_data;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
get = (USHORT *)src -> gx_pixelmap_data;
get += (width - 1 - x) * height;
get += y;
*put++ = *get;
}
}
if (rot_cx && rot_cy)
{
x = *rot_cx;
y = *rot_cy;
/* Get new rotation point. */
*rot_cx = (width - 1 - y);
*rot_cy = x;
}
}
else if (angle == 180)
{
GX_SWAP_VALS(width, height);
put = (USHORT *)destination -> gx_pixelmap_data;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
get = (USHORT *)src -> gx_pixelmap_data;
get += (height - 1 - y) * width;
get += width - 1 - x;
*put++ = *get;
}
}
if (rot_cx && rot_cy)
{
x = *rot_cx;
y = *rot_cy;
/* Get new rotation point. */
*rot_cx = (width - 1 - x);
*rot_cy = (height - 1 - y);
}
}
else
{
/* angle = 270. */
put = (USHORT *)destination -> gx_pixelmap_data;
for (y = 0; y < height; y++)
{
for (x = 0; x < width; x++)
{
get = (USHORT *)src -> gx_pixelmap_data;
get += x * height;
get += height - 1 - y;
*put++ = *get;
}
}
if (rot_cx && rot_cy)
{
x = *rot_cx;
y = *rot_cy;
/* Get new rotation point. */
*rot_cx = y;
*rot_cy = (height - 1 - x);
}
}
destination -> gx_pixelmap_height = (GX_VALUE)height;
destination -> gx_pixelmap_width = (GX_VALUE)width;
return GX_SUCCESS;
}