//==========================================================================
//
//      paint_lcd.c
//
//      For LCD display
//
//==========================================================================
//####ECOSGPLCOPYRIGHTBEGIN####
// -------------------------------------------
// This file is part of eCos, the Embedded Configurable Operating System.
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
//
// eCos is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 or (at your option) any later version.
//
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with eCos; if not, write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
//
// As a special exception, if other files instantiate templates or use macros
// or inline functions from this file, or you compile this file and link it
// with other works to produce a work based on this file, this file does not
// by itself cause the resulting work to be covered by the GNU General Public
// License. However the source code for this file must still be made available
// in accordance with section (3) of the GNU General Public License.
//
// This exception does not invalidate any other reasons why a work based on
// this file might be covered by the GNU General Public License.
//
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
// at http://sources.redhat.com/ecos/ecos-license/
// -------------------------------------------
//####ECOSGPLCOPYRIGHTEND####
//==========================================================================
//#####DESCRIPTIONBEGIN####
//
// Author(s):    Ray Wang
// Contributors:
// Date:         2008-03-27
// Current Ver : 0.1
// Purpose:
// Description:  For LCD display.
// Copyright:    2008 Kinpo Beijing, Inc.
//
//####DESCRIPTIONEND####
//
//==========================================================================

#include <redboot.h>
#include <cyg/io/paint_lcd.h>
#include <cyg/io/fonttable.h>

unsigned short *frame_buffer = ((unsigned short *)FRAMEBUF_BASE);
unsigned char *logoaddr = (unsigned char *)(0x100000);
/*
 * Purpose:	Paint a point
 *
 * Parameter:	x: x coordinate of a point
 *		y: y coordinate of a point
 *		color: the point color
 *
 * Return:	NULL
 */
void paint_pixel(int x, int y, color_t color)
{
	if (x<0 || x>(SCREEN_WIDTH-1)
		|| y<0
		|| y>(SCREEN_HEIGHT-1)) {
		return;
	}
	frame_buffer[y*SCREEN_WIDTH+x] = color;
	return;
}

/*
 * Purpose:     Paint a line with two point: a(x1,y1) b(x2,y2)
 *
 * Parameter:   x1,y1,x2,y2: coordinate of a point
 *              color: the point color
 *
 * Return:      NULL
 */
void paint_line(int x1, int y1, int x2, int y2, color_t color)
{
	int i;
	float slope;

	if (x1<0 || x1>(SCREEN_WIDTH-1)
		|| y1<0
		|| y1>(SCREEN_HEIGHT-1)) {
		return;
	}
	if (x2<0 || x2>(SCREEN_WIDTH-1)
		|| y2<0
		|| y2>(SCREEN_HEIGHT-1)) {
		return;
	}

	if (x1 == x2) { /* vertical line */
		for (i=MIN(y1, y2); i<=MAX(y1, y2); i++) {
			paint_pixel(x1, i, color);
		}
	} else if (y1 == y2) { /* horizontal line */
		for (i=MIN(x1, x2); i<=MAX(x1, x2); i++) {
			paint_pixel(i, y1, color);
		}
	} else { /* arbitrary line */
		slope = (float)(y2-y1)/(float)(x2-x1);
                for(i=MIN(x1, x2); i<=MAX(x1, x2); i++)
                {
			paint_pixel(i, (int)(slope*(i-MIN(x1, x2))+MIN(y1, y2)), color);
                }
	}
	return;
}

/*
 * Purpose:     Draw a rectangular box
 *
 * Parameter:   x,y: coordinate of a point
 *              width: width of the rectangular
 *		height: height of the rectangular
 *		color: color of the rectangular
 *
 * Return:      NULL
 */
void draw_rect(int x, int y, int width, int height, color_t color)
{
	if (x<0 || x+width>(SCREEN_WIDTH)
		|| y<0
		|| y+height>(SCREEN_HEIGHT)) {
		return;
	}
	paint_line(x,y,x+width,y,color);
        paint_line(x,y+height,x+width,y+height,color);
        paint_line(x,y,x,y+height,color);
        paint_line(x+width,y,x+width,y+height,color);
	return;
}

/*
 * Purpose:     Paint a rectangular background
 *
 * Parameter:   x,y: coordinate of a point
 *              width: width of the rectangular
 *		height: height of the rectangular
 *		color: background color of the rectangular
 *
 * Return:      NULL
 */
void paint_rect(int x, int y, int width, int height, color_t color)
{
	int i, j;
	if (x<0 || x+width>(SCREEN_WIDTH)
		|| y<0
		|| y+height>(SCREEN_HEIGHT)) {
		return;
	}

	for (i=x; i<x+width; i++)
		for (j=y; j<y+height; j++)
			paint_pixel(i, j, color);
	return;
}

/*
 * Purpose:     print a charactor
 *
 * Parameter:   x,y: coordinate of a point
 *              c_color: charactor color
 *              b_color: background color
 *		c: the charactor to print
 *
 * Return:      NULL
 */
void print_char(int x, int y, color_t c_color, color_t b_color, char c)
{
	const int mask[16] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01};
	register int i, j;

	if (x<0 || x>(SCREEN_WIDTH-1-8)
		|| y<0
		|| y>(SCREEN_HEIGHT-1-16)) {
		return;
	}
	for (i=0; i<16; i++) {
		for (j=0; j<8; j++) {
			if (mask[j] & (int) font8x16[c*16+i]) {
				paint_pixel(x+j, y+i, c_color);
			} else {
				if(b_color != TRANSPARENT)
					paint_pixel(x+j, y+i, b_color);
			}
		}

	}
}

/*
 * Purpose:     print a format string
 *
 * Parameter:   x,y: coordinate of a point
 *              c_color: charactor color
 *              b_color: background color
 *		fmt: format string
 *
 * Return:      NULL
 */
void print_fmt(int x, int y, color_t c_color, color_t b_color, char *fmt)
{
	char *buf = fmt;
	int tmpx, i;

	if (x<0 || x>(SCREEN_WIDTH-1-8)
		|| y<0
		|| y>(SCREEN_HEIGHT-1-16)) {
		return;
	}
	i = 0;
	tmpx = x;
	while(buf[i] != 0)
        {
                if(buf[i] > 0x1F && buf[i] < 0x7F)
                {
			print_char(tmpx, y, c_color, b_color, buf[i++]);
                        tmpx += 8;

                        if(tmpx > SCREEN_WIDTH-1 || buf[i] == 0x0d)
                        {
                                tmpx  =  x;
                                y += 16;
                                i += 1;
                        }
                }
                else
                {
                        i++;
                        tmpx += 10;
                }
        }
	return;
}

void read_logo(void)
{
        char buf[256];
        char *command;
        struct cmd *cmd;
        int argc = 6;
        char *argv[6];

        diag_sprintf(buf, "nand fatread -f splash.bmp -b 0x100000");
        command = &buf[0];

        if ((cmd = parse(&command, &argc, &argv[0])) != (struct cmd *)0) {
                (cmd->fun)(argc, argv);
        }
}
void SetMiliSecond(cyg_uint32 timer);
void paint_logo(void)
{
        int pixel_width;
        int pixel_height;
        int x, y, pixel_num;
        int realwidth = SCREEN_WIDTH;
        unsigned short color;
        unsigned char blue, green, red;
        unsigned char index;
        BITMAP_FILES logobmp;
        unsigned char *pBitmapAddr;
        unsigned char *pLogoAddr;
        RGBQUAD *quad;

	/* clean the framebuffer, before disaply logo */
	paint_rect(0,0,SCREEN_WIDTH,SCREEN_HEIGHT,BLACK);

        read_logo();
        SetMiliSecond(100);
        pBitmapAddr = logoaddr;
        pLogoAddr = logoaddr;

        memcpy(&(logobmp.bitmapfileheader.bfType), pBitmapAddr, 2);
        memcpy(&(logobmp.bitmapfileheader.bfSize), pBitmapAddr+2, 4);
        memcpy(&(logobmp.bitmapfileheader.bfOffBits), pBitmapAddr+10, 4);
        memcpy(&(logobmp.bitmapinfoheader),(pBitmapAddr+14),sizeof(BITMAPINFOHEADER));
        SetMiliSecond(100);
        logobmp.buffer = pBitmapAddr+logobmp.bitmapfileheader.bfOffBits;

        if(logobmp.bitmapfileheader.bfType != 0X4D42)
        {
                diag_printf("logo format err!\n");
                return;
        }
        if(logobmp.buffer<pLogoAddr || logobmp.buffer>(pLogoAddr+0x500))
                return;

        pixel_width = logobmp.bitmapinfoheader.biWidth;
        if(pixel_width>SCREEN_WIDTH)
                return;
        pixel_height =logobmp.bitmapinfoheader.biHeight;
        if(pixel_height>SCREEN_HEIGHT)
                return;
        if (logobmp.bitmapinfoheader.biBitCount == 24)          //24 bit bitmap
        {
                realwidth = (((pixel_width*24)+31)>>5)<<2;
                pixel_num = realwidth*pixel_height;
                for (y = 0; y < pixel_height; y++)
                {
                        for (x = 0; x < pixel_width; x++)
                        {
                                blue = (logobmp.buffer[pixel_num - 3 - realwidth*y - x*3 + 0-(realwidth-pixel_width*3)]) >> 3;
                                green = (logobmp.buffer[pixel_num - 3 - realwidth*y - x*3 + 1-(realwidth-pixel_width*3)]) >> 2;
                                red = (logobmp.buffer[pixel_num - 3 - realwidth*y - x*3 + 2-(realwidth-pixel_width*3)]) >> 3;
                                color = RGB565(red, green, blue);
                                paint_pixel(pixel_width-x-1, y, color);
                        }
                }
        }
        else if (logobmp.bitmapinfoheader.biBitCount == 16)     //16 bit bitmap
        {
                if(logobmp.bitmapinfoheader.biCompression != 0)
                        return;
                realwidth = (((pixel_width*16)+31)>>5)<<2;
                pixel_num = realwidth*pixel_height;
                for (y = 0; y < pixel_height; y++)
                {
                        for (x = 0; x < pixel_width; x++)
                        {
#if 1 // 5 5 5
                                blue=logobmp.buffer[pixel_num - 2 - y*realwidth-x*2 - (realwidth-pixel_width*2)]&0x1F;
                                green=((((logobmp.buffer[pixel_num - 2 - y*realwidth-x*2 + 1 - (realwidth-pixel_width*2)]<<6)&0xFF)>>3) + (logobmp.buffer[pixel_num - 2 - y*realwidth-x*2 - (realwidth-pixel_width*2)]>>5))<<1;
                                red=(logobmp.buffer[pixel_num - 2 - y*realwidth-x*2+1-(realwidth-pixel_width*2)]<<1)>>3;
#endif
#if 0 // 5 6 5
                                blue=logobmp.buffer[pixel_num - 2 - y*realwidth-x*2 - (realwidth-pixel_width*2)]&0x1F;
                                green = green=(((logobmp.buffer[pixel_num - 2 - y*realwidth-x*2 + 1 - (realwidth-pixel_width*2)]<<5)&0xFF)>>2) + (logobmp.buffer[pixel_num - 2 - y*realwidth-x*2 - (realwidth-pixel_width*2)]>>5);
                                red=(logobmp.buffer[pixel_num  - y*realwidth-x*2+1-(realwidth-pixel_width*2)]<<1)>>3;
#endif
                                color = RGB565(red, green, blue);
                                paint_pixel(pixel_width-x-1, y, color);
                        }
                }
        }
        else if (logobmp.bitmapinfoheader.biBitCount == 8)      //8 bit bitmap
        {
                quad = (RGBQUAD *)(pBitmapAddr + 14 + sizeof(BITMAPINFOHEADER));
                realwidth = (((pixel_width*8)+31)>>5)<<2;
                pixel_num = realwidth*pixel_height;
                for (y = 0; y < pixel_height; y++)
                {
                        for (x = 0; x < pixel_width; x++)
                        {
                                index = logobmp.buffer[pixel_num - 1 - realwidth*y - x + (realwidth-pixel_width)];
                                red = quad[index].rgbRed >> 3;
                                green = quad[index].rgbGreen >> 2;
                                blue = quad[index].rgbBlue >> 3;
                                color = RGB565(red, green, blue);
                                paint_pixel(pixel_width-x-1, y, color);
                        }
                }
        }
        else if (logobmp.bitmapinfoheader.biBitCount == 32)     //32 bit bitmap
        {
                realwidth = (((pixel_width*32)+31)>>5)<<2;
                pixel_num = realwidth*pixel_height;
                for (y = 0; y < pixel_height; y++)
                {
                        for (x = 0; x < pixel_width; x++)
                        {
                                blue=logobmp.buffer[pixel_num - 4 - y*realwidth - x*4] >> 3;
                                green=logobmp.buffer[pixel_num - 4 - y*realwidth - x*4 + 1] >> 2;
                                red=logobmp.buffer[pixel_num - 4 - y*realwidth - x*4 + 2] >> 3;
                                color = RGB565(red, green, blue);
                                paint_pixel(pixel_width-x-1, y, color);
                        }
                }
        } else {
                diag_printf("logo display failed! the logo is not 8,16,24,32 bmp file!\n");
        }
}

