Files
player/Project/Src/MyWin/MyWinCore/mywin_lcd.c
2025-07-06 18:46:13 +08:00

569 lines
15 KiB
C
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "mywin_inc.h"
WIN_LcdStruct *WIN_CreatVirtualLcd(int x_size, int y_size) {
WIN_LcdStruct *ret = mymalloc(sizeof(WIN_LcdStruct));
mymemset(ret, 0, sizeof(WIN_LcdStruct));
ret->x_size = x_size;
ret->y_size = y_size;
ret->WindowSrcX = 0;
ret->WindowSrcY = 0;
ret->WindowDstX = ret->x_size - 1;
ret->WindowDstY = ret->y_size - 1;
ret->ScreenDis = 1;
ret->BackColor = 0;
ret->Color = 0xffff;
ret->DrawMode = 1;
ret->DrawAddr = mymalloc(ret->x_size * ret->y_size * 2);
return ret;
}
void WIN_DeleteVirtualLcd(WIN_LcdStruct *lcd) {
if (lcd->DrawAddr)
myfree(lcd->DrawAddr);
myfree(lcd);
}
// 设置屏幕显示方向
void WIN_LcdSetScreenDis(WIN_LcdStruct *lcd, int d) {
if (d)
lcd->ScreenDis = 1;
else
lcd->ScreenDis = 0;
}
// 设置活动窗口
void WIN_LcdSetWindow(WIN_LcdStruct *lcd, int x_s, int y_s, int x_size,
int y_size) {
int dstx = 0;
int dsty = 0;
if (x_size < 1)
x_size = 1;
if (y_size < 1)
y_size = 1;
if (x_s > lcd->x_size - 1)
x_s = lcd->x_size - 1;
else if (x_s < 0)
x_s = 0;
if (y_s > lcd->y_size - 1)
y_s = lcd->y_size - 1;
else if (y_s < 0)
y_s = 0;
dstx = x_s + x_size - 1;
dsty = y_s + y_size - 1;
if (dstx > lcd->x_size - 1)
dstx = lcd->x_size - 1;
else if (dstx < 0)
dstx = 0;
if (dsty > lcd->y_size - 1)
dsty = lcd->y_size - 1;
else if (dsty < 0)
dsty = 0;
lcd->WindowSrcX = x_s;
lcd->WindowSrcY = y_s;
lcd->WindowDstX = dstx;
lcd->WindowDstY = dsty;
}
int WIN_LcdGetWindowSizeX(WIN_LcdStruct *lcd) {
return lcd->WindowDstX - lcd->WindowSrcX + 1;
}
int WIN_LcdGetWindowSizeY(WIN_LcdStruct *lcd) {
return lcd->WindowDstY - lcd->WindowSrcY + 1;
}
int WIN_LcdGetLcdSizeX(WIN_LcdStruct *lcd) { return lcd->x_size; }
int WIN_LcdGetLcdSizeY(WIN_LcdStruct *lcd) { return lcd->y_size; }
u32 WIN_LcdSetLcdColor(WIN_LcdStruct *lcd, u32 color) {
u32 ret = lcd->Color;
// g_lcd_struct.Color=color;
lcd->Color = COLOR888TO565(color);
return ret;
}
u32 WIN_LcdSetLcdBkColor(WIN_LcdStruct *lcd, u32 color) {
u32 ret = lcd->BackColor;
// g_lcd_struct.BackColor=color;
lcd->BackColor = COLOR888TO565(color);
return ret;
}
u32 WIN_LcdSetLcdColor16(WIN_LcdStruct *lcd, u32 color) {
u32 ret = lcd->Color;
lcd->Color = (color);
return ret;
}
u32 WIN_LcdSetLcdBkColor16(WIN_LcdStruct *lcd, u32 color) {
u32 ret = lcd->BackColor;
lcd->BackColor = (color);
return ret;
}
u32 WIN_LcdGetLcdColor(WIN_LcdStruct *lcd) {
u32 ret = lcd->Color;
return COLOR565TO888(ret);
}
u32 WIN_LcdGetLcdBkColor(WIN_LcdStruct *lcd) {
u32 ret = lcd->BackColor;
return COLOR565TO888(ret);
}
u32 WIN_LcdGetLcdColor16(WIN_LcdStruct *lcd) {
u32 ret = lcd->Color;
return ret;
}
u32 WIN_LcdGetLcdBkColor16(WIN_LcdStruct *lcd) {
u32 ret = lcd->BackColor;
return ret;
}
// 设置绘制模式1不绘制背景0绘制背景
void WIN_LcdSetLcdDrawMode(WIN_LcdStruct *lcd, int mode) {
if (mode) {
lcd->DrawMode = 1; // 此时调用画点函数时不绘制背景色
} else {
lcd->DrawMode = 0;
}
}
// 填充一条线,以窗口的起点为起点,最大填充到窗口的终点位置
static void WIN_LcdFillLine16(WIN_LcdStruct *lcd, u16 *buff, int y, int xsize) {
u16 *addr = lcd->DrawAddr;
int xsizeMax = lcd->WindowDstX + 1 - lcd->WindowSrcX;
if (xsize > xsizeMax)
xsize = xsizeMax;
if (lcd->ScreenDis) {
addr = &addr[y * lcd->x_size + lcd->WindowSrcX];
for (int x = 0; x < xsize; x++) {
addr[x] = *buff;
buff++;
}
} else {
addr = &addr[lcd->x_size * lcd->y_size - 1 -
(y * lcd->x_size + lcd->WindowSrcX)];
for (int x = 0; x < xsize; x++) {
*addr-- = *buff;
buff++;
}
}
}
// 把图像填充到屏幕的活动窗口中,
// 参数xsize,图像的宽度
// 参数ysize,图像的高度
static void WIN_LcdFillRect16(WIN_LcdStruct *lcd, u16 *buff, int xsize,
int ysize) {
int ysizeMax = lcd->WindowDstY + 1 - lcd->WindowSrcY;
if (ysize > ysizeMax)
ysize = ysizeMax;
for (int y = 0; y < ysize; y++) {
WIN_LcdFillLine16(lcd, buff, y + lcd->WindowSrcY, xsize);
buff += xsize;
}
}
// 把图像偏移之后填充到屏幕的活动窗口中,
// 参数x_s,图像要显示的横向起始坐标
// 参数y_s图像要显示的纵向起始坐标
// 参数xsize,图像的宽度
// 参数ysize,图像的高度
static void WIN_LcdFillRectOff16(WIN_LcdStruct *lcd, u16 *buff, int x_s,
int y_s, int xsize, int ysize) {
int offset = y_s * xsize + x_s;
WIN_LcdFillRect16(lcd, buff + offset, xsize, ysize - y_s);
}
// 在活动窗口的指定位置显示图片
// 参数s_x,图像在绘图窗口中的坐标
// 参数s_y,图像在绘图冲口中的坐标
// 参数s_xsize,要绘制的部分图像大小
// 参数s_ysize,要绘制的部分图像大小
// 参数x_s,图像要显示的横向起始坐标
// 参数y_s图像要显示的纵向起始坐标
// 参数xsize,图像的宽度
// 参数ysize,图像的高度
void WIN_LcdFillRectOff16At(WIN_LcdStruct *lcd, int s_x, int s_y, int s_xsize,
int s_ysize, u16 *buff, int x_s, int y_s, int xsize,
int ysize) {
// 保存以前的窗口大小
int w_x = lcd->WindowSrcX;
int w_y = lcd->WindowSrcY;
int w_x_e = lcd->WindowDstX;
int w_y_e = lcd->WindowDstY;
// 设置新的窗口大小
lcd->WindowSrcX = w_x + s_x;
lcd->WindowSrcY = w_y + s_y;
lcd->WindowDstX = lcd->WindowSrcX + s_xsize - 1;
lcd->WindowDstY = lcd->WindowSrcY + s_ysize - 1;
// 限制新的绘图区不能在以前的窗口之外
if (lcd->WindowDstX > w_x_e)
lcd->WindowDstX = w_x_e;
if (lcd->WindowDstY > w_y_e)
lcd->WindowDstY = w_y_e;
// 绘图
WIN_LcdFillRectOff16(lcd, buff, x_s + s_x, y_s + s_y, xsize, ysize);
// 恢复以前的绘图区
lcd->WindowSrcX = w_x;
lcd->WindowSrcY = w_y;
lcd->WindowDstX = w_x_e;
lcd->WindowDstY = w_y_e;
}
// 安全画点,以屏幕窗口的坐标为原点,并且画点不会超出窗口范围
void WIN_LcdDrawPointSafe(WIN_LcdStruct *lcd, int x, int y, int mode) {
x += lcd->WindowSrcX;
y += lcd->WindowSrcY;
// 在窗口以外的不画
if (x < lcd->WindowSrcX || x > lcd->WindowDstX)
return;
if (y < lcd->WindowSrcY || y > lcd->WindowDstY)
return;
u16 *DrawAddr = lcd->DrawAddr;
if (mode) {
if (lcd->ScreenDis)
DrawAddr[(y * lcd->x_size + x)] = lcd->Color;
else
DrawAddr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)] =
lcd->Color;
} else if (lcd->DrawMode == 0) {
if (lcd->ScreenDis)
DrawAddr[(y * lcd->x_size + x)] = lcd->BackColor;
else
DrawAddr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)] =
lcd->BackColor;
} else // 当g_lcd_struct.DrawMode==1时不绘制背景色
{
}
}
// 安全画点,以屏幕窗口的坐标为原点,并且画点不会超出窗口范围
// 以指定颜色画点,而不是前景色
void WIN_LcdDrawPointSafeColor(WIN_LcdStruct *lcd, int x, int y, u16 color) {
x += lcd->WindowSrcX;
y += lcd->WindowSrcY;
// 在窗口以外的不画
if (x < lcd->WindowSrcX || x > lcd->WindowDstX)
return;
if (y < lcd->WindowSrcY || y > lcd->WindowDstY)
return;
u16 *DrawAddr = lcd->DrawAddr;
if (1) {
if (lcd->ScreenDis)
DrawAddr[(y * lcd->x_size + x)] = color;
else
DrawAddr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)] = color;
}
}
// 快速ALPHA BLENDING算法.
// src:源颜色
// dst:目标颜色
// alpha:透明程度(0~32)
// 返回值:混合后的颜色.
static u16 alpha_blend565(u16 src, u16 dst, u8 alpha) {
u32 src2;
u32 dst2;
// Convert to 32bit |-----GGGGGG-----RRRRR------BBBBB|
src2 = ((src << 16) | src) & 0x07E0F81F;
dst2 = ((dst << 16) | dst) & 0x07E0F81F;
// Perform blending R:G:B with alpha in range 0..32
// Note that the reason that alpha may not exceed 32 is that there are only
// 5bits of space between each R:G:B value, any higher value will overflow
// into the next component and deliver ugly result.
dst2 = ((((dst2 - src2) * alpha) >> 5) + src2) & 0x07E0F81F;
return (dst2 >> 16) | dst2;
}
// 以指定色透明度画点0~32,0,全透明31不透明
void WIN_LcdDrawPointSafeColorAlpha(WIN_LcdStruct *lcd, int x, int y, u16 color,
u8 alpha) {
x += lcd->WindowSrcX;
y += lcd->WindowSrcY;
// 在窗口以外的不画
if (x < lcd->WindowSrcX || x > lcd->WindowDstX)
return;
if (y < lcd->WindowSrcY || y > lcd->WindowDstY)
return;
if (alpha > 31)
alpha = 31;
if (alpha == 0)
return;
u16 *DrawAddr = lcd->DrawAddr;
u16 color_old = 0;
if (1) {
if (lcd->ScreenDis) {
color_old = DrawAddr[(y * lcd->x_size + x)];
color = alpha_blend565(color_old, color, alpha);
DrawAddr[(y * lcd->x_size + x)] = color;
} else {
color_old =
DrawAddr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)];
color = alpha_blend565(color_old, color, alpha);
DrawAddr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)] = color;
}
}
}
// 填充矩形,已窗口坐标为原点
void WIN_LcdFillRectByColor(WIN_LcdStruct *lcd, int x, int y, int x_size,
int y_size) {
for (int i = y; i < y + y_size; i++) {
for (int j = x; j < x + x_size; j++) {
WIN_LcdDrawPointSafe(lcd, j, i, 1);
}
}
}
// 以透明度填充矩形,已窗口坐标为原点
void WIN_LcdFillRectByColorAlpha(WIN_LcdStruct *lcd, int x, int y, int x_size,
int y_size, u8 alpha) {
for (int i = y; i < y + y_size; i++) {
for (int j = x; j < x + x_size; j++) {
WIN_LcdDrawPointSafeColorAlpha(lcd, j, i, lcd->Color, alpha);
}
}
}
// 绘制图标,图标使用const数组编译在程序里其本身已经附带了大小等参数
// 此函数效率比较低,只用于绘制小图标,绘制图片使用矩形填充函数
void WIN_LcdDrawImag(WIN_LcdStruct *lcd, int x, int y, int xsize, int ysize,
const u8 *buff) {
if (buff == 0)
return;
u8 scan = buff[0];
u8 gray = buff[1];
u16 w = *((u16 *)&buff[2]);
u16 h = *((u16 *)&buff[4]);
u8 is565 = buff[6];
u8 rgb = buff[7];
// 必须所有参数都符合要求
if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) ||
(h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b))
return;
u16 *imag = (u16 *)(buff + 8);
if (xsize > w)
xsize = w;
if (ysize > h)
ysize = h;
for (int j = y; j < y + ysize; j++) {
for (int i = 0; i < xsize; i++) {
WIN_LcdDrawPointSafe(lcd, i + x, j, imag[i]);
}
imag += w;
}
}
// 绘制图标,但是不绘制指定颜色
void WIN_LcdDrawImagButColor(WIN_LcdStruct *lcd, int x, int y, int xsize,
int ysize, const u8 *buff, u16 color) {
if (buff == 0)
return;
u8 scan = buff[0];
u8 gray = buff[1];
u16 w = *((u16 *)&buff[2]);
u16 h = *((u16 *)&buff[4]);
u8 is565 = buff[6];
u8 rgb = buff[7];
// 必须所有参数都符合要求
if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) ||
(h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b))
return;
u16 *imag = (u16 *)(buff + 8);
if (xsize > w)
xsize = w;
if (ysize > h)
ysize = h;
for (int j = y; j < y + ysize; j++) {
for (int i = 0; i < xsize; i++) {
if (imag[i] != color)
WIN_LcdDrawPointSafe(lcd, i + x, j, imag[i]);
}
imag += w;
}
}
// 绘制图标,把图像的有效部分绘制为指定颜色
// 此函数效率比较低,只用于绘制小图标,绘制图片使用矩形填充函数
void WIN_LcdDrawImagByColor(WIN_LcdStruct *lcd, int x, int y, int xsize,
int ysize, const u8 *buff, u16 color) {
if (buff == 0)
return;
u8 scan = buff[0];
u8 gray = buff[1];
u16 w = *((u16 *)&buff[2]);
u16 h = *((u16 *)&buff[4]);
u8 is565 = buff[6];
u8 rgb = buff[7];
// 必须所有参数都符合要求
if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) ||
(h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b))
return;
u16 *imag = (u16 *)(buff + 8);
if (xsize > w)
xsize = w;
if (ysize > h)
ysize = h;
for (int j = y; j < y + ysize; j++) {
for (int i = 0; i < xsize; i++) {
if ((imag[i] != 0x0000) && (imag[i] != 0xffff))
WIN_LcdDrawPointSafeColor(lcd, i + x, j, color);
}
imag += w;
}
}
// 绘制图标,把原图像转化为透明度,用指定颜色来绘制
// 此函数效率比较低,只用于绘制小图标,绘制图片使用矩形填充函数
void WIN_LcdDrawImagByAlpha(WIN_LcdStruct *lcd, int x, int y, int xsize,
int ysize, const u8 *buff, u16 color) {
if (buff == 0)
return;
u8 scan = buff[0];
u8 gray = buff[1];
u16 w = *((u16 *)&buff[2]);
u16 h = *((u16 *)&buff[4]);
u8 is565 = buff[6];
u8 rgb = buff[7];
// 必须所有参数都符合要求
if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) ||
(h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b))
return;
u16 *imag = (u16 *)(buff + 8);
u8 r, g, b;
u8 alpha = 0;
if (xsize > w)
xsize = w;
if (ysize > h)
ysize = h;
for (int j = y; j < y + ysize; j++) {
for (int i = 0; i < xsize; i++) {
// 只绘制无效窗口内的屏幕
// WIN_Struct *ewin=WIN_GetWinStruct();
// if (POS_InRect
//(ewin->Invalid_x,ewin->Invalid_y,ewin->Invalid_x_size,ewin->Invalid_y_size,i+x,j))
{
// 白色全透明不绘制,加快速度
if ((imag[i] != 0x0000) && (imag[i] != 0xffff)) {
WIN_LcdDrawPointSafeColorAlpha(lcd, i + x, j, color,
31 - (imag[i] >> 11));
} else if (imag[i] == 0x0000) {
// 不透明直接画原来的颜色
WIN_LcdDrawPointSafeColor(lcd, i + x, j, color);
}
}
}
imag += w;
}
}
// 清除绘图窗口内的显示
void WIN_LcdClear(WIN_LcdStruct *lcd) {
u16 *addr = lcd->DrawAddr;
for (int y = lcd->WindowSrcY; y <= lcd->WindowDstY; y++) {
if (lcd->ScreenDis) {
for (int x = lcd->WindowSrcX; x <= lcd->WindowDstX; x++) {
addr[(y * lcd->x_size + x)] = lcd->BackColor;
}
} else {
for (int x = lcd->WindowSrcX; x <= lcd->WindowDstX; x++) {
addr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)] =
lcd->BackColor;
}
}
}
}
// 清除矩形内的显示
void WIN_LcdClearRect(WIN_LcdStruct *lcd, int x, int y, int x_size,
int y_size) {
u16 *addr = lcd->DrawAddr;
x = x + lcd->WindowSrcX;
y = y + lcd->WindowSrcY;
int x_e = x + x_size - 1;
if (x_e > lcd->WindowDstX)
x_e = lcd->WindowDstX;
int y_e = y + y_size - 1;
if (y_e > lcd->WindowDstY)
y_e = lcd->WindowDstY;
int temp = x;
for (; y <= y_e; y++) {
if (lcd->ScreenDis) {
for (x = temp; x <= x_e; x++) {
addr[(y * lcd->x_size + x)] = lcd->BackColor;
}
} else {
for (x = temp; x <= x_e; x++) {
addr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)] =
lcd->BackColor;
}
}
}
}
// 获取指定矩形空间的屏幕颜色,屏幕的绝对坐标
void WIN_LcdGetColors(WIN_LcdStruct *lcd, u16 *buff, int x_s, int y_s,
int x_size, int y_size) {
u16 *addr = lcd->DrawAddr;
if (x_s < 0)
x_s = 0;
else if (x_s > lcd->x_size - 1)
x_s = lcd->x_size - 1;
if (y_s < 0)
y_s = 0;
else if (y_s > lcd->y_size - 1)
y_s = lcd->y_size - 1;
if (x_size > lcd->x_size - x_s)
x_size = lcd->x_size - x_s;
else if (x_size < 0)
x_size = 0;
if (y_size > lcd->y_size - y_s)
y_size = lcd->y_size - y_s;
else if (y_size < 0)
y_size = 0;
for (int y = y_s; y < y_size + y_s; y++) {
if (lcd->ScreenDis) {
for (int x = x_s; x < x_size + x_s; x++) {
u32 temp = addr[(y * lcd->x_size + x)];
*buff = temp;
buff++;
}
} else {
for (int x = x_s; x < x_size + x_s; x++) {
u32 temp = addr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)];
*buff = temp;
buff++;
}
}
}
}