/*
 * Copyright (C) 2008 Michele Sanges <michele.sanges@gmail.com>
 *
 * Licensed under GPLv2 or later,see file LICENSE in this source tree.
 *
 * Originaly from busy box
 *
 * Seriously mucked about by:
 *
 * K.D.Hedger 2011 <kdheger@yahoo.co.uk>
 *
 */

#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <unistd.h>
#include <linux/fb.h>

#define BYTES_PER_PIXEL 2

unsigned char *fbmem;
fb_var_screeninfo scr_var;
fb_fix_screeninfo scr_fix;
	
char buffer[8193];

void fb_drawimage(void)
{
	char *read_ptr=buffer;
	unsigned char *pixline;
	unsigned i,j,width,height,line_size;

	while (true)
		{
			int w,h,max_color_val;
			int rem=buffer + sizeof(buffer) - read_ptr;
			if (rem<2|| fgets(read_ptr,rem,stdin) == NULL)
				{
					printf("bad PPM file\n");
					exit (1);
				}

			read_ptr=strchrnul(read_ptr,'#');
			*read_ptr='\0'; /* ignore #comments */
			if (sscanf(buffer,"P6 %u %u %u",&w,&h,&max_color_val) == 3 && max_color_val <= 255)
				{
					width=w;
					height=h;
					break;
				}
		}

	line_size=width*3;
	pixline=(unsigned char*)malloc(line_size);

	if (width>scr_var.xres)
		width=scr_var.xres;

	if (height>scr_var.yres)
		height=scr_var.yres;

	for (j=0;j<height; j++)
		{
			unsigned char *pixel;
			unsigned short *src;

			if (fread(pixline,1,line_size,stdin) != line_size)
				{
					printf("bad PPM file\n");
					exit(1);
				}

			pixel=pixline;
			src=(unsigned short *)(fbmem + j * scr_fix.line_length);
			for (i=0; i<width; i++)
				{
					unsigned thispix;
					thispix=(((unsigned)pixel[0] << 8) & 0xf800)| (((unsigned)pixel[1] << 3) & 0x07e0)| (((unsigned)pixel[2] >> 3));
					*src++=thispix;
					pixel += 3;
				}
		}
	free(pixline);
}

int main(int argc,char **argv)
{

	int fbfd=open("/dev/fb0",O_RDWR);

// framebuffer properties
	ioctl(fbfd,FBIOGET_VSCREENINFO,&scr_var);
	ioctl(fbfd,FBIOGET_FSCREENINFO,&scr_fix);

	if (scr_var.bits_per_pixel != 16)
		printf("only 16 bpp is supported\n");

// map the device in memory
	fbmem=(unsigned char*)mmap(NULL,scr_var.xres * scr_var.yres_virtual * BYTES_PER_PIXEL,PROT_WRITE,MAP_SHARED,fbfd,0);

	if (fbmem == MAP_FAILED)
		printf("mmap\n");

// point to the start of the visible screen
	fbmem += scr_var.yoffset * scr_fix.line_length + scr_var.xoffset * BYTES_PER_PIXEL;
	close(fbfd);

	fb_drawimage();

	return(0);

}
