#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<dos.h>
#include	<time.h>

#include	<egb.h>

#include	"tb.h"
#include	"tb_rand.h"
#include	"tb_scn.h"

#define	NUM_BLOCKBUFFER	(4)

static void	*Buftbl[NUM_BLOCKBUFFER] =
{
	NULL,	NULL,	NULL,	NULL,
};

/*************************************************************************
*	ポイントセット
*************************************************************************/

int		tbTST_egb_pointset(void)
{
	int			sec, count = 0;

	tbSCN_clearTestFrame();
	{
		clock_t		clk, clkwk;

		EGB_paintMode( EgbPtr, 0x002 );
		EGB_writeMode( EgbPtr, PSET);
		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			int		color;

			color = GETRNDCOL(count,TBscn.resoptr->maxcol);
			EGB_color(EgbPtr,0,color);
			{
				struct
				{
					unsigned short	n;
					short			x,y;
				} para;

				para.n = 1;
				para.x = GETRNDPX(count);
				para.y = GETRNDPY(count);
				EGB_pset( EgbPtr,(char *)&para);
			}

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  point set          \t%5d\n",count_per_sec);
	}
	return (0);
}

/*************************************************************************
*	ライン
*************************************************************************/

int		tbTST_egb_line(void)
{
	int			sec, count = 0;

	tbSCN_clearTestFrame();
	{
		clock_t		clk, clkwk;

		EGB_paintMode( EgbPtr, 0x002 );
		EGB_writeMode( EgbPtr, PSET);
		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			int		color;

			color = GETRNDCOL(count,TBscn.resoptr->maxcol);
			EGB_color(EgbPtr,0,color);
			{
				struct
				{
					unsigned short	n;
					short			x1,y1,x2,y2;
				} para;

				para.n = 2;
				para.x1 = GETRNDPX(count*2);
				para.y1 = GETRNDPY(count*2);
				para.x2 = GETRNDPX(count*2+1);
				para.y2 = GETRNDPY(count*2+1);
				EGB_connect( EgbPtr,(char *)&para);
			}

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  line               \t%5d\n",count_per_sec);
	}
	return (0);
}

/*************************************************************************
*	矩形
*************************************************************************/

int		tbTST_egb_boxfill(void)
{
	int			sec, count = 0;

	tbSCN_clearTestFrame();
	{
		clock_t		clk, clkwk;

		EGB_paintMode( EgbPtr, 0x020 );
		EGB_writeMode( EgbPtr, PSET);
		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			int		color;

			color = GETRNDCOL(count,TBscn.resoptr->maxcol);
			EGB_color(EgbPtr,2,color);
			{
				struct
				{
					short			x1,y1,x2,y2;
				} para;

				para.x1 = GETRNDPX(count*2);
				para.y1 = GETRNDPY(count*2);
				para.x2 = GETRNDPX(count*2+1);
				para.y2 = GETRNDPY(count*2+1);
				EGB_rectangle( EgbPtr,(char *)&para);
			}

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  box fill           \t%5d\n",count_per_sec);
	}
	return (0);
}


/*************************************************************************
*	円
*************************************************************************/

int		tbTST_egb_circle(void)
{
	int			sec, count = 0;

	tbSCN_clearTestFrame();
	{
		clock_t			clk, clkwk;
		unsigned int	rmax;

		rmax = _min(TBcfg.xsTest/2,TBcfg.ysTest/2);
		EGB_paintMode( EgbPtr, 0x020 );
		EGB_writeMode( EgbPtr, PSET);
		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			int		color;

			color = GETRNDCOL(count * 2,TBscn.resoptr->maxcol);
			EGB_color(EgbPtr,2,color);
			{
				struct
				{
					short			x,y,r;
				} para;

				para.x = GETRNDPX(count);
				para.y = GETRNDPY(count);
				para.r  = GETRNDCOL(count*2+1,0xFFFF) % rmax;
				EGB_circle( EgbPtr,(char *)&para);
			}

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  circle             \t%5d\n",count_per_sec);
	}
	return (0);
}

/*************************************************************************
*	ポリゴン
*************************************************************************/

int		tbTST_egb_polygon(void)
{
	int			sec, count = 0;

	tbSCN_clearTestFrame();
	{
		clock_t		clk, clkwk;

		EGB_paintMode( EgbPtr, 0x020 );
		EGB_writeMode( EgbPtr, PSET);
		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			int		color;

			color = GETRNDCOL(count,TBscn.resoptr->maxcol);
			EGB_color(EgbPtr,2,color);
			{
				struct
				{
					unsigned short	n;
					short			x1,y1,x2,y2,x3,y3,x4,y4;
				} para;

				para.n = 4;
				para.x1 = GETRNDPX(count*4  );	para.y1 = GETRNDPY(count*4  );
				para.x2 = GETRNDPX(count*4+1);	para.y2 = GETRNDPY(count*4+1);
				para.x3 = GETRNDPX(count*4+2);	para.y3 = GETRNDPY(count*4+2);
				para.x4 = GETRNDPX(count*4+3);	para.y4 = GETRNDPY(count*4+3);
				EGB_polygon( EgbPtr,(char *)&para);
			}

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  polygon            \t%5d\n",count_per_sec);
	}
	return (0);
}


/*************************************************************************
*	文字
*************************************************************************/

int		tbTST_egb_putchar(void)
{
	int			sec, count = 0;

	tbSCN_clearTestFrame();
	EGB_textDirection(EgbPtr,0);				/* 文字方向	*/
	EGB_textDisplayDirection(EgbPtr,0);			/* 表示方向	*/

	{
		clock_t		clk, clkwk;

		EGB_paintMode( EgbPtr, 0x022 );
		EGB_writeMode( EgbPtr, OPAQUE);
		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			int		colcha, colbak;

			colcha = GETRNDCOL(count*2  ,TBscn.resoptr->maxcol);
			colbak = GETRNDCOL(count*2+1,TBscn.resoptr->maxcol);

			EGB_color(EgbPtr,0,colcha);
			EGB_color(EgbPtr,1,colbak);
			{
				struct
				{
					short			x, y;
					unsigned short	n;
					unsigned char	ch;
				} para;

				para.x  = GETRNDPX(count);
				para.y  = GETRNDPY(count);
#if	0
				if ( para.x + 7 > TBcfg.frTest.x2 )
					para.x = TBcfg.frTest.x2 - 7;
				if ( para.y - 15 > TBcfg.frTest.y1 )
					para.y = TBcfg.frTest.y1 + 15;
#endif
				para.n  = 1;
				para.ch = count & 0xFF;
				EGB_asciiString( EgbPtr, 1, (char *)&para);
			}

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  put charactor      \t%5d\n",count_per_sec);
	}
	return (0);
}

/*************************************************************************
*	スクロール
*************************************************************************/

typedef struct
{
	unsigned int		sel;
	unsigned int		off;
	unsigned int		xbyte;
	unsigned int		xc, yc;
	void			   *buf;
} VRAMROLLPKT;

extern void	_vramroll(VRAMROLLPKT *);

#define	_FXBYTE(_x,_pixel)	(((_x) * (_pixel))>>3)

int		tbTST_dac_scroll(void)
{
	int			sec, count = 0;
	void	   *buf = NULL;

	if ( (buf = MALLOC(_FXBYTE(TBcfg.xsTest,TBscn.resoptr->pixel))) == NULL )
		tb_error_abort(TBERR_OUT_OF_MEMORY);

	{
		clock_t		clk, clkwk;

		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
#if	1
			VRAMROLLPKT	pkt;

			pkt.sel   = TBscn.resoptr->sel;
			pkt.off   = TBscn.resoptr->off
			            + _FXBYTE(TBcfg.frTest.x1,TBscn.resoptr->pixel)
			            +   TBcfg.frTest.y1 * TBscn.resoptr->xbyte;
			pkt.xbyte = TBscn.resoptr->xbyte;
			pkt.xc    = _FXBYTE(TBcfg.frTest.x2 - TBcfg.frTest.x1 + 1,TBscn.resoptr->pixel) / 4;
			pkt.yc    =  TBcfg.frTest.y2 - TBcfg.frTest.y1 + 1;
			pkt.buf   = buf;
			_vramroll(&pkt);
#else
			/* TEST */
			struct
			{
				unsigned int		off;
				unsigned short		sel;
				short				x1, y1, x2, y2;
			} para;
			int						y;

			para.x1 = TBcfg.frTest.x1;
			para.x2 = TBcfg.frTest.x2;

			{
				void _Far	*ptr;

				para.y1 = para.y2 = TBcfg.frTest.y1;
				ptr = (void _Far *)buf;
				para.off = _FP_OFF(ptr);
				para.sel = _FP_SEG(ptr);
				EGB_getBlock(EgbPtr,(char *)&para);
			}
			for ( y = 1; y < TBcfg.ysTest; ++y )
			{
				para.y1 = para.y2 = TBcfg.frTest.y1 + y;
				para.off = TBscn.resoptr->off
				            + _FXBYTE(TBcfg.frTest.x1,TBscn.resoptr->pixel)
				            + (TBcfg.frTest.y1 + y - 1) * TBscn.resoptr->xbyte;
				para.sel   = TBscn.resoptr->sel;
				EGB_getBlock(EgbPtr,(char *)&para);
			}
			{
				void _Far	*ptr;

				para.y1  = para.y2 = TBcfg.frTest.y2;
				ptr = (void _Far *)buf;
				para.off = _FP_OFF(ptr);
				para.sel = _FP_SEG(ptr);
				EGB_putBlock(EgbPtr, 0, (char *)&para);
			}
#endif
			++count;
		}
	}
	FREE(buf);

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tVRAM scroll             \t%5d\n",count_per_sec);
	}

	return (0);
}


/*************************************************************************
*	ブロック転送
*************************************************************************/

#define	MARGIN_SIZE	(256)

int		tbTST_egb_block(void)
{
	int			sec, count = 0;
	void	   *buf = NULL;
	size_t		bufsiz;

	bufsiz = _FXBYTE(TBcfg.xsTest,TBscn.resoptr->pixel) * TBcfg.ysTest;
	bufsiz += MARGIN_SIZE;
	if ( (buf = MALLOC(bufsiz)) == NULL )
		tb_error_abort(TBERR_OUT_OF_MEMORY);

	/* get block */
	{
		clock_t		clk, clkwk;

		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			struct
			{
				unsigned int		off;
				unsigned short		sel;
				short				x1, y1, x2, y2;
			} para;

			{
				void _Far	*ptr;

				ptr = (void _Far *)buf;
				para.off = _FP_OFF(ptr) + ((count<<2) & (MARGIN_SIZE-1));
				para.sel = _FP_SEG(ptr);
			}
			para.x1 = TBcfg.frTest.x1;
			para.y1 = TBcfg.frTest.y1;
			para.x2 = TBcfg.frTest.x2;
			para.y2 = TBcfg.frTest.y2;
			EGB_getBlock(EgbPtr,(char *)&para);

			++count;
		}
	}
	FREE(buf);

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  get block          \t%5d\n",count_per_sec);
	}

	/* put block */
	if ( tb_check_blockbuffer() )
		return (-1);
	count = 0;
	sec   = 0;
	{
		clock_t		clk, clkwk;

		EGB_writeMode(EgbPtr,OPAQUE);
		sec += TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			struct
			{
				unsigned int		off;
				unsigned short		sel;
				short				x1, y1, x2, y2;
			} para;

			buf = Buftbl[count & (NUM_BLOCKBUFFER-1)];
			{
				void _Far	*ptr;

				ptr = (void _Far *)buf;
				para.off = _FP_OFF(ptr);
				para.sel = _FP_SEG(ptr);
			}
			para.x1 = TBcfg.frTest.x1;
			para.y1 = TBcfg.frTest.y1;
			para.x2 = TBcfg.frTest.x2;
			para.y2 = TBcfg.frTest.y2;
			EGB_putBlock(EgbPtr,0, (char *)&para);

			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tEGB  put block          \t%5d\n",count_per_sec);
	}

	return (0);
}

typedef struct
{
	unsigned int		sel;
	unsigned int		off;
	unsigned int		xbyte;
	unsigned int		xc, yc;
	void			   *buf;
} VRAMBLOCKPKT;

extern void	_vram_getblock(VRAMBLOCKPKT *);
extern void	_vram_putblock(VRAMBLOCKPKT *);

int		tbTST_dac_block(void)
{
	int			sec, count = 0;
	void	   *buf = NULL;
	size_t		bufsiz;

	bufsiz = _FXBYTE(TBcfg.xsTest,TBscn.resoptr->pixel) * TBcfg.ysTest;
	bufsiz += MARGIN_SIZE;
	if ( (buf = MALLOC(bufsiz)) == NULL )
		tb_error_abort(TBERR_OUT_OF_MEMORY);

	/* get block */
	{
		clock_t		clk, clkwk;

		sec = TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			VRAMBLOCKPKT	pkt;

			pkt.sel   = TBscn.resoptr->sel;
			pkt.off   = TBscn.resoptr->off
			            + _FXBYTE(TBcfg.frTest.x1,TBscn.resoptr->pixel)
			            +   TBcfg.frTest.y1 * TBscn.resoptr->xbyte
			            + ((count<<2) & (MARGIN_SIZE-1));
			pkt.xbyte = TBscn.resoptr->xbyte;
			pkt.xc    = _FXBYTE(TBcfg.frTest.x2 - TBcfg.frTest.x1 + 1,TBscn.resoptr->pixel) / 4;
			pkt.yc    =  TBcfg.frTest.y2 - TBcfg.frTest.y1 + 1;
			pkt.buf   = buf;
			_vram_getblock(&pkt);
			++count;
		}
	}
	FREE(buf);

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tVRAM get block          \t%5d\n",count_per_sec);
	}

	/* put block */
	if ( tb_check_blockbuffer() )
		return (-1);
	count = 0;
	sec   = 0;
	{
		clock_t		clk, clkwk;

		sec += TBcfg.looptime;
		clk = clock() + sec * CLOCKS_PER_SEC;
		while ( CHKCLOCK(clk,clkwk) )
		{
			VRAMBLOCKPKT	pkt;

			buf = Buftbl[count & (NUM_BLOCKBUFFER-1)];
			pkt.sel   = TBscn.resoptr->sel;
			pkt.off   = TBscn.resoptr->off
			            + _FXBYTE(TBcfg.frTest.x1,TBscn.resoptr->pixel)
			            +   TBcfg.frTest.y1 * TBscn.resoptr->xbyte;
			pkt.xbyte = TBscn.resoptr->xbyte;
			pkt.xc    = _FXBYTE(TBcfg.frTest.x2 - TBcfg.frTest.x1 + 1,TBscn.resoptr->pixel) / 4;
			pkt.yc    =  TBcfg.frTest.y2 - TBcfg.frTest.y1 + 1;
			pkt.buf   = buf;
			_vram_putblock(&pkt);
			++count;
		}
	}

	/* 結果表示	*/
	{
		int		count_per_sec;

		count_per_sec = (int)( (double)count / (double)sec );
		tb_list_putf(TBcfg.listctrl,
		   "\tVRAM put block          \t%5d\n",count_per_sec);
	}

	return (0);
}

int		tb_get_blockbuffer(int n)
{
	if ( Buftbl[n] == NULL )
	{
		size_t	bufsiz;

		bufsiz = _FXBYTE(TBcfg.xsTest,TBscn.resoptr->pixel) * TBcfg.ysTest;
		if ( (Buftbl[n] = MALLOC(bufsiz)) == NULL )
			tb_error_abort(TBERR_OUT_OF_MEMORY);
	}

	{
		VRAMBLOCKPKT	pkt;

		pkt.sel   = TBscn.resoptr->sel;
		pkt.off   = TBscn.resoptr->off
		            + _FXBYTE(TBcfg.frTest.x1,TBscn.resoptr->pixel)
		            +   TBcfg.frTest.y1 * TBscn.resoptr->xbyte;
		pkt.xbyte = TBscn.resoptr->xbyte;
		pkt.xc    = _FXBYTE(TBcfg.frTest.x2 - TBcfg.frTest.x1 + 1,TBscn.resoptr->pixel) / 4;
		pkt.yc    =  TBcfg.frTest.y2 - TBcfg.frTest.y1 + 1;
		pkt.buf   = Buftbl[n];
		_vram_getblock(&pkt);
	}
	return (0);
}

int		tb_put_blockbuffer(int n)
{
	if ( Buftbl[n] == NULL )
		return (-1);

	{
		VRAMBLOCKPKT	pkt;

		pkt.sel   = TBscn.resoptr->sel;
		pkt.off   = TBscn.resoptr->off
		            + _FXBYTE(TBcfg.frTest.x1,TBscn.resoptr->pixel)
		            +   TBcfg.frTest.y1 * TBscn.resoptr->xbyte;
		pkt.xbyte = TBscn.resoptr->xbyte;
		pkt.xc    = _FXBYTE(TBcfg.frTest.x2 - TBcfg.frTest.x1 + 1,TBscn.resoptr->pixel) / 4;
		pkt.yc    =  TBcfg.frTest.y2 - TBcfg.frTest.y1 + 1;
		pkt.buf   = Buftbl[n];
		_vram_putblock(&pkt);
	}
	return (0);
}

void		tb_clear_blockbuffer(void)
{
	int		n;

	for ( n = 0; n < NUM_BLOCKBUFFER; ++n )
	{
		if ( Buftbl[n] != NULL )
		{
			FREE(Buftbl[n]);
			Buftbl[n] = NULL;
		}
	}
}

int		tb_check_blockbuffer(void)
{
	int		n;

	for ( n = 0; n < NUM_BLOCKBUFFER; ++n )
	{
		if ( Buftbl[n] == NULL )
		{
			if ( tb_get_blockbuffer(n) )
				return (-1);	/* error */
		}
	}
	return (0);
}
