/*
 * fb_demo.c — 极简版: JPEG 解码 → 直接写到 /dev/fb0 (左上角)
 *
 * 只做 3 件事:
 *   1. jpeg 解码出 RGB 像素
 *   2. mmap 映射显存
 *   3. RGB24 → XRGB8888 逐像素写入 (图片放屏幕左上角)
 *
 * 简化假设 (本机 /dev/fb0 实测 = 1280x800 32bpp XRGB8888):
 *   - 屏幕 32bpp: 每像素 4 字节, 内存序 [B][G][R][X]
 *   - 每行 1280*4 = 5120 字节
 *   换板子时改 SCREEN_W 和 bpp 相关代码即可。
 *
 * 编译: make fb_demo   用法: ./fb_demo <输入.jpg>
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <jpeglib.h>

#define SCREEN_W 1280
#define SCREEN_H 800

/* ---------- ① JPEG 解码 (和 jpeg_de.c 一样) ---------- */
static unsigned char *decode_jpeg(const char *path, int *out_w, int *out_h)
{
    FILE *fp = fopen(path, "rb");
    if (!fp) { perror("fopen"); return NULL; }

    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;
    cinfo.err = jpeg_std_error(&jerr);
    jpeg_create_decompress(&cinfo);
    jpeg_stdio_src(&cinfo, fp);
    if (jpeg_read_header(&cinfo, TRUE) != JPEG_HEADER_OK) return NULL;
    cinfo.out_color_space = JCS_RGB;
    jpeg_start_decompress(&cinfo);

    unsigned int rowbytes = cinfo.output_width * cinfo.output_components;
    unsigned char *buf = malloc(rowbytes * cinfo.output_height);
    unsigned char *row = buf;
    while (cinfo.output_scanline < cinfo.output_height) {
        jpeg_read_scanlines(&cinfo, &row, 1);
        row += rowbytes;
    }
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);
    fclose(fp);

    *out_w = cinfo.output_width;
    *out_h = cinfo.output_height;
    return buf;
}

int main(int argc, char *argv[])
{
    if (argc < 2) {
        fprintf(stderr, "用法: %s <输入.jpg>\n", argv[0]);
        return 1;
    }

    /* ① 解码 -> RGB 缓冲 */
    int w, h;
    unsigned char *rgb = decode_jpeg(argv[1], &w, &h);
    if (!rgb) { fprintf(stderr, "解码失败\n"); return 1; }
    printf("解码: %dx%d RGB\n", w, h);

    /* ② 打开屏幕设备 + 映射显存 */
    int fbfd = open("/dev/fb0", O_RDWR);
    if (fbfd < 0) { perror("open /dev/fb0"); return 1; }
    size_t fb_size = (size_t)SCREEN_W * SCREEN_H * 4;
    unsigned char *fb = mmap(NULL, fb_size, PROT_READ | PROT_WRITE,
                             MAP_SHARED, fbfd, 0);
    if (fb == MAP_FAILED) { perror("mmap"); return 1; }

    memset(fb, 0, fb_size);          /* 整屏刷黑 */

    /* ③ 写入: 图片从 (0,0) 开始, 每行 src 是 3 字节 RGB,
     *   每行 dst 是 4 字节 BGRX (XRGB8888 小端内存序) */
    for (int y = 0; y < h && y < SCREEN_H; y++) {
        unsigned char *src = rgb + (size_t)y * w * 3;
        unsigned char *dst = fb + (size_t)y * SCREEN_W * 4;
        for (int x = 0; x < w && x < SCREEN_W; x++) {
            dst[x*4 + 0] = src[x*3 + 2];   /* B */
            dst[x*4 + 1] = src[x*3 + 1];   /* G */
            dst[x*4 + 2] = src[x*3 + 0];   /* R */
            dst[x*4 + 3] = 0xFF;           /* X = 不透明 */
        }
    }

    printf("已写入 /dev/fb0 左上角 (%dx%d), 屏幕 %dx%d 32bpp\n", w, h, SCREEN_W, SCREEN_H);

    munmap(fb, fb_size);
    close(fbfd);
    free(rgb);
    return 0;
}