//*************************************************************************************************
//	File Name	: Vram.java
//	Theme	: Ragnarekkr Vram Emuration
//	History
//	'94/11/04	O.Ikegame	COMM.H/WORK.ASM
//	'04/09/10	H.Kuwata	java coding
//*************************************************************************************************

//=================================================================================================
//	Inport
//=================================================================================================
import java.awt.*;
import java.awt.image.*;

//=================================================================================================
//	Section																Class Definition
//=================================================================================================

public	class	Vram
{
	//;;==========   PC9801 4 Plane VRAM  =============
	static	final int	_vram_size_x = 640;
	static	final int	_vram_size_y = 400;

	static	final int	_plane	=	32768;//80*400;			// Plane Size

	static	byte [][]	_vram	=	new byte[2][_plane*4];
	static	byte []	vram_act	=	_vram[0];
	static	byte []	vram_disp	=	_vram[0];
	static	byte []	clut	=	new byte[16*3];

	static	final int	_blue	=	0;			// Segment 青
	static	final int	_red	=	_plane;		// Segment 赤
	static	final int	_green	=	_plane*2;	// Segment 緑
	static	final int	_half	=	_plane*3;	// Segment 明暗
	static	final int	_p_max	=	_plane*4;

	static	IndexColorModel		now_color;
	static	BufferedImage		now_image;
	static	DataBufferByte		vram_pixel;
	static	WritableRaster		vram_raster;

	//-------  ACT / DIS  ------

	static	int		SELECT	=	0;			// Drawing Screen //書き込み中 物理画面
	static	int		DISP_	=	0;			// Display Screen //表示中 物理画面 

	static	void	setupVram()
	{
		vram_pixel	=	new DataBufferByte( _vram_size_x*_vram_size_y, 1 );
		vram_raster	=	WritableRaster.createPackedRaster(
									vram_pixel,
									_vram_size_x,
									_vram_size_y,
									8,
									null );
		ANALOG_AP_DAT();
	}
	static	void	resetVram()
	{
		now_color	=	new IndexColorModel( 8, 16, Vram.clut, 0, false );
		now_image	=	new BufferedImage(
								now_color,
								vram_raster,
								false,
								null
								);
	}

	static	void	refreshVram()
	{
		byte [] pixel = vram_pixel.getData();

		int px ,py, pm;
		int	idx, vp;
		idx	=	0;
		vp	=	0;
		for ( py = 0 ; py < _vram_size_y ; py ++ )
		{
			for ( px = 0 ; px < _vram_size_x/8 ; px ++ )
			{
				int	_bp	=	Vram.vram_disp[ vp + Vram._blue ];
				int	_rp	=	Vram.vram_disp[ vp + Vram._red ];
				int	_gp	=	Vram.vram_disp[ vp + Vram._green ];
				int	_hp	=	Vram.vram_disp[ vp + Vram._half ];
				vp ++;
				for ( pm = 0x080 ; pm != 0 ; pm >>= 1 )
				{
					int	_bc	=	( (_bp & pm)!=0 ? 1 : 0 );
					int	_rc	=	( (_rp & pm)!=0 ? 2 : 0 );
					int	_gc	=	( (_gp & pm)!=0 ? 4 : 0 );
					int	_hc	=	( (_hp & pm)!=0 ? 8 : 0 );

					pixel[ idx ] = (byte)(_bc|_rc|_gc|_hc);
					idx++;
				}
			}
		}
	}

	static	Image	loadVram()
	{
		refreshVram();
		return now_image;
	}

	//;;==========   4 Plane Pattarn Drawing  =============

	//	BP:[BX]  ->  [DX]     Size [CH.CL]

	static	void	PUT_PATTRN( byte [] bp, int bx, int dx, int ch, int cl )
	{
		int plane, line, c;
		for ( plane = _blue ; plane < _p_max ; plane += _red )
		{
			int dxx = dx;
			for ( line = 0 ; line < cl ; line ++ )	// Size Y  [CL]
			{
				int	di = dxx;	// X Loop Count
				for ( c = 0 ; c < ch ; c++ )			// Size X  [BX]
				{
					vram_act[ plane + di ] = bp[ bx++ ];
					di++;
				}
				dxx += Work.YY;
			}
		}
	}

	//;;==========   Analog Palette Setting  =============

	//	Analog Pallet [BX]		(A8H)   G.AA,  R.AC,  B.AE

	static	void	ANALOG_AP_DAT()
	{
        // Set AP_DAT Palette //AP_DAT のパレットを設定
		ANALOG( Work.getAP_DAT(), 0 );	// AP_DAT read from FILE // FILE_READ 等で格納される。
	}

	static	void	ANALOG( byte [] pal, int bx )
	{
		int	c;
		for ( c = 0 ; c < 16 ; c++ )
		{
			int	b	=	pal[ bx+c*3+0 ] & 0x0ff;
			int	r	=	pal[ bx+c*3+1 ] & 0x0ff;
			int	g	=	pal[ bx+c*3+2 ] & 0x0ff;
			Work.NOW_PAL[ c*3+0 ]	=	(byte)b;
			Work.NOW_PAL[ c*3+1 ]	=	(byte)r;
			Work.NOW_PAL[ c*3+2 ]	=	(byte)g;
			if ( Tos.BIT_BIT( 5 ) != 0 ) {	// Check Color or B/W
				int a = (g * 9 + r * 5 + b * 2) / 16;
				b = a;
				r = a;
				g = a;
			}
			b = b | (b<<4);
			r = r | (r<<4);
			g = g | (g<<4);
			//clut[ c ] = 0xff000000 + (r<<16) + (g<<8) + b;
			//System.out.println( "clut["+c+"]=" + Integer.toHexString(clut[c]) );
			clut[ c*3+0 ]	=	(byte)r;
			clut[ c*3+1 ]	=	(byte)g;
			clut[ c*3+2 ]	=	(byte)b;
		}
		resetVram();
	}
	static	void	ANALOG( int [] pal )
	{
		int	c;
		for ( c = 0 ; c < 16 ; c++ )
		{
			int	b	=	pal[ c*3+0 ] & 0x0ff;
			int	r	=	pal[ c*3+1 ] & 0x0ff;
			int	g	=	pal[ c*3+2 ] & 0x0ff;
			Work.NOW_PAL[ c*3+0 ]	=	(byte)b;
			Work.NOW_PAL[ c*3+1 ]	=	(byte)r;
			Work.NOW_PAL[ c*3+2 ]	=	(byte)g;

			b = b | (b<<4);
			r = r | (r<<4);
			g = g | (g<<4);
			//clut[ c ] = 0xff000000 + (r<<16) + (g<<8) + b;
			clut[ c*3+0 ]	=	(byte)r;
			clut[ c*3+1 ]	=	(byte)g;
			clut[ c*3+2 ]	=	(byte)b;
		}
		resetVram();
	}

	//------  Put Kanji chara // 漢字 1文字 表示  (Bios)  -------

	//  漢字データ [DX] を1文字表示する。	ROMアドレス又はフォントアドレス
	//  シフト3度書き、縮小文字、オリジナルフォント 対応。
	//	F_PAT = 文字タイプ スイッチ  (0) 漢字ロム (1) 内部フォント

	//	漢字データ [DX]   / 表示アドレス [BX]   /  Position [CX]
	//	Data Ptr  [DX]   / Dst Vram Address [BX]   /  Position [CX]

	static	void	KPUT_( int BX, int code )
	{
		if ( Work.DUBLE_FACE != 0 )
		{
			// Double Face Mode // 両面 描画モード
			ACT_();
			KPUT_SINGLE_( BX, code );
			ACT_();
		}
		KPUT_SINGLE_( BX, code );
	}
	static	byte []	ktext	=	{	27, 0x24, 0x42, 0, 0	};

	static	void	KPUT_SINGLE_( int bx, int code )
	{
		// Draw 1 chara to Buffer // Buffer に一文字描画
		BufferedImage	font_image	=	new BufferedImage( 16,16, BufferedImage.TYPE_BYTE_GRAY );
		Graphics	g = font_image.getGraphics();

		String	kput = "X";
		try {
			ktext[3]	=	(byte)( (code>>8) & 0x0ff );
			ktext[4]	=	(byte)( code & 0x0ff );
			kput	=	new String( ktext, "ISO-2022-JP" );
		} catch( Exception e) {	e.printStackTrace(); }

		Font font = new Font( "MS Gothic" , Font.PLAIN, (Work.F_TYPE == 1 ? 10:16) ); // "MS ゴシック"

		g.setFont(font);
		//g.setColor(Color.WHITE);
		g.drawString( kput, 0,15 );

		WritableRaster	raster	=	font_image.getRaster();
		DataBufferByte	buffer	=	(DataBufferByte)raster.getDataBuffer();
		byte []	kimg	=	buffer.getData();

		//System.out.println( "Buf bank = " + buffer.getNumBanks() );
		//System.out.println( "Buf size = " + buffer.getSize() );
		//System.out.println( "kimg size = " + kimg.length );

		int		color	=	Work.OLINE_COL;
		byte	ALb = (byte)(((color & 1)!=0 ? 0x0ff : 0));
		byte	ALr = (byte)(((color & 2)!=0 ? 0x0ff : 0));
		byte	ALg = (byte)(((color & 4)!=0 ? 0x0ff : 0));
		byte	ALh = (byte)(((color & 8)!=0 ? 0x0ff : 0));

		int	y, x, e, m,n;
		for ( y = 0; y < 16 ; y++ )
		{
			for ( e = 0 ; e < 2 ; e++ )
			{
				m = 0x080;
				for ( x = 0 ; x < 8 ; x++ )		// Size X   [BX]
				{
					n = ~m;
					if ( kimg[y*16+e*8+x] != 0 )
					{
						if ( (ALb) != 0 ) {
							vram_act[ bx+_blue ]	|=	m;
						} else {
							vram_act[ bx+_blue ]	&=	n;
						}
						if ( (ALr) != 0 ) {
							vram_act[ bx+_red ]	|=	m;
						} else {
							vram_act[ bx+_red ]	&=	n;
						}
						if ( (ALg) != 0 ) {
							vram_act[ bx+_green ]	|=	m;
						} else {
							vram_act[ bx+_green ]	&=	n;
						}
						if ( (ALh) != 0 ) {
							vram_act[ bx+_half ]	|=	m;
						} else {
							vram_act[ bx+_half ]	&=	n;
						}
					}
					m >>= 1;
				}
				bx++;
			}
			bx += (Work.YY-2);
		}
	}

}