#include "tap.h"

#define ID_SCRCAP 0x8000010F

TAP_ID( ID_SCRCAP );
TAP_PROGRAM_NAME("ScreenCapture");
TAP_AUTHOR_NAME("TOPFIELD");
TAP_DESCRIPTION("Press UHF key to capture live screen");
TAP_ETCINFO(__DATE__);

#define LE16( p )	( (((p&0x00ff))<<8) | ((p&0xff00)>>8) )
#define LE32( p )	( (((p&0x000000ff))<<24) | (((p&0x0000ff00))<<8) | (((p&0x00ff0000))>>8) | ((p&0xff000000)>>24) )

struct BMP_HEAD {
    byte id[2];
	word size_l;
	word size_h;
    word reserved[2];
    word offset_l;
	word offset_h;
};

struct BMP_INFO {
    long info_size;
    long width;
    long height;
    word plane;
    word bits_per_pixel;
    long compress;
    long img_size;
    long x_res;
    long y_res;
    long color;
    long icolor;
};

static struct BMP_HEAD head;
static struct BMP_INFO info;

static int capture_num = 0;
static char out_name[64];
static byte *_bmpBuf = NULL;

int _bmpWidth;
int _bmpHeight;
TYPE_File *_bmpFile;

#define _R(y,u,v) (0x2568*(y)			   + 0x3343*(u)) /0x2000
#define _G(y,u,v) (0x2568*(y) - 0x0c92*(v) - 0x1a1e*(u)) /0x2000
#define _B(y,u,v) (0x2568*(y) + 0x40cf*(v)) 			 /0x2000

#define _S(a)		(a)>255 ? 255 : (a)<0 ? 0 : (a)

inline void YUV2RGB( word yy, word uu, word vv, byte *r, byte *g, byte *b )
{
	signed int _r,_g,_b;
	signed int y, u, v;

	y = yy; // - 12;
	u = (int)uu - 128;
	v = (int)vv - 128;

	_r = _R(y,u,v);
	_g = _G(y,u,v);
	_b = _B(y,u,v);

	*r = _S(_r);
	*g = _S(_g);
	*b = _S(_b);
}


void BMP_WriteHeader( int width, int height )
{
	long size;
	int i, j;
	word *p;

	size = sizeof( head ) + sizeof( info ) + (width*height)*3;

	head.id[0] = 'B';
	head.id[1] = 'M';
	head.size_l  = LE16( (size&0xffff) );
	head.size_h  = LE16( (size>>16) );
	i =  (sizeof( head ) + sizeof( info ));
	head.offset_l = LE16( i&0xffff );
	head.offset_h = LE16( i>>16 );

	info.info_size 	= LE32( 40 );
	info.width		= LE32( width );
	info.height        = LE32( height );
	info.plane		= LE16( 1 );
	info.bits_per_pixel	= LE16( 24 );
	info.compress       = LE32( 0 );
	info.img_size       = LE32( (width*height)*3 );
	info.x_res          = 0;
	info.y_res          = 0;
	info.color          = 0;
	info.icolor         = 0;

	TAP_SPrint( out_name, "SCR%04d.BMP", capture_num++ );
	TAP_Hdd_Create( out_name, ATTR_NORMAL );
	_bmpFile = TAP_Hdd_Fopen( out_name );
	if( _bmpFile==NULL ) 
		return;

	TAP_Hdd_Fwrite( &head, sizeof( head ), 1, _bmpFile );
	TAP_Hdd_Fwrite( &info, sizeof( info ), 1, _bmpFile );

	_bmpWidth = width;
	_bmpHeight = height;

	if( _bmpBuf )
	{
		TAP_MemFree( _bmpBuf );
		_bmpBuf = NULL;
	}
	_bmpBuf = TAP_MemAlloc( (width*height)*3 );
	
}

inline void BMP_SetPixel( int x, int y, byte r, byte g, byte b )
{
	register pos = (y * _bmpWidth + x)*3;
        _bmpBuf[ pos ] = b;
        _bmpBuf[ pos+1 ] = g;
        _bmpBuf[ pos+2 ] = r;
}

	
void BMP_End( void )
{
	if( _bmpFile==NULL ) 
		return;
	TAP_Hdd_Fwrite( _bmpBuf, _bmpWidth*3, _bmpHeight, _bmpFile );
	if( _bmpBuf )
	{
		TAP_MemFree( _bmpBuf );
		_bmpBuf = NULL;
	}
	TAP_Hdd_Fclose( _bmpFile );
}

void CaptureVideo( byte mainSub, int width, int height )
{
	TYPE_VideoBank videoBank;
	byte *picAddr, *chrAddr;
	int	x, y, xx, yy;
	dword xinc, yinc;
	byte r, g, b;
	int ypos, ypos2;
	int xpos;
	int yPos, cPos;

	memset( &videoBank, 0, sizeof(videoBank) );

	TAP_CaptureScreen( mainSub, &videoBank );

	picAddr = videoBank.yAddress;
	chrAddr = videoBank.cAddress;

	TAP_Print("yAddr = %x, cAddr = %x, videoBank.height = %d, videoBank.width = %d\r\n",
		picAddr, chrAddr, videoBank.height, videoBank.width );

	BMP_WriteHeader( width, height );
	for( yy = 0; yy<height; yy++ ) 
	{
		y = yy * videoBank.height / height;
 		ypos  = (( y    & 0xffffffe0) * 736) + (y&0x1f)*32;
		ypos2 = (((y/2) & 0xffffffe0) * 736)  + ((y/2)&0x1f)*32;
		for( xx=0; xx<width; xx++ )
		{
			x = xx * videoBank.width / width;
			xpos =  ((x & 0xffffffe0)<<5) + (x&0x1f);
			yPos  = ypos  + xpos;
			cPos = (ypos2 + xpos)&0xfffffffe;
				
			YUV2RGB( picAddr[yPos], chrAddr[cPos+1], chrAddr[cPos], &r, &g, &b );
			BMP_SetPixel( xx, height-yy-1, r, g, b ); // bottom -> top
		}
	}
	BMP_End();

	TAP_MemFree( videoBank.cAddress );
	TAP_MemFree( videoBank.yAddress );
	
}


dword TAP_EventHandler( word event, dword param1, dword param2 )
{
    if( event == EVT_KEY )
    {
		switch( param1 )
		{
			case RKEY_Uhf:
				CaptureVideo( CHANNEL_Main, 720/2, 576/2 );
				return 0;
				break;
		}
	    return param1;
    }
    return param1;
}

int TAP_Main(void)
{

    return 1;
}


