/*
	Ninja Library
	
	COPYRIGHT (C) SEGA ENTERPRISES,LTD.

	Create 2000.03.01

*/
#include <Ninja.h>
#include <Njutil.h>
#include <string.h>

static Sint8 *_st_ptr_;
static Sint8 *_r_ptr_;

/****************************************************************/
/*  関数名：nuMOpen									  		    */
/*  機  能：アドレスの設定								        */
/*  入  力：void *addr									        */
/*  出  力：なし		                                        */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static void nuMOpen(void *addr)
{
	_st_ptr_ = (Sint8*)addr;
	_r_ptr_ = _st_ptr_;

}

/****************************************************************/
/*  関数名：nuMRead									  		    */
/*  機  能：現在のアドレスを返す						        */
/*  入  力：Sint32 size									        */
/*  出  力：なし		                                        */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static void* nuMRead(Sint32 size)
{
	void *ptr;
	
	ptr = _r_ptr_;
	_r_ptr_ = (Sint8*)((Uint32)_r_ptr_ + size);

	return ptr;
}

/****************************************************************/
/*  関数名：nuMSeek									  		    */
/*  機  能：シーク										        */
/*  入  力：Sint32 size									        */
/*			Int type											*/
/*  出  力：なし		                                        */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static void nuMSeek(Sint32 size,Int type)
{
	switch(type){
	case SEEK_CUR:
		_r_ptr_ = (Sint8*)((Uint32)_r_ptr_ + size);
		break;
	case SEEK_SET:
		_r_ptr_ = (Sint8*)((Uint32)_st_ptr_ + size);
		break;
	}
}

/****************************************************************/
/*  関数名：nuMGetPtr								  		    */
/*  機  能：現在位置のアドレスを取得する				        */
/*  入  力：なし										        */
/*  出  力：なし		                                        */
/*  戻り値：現在位置のアドレス									*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static void *nuMGetPtr(void)
{
	return _r_ptr_;
}

/****************************************************************/
/*  関数名：nuGetWord								  		    */
/*  機  能：ワードで取り出す							        */
/*  入  力：char *src									        */
/*  出  力：Sint16 *dst                                         */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static void nuGetWord(Sint16 *dst,char *src)
{
	Sint8 *dst8;

	dst8 = (Sint8*)dst;
	*dst8++ = *src++;
	*dst8 = *src;

}

/****************************************************************/
/*  関数名：nuGetLong								  		    */
/*  機  能：ロングで取り出す							        */
/*  入  力：char *src									        */
/*  出  力：Sint32 *dst                                         */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static void nuGetLong(Sint32 *dst,char *src)
{
	Sint8 *dst8;

	dst8 = (Sint8*)dst;
	*dst8++ = *src++;
	*dst8++ = *src++;
	*dst8++ = *src++;
	*dst8 = *src;

}

/****************************************************************/
/*  関数名：nuSetTexListToPvmM						  		    */
/*  機  能：テクスチャリストにデータを設定する			        */
/*  入  力：NJS_TEXLIST *texlist 	テクスチャリスト	        */
/*			Sint32 read_size 1メンバに対してリードするバイト数	*/
/*			NJS_PVM_PVMH *pmh PVMHチャンクヘッダ				*/
/*  出  力：なし                                                */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/*                                                              */
/****************************************************************/
void nuSetTexListToPvmM(NJS_TEXLIST *texlist,Sint32 read_size,NUS_PVM_PVMH_HEAD* pmh)
{
	Sint8 *phinfo;
	NJS_TEXNAME *texname;
	Sint32 count;
	Sint16 entrycount;
	Uint16 pvmstatus;
	Uint16 entryid;
	Sint32 i;
	Uint32 globalIndex;
	Uint16 bank;
	Int ln;

	pvmstatus = pmh->pvmstatus;
	entrycount = pmh->entrycount;

	/* エントリ数分ロードする */
	for(i = 0;i < entrycount;i++){
		phinfo = nuMRead(read_size);
	
		texname = (NJS_TEXNAME *)&texlist->textures[i];
	
		/* attrの後ろの2バイトにentryIdを入れておく */
		nuGetWord((Sint16*)&entryid,(Sint8*)phinfo);
		texname->attr = ((texname->attr)&0xFFFF0000)|(entryid&0x0000FFFF);
		phinfo += 2;
		
		if(pvmstatus & NUD_PVMH_PS_PVRNAME){
			/* ファイル名を28バイトロードする */
			ln = strlen(phinfo);
			if(ln > 0)
				syMemCopy(texname->filename,phinfo,ln);
			phinfo += 28;
		}

		/* カテゴリーコードは今は読み飛ばす */
		if(pvmstatus & NUD_PVMH_PS_CATEGORYCODE){
			/*nuGetWord(&categorycode,phinfo);*/
			phinfo += 2;
		}
		
		/* エントリインフォは今は読み飛ばす */
		if(pvmstatus & NUD_PVMH_PS_ENTRYINFO){
			/*nuGetWord(&entryinfo,phinfo);*/
			phinfo += 2;
		}
		
		/* 
			NJD_TEXATTR_GLOBALINDEX,NJD_TEXATTR_PALGLOBALINDEXが設定されている場合
			その設定を優先する
		*/
		if(!((texname->attr & NJD_TEXATTR_GLOBALINDEX)||(texname->attr & NJD_TEXATTR_PALGLOBALINDEX))){//<--2000/7/31 追加
			/* パレットをロードする */
			if(pvmstatus & NUD_PVMH_PS_BANKID){
				/* グローバルインデックスをロードし、texaddrに入れておく */
				if(pvmstatus & NUD_PVMH_PS_GLOBALINDEX){
					/* bank(31 - 26)globalIndex(25 - 0)*/
					nuGetLong((Sint32*)&texname->texaddr,phinfo);
					texname->attr |= NJD_TEXATTR_PALGLOBALINDEX;
				}
			}
			else{
				/* グローバルインデックスをロードし、texaddrに入れておく */
				if(pvmstatus & NUD_PVMH_PS_GLOBALINDEX){
					nuGetLong((Sint32*)&texname->texaddr,phinfo);
					texname->attr |= NJD_TEXATTR_GLOBALINDEX;
				}
			}
		}
	}
		
}

/****************************************************************/
/*  関数名：nuCalcPvmStatusSize						  		    */
/*  機  能：PVM STATUSのデータが何バイトあるか計算する	        */
/*  入  力：Uint16 pvmstatus 	PVMSTATUSフラグ			        */
/*  出  力：なし                                                */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/****************************************************************/
static Sint32 nuCalcPvmStatusSize(Uint16 pvmstatus)
{
	Sint32 read_size=2;
	
	if(pvmstatus & NUD_PVMH_PS_PVRNAME){
		read_size += 28;
	}
	if(pvmstatus & NUD_PVMH_PS_CATEGORYCODE){
		read_size += 2;
	}
	if(pvmstatus & NUD_PVMH_PS_ENTRYINFO){
		read_size += 2;
	}
	if(pvmstatus & NUD_PVMH_PS_GLOBALINDEX){
		read_size += 4;
	}

	if(pvmstatus & NUD_PVMH_PS_BANKID){
		read_size += 2;
	}

	return read_size;
}


/****************************************************************/
/*  関数名：nuSearchPvrChunkM						  		    */
/*  機  能：チャンクを探して値をセットする				        */
/*  入  力：なし										        */
/*  出  力：なし                                                */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/*                                                              */
/****************************************************************/
void nuSearchPvrChunkM(void)
{
	Uint32 *ch;
	Sint32 *nextptr;
	Sint32 next;
	NUS_PALETTE_HEADR	*ph;
	Sint32 *palette;
	Sint32 byte;

	/* その他のチャンクをロードする */
	do{
		/* チャンクを読む ４バイト */
		ch = nuMRead(4);
		switch(*ch){
		case NUD_PVM_MDLN_TAG:
		case NUD_PVM_CONV_TAG:
		case NUD_PVM_PVMI_TAG:
		case NUD_PVM_IMGC_TAG:
		case NUD_PVM_COMM_TAG:
			nextptr = nuMRead(4);
			nuMSeek(*nextptr,SEEK_CUR);
			break;
		case NUD_PVM_PVPL_TAG:
			/* ヘッダのロード */
			ph = nuMRead(12);
			/* バンクの設定 */
			njSetPaletteBank(ph->mode);
			switch(ph->bank){
			case NJD_TEXFMT_ARGB_8888:
				byte = 4;
				break;
			default:
				byte = 2;
				break;
			}
			palette = nuMRead((Uint32)(ph->entrycount*byte));
			next = (ph->nextptr - 8) - ph->entrycount*byte;
			nuMSeek(next,SEEK_CUR);
			/* パレットカラーモードの設定 */
			njSetPaletteMode((Uint32)ph->mode);
			/* パレットをロードする*/
			njSetPaletteData((Sint32)(ph->entryoffset+ph->bank*16),(Sint32)(ph->entrycount),palette);
			break;
		case NUD_PVM_PVRT_TAG:
			nuMSeek(-4,SEEK_CUR);
			break;
		default:
			nextptr = nuMRead(4);
			nuMSeek(*nextptr,SEEK_CUR);
			break;
		}
		/* PVRTタグを見つけたらループ終了 */
	}while(*ch != NUD_PVM_PVRT_TAG);
}

/****************************************************************/
/*  関数名：nuLoadTexturePvmMemory						        */
/*  機  能：PVMメモリ形式をテクスチャリストにセットする 		*/
/*  入  力：Sint8 *pTexture								        */
/*          NJS_TEXLIST *texlist テクスチャリスト				*/
/*  出  力：成功 １ 失敗ー１                                    */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
Sint32 nuLoadTexturePvmMemory(Sint8 *pTexture,NJS_TEXLIST *texlist)
{
	Uint32 globalIndex;
	Sint32 ret;
	Sint32 i,n;
	Sint32 read_size;
	Uint32 bank = NJD_BANK_FIRST_VAL;
	Sint8 *tex_start;
	NUS_PVM_PVMH_HEAD *pmh;
	NUS_PVR_PVRT_HEAD *pvrh;
	Sint32 texmng_no;
	Sint32 entrycount;
	
	njInitTextureErrStat();
	
	if(pTexture == NULL){
		_nj_texerr_.texerr = NJD_TEXERR_OTHER;
		return -1;
	}
	nuMOpen(pTexture);

	/* チャンクを読む ４バイト */
	pmh = nuMRead(12);

	/* PVMHチャンクか */
	if(pmh->chunk != NUD_PVM_PVMH_TAG){
		/* PVMHチャンクが先頭に無い場合はエラー */
		_nj_texerr_.texerr = NJD_TEXERR_HEADER;
		return -1;
	}

	texlist->nbTexture = pmh->entrycount;
	/* エントリされたデータが何バイトか計算する */
	read_size = nuCalcPvmStatusSize(pmh->pvmstatus);
	/* テクスリストにデータをセットする */
	nuSetTexListToPvmM(texlist,read_size,pmh);

	nuMSeek(pmh->nextptr+8,SEEK_SET);

	/* その他のチャンクをロードし、PVRチャンクを探す */
	nuSearchPvrChunkM();

	entrycount = texlist->nbTexture;
	/* ここからPVRTチャンク：エントリカウントの数だけループする */
	for(i = 0;i < entrycount;i++){
		/* njSetTexListToPvm関数で設定したentryIdをテクスチャリストから探す */
		for(n = 0;n < entrycount;n++){
			if((texlist->textures[n].attr&0x0000FFFF) == i){
				break;
			}
		}

		ret = njCheckAttrGlobalIndex(texlist,n,&globalIndex,&bank);
		if(ret == -1){
			_nj_texerr_.texerr = NJD_TEXERR_MAINMEMORY;
			return -1;
		}
		/* PVRTヘッダをチェック */
		pvrh = nuMRead(16);
		if(pvrh->chunk != NUD_PVM_PVRT_TAG){
			_nj_texerr_.texerr = NJD_TEXERR_HEADER;
			return -1;
		}
		tex_start = nuMRead(pvrh->nextptr - 8);
		
		if(ret == 0){
			ret = njEntryTextureManageNum(texlist,n,globalIndex,bank,&pvrh->data,&texmng_no);

			switch(ret){
			case -1:
				_nj_texerr_.texerr = NJD_TEXERR_SURFACE;
				return -1;
				break;
			case 0:
				if(njLoadTextureManageNum(texmng_no,tex_start)== -1){
					njReleaseTextureManageNum(texmng_no);
					texlist->textures[n].attr &= ~NJD_TEXATTR_REGISTRATION;
					texlist->textures[n].texaddr = 0;
					return -1;
				}

				while(njLoadTextureFinishDMA() != 1);
				break;
			/* case 1:は　何もしない*/
			}
		}
	}	

	return 1;

}
