/*
 *						'Magl.rex' 		for FM-TOWNS
 *
 *				- MAKIchan Graphic loader is not 鮪だ！ -
 *
 *					Version 1.03	Update 1991/05/12
 *
 *							programmed by MALOR
 */

/*
 *			1991/04/25	v1.00	正常に展開されたぞ
 *				 05/06	v1.01	カラーパレットの障害を修正
 *					10	v1.02	スタックにヒープを取るようにして、
 *								実行ファイル512Ｋの地獄を脱した(^_^;)
 *					12	v1.03	256色モードのパレットの障害を修正
 *  今後の課題
 */

#include <egb.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "pixel.h"

#define VERSION	"1.03"
#define UPDATE	"1991/05/12 11:28"

#define tolower(x) ((x)<'Z')&&((x)>'A')?((x)-'A'+'a'):(x)

#define FNAME16 0x0006118c
#define FNAME25 0x000610fc
#define FNAME32 0x000614dc

#define PALADDR16 0x00062B58	/* 16色モード時 */
#define RGB2HSV16 0x0002C774
#define PALADDR25 0x00062A08	/* 256色モード時 */
#define RGB2HSV25 0x0002c274

#define MemorySize 512*1024		/* Buffer is 512Kbyte */

#ifndef NULL
#define NULL	0
#endif

#define FALSE	0
#define TRUE	-1
#define EOC		0x1a		/* End Of Comment */
#define CR		0x0d
#define LF		0x0a
#define BufSize	256

#define PLANE20	0x001c
#define PLANE21	0x0104
#define PLANE10	0x010c

#define PALNO	0xfd90
#define PALB	0xfd92
#define PALR	0xfd94
#define PALG	0xfd96

#define LINE200	0x01			/* 200ラインフラグ */
#define COL8	0x02			/* 8色フラグ */
#define DIGITAL	0x04			/* デジタルフラグ */
#define COL256	0x80			/* 256色フラグ */

#define VRAM	0x20			/* 強制ＶＲＡＭ展開フラグ */

typedef union {
	struct { unsigned char h,l; } m;
	unsigned short	s;
	} WORD;

typedef struct {
	char	header;			/* ヘッダの先頭 */
	char	machine;		/* 機種コード */
	char	rflg;			/* 機種依存フラグ */
	char	screen;			/* スクリーンモード */
	short	lx;				/* 表示開始位置Ｘ */
	short	ly;				/* 表示開始位置Ｙ */
	short	rx;				/* 表示終了位置Ｘ */
	short	ry;				/* 表示終了位置Ｙ */
	int		offa;			/* フラグＡのオフセット */
	int		offb;			/* フラグＢのオフセット */
	int		sizb;			/* フラグＢのサイズ */
	int		offp;			/* ピクセルのオフセット */
	int		sizp;			/* ピクセルのサイズ */
	} MAGHEADER;

typedef struct {
	char	id[8];			/* MAKI識別子'MAKI01A ' or 'MAKI01B ' */
	char	comment[24];	/* セーバー作者コメント */
	WORD	sizb;			/* フラグＢのサイズ */
	WORD	sizpa;			/* ピクセルＡのサイズ */
	WORD	sizpb;			/* ピクセルＢのサイズ */
	WORD	tile;			/* タイルデータのサイズ */
	WORD	lx;				/* 表示開始位置Ｘ */
	WORD	ly;				/* 表示開始位置Ｙ */
	WORD	rx;				/* 表示終了位置Ｘ */
	WORD	ry;				/* 表示終了位置Ｙ */
	} MKIHEADER;

typedef struct {
	unsigned short g,r,b,h,s,v;
	} PALTABLE;

typedef void (*PALCONV)( int r, int g, int b, short *h, short *s, short *v );

/* Prototype declaration */

extern void	load(int dummy,int mode,char *egbwork,char *usrwork,int sx,int sy,int ex,int ey);
void	load(int dummy,int mode,char *egbwork,char *usrwork,int sx,int sy,int ex,int ey);
char	*getext(char *arg);
int		memory_allocate(int size);
int		stringcmp(char *s,char *d);
int		mag_get_head(FILE *fp);
int		mag_decode(FILE *fp,int mode,int x,int y);
int		mki_get_head(FILE *fp);
int		mki_decode(FILE *fp,int mode,int x,int y);
int		set_palette(void);

/* Global Vari. */

extern char	mem[];						/* Heap Buffer pointer */
char		*egb;						/* EGBworkへのポインタ(Global版) */

MAGHEADER	maghead;					/* MAGのヘッダ */
MKIHEADER	mkihead;					/* MAKIのベッダ */
int			sizp;						/* MAKIのピクセルサイズ */
int			siza;						/* MAGのflag aのサイズ */
int			headtop;					/* MAGのヘッダのオフセット */
char		pal[768];					/* 現在のパレット情報 */
char		*flga,*flgb,*flg,*pix;		/* flag&pixel格納アドレス */
int			xpixel;						/* 横方向のピクセル数の半分 */
/* 現在メモリに存在するイメージ情報 */
char		*vram=NULL;					/* イメージ格納アドレス */
int			screen_mode;				/* スクリーンモード(MAG互換) */

/* Main program */

void	load(int dummy,int mode,char *egbwork,char *usrwork,int sx,int sy,int ex,int ey)
{
	char *s,*d,*p,fname[BufSize];
	FILE *fp;
	int dx,dy,i;

	dx=0; dy=0;
	egb = egbwork;

	if (mode == 4) 
		p = (char *)FNAME16;
	else if (mode == 8)
		p = (char *)FNAME25;
	else if (mode == 16)
		p = (char *)FNAME32;
	else
		return;

	for(d=fname,s=p,i=0;i<8;i++)
		*d++ = ((*s!='\0')&&(*s!='.'))?(*s++):' ';

	for(s=".mag";*s!='\0';*d++ = *s++);
	*d = '\0';
	if ((fp=fopen(fname,"rb"))==NULL) {
		for(d=getext(fname),s="mki";*s!='\0';*d++ = *s++);
		*d = '\0';
		if ((fp=fopen(fname,"rb"))==NULL)
			return;
	}

	if (mag_get_head(fp)) {
		if ((maghead.screen&COL256)&&(mode!=8))
			return;
		if ((!(maghead.screen&COL256))&&(mode!=4))
			return;
		set_palette();
		/* printf("magl : start mag_decode \n"); */
		mag_decode(fp,mode,dx,dy);
	} else if (mki_get_head(fp)) {
		if (mode!=4)
			return;
		set_palette();
		mki_decode(fp,mode,dx,dy);
	}

	fclose(fp);

}

char	*getext(char *arg)
{
	char *p;
	
	for(p=arg;*arg!='\0';arg++)
		if (*arg=='\\') p=arg+1;
	for(;*p!='.'&&*p!='\0';p++);
	if (*p=='\0')
		return NULL;
	else
		return p+1;
}

int		memory_allocate(int size)
{
	static char *bottom = mem;
	static int total_size = 0;

	if (total_size+size>=MemorySize)
		return 0;
	else {
		bottom += size;
		total_size += size;
		return (int)bottom-size;
	}
}

int		stringcmp(char *s,char *d)
{
	for (;*s!='\0';s++,d++)
		if ((tolower(*s))!=(tolower(*d)))
			return FALSE;
	return TRUE;
}

int		mag_get_head(FILE *fp)
{
	char buf[10];
	
	fseek(fp,0,0);
	fread(buf,1,8,fp);
	if (!stringcmp("MAKI02",buf))
		return FALSE;

	fseek(fp,0,0);

	for(headtop=0;;headtop++) {
		if (fread(buf,1,1,fp)!=1)
			return FALSE;
		if (*buf==EOC) {
			headtop++;
			break;
		}
	}
	
	if (fread((char *)&maghead,1,sizeof(MAGHEADER),fp)<sizeof(MAGHEADER))
		return FALSE;

	xpixel = (maghead.screen&COL256)?(maghead.rx/4-maghead.lx/4+1)
									:(maghead.rx/8-maghead.lx/8+1);
	siza = (xpixel*(maghead.ry-maghead.ly+1)+7) / 8;

	screen_mode = maghead.screen;

	fread(pal,1,(screen_mode&COL256)?768:48,fp);		/* palette read */

	return TRUE;
}

int		mag_decode(FILE *fp,int mode,int x,int y)
{
	/* flag a size */
	xpixel = (maghead.screen&COL256)?(maghead.rx/4-maghead.lx/4+1)
									:(maghead.rx/8-maghead.lx/8+1);
	siza = (xpixel*(maghead.ry-maghead.ly+1)+7) / 8;
			/* xpixel = 横方向のピクセル数の半分 */

	if ((flga=(char *)memory_allocate(siza))==NULL) {
		printf("magl : can't allocate memory ( flag a )\n");
		goto Exit;
	}

	if ((flgb=(char *)memory_allocate(maghead.sizb))==NULL) {
		printf("magl : can't allocate memory ( flag b )\n");
		goto Exit;
	}

	if ((pix=(char *)memory_allocate(maghead.sizp))==NULL) {
		printf("magl : can't allocate memory ( pixcel )\n");
		goto Exit;
	}

	if ((flg=(char *)memory_allocate(siza*8))==NULL) {
		printf("magl : can't allocate memory ( flag )\n");
		goto Exit;
	}

	fseek(fp,headtop+maghead.offa,0);				/* flag a read */
	if (fread(flga,1,siza,fp)!=siza)
		printf("magl : inproper size ( flag a )\n");

	fseek(fp,headtop+maghead.offb,0);				/* flag b read */
	if (fread(flgb,1,maghead.sizb,fp)!=maghead.sizb)
		printf("magl : inproper size ( flag b )\n");

	fseek(fp,headtop+maghead.offp,0);				/* pixcel read */
	if (fread(pix,1,maghead.sizp,fp)!=maghead.sizp)
		printf("magl : inproper size ( pixcel )\n");

	Lineofs = (unsigned int)1024*((maghead.screen&COL256)?2:1);
	Mofs[0]  = -(int)(( 0+ 0*Lineofs)/2);
	Mofs[1]  = -(int)(( 4+ 0*Lineofs)/2);
	Mofs[2]  = -(int)(( 8+ 0*Lineofs)/2);
	Mofs[3]  = -(int)((16+ 0*Lineofs)/2);
	Mofs[4]  = -(int)(( 0+ 1*Lineofs)/2);
	Mofs[5]  = -(int)(( 4+ 1*Lineofs)/2);
	Mofs[6]  = -(int)(( 0+ 2*Lineofs)/2);
	Mofs[7]  = -(int)(( 4+ 2*Lineofs)/2);
	Mofs[8]  = -(int)(( 8+ 2*Lineofs)/2);
	Mofs[9]  = -(int)(( 0+ 4*Lineofs)/2);
	Mofs[10] = -(int)(( 4+ 4*Lineofs)/2);
	Mofs[11] = -(int)(( 8+ 4*Lineofs)/2);
	Mofs[12] = -(int)(( 0+ 8*Lineofs)/2);
	Mofs[13] = -(int)(( 4+ 8*Lineofs)/2);
	Mofs[14] = -(int)(( 8+ 8*Lineofs)/2);
	Mofs[15] = -(int)(( 0+16*Lineofs)/2);

	Lineofs /= 2;

	if ((maghead.rx-maghead.lx)>1023) {
		printf("magl : picture is too wide \n");
		goto Exit;
	}
	if ((maghead.ry-maghead.ly)>479) {
		maghead.ly = 0;
		maghead.ry = 479;
		y = 0;
	}
	if ((maghead.rx+x)>1023||(maghead.ry+y)>511
				||(maghead.lx+x)<0||(maghead.ly+y)<0) {
		x = 0;
		y = 0;
	}
	/* printf("magl : pixcel decode start\n"); */
	mag((char *)(&maghead),mode|VRAM
		,(x+y*1024)/((maghead.screen&COL256)?1:2),xpixel);
	/* printf("magl : pixcel decode end \n"); */

/*
	free(flg);
	free(pix);
	free(flgb);
	free(flga);
*/

	flg = NULL; pix = NULL; flgb = NULL; flga = NULL;

	return TRUE;

Exit:
/* 
	if (flg!=NULL)
		free(flg);
	if (pix!=NULL)
		free(pix);
	if (flgb!=NULL)
		free(flgb);
	if (flga!=NULL)
		free(flga);
*/
	flg = NULL; pix = NULL; flgb = NULL; flga = NULL;

	return FALSE;
}

int		mki_get_head(FILE *fp)
{
	unsigned char tmp;
	headtop = 0;

	fseek(fp,0,0);
	if (fread((char *)&mkihead,1,sizeof(MKIHEADER),fp)<sizeof(MKIHEADER))
		return FALSE;

	if ((!stringcmp("MAKI01A",mkihead.id))&&(!stringcmp("MAKI01B",mkihead.id)))
		return FALSE;

	/* モトローラ形式 -> インテル形式 */
	tmp              = mkihead.sizb.m.h ;
	mkihead.sizb.m.h = mkihead.sizb.m.l ;
	mkihead.sizb.m.l = tmp ;
	tmp               = mkihead.sizpa.m.h ;
	mkihead.sizpa.m.h = mkihead.sizpa.m.l ;
	mkihead.sizpa.m.l = tmp ;
	tmp               = mkihead.sizpb.m.h ;
	mkihead.sizpb.m.h = mkihead.sizpb.m.l ;
	mkihead.sizpb.m.l = tmp ;

	sizp = mkihead.sizpa.s + mkihead.sizpb.s;

	screen_mode = 0;

	fread(pal,1,48,fp);							/* palette read */

}

int		mki_decode(FILE *fp,int mode,int x,int y)
{
	/* flag a size : 1000 = 320*400 / (4*4) / 8 */
	if ((flga=(char *)memory_allocate(1000))==NULL) {
		printf("magl : can't allocate memory ( flag a )\n");
		return FALSE;
	}

	if ((flgb=(char *)memory_allocate(mkihead.sizb.s))==NULL) {
		printf("magl : can't allocate memory ( flag b )\n");
		return FALSE;
	}

	if ((pix=(char *)memory_allocate(sizp))==NULL) {
		printf("magl : can't allocate memory ( pixcel )\n");
		return FALSE;
	}

	/* flag size : 16000 = 320*400 / 8 */
	if ((flg=(char *)memory_allocate(16000))==NULL) {
		printf("magl : can't allocate memory ( flag )\n");
		return FALSE;
	}

	fread(flga,1,1000,fp);								/* flag a read */
	fread(flgb,1,mkihead.sizb.s,fp);					/* flag b read */
	fread(pix,1,sizp,fp);								/* pixcel read */
	
	if ((x+639)>1023||(y+399)>511||x<0||y<0) {
		x = 0;
		y = 0;
	}
	mki((char *)(&mkihead),mode|VRAM,(x+y*1024)/2);
	/* printf("magl : mki pixcel decode end \n"); */

/*
	free(flg);
	free(pix);
	free(flgb);
	free(flga);
*/
	return TRUE;
}

int		set_palette(void)
{
	unsigned char *p;
	int		i,r,g,b;
	short	h,s,v;
	PALCONV *rgb_hsv1,*rgb_hsv2;
	PALTABLE *rgb_val;

	if (screen_mode&COL256) {
		rgb_hsv1 = (PALCONV *)RGB2HSV25;
		rgb_hsv2 = (PALCONV *)(&rgb_hsv1);
		rgb_val = (PALTABLE *)PALADDR25;
		for (i=0,p=(unsigned char *)pal;i<256;i++) {
			g = (int)*p++;
			r = (int)*p++;
			b = (int)*p++;
			outpb(PALNO,i);
			outpb(PALB,b);
			outpb(PALR,r);
			outpb(PALG,g);
			(*rgb_hsv2)(r,g,b,&h,&s,&v);
			rgb_val->r = (unsigned short)r;
			rgb_val->g = (unsigned short)g;
			rgb_val->b = (unsigned short)b;
			rgb_val->h = (unsigned short)h;
			rgb_val->s = (unsigned short)s;
			rgb_val->v = (unsigned short)v;
			rgb_val += 1;
		}
	} else {
		rgb_hsv1 = (PALCONV *)RGB2HSV16;
		rgb_hsv2 = (PALCONV *)(&rgb_hsv1);
		rgb_val = (PALTABLE *)PALADDR16;
		for (i=0,p=(unsigned char *)pal;i<16;i++) {
			g = ((int)*p++)&0xf0;
			r = ((int)*p++)&0xf0;
			b = ((int)*p++)&0xf0;
			outpb(PALNO,i);
			outpb(PALB,b);
			outpb(PALR,r);
			outpb(PALG,g);
			if (r) r |= 0xf;
			if (g) g |= 0xf;
			if (b) b |= 0xf;
			(*rgb_hsv2)(r,g,b,&h,&s,&v);
			rgb_val->r = (unsigned short)r;
			rgb_val->g = (unsigned short)g;
			rgb_val->b = (unsigned short)b;
			rgb_val->h = (unsigned short)h;
			rgb_val->s = (unsigned short)s;
			rgb_val->v = (unsigned short)v;
			rgb_val += 1;
		}
	}

	return TRUE ;

}

