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

	Create 2000.03.01

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

/****************************************************************/
/*  関数名：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;

}

/****************************************************************/
/*  関数名：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;
	}

	return read_size;
}

/****************************************************************/
/*  関数名：nuSetTexListToPvm						  		    */
/*  機  能：テクスチャリストにデータを設定する			        */
/*  入  力：NJS_TEXLIST *texlist 	テクスチャリスト	        */
/*			Sint32 read_size 1メンバに対してリードするバイト数	*/
/*			NUS_PVM_PVMH_HEAD *pmh PVMHチャンクヘッダ			*/
/*  出  力：なし                                                */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/*                                                              */
/****************************************************************/
Sint32 nuSetTexListToPvm(NJS_TEXLIST *texlist,Sint32 read_size,NUS_PVM_PVMH_HEAD* pmh)
{
	Uint8 phinfo[40];
	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++){
		if(nuTexFread(phinfo,read_size) < 0){
			return -1;
		}
	
		texname = (NJS_TEXNAME *)&texlist->textures[i];
	
		/* attrの後ろの2バイトにentryIdを入れておく */
		nuGetWord((Sint16*)&entryid,(Sint8*)phinfo);
		texname->attr = ((texname->attr)&0xFFFF0000)|(entryid&0x0000FFFF);
		count = 2;
		
		if(pvmstatus & NUD_PVMH_PS_PVRNAME){
			/* ファイル名を28バイトロードする */
			ln = strlen((Sint8*)&phinfo[count]);
			if(ln > 0)
				syMemCopy(texname->filename,&phinfo[count],ln);
			count += 28;
		}

		/* カテゴリーコードは今は読み飛ばす */
		if(pvmstatus & NUD_PVMH_PS_CATEGORYCODE){
			/*nuGetWord(&categorycode,&phinfo[count]);*/
			count += 2;
		}
		
		/* エントリインフォは今は読み飛ばす */
		if(pvmstatus & NUD_PVMH_PS_ENTRYINFO){
			/*nuGetWord(&entryinfo,&phinfo[count]);*/
			count += 2;
		}
		/* パレットをロードする */
		if(pvmstatus & NUD_PVMH_PS_BANKID){
			/* グローバルインデックスをロードし、texaddrに入れておく */
			if(pvmstatus & NUD_PVMH_PS_GLOBALINDEX){
				/* bank(31 - 26)globalIndex(25 - 0)*/
				nuGetLong((Sint32*)&texname->texaddr,(Sint8*)&phinfo[count]);
				texname->attr |= NJD_TEXATTR_PALGLOBALINDEX;
			}
		}
		else{
			/* グローバルインデックスをロードし、texaddrに入れておく */
			if(pvmstatus & NUD_PVMH_PS_GLOBALINDEX){
				nuGetLong((Sint32*)&texname->texaddr,(Sint8*)&phinfo[count]);
				texname->attr |= NJD_TEXATTR_GLOBALINDEX;
			}
		}
	}
		
		return 1;
}

/****************************************************************/
/*  関数名：nuSearchPvrChunk						  		    */
/*  機  能：チャンクを探して値をセットする				        */
/*  入  力：なし										        */
/*  出  力：なし                                                */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：内部関数                                            */
/*                                                              */
/****************************************************************/
Sint32 nuSearchPvrChunk(void)
{
	Uint32 ch;
	Sint32 nextptr;
	NUS_PALETTE_HEADR	ph;
	Sint32 palette[1024];
	NJS_TEXPALETTE pl;
	Sint32 byte;
	
	/* その他のチャンクをロードする */
	do{
		/* チャンクを読む ４バイト */
		if(nuTexFread(&ch,4) < 0){
			return -1;
		}
		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:
			if(nuTexFread(&nextptr,4) < 0){
				return -1;
			}
			nuTexFseek(nextptr,SEEK_CUR);
			break;
		case NUD_PVM_PVPL_TAG:
			/* ヘッダのロード */
			if(nuTexFread(&ph,12) != 1){
				return -1;
			}
			/* バンクの設定 */
			njSetPaletteBank(ph.mode);
			switch(ph.mode){
			case NJD_TEXFMT_ARGB_8888:
				byte = 4;
				break;
			default:
				byte = 2;
				break;
			}
			if(nuTexFread(palette,(Uint32)(ph.entrycount*byte)) < 0){
				return -1;
			}
			nextptr = (ph.nextptr - 8) - ph.entrycount*byte;
			nuTexFseek((Uint32)(nextptr),SEEK_CUR);
			/* パレットカラーモードの設定 */
			njSetPaletteMode((Uint32)ph.mode);
			/* パレットをロードする*/
			njSetPaletteData((Sint32)(ph.entryoffset+ph.bank*16),(Sint32)(ph.entrycount),palette);
			break;
		case NUD_PVM_PVRT_TAG:
			nuTexFseek(-4,SEEK_CUR);
			break;
		default:
			if(nuTexFread(&nextptr,4) < 0){
				return -1;
			}
			nuTexFseek(nextptr,SEEK_CUR);
			break;
		}
		/* PVRTタグを見つけたらループ終了 */
	}while(ch != NUD_PVM_PVRT_TAG);
	
	return 1;
}

/****************************************************************/
/*  関数名：nuLoadTexturePvmFile					            */
/*  機  能：PVMファイルをロードし、テクスチャリストにセットする */
/*  入  力：const char filename pvmファイル名			        */
/*          NJS_TEXLIST *texlist テクスチャリスト				*/
/*  出  力：成功 １ 失敗ー１                                    */
/*  戻り値：なし												*/
/*  概　要：                                                    */
/*  備　考：                                                    */
/*                                                              */
/****************************************************************/
Sint32 nuLoadTexturePvmFile(const char *filename,NJS_TEXLIST *texlist)
{
	char filename2[32];
	Uint32 ch;
	Sint16 entrycount;
	Uint16 pvmstatus;
	NUS_PVM_PVMH_HEAD pmh;
	Uint32 globalIndex;
	Sint32 ret;
	Sint32 i,n;
	Sint32 read_size;
	Sint32 size,offset;
	Sint32 nextptr;
	Uint32 bank = NJD_BANK_FIRST_VAL;
	Sint8 *tex_start;
	NUS_PVR_PVRT_HEAD pvrh;
	Sint32 texmng_no;
	Sint8 *texbuf;
	Int texbuf_size;
	
	
	njInitTextureErrStat();

	/* 拡張子の確認をする */
	njCheckFileName(filename2,filename,".PVM");
	
	/* ファイルのオープン */
	if((ret = nuTexFopen(filename2)) < 0){
		return -1;
	}

	/* チャンクを読む 12バイト */
	if(nuTexFread(&pmh,12) < 0){
		nuTexFclose();
		return -1;
	}

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

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

	/* その他のチャンクをロードし、PVRチャンクを探す */
	if(nuSearchPvrChunk() < 0){
		nuTexFclose();
		return -1;
	}

	/* テクスチャバッファ情報の取得 */
	nuGetTextureBuffer(&texbuf,&texbuf_size);
	
	/* ここからPVRTチャンク：エントリカウントの数だけループする */
	for(i = 0;i < entrycount;i++){
		/* nuSetTexListToPvm関数で設定した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;
			nuTexFclose();
			return -1;
		}

		if(nuTexFread(&pvrh,16) < 0){
			nuTexFclose();
			return -1;
		}

		if(pvrh.chunk != NUD_PVM_PVRT_TAG){
			_nj_texerr_.texerr = NJD_TEXERR_HEADER;
			return -1;
		}

		if(ret == 0){
			ret = njEntryTextureManageNum(texlist,n,globalIndex,bank,&pvrh.data,&texmng_no);

			switch(ret){
			case -1:
				nuTexFclose();
				_nj_texerr_.texerr = NJD_TEXERR_SURFACE;
				return -1;
				break;
			case 1:
				nuTexFseek(pvrh.nextptr - 8,SEEK_CUR);
				break;
			case 0:
				read_size = njCalcTextureSize2(&pvrh.data);
				nextptr = pvrh.nextptr - 8;
				if(nextptr > read_size){
					nextptr = nextptr - read_size;
				}
				else{
					read_size = nextptr;
					nextptr = 0;
				}

				offset = 0;
				do{
					if(read_size <= texbuf_size){
						size = read_size;
					}
					else{
						size = texbuf_size;
					}
				
					if(nuTexFread(texbuf,size) < 0){
						njReleaseTextureManageNum(texmng_no);
						texlist->textures[n].attr &= ~NJD_TEXATTR_REGISTRATION;
						texlist->textures[n].texaddr = 0;
						nuTexFclose();
						return -1;
					}
					syCacheOCWB(texbuf,size);
					
					if(njLoadTexturePartManageNum(texmng_no,texbuf,offset,size)== -1){
						njReleaseTextureManageNum(texmng_no);
						texlist->textures[n].attr &= ~NJD_TEXATTR_REGISTRATION;
						texlist->textures[n].texaddr = 0;
						/* テクスチャロードエラー　*/
						nuTexFclose();
						return -1;
					}
					read_size -= size;
					offset += size;
					while(njLoadTextureFinishDMA() != 1);
				}while(read_size > 0);
				
				if(nextptr > 0){
					nuTexFseek(nextptr,SEEK_CUR);
				}
				break;
			}
		}
		else{
			/* 同じパレットテクスチャなのでテクスチャを読み飛ばす */
			nuTexFseek(pvrh.nextptr - 8,SEEK_CUR);
		}
		
	}	
		
	nuTexFclose();
	
	return 1;

}

