#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; } uint32_t WIN_LcdSetLcdColor(WIN_LcdStruct *lcd, uint32_t color) { uint32_t ret = lcd->Color; // g_lcd_struct.Color=color; lcd->Color = COLOR888TO565(color); return ret; } uint32_t WIN_LcdSetLcdBkColor(WIN_LcdStruct *lcd, uint32_t color) { uint32_t ret = lcd->BackColor; // g_lcd_struct.BackColor=color; lcd->BackColor = COLOR888TO565(color); return ret; } uint32_t WIN_LcdSetLcdColor16(WIN_LcdStruct *lcd, uint32_t color) { uint32_t ret = lcd->Color; lcd->Color = (color); return ret; } uint32_t WIN_LcdSetLcdBkColor16(WIN_LcdStruct *lcd, uint32_t color) { uint32_t ret = lcd->BackColor; lcd->BackColor = (color); return ret; } uint32_t WIN_LcdGetLcdColor(WIN_LcdStruct *lcd) { uint32_t ret = lcd->Color; return COLOR565TO888(ret); } uint32_t WIN_LcdGetLcdBkColor(WIN_LcdStruct *lcd) { uint32_t ret = lcd->BackColor; return COLOR565TO888(ret); } uint32_t WIN_LcdGetLcdColor16(WIN_LcdStruct *lcd) { uint32_t ret = lcd->Color; return ret; } uint32_t WIN_LcdGetLcdBkColor16(WIN_LcdStruct *lcd) { uint32_t 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, uint16_t *buff, int y, int xsize) { uint16_t *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, uint16_t *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, uint16_t *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, uint16_t *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; uint16_t *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, uint16_t color) { x += lcd->WindowSrcX; y += lcd->WindowSrcY; // 在窗口以外的不画 if (x < lcd->WindowSrcX || x > lcd->WindowDstX) return; if (y < lcd->WindowSrcY || y > lcd->WindowDstY) return; uint16_t *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 uint16_t alpha_blend565(uint16_t src, uint16_t dst, uint8_t alpha) { uint32_t src2; uint32_t 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, uint16_t color, uint8_t 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; uint16_t *DrawAddr = lcd->DrawAddr; uint16_t 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, uint8_t 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 uint8_t *buff) { if (buff == 0) return; uint8_t scan = buff[0]; uint8_t gray = buff[1]; uint16_t w = *((uint16_t *)&buff[2]); uint16_t h = *((uint16_t *)&buff[4]); uint8_t is565 = buff[6]; uint8_t rgb = buff[7]; // 必须所有参数都符合要求 if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) || (h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b)) return; uint16_t *imag = (uint16_t *)(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 uint8_t *buff, uint16_t color) { if (buff == 0) return; uint8_t scan = buff[0]; uint8_t gray = buff[1]; uint16_t w = *((uint16_t *)&buff[2]); uint16_t h = *((uint16_t *)&buff[4]); uint8_t is565 = buff[6]; uint8_t rgb = buff[7]; // 必须所有参数都符合要求 if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) || (h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b)) return; uint16_t *imag = (uint16_t *)(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 uint8_t *buff, uint16_t color) { if (buff == 0) return; uint8_t scan = buff[0]; uint8_t gray = buff[1]; uint16_t w = *((uint16_t *)&buff[2]); uint16_t h = *((uint16_t *)&buff[4]); uint8_t is565 = buff[6]; uint8_t rgb = buff[7]; // 必须所有参数都符合要求 if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) || (h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b)) return; uint16_t *imag = (uint16_t *)(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 uint8_t *buff, uint16_t color) { if (buff == 0) return; uint8_t scan = buff[0]; uint8_t gray = buff[1]; uint16_t w = *((uint16_t *)&buff[2]); uint16_t h = *((uint16_t *)&buff[4]); uint8_t is565 = buff[6]; uint8_t rgb = buff[7]; // 必须所有参数都符合要求 if ((scan != 0x00) || (gray != 0x10) || (w > WIN_IMAGE_MAXSIZE) || (h > WIN_IMAGE_MAXSIZE) || (is565 != 0x01) || (rgb != 0x1b)) return; uint16_t *imag = (uint16_t *)(buff + 8); uint8_t r, g, b; uint8_t 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) { uint16_t *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) { uint16_t *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, uint16_t *buff, int x_s, int y_s, int x_size, int y_size) { uint16_t *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++) { uint32_t temp = addr[(y * lcd->x_size + x)]; *buff = temp; buff++; } } else { for (int x = x_s; x < x_size + x_s; x++) { uint32_t temp = addr[lcd->x_size * lcd->y_size - 1 - (y * lcd->x_size + x)]; *buff = temp; buff++; } } } }