/*	
 *	clipuvi.h
 *
 *	P/ECE Signetics 2637 UVI(Universal Video Interface) Emulator
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Sat Apr 30 13:14:00 JST 2005 Naoyuki Sawa
 *	- 作成開始。
 */
#ifndef __CLIP_UVI_H__
#define __CLIP_UVI_H__

/****************************************************************************
 *
 ****************************************************************************/

/* UVI_ASMシンボル定義を読み込みます。
 * UVI_ASMシンボルの未定義/定義によるC/アセンブラコードの切り替えは、
 * Cソースファイル(*.c)とアセンブラソースファイル(*.s)から参照するので、
 * 別のインクルードファイルに分けています。
 * (C言語特有の定義を含むインクルードファイルをそのままアセンブラソースに
 *  インクルードすると、アセンブルエラーになってしまうため。)
 */
#include "clipuvia.h"

/********** これ以降は書き換えないでください **********/

/* P/ECE以外ではアセンブラコードは使用できません。
 */
#ifndef PIECE
#undef UVI_ASM
#endif /*PIECE*/

/****************************************************************************
 *	UVI (Universal Video Interface)
 ****************************************************************************/

//			  +++------------------------- TV picture width
//			  ||| +++--------------------- horizontalblank
//			  ||| |||   +++--------------- TV picture height
//			  ||| |||   ||| ++------------ vertical blank
//			  ||| |||   ||| || +---------- vertical sync
//			  ||| |||   ||| || |  ++------ 60 frames per second
//			  ||| |||   ||| || |  ||
//#define UVI_CLOCK	((128+100)*(208+51+3)*60)   /* NTSC版UVI入力Clock */
/* 計算上は↑の通りですが、実際のNTSC Clockは↓やや遅めに設定されています。 */
#define UVI_CLOCK	NTSC_COLOR_SUBCARRIER
#define ARCADIA_CLOCK	UVI_CLOCK             /* NTSC版ARCADIA CPU入力Clock */

#define UVIBUFLEN 320 /* =16000/50 … 1[tick](=1/50[sec])当たりのサンプル数 */

#ifdef PIECE
#define UVI_GRAYSCALE
#endif /*PIECE*/

/* ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ */
/* ★アセンブラルーチンから直接参照しているので、フォーマット固定です。★ */
/* ★フォーマットを変更したときは、clipuvia.hの定義も追従してください。★ */
/* ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ */

typedef struct _UVIOBJ {
	unsigned char size;				/* + 0,1: サイズ (0=標準,1=縦2倍拡大) */
	unsigned char color;				/* + 1,1: カラー */
	short resv;					/* + 2,2: (予約) */
	short x;					/* + 4,2: X座標 */
	short y;					/* + 6,2: Y座標 */
	unsigned char* font/*[8]*/;			/* + 8,4: フォント */
} UVIOBJ;						/* =12 */
#define SIZEOF_UVIOBJ					    12

typedef struct _UVI {
	/*---------- Video ----------*/
	unsigned char* ram/*[0x400]*/;			/* +  0,  4: 外部RAM、内部レジスタ */
	unsigned char* vbuff/*[128*208]*/;		/* +  4,  4: 現在の仮想画面 (NULL=実描画無し) */
	short scan_start;				/* +  8,  2: 前回のスキャンライン位置 (描画区間上端  ) */
	short scan_end;					/* + 10,  2: 現在のスキャンライン位置 (描画区間下端+1) */
	short scroll_y;					/* + 12,  2: 垂直スクロール (フレーム単位) */
	char  scroll_x[26/*Row*/];			/* + 14, 26: 水平スクロール (-1:行未取得、0..7:取得済) */
	unsigned short bg[26/*Row*/][16/*Col*/];	/* + 40,832: BG (000000cc0gffffff c=Color,g=GM,f=Code) */
	unsigned char color[4/*B7:6*/][2/*Font*/];	/* +872,  8: BGカラー */
	unsigned char pot[4];				/* +880,  4: A/D Potentiometer */
	UVIOBJ obj[4];					/* +884, 48: OBJ1,OBJ2,OBJ3,OBJ4 */
	/*---------- Sound ----------*/
	int tone_count;					/* +932,  4: Tone  進行カウンタ */
	int noise_count;				/* +936,  4: Noise 進行カウンタ */
	unsigned short tone_polar;			/* +940,  2: Tone  出力極性 */
	unsigned short noise_lfsr;			/* +942,  2: Noise Linear Feedback Shift Register */
} UVI;							/* =944 */
#define SIZEOF_UVI					    944

/****************************************************************************
 *	グローバル変数
 ****************************************************************************/

extern UVI uvi;
extern unsigned char uvi_font[8/*Line*/ * 64/*Character*/ * 2/*Mode*/];

#ifdef UVI_GRAYSCALE
extern const unsigned char uvi_grayscale_table[8/*Color*/];
#else /*UVI_GRAYSCALE*/
extern const unsigned char uvi_color_table[8/*Color*/][3/*R,G,B*/];
#endif /*UVI_GRAYSCALE*/

/****************************************************************************
 *	内部関数 (Video)
 ****************************************************************************/

void uvi_update_pot();
void uvi_update_color();

void uvi_partial_update();
void uvi_draw_chr_8x8(int x, int y, int code, int color);
void uvi_draw_chr_8x16(int x, int y, int code, int color);
void uvi_draw_obj_8x8(UVIOBJ* obj);
void uvi_draw_obj_8x16(UVIOBJ* obj);

void uvi_collision();
int uvi_collision_obj_8x8_bg_8x8(UVIOBJ* obj);
int uvi_collision_obj_8x8_bg_8x16(UVIOBJ* obj);
int uvi_collision_obj_8x16_bg_8x8(UVIOBJ* obj);
int uvi_collision_obj_8x16_bg_8x16(UVIOBJ* obj);
int uvi_collision_obj_8x8_obj_8x8(UVIOBJ* obj1, UVIOBJ* obj2);
int uvi_collision_obj_8x8_obj_8x16(UVIOBJ* obj1, UVIOBJ* obj2);
int uvi_collision_obj_8x16_obj_8x8(UVIOBJ* obj1, UVIOBJ* obj2);
int uvi_collision_obj_8x16_obj_8x16(UVIOBJ* obj1, UVIOBJ* obj2);
int uvi_collision_font_8x8_font_8x8(int x1, int y1, const unsigned char* font1/*[8]*/, int x2, int y2, const unsigned char* font2/*[8]*/);
int uvi_collision_font_8x8_font_8x16(int x1, int y1, const unsigned char* font1/*[8]*/, int x2, int y2, const unsigned char* font2/*[8]*/);
int uvi_collision_font_8x16_font_8x8(int x1, int y1, const unsigned char* font1/*[8]*/, int x2, int y2, const unsigned char* font2/*[8]*/);
int uvi_collision_font_8x16_font_8x16(int x1, int y1, const unsigned char* font1/*[8]*/, int x2, int y2, const unsigned char* font2/*[8]*/);

/****************************************************************************
 *	アプリケーション用関数 (Video)
 ****************************************************************************/

/* UVIコアをリセットします。
 * [in]
 *	ram		UVIの外部RAMの先頭アドレスを指定してください。
 *			ARCADIAの場合、CPUメインメモリ空間の$1800..$1BFFを指定します。
 */
void uvi_reset(unsigned char* ram/*[0x400]*/);

/* 外部RAMまたはUVIレジスタを読み出します。
 * [in]
 *	addr		外部RAMまたはUVIレジスタアドレス。($000..$3FF)
 * [out]
 *	戻り値		読み出したデータ。($00..$FF)
 */
int uvi_read(int addr);

/* 外部RAMまたはUVIレジスタへ書き込みます。
 * [in]
 *	addr		外部RAMまたはUVIレジスタアドレス。($000..$3FF)
 *	data		書き込むデータ。($00..$FF)
 */
void uvi_write(int addr, int data);

/* アナログ入力値を設定します。
 * [in]
 *	pot		ポートアドレス。(0=POT1,1=POT2,2=POT3,3=POT4)
 *	data		アナログ入力値。($00..$FF)
 *			ARCADIAの場合、おおよそ 左:$00〜中央:$70〜右:$F0 となります。
 */
void uvi_set_pot(int pot, int data);

/* 新しいフレームを開始します。
 * [in]
 *	vbuff		描画する仮想画面。
 *			NULLを指定すると、このフレームは実描画無しとなります。
 */
void uvi_new_frame(unsigned char* vbuff/*[128*208]*/);

/* スキャンラインを1ライン進めます。
 * [out]
 *	戻り値		次回のスキャンラインがVblank期間ならば1を返します。
 *			ARCADIAの場合、2650 CPU へのSENSE入力に相当します。
 * [note]
 *	* ARCADIAの場合、uvi_new_frame()とuvi_next_line()を、次のように使ってください。
 *		1. 新しいフレームを開始する。		uvi_new_frame(vbuff)
 *		2. 2650 CPUのSENSE入力を0とする。	s2650_set_sense(0)
 *		3. 1ライン分のCPU実行。			s2650_run(ARCADIA_CLOCK/60/262)
 *		4. スキャンラインを進める。		uvi_next_line()
 *		   戻り値が0ならば、3から繰り返す。
 *		5. 2650 CPUのSENSE入力を1とする。	s2650_set_sense(1)
 *		6. 1ライン分のCPU実行。			s2650_run(ARCADIA_CLOCK/60/262)
 *		7. スキャンラインを進める。		uvi_next_line()
 *		   戻り値が1ならば、5から繰り返す。
 *		8. 1フレーム分の処理が完了したので、仮想画面をディスプレイに転送する。
 */
int uvi_next_line();

#ifdef UVI_GRAYSCALE
/* 128x208x16諧調グレイスケールを、88x128x16諧調グレイスケールへ縮小コピーします。
 * [in]
 *	src		128x208x16諧調グレイスケール画面バッファ。
 *	dst		 88x128x16諧調グレイスケール画面バッファ。
 *
 * [note]
 *	* srcとdstは同じアドレスを指していても構いません。
 *	  最終的に88x128の画面イメージだけが必要ならば、128x208と88x128の画面バッファを共通化して、
 *	  メモリを節約できます。
 */
void uvi_reduce(unsigned char dst[/*88*128*/], const unsigned char src[/*128*208*/]);
#endif UVI_GRAYSCALE

/****************************************************************************
 *	内部関数 (Sound)
 ****************************************************************************/

void uvi_tone_mix(short wbuff[/*UVIBUFLEN*/], int volume, int period);
void uvi_noise_mix(short wbuff[/*UVIBUFLEN*/], int volume, int period);
void uvi_volume_shift(short wbuff[/*UVIBUFLEN*/]);

/****************************************************************************
 *	アプリケーション用関数 (Sound)
 ****************************************************************************/

/* 出力サンプリングレート=SPEAKER_OUTPUT[Hz]で、UVIBUFLENサンプルのミキシングを行います。
 * [in]
 *	wbuff		出力サンプルバッファ。
 */
void uvi_mix(short wbuff[/*UVIBUFLEN*/]);

#endif /*__CLIP_UVI_H__*/
