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


		    ***************   lwo object format loader procedures ***************


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

// Conversion from Big to little edian.
unsigned long mcloaddword(char *adr){
	unsigned char byte0,byte1,byte2,byte3;
	byte0=*adr;
	byte1=*(adr+1);
	byte2=*(adr+2);
	byte3=*(adr+3);
	unsigned long dword=(byte0<<24)+(byte1<<16)+(byte2<<8)+byte3;
	return dword;
}
unsigned short mcloadword(char *adr){
	unsigned char byte0,byte1;
	byte0=*adr;
	byte1=*(adr+1);
	unsigned short word=(byte0<<8)+byte1;
	return word;
} // Conversion BIG little edian.

//  check if a surface exist in the specified scene class
long surfaceExist(char *sName, surf *s, long nsurf)
{
	for(long i=0;i<nsurf;i++)
	{
		if( 0== strcmp(sName, s[i].surfName)) return i;
	}
	return -1;
}

long loadLWO(scen *cS, long no, surf *Tsurface, textu *Ttext)
{
	fileOperations objectFile(cS->aObject[no].objectFileName);

	// get scene number, used by textures
	long sceneNumber;
	long d;
	for(d=0;d<scnMan.nbs;d++)
	{
		if(cS==&scene[d])
		{
			sceneNumber = d;
			break;
		}
	}
	if(d==scnMan.nbs) quitMessage("loadLWO","Can't find scene");

	long sof=objectFile.getfilesize();
	char *LWbase,*EndOfChunk,*EndOfFile;
	unsigned long sizeofchunk;
	long i;

	char *LWO=(char*)objectFile.qloadfile(), *LWO2;

	EndOfFile = LWO + sof;
	LWbase=LWO;

	char SurfName[512];
	while (LWO<(char*)EndOfFile)		// Check for if it's a layered object.
	 if(mcloaddword(LWO++)==0x4C415952)  // *** LAYR   CHUNK ***
		 quitMessage("LWO loader:","Layered Objects are not supported.");
	LWO=LWbase;

	while (mcloaddword(LWO++)!=0x53524653);  // *** SRFS   CHUNK ***
	EndOfChunk=mcloaddword(LWO+3)+LWO+7;
	LWO+=7;
	USHORT localNS = 0;
    while (LWO<EndOfChunk)
	{
		if(*LWO==0) LWO++;
		else
		{
		 long op = 0;
		 while(*LWO!=0) SurfName[op++] = *LWO++;
		 SurfName[op++] = *LWO;
		 if( surfaceExist(SurfName, Tsurface, cS->nsurface) < 0 )
		 {
			Tsurface[cS->nsurface].surfName = new char[op];
			strcpy(Tsurface[cS->nsurface].surfName, SurfName);
			Tsurface[cS->nsurface].isDefault();	// init surface to default
			cS->nsurface++;
			if(cS->nsurface >= AF_MAX_SURFACES) quitMessage("loadLWO", "too much surfaces");
		 }
		 localNS++;
		}
	}
	cS->aObject[no].nosurf = localNS;
	cS->aObject[no].oss = new USHORT[localNS];

	localNS = 0;
//	---------pass 2:NOW SET OSS BUFFER-------------
	LWO=LWbase;
	while (mcloaddword(LWO++)!=0x53524653);  // *** SRFS   CHUNK ***
	EndOfChunk=mcloaddword(LWO+3)+LWO+7;
	LWO+=7;
	localNS = 0;
    while (LWO<EndOfChunk)
	{
		if(*LWO==0) LWO++;
		else
		{
		 long op = 0;
		 while(*LWO!=0) SurfName[op++] = *LWO++;
		 SurfName[op++] = *LWO;
		 if ((i = surfaceExist(SurfName, Tsurface, cS->nsurface)) < 0)
			quitMessage("loadLWO","Invalid case loading surfaces ;(");
		 cS->aObject[no].oss[localNS++] = (USHORT)i;
		}
	}
//	----------------------------------------

    LWO=LWbase;							    // ***  Chunk PNTS  ***
	while (mcloaddword(LWO++)!=0x504E5453);
	// i = nbr de surfaces
	LWO+=3;
	sizeofchunk=mcloaddword(LWO);
	EndOfChunk=LWO+sizeofchunk;
	LWO+=4;
	cS->aObject[no].allocPoints((long)sizeofchunk/12);
	cS->aObject[no].nbp = sizeofchunk/12;
	long *pop		= (long *)cS->aObject[no].shape3D;
	while (LWO<EndOfChunk)
	{
		*pop++=mcloaddword(LWO);
		*pop++=(0x80000000)^mcloaddword(LWO+4);	// inverse y
		*pop++=mcloaddword(LWO+8);
		LWO+=12;
	}
    LWO=LWbase;
	while (mcloaddword(LWO++)!=0x504F4C53);	//***  Chunk POLS   ***
	LWO+=3;
	
	sizeofchunk=mcloaddword(LWO);
	EndOfChunk = LWO + sizeofchunk;
	LWO+=4;

	// ---------	Count number of polys.
	long alloupt=0,nbtri=0;
	LWO2=LWO;

	while (LWO2<EndOfChunk)
	{
		unsigned short ngone = mcloadword(LWO2);
		LWO2 += 4+(ngone*2);
		alloupt+=ngone+1;	// number of points + points
		nbtri++;
	}

	//	---------
	cS->aObject[no].nbf=nbtri;
	cS->aObject[no].allocFaces(alloupt,nbtri);
	cS->aObject[no].allocPF = alloupt-nbtri;
	USHORT *rel = cS->aObject[no].rel;
	USHORT *IDF = cS->aObject[no].IDF;

	while (LWO<EndOfChunk)
	{
		unsigned short ngone = mcloadword(LWO);
		LWO+=2;
		*rel++ = (USHORT)ngone;					// save number of points
		for(long i=0; i<ngone; i++)
		{
		 *rel++ = 3*(USHORT)mcloadword(LWO);
		 LWO+=2;
		}
		SHORT val = mcloadword(LWO);
		if( val < 0) quitMessage("loadLWO","Detail polygons not allowed :(");
		*IDF = (USHORT)val-1;		// save surface number
		IDF++; 
		LWO+=2;
	}

	LWO=LWbase;
	bool badT=false;
	long tmp;

	while((LWO+4)<(char*)EndOfFile)
	{
	 while (mcloaddword(LWO++)!=0x53555246)// ****  Chunks  SURF  ****
	 {
		 if(LWO>=(char*)EndOfFile) { badT=true; break; }
	 }

	 // no SURF chunk, quit.
	 if(badT)break;

	 EndOfChunk=mcloaddword(LWO+3)+LWO+7;
	 LWO+=7;

//		Get the number of the current surface
	 i = surfaceExist(LWO, Tsurface, cS->nsurface);
	 LWO2 = LWO;	// LWO2 = Debut de chunk

	 while((LWO+4)<EndOfChunk)
	 {	  
		tmp=mcloaddword(LWO++);

		if(tmp==0x434f4c52)// Sub Chunk COLR
		{
		 LWO+=5;	// 3char r,g,b flollows...
		 Tsurface[i].sColor.getInteger(*LWO, LWO[1], LWO[2]);
		 Tsurface[i].sColor.toFloat();
		 // charger la couleur dans surface[i].color
		}
		else if (tmp==0x464C4147)		// FLAG
		{
		 LWO+=5;
		 short render_flag=mcloadword(LWO);

		 if((render_flag & 0x200) !=0)		// additive
		 Tsurface[i].flags |= AF_FLAGS_ADDI;

		 // sharp terminator in Lw
		 if( (render_flag & 0x80)!=0)		// Flat shading
		 {
			Tsurface[i].flags &= ~AF_FLAGS_FLAT;
			Tsurface[i].flags |= AF_FLAGS_SCOL;
		 }

		 if((render_flag & 4)!=0)			// Gouraud shading
			Tsurface[i].flags |= AF_FLAGS_GOUR;

		 if((render_flag & 8)!=0)			// Glow
		 {									// Color HighLight in Lighwave
		  Tsurface[i].flags = AF_FLAGS_GLOW;
		 }

		 if((render_flag & 256)!=0)			// Double sided
		  Tsurface[i].flags |= AF_FLAGS_DSID;

		 if((render_flag & 2)!=0)			// Outline only
		 {
		  Tsurface[i].flags |= AF_FLAGS_LINE;
		 }
		}
		else if (tmp==0x534D414E)		// SMAN	: max_smoothing_angle
		{
		 LWO +=5;
		 pop = (long*) &Tsurface[i].maxSmooth;
		 *pop = mcloaddword(LWO);
		 Tsurface[i].maxSmooth = (float)cos(Tsurface[i].maxSmooth);
		}
		else if (tmp==0x474C4F53)		// GLOS	: glossiness level: specular only
		{
		 // 16,64,256,512 or 1024		// value possible are...
		 LWO +=5;
		 USHORT hop = mcloadword(LWO);
		 Tsurface[i].gloss = hop;
		 // get the glossiness value in hop :)
		}
		else if (tmp==0x53504543)// SPEC	: speculare level
		{
		 LWO +=5;
		 USHORT hop;
		 if((hop=mcloadword(LWO))) Tsurface[i].flags |= AF_FLAGS_SPEC;
		 Tsurface[i].specLevel = float(hop)/256.0f;
		 // get the specular value in hop :)	0->256  means 0% to 100%
		}
		else if((tmp==0x52544558) || tmp==0x43544558)
		{							// All following Chunks are part of RTEX or CTEX
		 char Tflag=0;
		 if(tmp==0x52544558) Tflag=1;	// RTEX: Phong
		 if (strcmp("Planar Image Map",LWO+5)) Tflag=-1;// texture non geree
		 LWO+=3;					// gere uniquement planar image map
		 LWO+=2+mcloadword(LWO);	// donc on passe au sub-chunk suivant
		 tmp=0;
		 badT = 0;
		// Parcours le sub-chunk jusqu'a trouver un autre sub-chunk ou un autre SURF
		 while((tmp!=0x52544558) && (tmp!=0x43544558) && (tmp!=0x44544558) &&
			   (tmp!=0x53544558) && (tmp!=0x54544558) && (tmp!=0x42544558) &&
			   (tmp!=0x53555246) && ((LWO+4)<EndOfChunk) )
		 {
			tmp = mcloaddword(LWO++);
			if (tmp==0x54494d47) 	// Sub Chunk TIMG
			{
				LWO+=5;
				if (strcmp(LWO,"(none)")==0 )
					goto notexture;

			    bool sma=0;
				long j;
				if(Tflag==1) 
				{
					Tsurface[i].flags |= AF_FLAGS_PHNG;
				}

				// first check if texture exist in current scene :)
				for(j=0;j<cS->ntexture;j++)
				{
					if (strcmp(Ttext[j].tName,LWO)==0 )
					{
						// Texture is already loaded, take old bitmap ptr.
						Tsurface[i].bitmap = (sceneNumber<<16) | j;
						Ttext[j].COMval++;
						sma = true;
						break;
					}
				}

				// texture doesnt exist in the current scene
				// now check in previous loaded scenes
				if(!sma)
				{
					for(long di=0;di<sceneNumber;di++)
					{
						for(j=0;j<scene[di].ntexture;j++)
						{
							if (strcmp(scene[di].texture[j].tName,LWO)==0 )
							{
								// Texture is already loaded, take old bitmap ptr.
								Tsurface[i].bitmap = (di<<16) | j;
								scene[di].texture[j].COMval++;
								sma = true;
								break;
							}
						}
						if(sma) break;
					}
				}

				// texture doesnt exist in all scenes
				if(!sma)	// New texture
				{
					long a=0;
					bool okToAdd=true;
					while( LWO[a++] !=0);
					Ttext[cS->ntexture].tName = new char[a];
					strcpy(Ttext[cS->ntexture].tName,LWO);
//					 here is the code to load the image file ...
					okToAdd = Ttext[cS->ntexture].loadIMG(0);
					if( !okToAdd ) Tsurface[i].bitmap = (sceneNumber<<16) | cS->ntexture++;
					else badT = true;
					if(cS->ntexture >= AF_MAX_TEXTURES) quitMessage("loadLWO","too much textures");
				}
			}
			else if (tmp==0x54464C47)		// (TFLG)
			{
			   if(Tsurface[i].surfTexture == NULL)
						Tsurface[i].surfTexture = new surf::surfTextur;
			   LWO+=5;
			   unsigned short  TfData =mcloadword(LWO);
			   if(!Tflag)
			   {
				// True map flag
				if ( ((TfData) & 0x40 )==0) Tsurface[i].flags |= AF_FLAGS_TMAP;
				else Tsurface[i].flags |= AF_FLAGS_FMAP;

				if ( ((TfData) & 1 )!=0)
					Tsurface[i].surfTexture->axis = 1;
				else if( (TfData & 2 ) !=0)
					Tsurface[i].surfTexture->axis = 2;
				else if( (TfData & 4 ) !=0)
					Tsurface[i].surfTexture->axis = 3;
			   }
			   LWO+=2;
			}
			else if (tmp==0x5453495A)	// coord mapp (TSIZ) Size Of Mapping
			{
			 LWO+=3;
			 pop=(long *)&Tsurface[i].surfTexture->Xsiz;
			 LWO+=2;
			 *pop++=mcloaddword(LWO);
			 LWO+=4;
			 *pop++=mcloaddword(LWO);
			 LWO+=4;
			 *pop++=mcloaddword(LWO);
			 LWO+=4;
			}
		    else if (tmp==0x54435452)	// coord mapp (TCTR) Center for mapping
			{
			 LWO+=3;
			 pop=(long *)&Tsurface[i].surfTexture->Xcenter;
			 LWO+=2;
			 *pop++=mcloaddword(LWO);
			 LWO+=4;
			 *pop++=mcloaddword(LWO);
			 LWO+=4;
			 *pop++=mcloaddword(LWO);
			 LWO+=4;
			}
		 }
		 if( ( (Tsurface[i].flags & (AF_FLAGS_TMAP | AF_FLAGS_FMAP) ) != 0) && 
			 (Tsurface[i].bitmap == -1)) Tsurface[i].isDefault();
		 if(badT) Tsurface[i].isDefault();		// reinit surface
		}
notexture:;
	 }
	 if(cS->aObject[no].nosurf==1) Tsurface[i].flags |= AF_FLAGS_OSRF;
	}
//	-------------------- End of CHUNKS --------------------
	long test = AF_FLAGS_FLAT + AF_FLAGS_ADDI + AF_FLAGS_TMAP;
	delete LWbase;	// delete the file memory
	return 0;
}
