/* << HighC V1.7 >> [FM-TOWNS] **********************************************
*
*	.PVS → TIFF 保存
*	----------------------------------------------------------------------
*	Programmed by Y.Hirata ( NIFTY-ID: NAB03321  パオパオ )
*
*	NOTE: TAB=4
****************************************************************************/

#include <stdlib.h>		/*  malloc,free	*/
#include <string.h>		/*  movedata	*/
#include <msdos.cf>		/*  getds		*/
#include <dos.h>		/*  _dos_*		*/
#include "egbtxt.h"
#include "pvd.h"
#include "tiffhead.h"

#define	NEW_ATTR			0x37				/*  VOL以外の全属性対象	*/

enum Values_for_ErrorNumber {					/*  ｴﾗｰ識別番号			*/
		ERR_NONE,	ERR_OPEN,	ERR_SEEK,	ERR_WRITE,	/*  0 -  3		*/
		ERR_CLOSE
} ;

char	_tiff_name[13] ;						/*  TIFFﾌｧｲﾙ名			*/
char	*_rep_name  = "PVD.REP" ;				/*  ﾚﾎﾟｰﾄﾌｧｲﾙ名			*/

TIFF_HEAD	_head = {	'II',	42,		8	} ;

/*  IFD内の番号
--------------- */
#define	IFD_XDOTS			1					/*  横ﾄﾞｯﾄ数			*/
#define	IFD_YDOTS			2					/*  縦ﾄﾞｯﾄ数			*/
#define	IFD_PIXEL			3					/*  ﾋﾟｸｾﾙ数				*/
#define	IFD_INTERP			5					/*  ﾃﾞｰﾀｶﾗｰ種別			*/
#define	IFD_16COLOR			6					/*  16色識別用			*/
#define	IFD_OFFSET			7					/*  画像ﾃﾞｰﾀｵﾌｾｯﾄ		*/
#define	IFD_RpS				9					/*  =縦ﾄﾞｯﾄ数			*/
#define	IFD_BYTE			10					/*  画像ﾃﾞｰﾀｻｲｽﾞ		*/
#define	IFD_MAX				11					/*  画像ﾃﾞｰﾀ内最大値	*/

TIFF_IFD	_ifd[15] = {						/*  32K色時の初期値		*/
/* 00 */	{	0x00FE,	4,	1,	0		},		/*  New Subfile Type	*/
/* 01 */	{	0x0100,	3,	1,	320		},		/*  横ﾄﾞｯﾄ数			*/
/* 02 */	{	0x0101,	3,	1,	240		},		/*  縦ﾄﾞｯﾄ数			*/
/* 03 */	{	0x0102,	3,	1,	16		},		/*  16ﾋﾞｯﾄﾋﾟｸｾﾙ			*/
/* 04 */	{	0x0103,	3,	1,	1		},		/*  1:非圧縮, 5:LZW圧縮	*/
/* 05 */	{	0x0106,	3,	1,	1		},		/*  1:ｶﾗｰ, 3:ﾊﾟﾚｯﾄ		*/
/* 06 */	{	0x010A,	3,	1,	1		},		/*  2:16色ﾓｰﾄﾞ,1:その他	*/
/* 07 */	{	0x0111,	4,	1,	0x200	},		/*  画像ﾃﾞｰﾀ格納位置	*/
/* 08 */	{	0x0115,	3,	1,	1		},		/*  3:ﾌﾙｶﾗｰ, 1:その他	*/
/* 09 */	{	0x0116,	4,	1,	240		},		/*  Rows/Strip=縦ﾄﾞｯﾄ数	*/
/* 10 */	{	0x0117,	4,	1,	153600	},		/*  画像ﾃﾞｰﾀｻｲｽﾞ(ﾊﾞｲﾄ)	*/
/* 11 */	{	0x0119,	3,	1,	0x7FFF	},		/*  画像ﾃﾞｰﾀ内最大値	*/
/* 12 */	{	0x011A,	5,	1,	0x1F0	},		/*  横解像度ｵﾌｾｯﾄ		*/
/* 13 */	{	0x011B,	5,	1,	0x1F8	},		/*  縦解像度ｵﾌｾｯﾄ		*/
/* 14 */	{	0x011C,	3,	1,	1		}		/*  1固定				*/
} ;
TIFF_IFD	_clut ;								/*  ﾊﾟﾚｯﾄ用IFD			*/

void wait10us( int cnt )
{
	union REGS	regs ;

	regs.x.cx = cnt ;
	int86( 0xFD,&regs,&regs ) ;
}

void beep( int sw )
{
	union REGS	regs ;

	regs.h.ah = sw ? 0 : 1 ;
	int86( 0x9E,&regs,&regs ) ;
}

void err_beep( void )
{
	beep( TRUE ) ;								/*  beep on				*/
	wait10us( 10000 ) ;							/*  100ms				*/
	beep( FALSE ) ;								/*  beep off			*/
	wait10us( 10000 ) ;							/*  100ms				*/
	beep( TRUE ) ;								/*  beep on				*/
	wait10us( 15000 ) ;							/*  150ms				*/
	beep( FALSE ) ;								/*  beep off			*/
}

void make16Header( int sx,int sy )
{
	_ifd[IFD_XDOTS].val		= sx ;				/*  横ﾄﾞｯﾄ数			*/
	_ifd[IFD_YDOTS].val		= sy ;				/*  縦ﾄﾞｯﾄ数			*/
	_ifd[IFD_PIXEL].val		= 4 ;				/*  4ﾋﾞｯﾄﾋﾟｸｾﾙ			*/
	_ifd[IFD_INTERP].val	= 3 ;				/*  ﾊﾟﾚｯﾄﾃﾞｰﾀ			*/
	_ifd[IFD_16COLOR].val	= 2 ;				/*  16色ﾃﾞｰﾀ			*/
	_ifd[IFD_OFFSET].val	= 0x200 ;			/*  画像ﾃﾞｰﾀｵﾌｾｯﾄ		*/
	_ifd[IFD_RpS].val		= sy ;				/*  縦ﾄﾞｯﾄ数			*/
	_ifd[IFD_BYTE].val		= sx * sy / 2 ;		/*  画像ﾃﾞｰﾀｻｲｽﾞ		*/
	_ifd[IFD_MAX].val		= 0x0F ;			/*  最大値				*/
	_clut.tag	= 0x0140 ;						/*  ﾀｸﾞ種別				*/
	_clut.type	= 3 ;							/*  ﾌｨｰﾙﾄﾞﾀｲﾌﾟ			*/
	_clut.len	= 48 ;							/*  ﾌｨｰﾙﾄﾞ長			*/
	_clut.val	= 0x100 ;						/*  CLUTｵﾌｾｯﾄ			*/
}

void make256Header( int sx,int sy )
{
	_ifd[IFD_XDOTS].val		= sx ;				/*  横ﾄﾞｯﾄ数			*/
	_ifd[IFD_YDOTS].val		= sy ;				/*  縦ﾄﾞｯﾄ数			*/
	_ifd[IFD_PIXEL].val		= 8 ;				/*  8ﾋﾞｯﾄﾋﾟｸｾﾙ			*/
	_ifd[IFD_INTERP].val	= 3 ;				/*  ﾊﾟﾚｯﾄﾃﾞｰﾀ			*/
	_ifd[IFD_16COLOR].val	= 1 ;				/*  16色ﾃﾞｰﾀ以外		*/
	_ifd[IFD_OFFSET].val	= 0x800 ;			/*  画像ﾃﾞｰﾀｵﾌｾｯﾄ		*/
	_ifd[IFD_RpS].val		= sy ;				/*  縦ﾄﾞｯﾄ数			*/
	_ifd[IFD_BYTE].val		= sx * sy ;			/*  画像ﾃﾞｰﾀｻｲｽﾞ		*/
	_ifd[IFD_MAX].val		= 0xFF ;			/*  最大値				*/
	_clut.tag	= 0x0140 ;						/*  ﾀｸﾞ種別				*/
	_clut.type	= 3 ;							/*  ﾌｨｰﾙﾄﾞﾀｲﾌﾟ			*/
	_clut.len	= 768 ;							/*  ﾌｨｰﾙﾄﾞ長			*/
	_clut.val	= 0x200 ;						/*  CLUTｵﾌｾｯﾄ			*/
}

void make32KHeader( int sx,int sy )
{
	_ifd[IFD_XDOTS].val		= sx ;				/*  横ﾄﾞｯﾄ数			*/
	_ifd[IFD_YDOTS].val		= sy ;				/*  縦ﾄﾞｯﾄ数			*/
	_ifd[IFD_RpS].val		= sy ;				/*  縦ﾄﾞｯﾄ数			*/
	_ifd[IFD_BYTE].val		= sx * sy * 2 ;		/*  画像ﾃﾞｰﾀｻｲｽﾞ		*/
}

void savesize( int sw )
{
	switch ( _para.disp ) {
	case 1:										/*  page0のみ表示		*/
	case 3:										/*  page0前面表示		*/
			_para.page = 0 ;					/*  保存するﾍﾟｰｼﾞ		*/
			if ( sw ) {							/*  仮想画面ｻｲｽﾞ		*/
				if ( _para.p0 < 0 ) {			/*  MS-DOS(ｸﾞﾗﾌｨｯｸ)		*/
					_para.xsize = 640 ;
					_para.ysize = 819 ;
					_para.pixel = 4 ;
				} else {						/*  MS-DOS以外			*/
					_para.xsize = _vx0 ;
					_para.ysize = _vy0 ;
					_para.pixel = _pixel0 ;
				}
			} else {							/*  表示画面ｻｲｽﾞ		*/
				if ( _para.p0 < 0 ) {			/*  MS-DOS(ｸﾞﾗﾌｨｯｸ)		*/
					_para.xsize = 640 ;
					_para.ysize = 400 ;
					_para.pixel = 4 ;
				} else {						/*  MS-DOS以外			*/
					_para.xsize = _sx0 ;
					_para.ysize = _sy0 ;
					_para.pixel = _pixel0 ;
				}
			}
			break ;
	case 2:										/*  page1のみ表示		*/
	case 4:										/*  page1前面表示		*/
			_para.page = 1 ;					/*  保存するﾍﾟｰｼﾞ		*/
			if ( sw ) {							/*  仮想画面ｻｲｽﾞ		*/
				if ( _para.p0 < 0 ) {			/*  MS-DOS(ﾃｷｽﾄ)		*/
					_para.xsize = 1024 ;
					_para.ysize = 512 ;
					_para.pixel = 4 ;
				} else {						/*  MS-DOS以外			*/
					_para.xsize = _vx1 ;
					_para.ysize = _vy1 ;
					_para.pixel = _pixel1 ;
				}
			} else {							/*  表示画面ｻｲｽﾞ		*/
				if ( _para.p0 < 0 ) {			/*  MS-DOS(ﾃｷｽﾄ)		*/
					_para.xsize = 640 ;
					_para.ysize = 400 ;
					_para.pixel = 4 ;
				} else {						/*  MS-DOS以外			*/
					_para.xsize = _sx1 ;
					_para.ysize = _sy1 ;
					_para.pixel = _pixel1 ;
				}
			}
			break ;
	}
}

int padding( int size,FILE *fp )
{
	if ( fwrite( _tmp,1,size,fp ) != size ) return ERR_WRITE ;
	return ERR_NONE ;
}

int resolution( ULONG r1,ULONG r2,ULONG r3,ULONG r4,FILE *fp )
{
	size_t	size=sizeof( ULONG ) ;

	if ( fwrite( &r1,1,size,fp ) != size ) return ERR_WRITE ;
	if ( fwrite( &r2,1,size,fp ) != size ) return ERR_WRITE ;
	if ( fwrite( &r3,1,size,fp ) != size ) return ERR_WRITE ;
	if ( fwrite( &r4,1,size,fp ) != size ) return ERR_WRITE ;
	return ERR_NONE ;
}

USHORT palcnv( UCHAR pal )
{
	USHORT	wk ;

	wk = (USHORT)pal << 8 ;
	return ( wk | (USHORT)pal ) ;
}

int header16_save( FILE *fp )
{
	USHORT	pal[16] ;
	size_t	size=sizeof( pal ) ;
	_PAL_16	*clut ;
	int		cnt ;

	if ( padding( 50,fp ) != ERR_NONE ) return ERR_WRITE ;
	clut = _para.page == 1 ? &_pal161 : &_pal160 ;
	for ( cnt=0; cnt<16; cnt++ ) pal[cnt] = palcnv( clut->pal[cnt].r ) ;
	if ( fwrite( pal,1,size,fp ) != size ) return ERR_WRITE ;
	for ( cnt=0; cnt<16; cnt++ ) pal[cnt] = palcnv( clut->pal[cnt].g ) ;
	if ( fwrite( pal,1,size,fp ) != size ) return ERR_WRITE ;
	for ( cnt=0; cnt<16; cnt++ ) pal[cnt] = palcnv( clut->pal[cnt].b ) ;
	if ( fwrite( pal,1,size,fp ) != size ) return ERR_WRITE ;

	if ( padding( 144,fp ) != ERR_NONE ) return ERR_WRITE ;
	if ( resolution( 75,1,75,1,fp ) != ERR_NONE ) return ERR_WRITE ;
	return ERR_NONE ;
}

int header256_save( FILE *fp )
{
	USHORT	pal[256] ;
	size_t	size=sizeof( pal ) ;
	int		cnt ;

	if ( padding( 290,fp ) != ERR_NONE ) return ERR_WRITE ;
	if ( resolution( 75,1,75,1,fp ) != ERR_NONE ) return ERR_WRITE ;
	for ( cnt=0; cnt<256; cnt++ ) pal[cnt] = palcnv( _pal256.pal[cnt].r ) ;
	if ( fwrite( pal,1,size,fp ) != size ) return ERR_WRITE ;
	for ( cnt=0; cnt<256; cnt++ ) pal[cnt] = palcnv( _pal256.pal[cnt].g ) ;
	if ( fwrite( pal,1,size,fp ) != size ) return ERR_WRITE ;
	for ( cnt=0; cnt<256; cnt++ ) pal[cnt] = palcnv( _pal256.pal[cnt].b ) ;
	if ( fwrite( pal,1,size,fp ) != size ) return ERR_WRITE ;
	return ERR_NONE ;
}

int header32K_save( FILE *fp )
{
	if ( padding( 302,fp ) != ERR_NONE ) return ERR_WRITE ;
	if ( resolution( 75,2,75,2,fp ) != ERR_NONE ) return ERR_WRITE ;
	return ERR_NONE ;
}

int header_save( FILE *fp )
{
	USHORT	ntag ;
	ULONG	etag=0L ;
	size_t	size ;
	int		cnt, ret ;

	if ( _para.pixel == 4 ) {					/*  16色				*/
		ntag = 16 ;
		make16Header( _para.xsize,_para.ysize ) ;
	} else if ( _para.pixel == 8 ) {			/*  256色				*/
		ntag = 16 ;
		make256Header( _para.xsize,_para.ysize ) ;
	} else {									/*  32K色				*/
		ntag = 15 ;
		make32KHeader( _para.xsize,_para.ysize ) ;
	}
	size = sizeof( USHORT ) ;
	if ( fwrite( &ntag,1,size,fp ) != size ) return ERR_WRITE ;
	size = sizeof( _ifd ) ;
	if ( fwrite( &_ifd,1,size,fp ) != size ) return ERR_WRITE ;
	if ( _para.pixel == 4 || _para.pixel == 8 ) {	/*  ﾊﾟﾚｯﾄ用IFD		*/
		size = sizeof( _clut ) ;
		if ( fwrite( &_clut,1,size,fp ) != size ) return ERR_WRITE ;
	}
	size = sizeof( ULONG ) ;
	if ( fwrite( &etag,1,size,fp ) != size ) return ERR_WRITE ;
	for ( cnt=0; cnt<TMP_SIZE; cnt++ ) _tmp[cnt] = 0 ;
	if ( _para.pixel == 4 ) {					/*  16色				*/
		ret = header16_save( fp ) ;
	} else if ( _para.pixel == 8 ) {			/*  256色				*/
		ret = header256_save( fp ) ;
	} else {									/*  32K色				*/
		ret = header32K_save( fp ) ;
	}
	return ret ;
}

int vramdata_save( FILE *fp )
{
	size_t	size=(size_t)_ifd[IFD_BYTE].val ;
	int		ret=ERR_NONE ;
	int		cnt ;

	EGB_writePage( Gwork,_para.page ) ;			/*  ｱｸﾃｨﾌﾞﾍﾟｰｼﾞの設定	*/
	if ( _para.buf == NULL ) {					/*  VRAM領域確保失敗時	*/
		size = (size_t)_para.xsize ;
		if ( _para.pixel == 4 )		size >>= 1 ;	/*  1/2倍		*/
		if ( _para.pixel == 16 )	size <<= 1 ;	/*  2倍			*/
		for ( cnt=0; cnt<_para.ysize; cnt++ ) {
			gget( 0,cnt,_para.xsize-1,cnt,(unsigned int)_tmp ) ;
			if ( fwrite( _tmp,1,size,fp ) != size ) return ERR_WRITE ;
		}
	} else {									/*  VRAM領域確保済		*/
		char	*buf=_para.buf ;
		UINT	bufp ;
		if ( _para.page ) buf = _para.buf + VRAM_HALF ;
		bufp = (UINT)buf ;
		gget( 0,0,_para.xsize-1,_para.ysize-1,bufp ) ;
		if ( fwrite( buf,1,size,fp ) != size ) ret = ERR_WRITE ;
		if ( _para.p0 >= 12 ) {					/*  page0のみ			*/
			movedata( 0x120,0,getds(),bufp,VRAM_SIZE ) ;
		} else {
			if ( _para.page ) {					/*  page1				*/
				movedata( 0x120,VRAM_HALF,getds(),bufp,VRAM_HALF ) ;
			} else {							/*  page0				*/
				movedata( 0x120,0,getds(),bufp,VRAM_HALF ) ;
			}
		}
	}
	return ret ;
}

int dos_save( FILE *fp )
{
	size_t	size, vx ;
	int		cnt, off ;

	size = (size_t)_para.xsize >> 1 ;			/*  1/2倍(4ﾋﾞｯﾄﾋﾟｸｾﾙ)	*/
	if ( _para.page ) {							/*  page1(ﾃｷｽﾄ)			*/
		off = VRAM_HALF ;
		vx  = 512 ;								/*  1024/2				*/
	} else {									/*  page0(ｸﾞﾗﾌｨｯｸ)		*/
		off = 0 ;
		vx  = 320 ;								/*  640/2				*/
	}
	for ( cnt=0; cnt<_para.ysize; cnt++, off+=vx ) {
		movedata( 0x120,off,getds(),(UINT)_tmp,size ) ;
		if ( fwrite( _tmp,1,size,fp ) != size ) return ERR_WRITE ;
	}
	return ERR_NONE ;
}

int vram_save( FILE *fp )
{
	char	*buf=NULL ;
	size_t	size=(size_t)_ifd[IFD_BYTE].val ;
	int		ret=ERR_NONE ;

	if ( _para.p0 < 0 ) return dos_save( fp ) ;	/*  MS-DOS画面の保存	*/
	buf = (char *)malloc( size+4 ) ;
	if ( buf == NULL ) return vramdata_save( fp ) ;	/*  ﾒﾓﾘ不足時		*/
	EGB_writePage( Gwork,_para.page ) ;			/*  ｱｸﾃｨﾌﾞﾍﾟｰｼﾞの設定	*/
	gget( 0,0,_para.xsize-1,_para.ysize-1,(unsigned int)buf ) ;
	if ( fwrite( buf,1,size,fp ) != size ) ret = ERR_WRITE ;
	free( buf ) ;
	return ret ;
}

int tiff_create( void )
{
	int		ret=ERR_NONE, err ;
	FILE	*fp ;
	size_t	size ;

	if ( (fp = fopen( _tiff_name,"wb" )) == NULL ) return ERR_OPEN ;
	size = sizeof( TIFF_HEAD ) ;
	if ( fwrite( &_head,1,size,fp ) != size ) goto close ;
	ret = header_save( fp ) ;					/*  ﾍｯﾀﾞ部分保存		*/
	if ( ret != ERR_NONE ) goto close ;
	ret = vram_save( fp ) ;						/*  画像ﾃﾞｰﾀ保存		*/
close:
	err = fclose( fp ) ;
	if ( err && ret == ERR_NONE ) ret = ERR_CLOSE ;
	return ret ;
}

char	*mode_msg[] = {
		" DOS ( 640 * 400,  16色, 24KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　１ ( 640 * 400,  16色, 24KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　２ ( 640 * 200,  16色, 24KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　３ ( 640 * 480,  16色, 31KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　４ ( 640 * 400,  16色, 24KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　５ ( 256 * 256, 32K色, 31KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　６ ( 256 * 256, 32K色, 24KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　７ ( 256 * 240, 32K色, 15KHz,   ｲﾝﾀﾚｰｽ )",
		"　８ ( 256 * 240, 32K色, 15KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"　９ ( 360 * 240, 32K色, 15KHz,   ｲﾝﾀﾚｰｽ )",
		"１０ ( 320 * 240, 32K色, 31KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"１１ ( 320 * 240, 32K色, 15KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"１２ ( 640 * 480, 256色, 31KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"１３ ( 640 * 400, 256色, 24KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"１４ ( 720 * 480, 256色, 15KHz,   ｲﾝﾀﾚｰｽ )",
		"１５ ( 320 * 480, 32K色, 31KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"１６ ( 320 * 480, 32K色, 15KHz,   ｲﾝﾀﾚｰｽ )",
		"１７ ( 512 * 480, 32K色, 31KHz, ﾉﾝｲﾝﾀﾚｰｽ )",
		"１８ ( 512 * 480, 32K色, 15KHz,   ｲﾝﾀﾚｰｽ )"
} ;

void mode_report( FILE *fp )
{
	int		wk ;

	fprintf( fp,"保存TIFFファイル : %s\n",_tiff_name ) ;
	fprintf( fp,"画面モード: " ) ;
	wk = _para.p0 < 0 ? 0 : ( _para.page ? _para.p1 : _para.p0 ) ;
	fprintf( fp,"%s,  対象頁: %d\n",mode_msg[wk],_para.page ) ;
	fprintf( fp,"横サイズ: %dドット,  ",_para.xsize ) ;
	fprintf( fp,"縦サイズ: %dドット,  ",_para.ysize ) ;
	fprintf( fp,"ピクセル数: %dビット/ドット\n",_para.pixel ) ;
}

int tiff_save( void )
{
	static int	fno=0 ;
	struct find_t	dta ;
	int		cnt, ret ;
	FILE	*fp ;

	for ( cnt=fno; cnt<100000; cnt++ ) {
		sprintf( _tiff_name,"PVD%05d.TIF",cnt ) ;
		if ( _dos_findfirst( _tiff_name,NEW_ATTR,&dta ) ) {
			fno = cnt ;
			break ;
		}
	}
	if ( (fp = fopen( _rep_name,"a" )) == NULL ) {
		err_beep() ;
		return 1 ;
	}
	fprintf( fp,"\n.PVSファイル     : %s\n",_para.fname ) ;
	if ( fno != cnt ) {							/*  TIFFﾌｧｲﾙ作成しない	*/
		fprintf( fp,"<< これ以上TIFFファイルを作成できません. >>\n" ) ;
		err_beep() ;
		ret = 1 ;
	} else {									/*  TIFF保存開始		*/
		mode_report( fp ) ;
		if ( tiff_create() == ERR_NONE ) {		/*  TIFFﾌｧｲﾙ作成		*/
			ret = 0 ;
		} else {								/*  TIFFﾌｧｲﾙ作成失敗	*/
			fprintf( fp,"<< TIFFファイルの作成に失敗しました. >>\n" ) ;
			err_beep() ;
			ret = 1 ;
		}
	}
	fclose( fp ) ;
	return ret ;
}

/*	HISTORY
-----------------------------------------------------------------------------
*	1994.01.13 : CREATE
---------------------------------------------------------------------------*/
