标签:picture,相册,int,画图,ts,bmp,pos,&&,刮乐 From: https://blog.csdn.net/2401_86344273/article/details/142148571#include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> #include <unistd.h> #include <stdio.h> #include <sys/mman.h> //mmap #include <linux/input.h> #include <string.h> #include <pthread.h> #include <stdlib.h> typedef short WORD; typedef int DWORD; typedef long LONG; typedef struct tagBITMAPFILEHEADER { WORD bfType; // 位图文件的类型,必须为BM(1-2字节) DWORD bfSize; // 位图文件的大小,以字节为单位(3-6字节,低位在前) WORD bfReserved1; // 位图文件保留字,必须为0(7-8字节) WORD bfReserved2; // 位图文件保留字,必须为0(9-10字节) DWORD bfOffBits; // 位图数据的起始位置,以相对于位图(11-14字节,低位在前) // 文件头的偏移量表示,以字节为单位 } __attribute__((packed)) BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; // 本结构所占用字节数(15-18字节) LONG biWidth; // 位图的宽度,以像素为单位(19-22字节)【*】 LONG biHeight; // 位图的高度,以像素为单位(23-26字节)【*】 WORD biPlanes; // 目标设备的级别,必须为1(27-28字节) WORD biBitCount; // 每个像素所需的位数,必须是1(双色),(29-30字节)【*】 // 4(16色),8(256色)16(高彩色)或24(真彩色)之一 DWORD biCompression; // 位图压缩类型,必须是0(不压缩),(31-34字节) // 1(BI_RLE8压缩类型)或2(BI_RLE4压缩类型)之一 DWORD biSizeImage; // 位图的大小(其中包含了为了补齐列数是4的倍数而添加的空字节),以字节为单位(35-38字节) LONG biXPelsPerMeter; // 位图水平分辨率,每米像素数(39-42字节) LONG biYPelsPerMeter; // 位图垂直分辨率,每米像素数(43-46字节) DWORD biClrUsed; // 位图实际使用的颜色表中的颜色数(47-50字节) DWORD biClrImportant; // 位图显示过程中重要的颜色数(51-54字节) } __attribute__((packed)) BITMAPINFOHEADER; #define LCD_WIDTH 800 #define LCD_HEIGHT 480 #define RGB(r, g, b) ((r << 16) | (g << 8) | b) // 定义颜色宏 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) // 数组长度 char color_buf[800 * 480 * 4] = {0}; // 颜色缓存器 unsigned int *g_fb = NULL; // 指向显存的首地址 int g_fd_lcd; // 显存文件描述符 int g_fd_ts; // 触摸屏文件描述符 /*菜单结构体*/ typedef struct _menu_t { const char *name; // 菜单的名字 int (*fun)(void); // 菜单执行的功能函数 struct _menu_t *parent; // 父菜单 struct _menu_t *child; // 子菜单 } menu_t; // 触摸屏坐标结构体 typedef struct _ts_pos_t { int x; int y; int sta; } ts_pos_t; // 描点操作 void lcd_draw_point(int x, int y, unsigned int color) { *(g_fb + y * 800 + x) = color; } // 清屏操作 void lcd_clear(unsigned int color) { int x, y; for (y = 479; y >= 0; y--) { for (x = 0; x < 800; x++) { // 对每个像素点进行赋值 lcd_draw_point(x, y, color); } } } // 填充函数 void lcd_fill(int x, int y, int width, int height, unsigned int color) { int x_s = x; int y_s = y; int x_e = x + width; int y_e = y + height; if (x_e > LCD_WIDTH) // 防止越界 x_e = LCD_WIDTH; if (y_e > LCD_HEIGHT) y_e = LCD_HEIGHT; for (y = y_s; y < y_e; y++) { for (x = x_s; x < x_e; x++) { // 对每个像素点进行赋值 lcd_draw_point(x, y, color); } } } // 位图显示 int lcd_draw_bmp(const char *pathname, int x, int y) { // 打开 bmp int fd_bmp = open(pathname, O_RDONLY); if (fd_bmp < 0) { printf("open %s fail\n", pathname); return -1; } // 位图文件头 BITMAPFILEHEADER file_head; read(fd_bmp, &file_head, sizeof(file_head)); printf("%s图片大小:%d bytes\n", pathname, file_head.bfSize); // 位图信息段,获取位图的高度、宽度、颜色深度 BITMAPINFOHEADER info_head; read(fd_bmp, &info_head, sizeof(info_head)); printf("%s图片尺寸:宽%ld 高%ld\n", pathname, info_head.biWidth, info_head.biHeight); printf("%s图片颜色深度:%d\n", pathname, info_head.biBitCount); int bmp_rgb_size = info_head.biWidth * info_head.biHeight * info_head.biBitCount / 8; // 定义一个变长数组 char bmp_buf[bmp_rgb_size]; // 读取该bmp的所有RGB的数据 read(fd_bmp, bmp_buf, bmp_rgb_size); // 关闭bmp文件 close(fd_bmp); // 开始显示图片 int x_s = x; int y_s = y; int x_e = x_s + info_head.biWidth; int y_e = y_s + info_head.biHeight; int x_pos, y_pos; unsigned int color; int i = 0; for (y_pos = y_e - 1; y_pos >= y_s; y_pos--) { for (x_pos = x_s; x_pos < x_e; x_pos++, i += 3) { color = (bmp_buf[i + 2] << 16) | (bmp_buf[i + 1] << 8) | bmp_buf[i]; lcd_draw_point(x_pos, y_pos, color); } } return 0; } int lcd_draw_game(const char *pathname, int x, int y) { // 打开 bmp int fd_bmp = open(pathname, O_RDONLY); if (fd_bmp < 0) { printf("open %s fail\n", pathname); return -1; } // 位图文件头 BITMAPFILEHEADER file_head; read(fd_bmp, &file_head, sizeof(file_head)); printf("%s图片大小:%d bytes\n", pathname, file_head.bfSize); // 位图信息段,获取位图的高度、宽度、颜色深度 BITMAPINFOHEADER info_head; read(fd_bmp, &info_head, sizeof(info_head)); printf("%s图片尺寸:宽%ld 高%ld\n", pathname, info_head.biWidth, info_head.biHeight); printf("%s图片颜色深度:%d\n", pathname, info_head.biBitCount); int bmp_rgb_size = info_head.biWidth * info_head.biHeight * info_head.biBitCount / 8; // 定义一个变长数组 char bmp_buf[bmp_rgb_size]; // 读取该bmp的所有RGB的数据 read(fd_bmp, bmp_buf, bmp_rgb_size); // 关闭bmp文件 close(fd_bmp); // 开始显示图片 int x_s = x; int y_s = y; int x_e = x_s + info_head.biWidth; int y_e = y_s + info_head.biHeight; int x_pos, y_pos; unsigned int color; int i = 0; for (y_pos = y_e - 1; y_pos >= y_s; y_pos--) { for (x_pos = x_s; x_pos < x_e; x_pos++, i += 3) { color = (bmp_buf[i + 2] << 16) | (bmp_buf[i + 1] << 8) | bmp_buf[i]; if (color == 0xFFFFFF) continue; lcd_draw_point(x_pos, y_pos, color); } } return 0; } // 打开显存 int lcd_open(const char *pathname) { // 打开/dev/fb0 int g_fd_lcd = open(pathname, O_RDWR); if (g_fd_lcd < 0) { printf("open %s fail\n", pathname); return -1; } // 将设备文件/dev/fb0映射到内存 g_fb = mmap(NULL, // 映射区的起始地址由系统自动分配 800 * 480 * 4, // 映射内存的大小,往往填写文件的大小 PROT_READ | PROT_WRITE, // 映射区的保护形式,当前是可读可写 MAP_SHARED, // 共享,把映射内存的数据同步到文件 g_fd_lcd, // 映射的文件描述符 0); // 文件的偏移量,0就不需要进行的偏移 if (g_fb == MAP_FAILED) { printf("mmap fail\n"); return -1; } return 0; } int lcd_close(void) { if (g_fd_lcd > 0) close(g_fd_lcd); // 解除内存映射 if (g_fb) munmap(g_fb, 800 * 480 * 4); return 0; } int ts_open(const char *pathname) { // 打开触摸屏设备 g_fd_ts = open(pathname, O_RDONLY); if (g_fd_ts < 0) { perror("open"); return -1; } return 0; } int ts_close(void) { if (g_fd_ts > 0) close(g_fd_ts); return 0; } int ts_read(int *x, int *y, int *sta) { if (g_fd_ts < 0) return -1; struct input_event ie; while (1) { read(g_fd_ts, &ie, sizeof(ie)); // 绝对坐标的事件 if (ie.type == EV_ABS) { if (ie.code == ABS_X) *x = ie.value * 800 / 1024; // 黑色边框的触摸屏需要*800/1024 if (ie.code == ABS_Y) *y = ie.value * 480 / 600; // 黑色边框的触摸屏需要*800/1024 } if (ie.type == EV_KEY && ie.code == BTN_TOUCH) { *sta = ie.value; break; } } return 0; } menu_t menu_startup; menu_t menu_login; menu_t menu_main; int menu_startup_func(void) // 开机界面 { int x = 0, y = 0; int ts_x, ts_y, ts_sta; int ts_x_press, ts_y_press; int rt; // 显示开机界面 lcd_draw_bmp("picture/startup.bmp", 0, 0); sleep(1); // 显示开车蹦迪进度条 int bmp_width = 140; int bmp_height = 140; y = LCD_HEIGHT - bmp_height; int i = 0; const char *bmp_tbl[] = { "picture/boot_animation/1.bmp", "picture/boot_animation/2.bmp", "picture/boot_animation/3.bmp", "picture/boot_animation/4.bmp", "picture/boot_animation/5.bmp", "picture/boot_animation/6.bmp", "picture/boot_animation/7.bmp", "picture/boot_animation/8.bmp", "picture/boot_animation/9.bmp", "picture/boot_animation/10.bmp", }; while (1) { rt = ts_read(&ts_x, &ts_y, &ts_sta); if (rt < 0) continue; printf("上滑登录"); if (ts_sta) { ts_x_press = ts_x; ts_y_press = ts_y; continue; } else if (ts_y_press - ts_y > 80) { printf("向上滑动\n"); break; } } while (x + bmp_width < LCD_WIDTH) { // 填充背景色,清空残留的图像 lcd_fill(0, y, x + bmp_width, bmp_height, RGB(246, 244, 249)); // 显示开车蹦迪 lcd_draw_bmp(bmp_tbl[i % 10], x, y); // 图片往前移动30个像素点 x += 30; // 延时50ms usleep(50 * 1000); // 指定下一张开车蹦迪的图片 i++; } return 0; } int menu_login_func(void) // 登录界面 { int ts_x, ts_y, ts_sta; int rt; char pass_correct[6] = {'1', '2', '3', '4', '5', '6'}; char pass_input[7] = {0}; char pass_cnt = 0; lcd_draw_bmp("picture/login.bmp", 0, 0); while (1) { rt = ts_read(&ts_x, &ts_y, &ts_sta); if (rt < 0) continue; printf("ts_x:%d ts_y:%d ts_sta:%d\n", ts_x, ts_y, ts_sta); // 若是按压状态,则重新新的一轮循化 if (ts_sta) continue; if (ts_x > 295 && ts_x < 375 && ts_y > 345 && ts_y < 460) // 隐藏入口 break; if (ts_x >= 175 && ts_x <= 255) // 最右列:369Y { if (ts_y >= 285 && ts_y <= 365) // Y { if (memcmp(pass_correct, pass_input, 6) == 0) { lcd_draw_bmp("picture/yes.bmp", 300, 200); sleep(1); printf("密码正确\n"); break; } lcd_draw_bmp("picture/no.bmp", 300, 200); sleep(1); printf("密码错误,请重新输入...\n"); lcd_draw_bmp("picture/login.bmp", 0, 0); pass_cnt = 0; memset(pass_input, 0, sizeof(pass_input)); continue; } if (ts_y >= 205 && ts_y <= 285) // 9 { pass_input[pass_cnt] = '9'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 125 && ts_y <= 205) // 6 { pass_input[pass_cnt] = '6'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 50 && ts_y <= 125) // 3 { pass_input[pass_cnt] = '3'; if (pass_cnt < 5) pass_cnt++; } printf("当前输入的密码:%s\n", pass_input); } if (ts_x >= 85 && ts_x <= 175) // 中间列:2580 { if (ts_y >= 285 && ts_y <= 365) // 0 { pass_input[pass_cnt] = '0'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 205 && ts_y <= 285) // 8 { pass_input[pass_cnt] = '8'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 125 && ts_y <= 205) // 5 { pass_input[pass_cnt] = '5'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 50 && ts_y <= 125) // 2 { pass_input[pass_cnt] = '2'; if (pass_cnt < 5) pass_cnt++; } printf("当前输入的密码:%s\n", pass_input); } if (ts_x >= 0 && ts_x <= 85) // 最左列:147N { if (ts_y >= 285 && ts_y <= 365) // n { pass_cnt = 0; memset(pass_input, 0, sizeof(pass_input)); printf("已清空输入密码,请重新输入...\n"); } if (ts_y >= 205 && ts_y <= 285) // 7 { pass_input[pass_cnt] = '7'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 125 && ts_y <= 205) // 4 { pass_input[pass_cnt] = '4'; if (pass_cnt < 5) pass_cnt++; } if (ts_y >= 50 && ts_y <= 125) // 1 { pass_input[pass_cnt] = '1'; if (pass_cnt < 5) pass_cnt++; } printf("当前输入的密码:%s\n", pass_input); } if (ts_x >= 720 && ts_x <= 800 && ts_y >= 0 && ts_y <= 80) // 返回开机界面 { printf("返回开机界面\n"); return 1; } } return 0; } int icon_app1_func(void); int icon_app2_func(void); int icon_app3_func(void); int icon_app4_func(void); int menu_main_func(void) // 主界面 { int ts_x, ts_y, ts_sta; int icon_pos = 0; int rt; menu_t menu_icon_tbl[] = { {.name = "主界面", .fun = NULL, .parent = NULL, .child = NULL}, {.name = "相册", .fun = icon_app1_func, .parent = &menu_main, .child = NULL}, {.name = "游戏", .fun = icon_app2_func, .parent = &menu_main, .child = NULL}, {.name = "绘画", .fun = icon_app3_func, .parent = &menu_main, .child = NULL}, {.name = "彩票", .fun = icon_app4_func, .parent = &menu_main, .child = NULL}}; lcd_draw_bmp("picture/main.bmp", 0, 0); while (1) { rt = ts_read(&ts_x, &ts_y, &ts_sta); if (rt < 0) continue; printf("ts_x:%d ts_y:%d ts_sta:%d\n", ts_x, ts_y, ts_sta); // 若是按压状态,则重新新的一轮循环 if (ts_sta) continue; if (ts_x >= 725 && ts_x <= 800 && ts_y >= 0 && ts_y <= 70) { /* 返回1,表示进入父菜单*/ return 1; } if (ts_x >= 0 && ts_x <= 90) { if (ts_y >= 0 && ts_y <= 90) { icon_pos = 1; } else if (ts_y >= 90 && ts_y <= 175) { icon_pos = 2; } else if (ts_y >= 175 && ts_y <= 275) { icon_pos = 3; } else if (ts_y >= 275 && ts_y <= 370) { icon_pos = 4; } else { continue; } printf("运行%s\n", menu_icon_tbl[icon_pos].name); if (menu_icon_tbl[icon_pos].fun) menu_icon_tbl[icon_pos].fun(); icon_pos = 0; lcd_draw_bmp("picture/main.bmp", 0, 0); } } return 0; } void *thread_game_func(void *parg) // 游戏线程 { ts_pos_t *ts_pos = (ts_pos_t *)parg; lcd_draw_bmp("picture/game_animation/game.bmp", 0, 0); const char *bmp_game_pet[] = { "picture/game_animation/pet/1.bmp", "picture/game_animation/pet/2.bmp", "picture/game_animation/pet/3.bmp", "picture/game_animation/pet/4.bmp", "picture/game_animation/pet/5.bmp", "picture/game_animation/pet/6.bmp", "picture/game_animation/pet/7.bmp", "picture/game_animation/pet/8.bmp", }; printf("thread_game_func is created success\n"); int i = 0; int x = 660, y = 330; int b = 0; int energy = 100; // 能量值 while (1) { // 显示游戏背景图 lcd_draw_bmp("picture/game_animation/game.bmp", 0, 0); // 显示宠物小精灵 lcd_draw_game(bmp_game_pet[i % 8], x, y); // 点击电灯图标补充能量值 if (ts_pos->x > 0 && ts_pos->x < 75 && ts_pos->y > 80 && ts_pos->y < 175) { printf("energy full\n"); // 满能量 energy = 100; // 清空读取到的坐标值、按压状态 bzero(ts_pos, sizeof(ts_pos_t)); } switch (energy) // 不同能量值显示不同颜色 { case 90 ... 100: lcd_fill(80, 10, 1 + energy, 30, RGB(0, 255, 0)); // 绿色 break; case 60 ... 89: lcd_fill(80, 10, 1 + energy, 30, RGB(255, 255, 0)); // 黄色 break; default: lcd_fill(80, 10, 1 + energy, 30, RGB(255, 0, 0)); // 红色 break; } if (energy >= 5) // 每次扣5点血 energy -= 5; i++; if (b) { if (x + 100 < LCD_WIDTH) x += 10; // 宠物向右移动10像素点 else b = !b; } else { if (x >= 10) // 宠物向左移动10像素点 x -= 10; else b = !b; } usleep(500 * 1000); } } int icon_app1_func(void) // 相册 { const char *bmp_photo_tbl[] = { "picture/photo_album/1.bmp", "picture/photo_album/2.bmp", "picture/photo_album/3.bmp", "picture/photo_album/4.bmp", "picture/photo_album/5.bmp", "picture/photo_album/6.bmp", "picture/photo_album/7.bmp", "picture/photo_album/8.bmp", "picture/photo_album/9.bmp", "picture/photo_album/10.bmp", "picture/photo_album/11.bmp", "picture/photo_album/12.bmp", "picture/photo_album/13.bmp", "picture/photo_album/14.bmp", "picture/photo_album/15.bmp", "picture/photo_album/16.bmp", "picture/photo_album/17.bmp", "picture/photo_album/18.bmp", "picture/photo_album/19.bmp", "picture/photo_album/20.bmp", "picture/photo_album/21.bmp", "picture/photo_album/22.bmp", "picture/photo_album/23.bmp", "picture/photo_album/24.bmp", "picture/photo_album/25.bmp", "picture/photo_album/26.bmp", "picture/photo_album/27.bmp", "picture/photo_album/28.bmp", }; printf("icon_app1_func\n"); int i = 0; int ts_x_press, ts_y_press; int ts_x, ts_y, ts_sta; int rt; lcd_draw_bmp(bmp_photo_tbl[0], 0, 0); while (1) { rt = ts_read(&ts_x, &ts_y, &ts_sta); if (rt < 0) continue; printf("[app1] ts_x:%d ts_y:%d ts_sta:%d\n", ts_x, ts_y, ts_sta); // 保存点击后的坐标 if (ts_sta) { ts_x_press = ts_x; ts_y_press = ts_y; continue; } else { // 左滑切换上一张图片 if (ts_x - ts_x_press < -90) { i--; if (i < 0) i = 27; lcd_draw_bmp(bmp_photo_tbl[i], 0, 0); printf("向左滑动\n"); } // 右滑切换下一张图片 if (ts_x - ts_x_press > 90) { i++; if (i > 27) i = 0; lcd_draw_bmp(bmp_photo_tbl[i], 0, 0); printf("向右滑动\n"); } // 下滑退出 if (ts_y - ts_y_press > 150) { printf("向下滑动\n"); break; } } } return 1; } int icon_app2_func(void) // 游戏 { const char *bmp_game_tbl[] = { "picture/game_animation/1.bmp", "picture/game_animation/2.bmp", "picture/game_animation/3.bmp", "picture/game_animation/4.bmp", "picture/game_animation/5.bmp", "picture/game_animation/6.bmp", "picture/game_animation/7.bmp", "picture/game_animation/8.bmp", "picture/game_animation/9.bmp", "picture/game_animation/10.bmp", "picture/game_animation/11.bmp", }; printf("icon_app2_func\n"); int i; int ts_x, ts_y, ts_sta; int rt; // 显示游戏进入动画 for (i = 0; i < ARRAY_SIZE(bmp_game_tbl); i++) { lcd_draw_bmp(bmp_game_tbl[i], 0, 0); usleep(30 * 1000); } pthread_t tid; ts_pos_t ts_pos; // 创建游戏线程,并传递ts_pos参数给线程 pthread_create(&tid, NULL, thread_game_func, &ts_pos); while (1) { // 获取坐标值 rt = ts_read(&ts_x, &ts_y, &ts_sta); if (rt < 0) continue; if (ts_sta) continue; printf("[icon_func1_func] ts_x:%d ts_y:%d ts_sta:%d\n", ts_x, ts_y, ts_sta); // 设置ts_pos成员,由于其ts_pos变量地址已经传递给线程,线程可以访问到 ts_pos.x = ts_x; ts_pos.y = ts_y; ts_pos.sta = ts_sta; // 点击右上角,游戏退出 if (ts_x > 635 && ts_x < 780 && ts_y > 15 && ts_y < 60) { // 退出游戏线程 pthread_cancel(tid); break; } } return 1; } void lcd_draw_circle(unsigned r_x, unsigned int r_y, unsigned int r, unsigned int color) { unsigned int x, y; if (r_x - r < 0) { r_x = r; } if (r_y - r < 0) { r_y = r; } for (y = r_y - r; y < r_y + r; y++) { for (x = r_x - r; x < r_x + r; x++) { if ((r_x - x) * (r_x - x) + (r_y - y) * (r_y - y) <= r * r) // 判断是否大于圆的范围 { lcd_draw_point(x, y, color); } } } } int icon_app3_func(void) // 绘画 { int ts_x, ts_y, ts_sta; int ts_x_press, ts_y_press; unsigned int pen_color = RGB(0, 0, 0); int rt; int r = 10; printf("icon_app3_func\n"); lcd_draw_bmp("picture/painting.bmp", 0, 0); struct input_event ie; while (1) { rt = read(g_fd_ts, &ie, sizeof(ie)); if (rt < 0) continue; // 绝对坐标值的事件 if (ie.type == EV_ABS) { if (ie.code == ABS_X) ts_x = ie.value * 800 / 1024; if (ie.code == ABS_Y) ts_y = ie.value * 480 / 600; } if (ie.type == EV_KEY && ie.code == BTN_TOUCH) { ts_sta = ie.value; // 触摸屏点击后的释放状态 if (ts_sta == 0) { if (ts_y >= 0 && ts_y <= 65) { if (ts_x <= 73) { break; // 退出 } if (ts_x >= 73 && ts_x < 140) pen_color = RGB(255, 255, 255); // 橡皮擦 if (ts_x >= 140 && ts_x < 207) // 一键清除 { for (int i = 65; i < 480; i++) { for (int j = 0; j < 800; j++) { lcd_fill(j, i, 1, 1, RGB(255, 255, 255)); } } continue; } if (ts_x >= 207 && ts_x <= 275) { printf("画圆\n"); lcd_draw_circle(400, 260, r, pen_color); } if (ts_x >= 275 && ts_x <= 323 && r < 150) r += 5; if (ts_x >= 327 && ts_x < 377) r -= 5; // 画笔颜色选择 if (ts_x >= 380 && ts_x <= 427) pen_color = RGB(0, 0, 0); // 黑色 if (ts_x >= 431 && ts_x < 481) pen_color = RGB(255, 0, 0); // 红色 if (ts_x >= 485 && ts_x <= 535) pen_color = RGB(255, 127, 39); // 橙色 if (ts_x >= 539 && ts_x <= 587) pen_color = RGB(255, 242, 0); // 黄色 if (ts_x >= 591 && ts_x < 641) pen_color = RGB(34, 177, 76); // 绿色 if (ts_x >= 644 && ts_x <= 693) pen_color = RGB(0, 162, 232); // 蓝色 if (ts_x >= 696 && ts_x < 746) pen_color = RGB(63, 72, 204); // 深蓝色 if (ts_x >= 750 && ts_x <= 800) pen_color = RGB(163, 73, 162); // 紫色 continue; } } } if (ts_y > 65 && ts_sta) lcd_fill(ts_x, ts_y, r, r, pen_color); } return 1; } char bmp_buf[800 * 480 * 3] = {0}; // 用于接收图片颜色数据 // 读取刮刮乐的颜色数据 int *lcd_draw_ggl(const char *pathname, int x, int y) { // 打开图片文件 int fd_bmp = open(pathname, O_RDWR); if (fd_bmp == -1) { printf("open %s fail\n", pathname); return NULL; } // 位图文件头 // BITMAPFILEHEADER 结构体别名,定义一个名为file_head的结构体变量 BITMAPFILEHEADER file_head; read(fd_bmp, &file_head, sizeof(file_head)); // 光标自动移动到位图信息段头部 // printf("%s图片大小%d\n", pathconf, file_head.bfSize); // 位图信息段,获取位图的高度、宽度、颜色深度 // BITMAPINFOHEADER 结构体别名,定义一个名为info_head的结构体变量 BITMAPINFOHEADER info_head; read(fd_bmp, &info_head, sizeof(info_head)); // 光标自动移动到RGB数据头部 // // 宽(就是x)info_head.biWidth 高(就是y)info_head.biHeight // printf("%s图片尺寸:宽%d 高%d\n", pathconf, info_head.biWidth, info_head.biHeight); // printf("%s图片颜色深度:%d\n", pathname, info_head.biBitCount); // 读取RGB颜色数据 read(fd_bmp, bmp_buf, info_head.biWidth * info_head.biHeight * info_head.biBitCount / 8); // 关闭文件 close(fd_bmp); // 开始显示图片 int x_s = x; int y_s = y; int x_e = x_s + info_head.biWidth; int y_e = y_s + info_head.biHeight; // 防止超出内存 if (x_e > 800 || y_e > 480) { printf("%s: 图片尺寸超出范围\n", pathname); return NULL; } int i = 0; int *lcdbuff = malloc(y_e * x_e * 4); if (lcdbuff == NULL) { printf("malloc failed\n"); return NULL; } // 循环读取RGB颜色数据并存入lcdbuff int x_pos, y_pos; for (y_pos = y_e - 1; y_pos >= y_s; y_pos--) { for (x_pos = x_s; x_pos < x_e && x_pos < 800; x_pos++, i += 3) { *(lcdbuff + (y_pos * 800) + x_pos) = (bmp_buf[i + 2] << 16) | (bmp_buf[i + 1] << 8) | bmp_buf[i]; } } return lcdbuff; } // 读取刮刮乐颜色数据; void lcd_fill_ggl(int x, int y, int *lcdbuff) // 显示刮刮乐的图片 { int i; int j; if (x + 20 > 800) { x = 780; } if (y + 20 > 480) { y = 460; } for (i = y - 20; i <= y + 20; i++) // 循环画点 { for (j = x - 20; j <= x + 20; j++) { if ((i - y) * (i - y) + (j - x) * (j - x) <= 400) ; // 判断是否在圆形内 { int color = *(lcdbuff + (i * 800) + j); // 获取颜色 lcd_draw_point(j, i, color); // 画点 } } } } int icon_app4_func(void) // 进入刮刮乐 { lcd_draw_bmp("picture/lottery/prompt.bmp", 0, 0); // 显示提示 sleep(3); printf("进入刮刮乐成功\n"); // 定义个数组指针来存储刮刮乐的图片 const char *bmp_lottery_tbl[] = { "picture/lottery/1.bmp", "picture/lottery/2.bmp", "picture/lottery/3.bmp", "picture/lottery/4.bmp", "picture/lottery/5.bmp", "picture/lottery/6.bmp", "picture/lottery/7.bmp", "picture/lottery/8.bmp", "picture/lottery/9.bmp", "picture/lottery/10.bmp", }; int x_press, y_press; int ts_x, ts_y, ts_sta; // 触摸屏的x和y坐标,ts_sta为按压状态 int rt; // 用于接收ts_read函数的返回值,0为成功,-1为失败 unsigned int lottery_color; // 定义一个变量来存储刮刮乐的颜色 struct input_event buf; // 定义一个结构体变量来存储触摸屏的事件 int fd_ts = open("/dev/input/event0", O_RDWR); if (fd_ts < 0) { perror("open /dev/input/event0"); return -1; } refresh: lcd_draw_bmp("picture/lottery/lottery.bmp", 0, 0); // 显示彩票界面 srand((unsigned int)time(NULL)); // 初始化随机数种子 int i = rand() % 10; // 随机数 int *lcdbuff = lcd_draw_ggl(bmp_lottery_tbl[i], 0, 80); // 获取图片的指针 ts_open("/dev/input/event0"); while (1) { rt = read(g_fd_ts, &buf, sizeof(buf)); printf("ts_x:%d ts_y:%d ts_sta:%d\n", ts_x, ts_y, ts_sta); if (rt < 0) continue; // 判断触摸屏的事件类型 if (buf.type == EV_ABS) // 获取触摸屏的坐标 { if (buf.code == ABS_X) { ts_x = buf.value * 800 / 1024; if (ts_x > 800) // 防止超出屏幕 { continue; } } if (buf.code == ABS_Y) // { ts_y = buf.value * 480 / 600; if (ts_y > 480) // 防止超出屏幕 { continue; } } } if (buf.type == EV_KEY && buf.code == BTN_TOUCH) { ts_sta = buf.value; // 获取按压状态 // 触摸屏点击后的释放状态 if (ts_sta == 0) { if (ts_x >= 0 && ts_x <= 80 && ts_y >= 0 && ts_y <= 80) { printf("返回主界面\n"); return 1; } if (ts_x >= 650 && ts_x <= 720 && ts_y >= 0 && ts_y <= 80) { printf("清屏\n"); lcd_draw_bmp(bmp_lottery_tbl[i], 0, 80); } if (ts_x >= 720 && ts_x <= 800 && ts_y >= 0 && ts_y <= 80) { printf("刷新图片\n"); goto refresh; } else // 防止超出屏幕 { continue; } } // 判断是否点击刮刮乐 // if (ts_y > 80 && ts_sta) } if ((ts_y - 20) >= 75 && (ts_y + 20) <= 479 && (ts_x - 20) >= 0 && (ts_x + 20) <= 799 && ts_sta) { lcd_fill_ggl(ts_x, ts_y, lcdbuff); } } ts_close(); return 1; } menu_t menu_startup = { .name = "开机界面", .fun = menu_startup_func, .parent = NULL, .child = &menu_login, }; menu_t menu_login = { .name = "登录界面", .fun = menu_login_func, .parent = &menu_startup, .child = &menu_main, }; menu_t menu_main = { .name = "主界面", .fun = menu_main_func, .parent = &menu_login, .child = NULL, }; int main(int argc, char **argv) { menu_t *pmenu = &menu_startup; // 打开LCD设备 lcd_open("/dev/fb0"); // 打开触摸屏设备 ts_open("/dev/input/event0"); while (1) { if (pmenu->fun) { printf("执行%s\n", pmenu->name); // 如果函数执行完毕,返回值为1,则进入父菜单 if (pmenu->fun()) { pmenu = pmenu->parent; continue; } } if (pmenu->child == NULL) { printf("没有子菜单\n"); printf("重新进入开机界面\n"); pmenu = &menu_startup; continue; } // 得到子菜单1 pmenu = pmenu->child; } // 关闭LCD设备 lcd_close(); // 关闭触摸屏 ts_close(); // 正确的返回 return 0; }