/*
 * vg_ip_test.cpp
 *
 *  Created on: 20/giu/2018
 *      Author: chessaa
 */




#include "vg_driver.h"

#include <stdint.h>
#include <string.h>

#include <math.h>

struct gc_test_frame_buffer_t
{
	int dx;
	int dy;
	int stride;
	uint8_t* image;
	int total_size;
	gc_test_frame_buffer_t(void* p, int dx_, int dy_, int stride_=0):
		dx(dx_),
		dy(dy_),
		stride(stride_ ? stride_ : dx),
		image(reinterpret_cast<uint8_t*>(p)),
		total_size(dy*stride)
	{
	}

	uint8_t* operator [](int y) { return &image[y*stride];}

	void clear()
	{
		memset(image, 0, total_size);
	}

	void draw_rect(int ox, int oy, int ex, int ey, int color)
	{
		for(int x=ox; x<=ex; ++x)
		{
			this->operator [](oy)[x]=color;
			this->operator [](ey)[x]=color;
		}
		for(int y=oy; y<=ey; ++y)
		{
			this->operator [](y)[ox]=color;
			this->operator [](y)[ex]=color;
		}
	}

	uint8_t* row(int y) { return this->operator[](y);}
	void putPixel(int x, int y, int c)
	{
		row(y)[x]=c;
	}

	void circle(int x, int y, int r, int c)
	{
	  int major = 0, minor = r, tmp;
	  int squared_radius = r * r;

	  do
	    {
		  putPixel(x+major, y-minor, c);
		  putPixel(x-major, y-minor, c);
		  putPixel(x+major, y+minor, c);
		  putPixel(x-major, y+minor, c);
		  putPixel(x+minor, y-major, c);
		  putPixel(x-minor, y-major, c);
		  putPixel(x+minor, y+major, c);
		  putPixel(x-minor, y+major, c);
	      major++;
	      tmp = squared_radius - (major * major);
	      minor = (int)(sqrtf((double)(tmp)) + 0.5f);
	    }
	  while(major<=minor);
	}

};



void vg_drv_gen_test_palette(void* palette_buffer)
{
	uint32_t* p=reinterpret_cast<uint32_t*>(palette_buffer);
	for(int unsigned i=0; i<256; ++i)
	{
		uint32_t c=((uint32_t)i) & 0x0FF;
		uint32_t luminance=0xFF000000U;	//c<<24 - FW bug? it seems to be alpha channel, so we have to set it to 0xFF to be opaque
		uint32_t c32=luminance|c|(c<<8)|(c<<16);
		p[i]=c32;
	}
	return;
}

static unsigned vg_drv_white_level=255;

int vg_drv_gen_test_pattern(int patternid, unsigned int white, void* gc_buffer, int dx_, int dy_, int stride_)
{
	const int dx=dx_;
	const int dy=dy_;
	const int ex=dx-1;
	const int ey=dy-1;
	const int stride=stride_ ? stride_ : dx;

	if (patternid==0)
		return 0;

	if (white!=0)
		vg_drv_white_level=white;

	//const int o484=(dx-484)/2;

	gc_test_frame_buffer_t tb(gc_buffer, dx, dy, stride);
	//gc_test_frame_buffer_t tb512(gc_buffer, 512, 512, stride);
	//gc_test_frame_buffer_t tb484(&tb[o484][o484], 484, 484, stride);
	gc_test_frame_buffer_t& tb512=tb;
	gc_test_frame_buffer_t& tb484=tb;


	if ((patternid & 0x1000)==0)
		tb.clear();

	if (patternid & 0x1)
		tb484.draw_rect(0, 0, 483, 483, vg_drv_white_level);	//BR frame

	if (patternid & 0x2)
		tb.draw_rect(0, 0, 573, 573, vg_drv_white_level);		//S7 Frame

	if (patternid & 0x04)
		tb512.draw_rect(0, 0, 511, 511, vg_drv_white_level);	//512 M3 Internal frame


	if (patternid & 0x08)
	{
		if (ex>600)
			tb.draw_rect(0, 0, 600, ey, vg_drv_white_level);
		tb.draw_rect(0, 0, ex, ey, vg_drv_white_level);
	}

	if (patternid & 0x400)
	{
		vg_drv_gfx_palette_set_gray_scale(false);
		for(unsigned int r=0; r<256; ++r)
		{
			for(unsigned int c=0; c<574; ++c)
			{

				tb[r][c]=c & 0x0FF;
			}
		}
		return 0;
	}
	if (patternid & 0x800)
	{
		for(unsigned int r=0; r<574; ++r)
			tb[r][r]=vg_drv_white_level;
		return 0;
	}

	if (patternid & 0x200)
	{
		for(int y=0; y<(dy-4); y+=2)
		{
			uint32_t* even=(uint32_t*)&tb[y][0];
			uint32_t* odd=(uint32_t*)&tb[y+1][4];
			uint32_t  ceven=vg_drv_white_level & 0x0FF;
			ceven=ceven|(ceven<<8)|(ceven<<16)|(ceven<<24);
			uint32_t  codd=(vg_drv_white_level-16) & 0x0FF;
			codd=codd|(codd<<8)|(codd<<16)|(codd<<24);
			for(int x=0; x<((dx/4)-3); x+=2)
			{
				even[x]=ceven;
				odd[x]=codd;
			}
		}
	}

	if ((patternid & 0x100)==0)
		return 0;

	{
		for(int i=8; i<64; i+=8)
		{
			for(int y=0; y<dy; ++y)
			  tb[y][i]=vg_drv_white_level;
			memset(&tb[i][0], vg_drv_white_level, dx);
		}
	}

	{//Cross
		for(int i=0; i<484; ++i)
		{
			tb484[i][i]=vg_drv_white_level;
			tb484[483-i][i]=vg_drv_white_level;
		}
	}
	{//Gray scale
		int oy=64+8;
		int ox=(484-256)/2;
		int cstep=(128-16)/16;
		int c=16/2;

		for(int i=127; i>15; i-=cstep)
		{
			for(int y=0; y<16; ++y)
			{
				for(int x=0; x<16; ++x)
				{
					tb484[oy+y][ox+x]=128+i;
				}
			}
			c+=16/2;
			ox+=16;
		}

		ox=(484-256)/2;
		oy=64+16+16;
		for(int i=0; i<256; ++i)
		{

			tb484[oy][ox+i]=128+(i>>1);
			tb484[oy+1][ox+i]=128+(i>>1);
			tb484[oy+2][ox+i]=128+(i>>1);
			tb484[oy+3][ox+i]=128+(i>>1);
		}
		tb484.circle(484/2, 484/2, 64, vg_drv_white_level);
		tb484.circle(484/2, 484/2, 128, vg_drv_white_level);
	}

	{//Running colors
		int dx=484/2;
		int dy=64;
		gc_test_frame_buffer_t tbx(&tb484[484-(64+32)][242-dx/2], dx, dy, stride);
		static unsigned int start_color=0;

		uint8_t c=start_color>>4;
		++start_color;
		for(int i=0; i<dy; ++i)
			for(int j=0; j<dx; ++j)
				tbx[i][j]=c++;
	}
	return 0;
}

