#include "add_math.h"

class cam
{
public:
	cam()
	{
		target = -1;	
		distcam = 0.0000001f;	// to be changed !!!!!
	}

	long target;
	float focal, LWfocal;
	float distcam;
	~cam()
	{}
};

class light
{
public:
	long type;		// distant:0, point:1, spot:2
	Color lCol;
	float intensity;
	float x,y,z;	// position of the light
	float nx,ny,nz;	// direction if spot or distant type
	float fx,fy,fz;	// final position in object space, filled with each object
	float fnx,fny,fnz;	// final direction in object space, filled with each object
	// all coord are eye space, world space coord are keeped in the currentFrame buffer
	~light()
	{}
};

#include "entitiy.h"

// used in class object
class scen;

#include "object.h"
#include "textu.h"

class surf
{
public:
	char	*surfName;
	ULONG	flags;		// render flags, see attilaDefs.h :)
	float	specLevel;
	USHORT   gloss;
	Color   sColor;
	float   maxSmooth;	// max smoothing angle
	ULONG	bitmap;// contain (scene)(texturenb) during loading first, then texture class @
	long	nValue;	// number of values to clip

	// methods
//	---------------------- surfaces -------------------------
//	note: surfName will be deleted in scen::deleteSurfacesNames() method
	surf()
	{
		specLevel = 0;
		surfName = NULL;
		surfTexture = NULL;
		isDefault();
		bitmap = -1;
		maxSmooth = (float) cos((89.5f/180.0f)*pi);
		nValue = 0;
	}

	void isDefault()
	{
		flags = AF_FLAGS_FLAT;
		// default lightwave color
		sColor.iRedValue   = 200;
		sColor.iGreenValue = 200;
		sColor.iBlueValue  = 200;
		sColor.to16Bits();
		sColor.toFloat();
	}

	void initPtr()
	{
	//	surfTexture = NULL;
	}

	~surf()
	{
		if( surfTexture != NULL) 
		{
			delete surfTexture;
			surfTexture = NULL;
		}
	}

	class surfTextur
	{
	public:
		float Xcenter, Ycenter, Zcenter;
		float Xsiz, Ysiz, Zsiz;
		char	axis;		// 1: X;	2: Y;	3: Z

		surfTextur()
		{
			Xcenter = 0;
			Ycenter = 0;
			Zcenter = 0;
			Xsiz = 1;
			Ysiz = 1;
			Zsiz = 1;
		}
	}*surfTexture;
};


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


	      	  ***************   lws scene class definition ***************


/////////////////////////////////////////////////////////////////////////////////////////////////
*/
#include "particules.cpp"
class scen
{
public:
	// fields:
	long clipUp, clipDown, clipRight, clipLeft;
	long frames, FPS;
	long totalface, nb_entity;
	float CameraMaxOffset, framecpt;
	Color Background, Ambient;
	float AmbientIntensity;
	ULONG startTick;
	float gridSize;	// scene resize value

	spart *particules;
	long camera_at;
	long light_at; //offset of the first light in the entity list
	long nlight;
	long object_at; //offset of the first object in the entity list
	long nobject;	  // for objects: always 0
	long nsurface;
	long ntexture;
	long frameFPS;		// number of frames rendered by second

	bool cleared;

	long nFace;			// number of faces in the current frame
	long nFaceLight;	// number of faces + number of lights
	long nPoint;
	long allocPoint;	// number of points we've got to allocate (taking care of clipping needs):)
	struct	daFace *bigFace;
	daPoint *bigPoint;

	long *fOS;			// faces offsets
	long *radixBuffer;	// a 256 array
	long *fOSorted;		// faces offsets sorted
	long *radixDatabuffer;	// z data


// methods:
	scen();
	scen(char*);
	void loadScene(char *filename);

	void resize(float );
	void unresize(float);
	//	managing memory used only when playing scene   :)
	void init4Play();
	void release4Play();

	void initHierarchy();
	void initNormals();

	void iLights(long);	// inverse transform lights to object space
	void tLightsGL();
	float getItPtGL(float *pn,float,float);
	float getFaceItGL(float *fn);

	bool play();
	void transformWorld();
	void proceedMatrixs();
	void proceedMatrixsGL();
	void transformEntityToCamera( long );

	void deleteObjectsNames();
	void deleteSurfacesNames();
	void deleteTexturesNames();
	void releaseAll();
	void drawGL();

	void initParticules();
	void updateParticules();
	void drawParticules(float,float,float);
	long glPart;		// gl particule texture ptr

	~scen();
//	--------------------------------------------------

	// class members:
	//   ---------> CAMERA
	class cam camera;

//   ---------> LIGHTS
	class light *aLight;

	//   ---------> ENTITIES
	class ent *entity;

	//   ---------> OBJECTS
	class object *aObject;

	//   ---------> TEXTURES
	class textu *texture;

	textu tPart;
	long np;	// number of particules
	ULONG lastTime;

	textu *bgImage;
	ULONG bgImageGL;

	//   ---------> SURFACES
	class surf *surface;

}*scene;

//	default texture
class textu defaultTextu;
//  ------------------------  scen methods ------------------------------

void scen::initParticules()
{
	np = 0;
	for(long i = 0;i<NPART;i++)	
	{
		particules[i].active = false;
	}
}
void scen::updateParticules()
{
	sprintf(OutputBuffer, "\nnumber of particles: %i",np);
	if( debug() ) debugPrint->addText(OutputBuffer);

	if( (MyGetTickCount() - lastTime) >= (PARTOVER / NPART))
	{
		if( np < NPART )
		{
			particules[np++].create();
		}
		lastTime = MyGetTickCount();
	}
	for(int i=0;i<np;i++) particules[i].update();
}

void scen::drawParticules(float x, float y, float z)
{
	float ps;
	glColor4f( 1, 1, 1, 1);
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, GLtexture[glPart]);
	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE, GL_ONE);
	glDepthMask(false);
	glBegin(GL_QUADS);
	for(long i=0; i<np; i++)
	{
		ps = 0.5f - (float)particules[i].time/(PARTOVER<<1);
		glTexCoord2f( 0, 1);
		glVertex3f( x+particules[i].x-ps, y+particules[i].y+ps,z+particules[i].z);

		glTexCoord2f( 1, 1);
		glVertex3f( x+particules[i].x+ps, y+particules[i].y+ps,z+particules[i].z);

		glTexCoord2f( 1, 0);
		glVertex3f( x+particules[i].x+ps, y+particules[i].y-ps,z+particules[i].z);

		glTexCoord2f( 0, 0);
		glVertex3f( x+particules[i].x-ps, y+particules[i].y-ps,z+particules[i].z);
	}
	glEnd();
	glDisable(GL_BLEND);
	glDepthMask(true);
	glDisable(GL_TEXTURE_2D);
}

scen::scen()
{
	bigFace = NULL;
	bigPoint = NULL;
	cleared = false;
	nobject = 0;
	totalface = 0;
	nb_entity=0;
	nlight = 0;
	object_at = 0;
	nsurface = 0;
	ntexture = 0;
	Background.isBlack();
	Ambient.isBlack();
	fOSorted = NULL;
	fOS = NULL;
	radixBuffer = NULL;
	radixDatabuffer = NULL;
	particules = NULL;
	bgImage = NULL;
	bgImageGL = NULL;

	// load particule sprite 
	tPart.tName = "D:\\gozervrac\\Dimension3\\particle.jpg";
	if ( tPart.loadIMG(0)) warningMessage("scen constructor","couldn't load particule sprite");
	tPart.tName = NULL;
}

scen::scen(char *filename)
{
	bigFace = NULL;
	bigPoint = NULL;
	cleared = false;
	loadScene(filename);
	nsurface = 0;
	totalface = 0;
	nobject = 0;
	nb_entity=0;
	ntexture = 0;
	nlight = 0;
	object_at = 0;
	Background.isBlack();
	Ambient.isBlack();
	fOSorted = NULL;
	fOS = NULL;
	radixBuffer = NULL;
	radixDatabuffer = NULL;
	particules = NULL;
}

void scen::resize(float grid)
{
	long i;
	for( i=0;i<nobject;i++)
	{
		if( !aObject[i].dataLocation->resized && !entity[i].type )
		{
			long j;
			for(j=0;j<(aObject[i].nbp*3);j+=3)
			{
				aObject[i].shape3D[j]	*= grid;
				aObject[i].shape3D[j+1] *= grid;
				aObject[i].shape3D[j+2] *= grid;
			}
			aObject[i].dataLocation->resized = true;
		}
	}

	for( i=0;i<nb_entity;i++)
	{
		long j;
		for( j=0;j<entity[i].anim.keys;j++)
		{
			entity[i].anim.keylist[j].cv[0] *= grid;
			entity[i].anim.keylist[j].cv[1] *= grid;
			entity[i].anim.keylist[j].cv[2] *= grid;
		}
		entity[i].pivotx *= grid;
		entity[i].pivoty *= grid;
		entity[i].pivotz *= grid;
	}
}

void scen::unresize(float grid)
{
	long i;
	for( i=0;i<nobject;i++)
	{
		if( aObject[i].dataLocation->resized )
		{
			long j;
			for( j=0;j<(aObject[i].nbp*3);j+=3)
			{
				aObject[i].shape3D[j]	*= grid;
				aObject[i].shape3D[j+1] *= grid;
				aObject[i].shape3D[j+2] *= grid;
			}
			aObject[i].dataLocation->resized = false;
		}
	}

	for( i=0;i<nb_entity;i++)
	{	
		long j;
		for( j=0;j<entity[i].anim.keys;j++)
		{
			entity[i].anim.keylist[j].cv[0] *= grid;
			entity[i].anim.keylist[j].cv[1] *= grid;
			entity[i].anim.keylist[j].cv[2] *= grid;
		}
		entity[i].pivotx *= grid;
		entity[i].pivoty *= grid;
		entity[i].pivotz *= grid;
	}
}


void
initViewGL(cam *camera, Color *c);

void scen::init4Play()
{
	resize(1.0f/gridSize);

	if( particules != NULL ) initParticules();

	long finalAllocFace = totalface+nlight;
	bigFace = new struct daFace[finalAllocFace];
	bigPoint = new daPoint[allocPoint+nlight];	// light are stored in this buffer for sorting

	// buffers for sorting faces...
//	if( (appFlags & AF_SOFT3D) !=0 )	// used by alpha faces
	{
		fOSorted = new long[finalAllocFace];
		fOS = new long[finalAllocFace];
		radixDatabuffer = new long[finalAllocFace];
		radixBuffer = new long[256];
	}
	// to avoid false static detection
	long i;
	for( i = 0;i<nb_entity;i++)
		entity[i].currentFrame[0] = FLT_MAX;

	initViewGL(&camera, &Background);

	startTick = MyGetTickCount();
//	startTick = (ULONG)SetTimer(NULL,NULL,0xffffffff,NULL);
}

void scen::release4Play()
{
	unresize(gridSize);

	if( bigFace  != NULL)
	{
		delete bigFace;
		bigFace = NULL;
	}
	if( bigPoint != NULL)
	{
		delete bigPoint;
		bigPoint = NULL;
	}
	if( fOSorted != NULL)
	{
		delete fOSorted;
		fOSorted = NULL;
	}
	if( fOS != NULL)
	{
		delete fOS;
		fOS = NULL;
	}
	if( radixBuffer != NULL)
	{
		delete radixBuffer;
		radixBuffer = NULL;
	}
}

void checkError();
void fillMatrixGL(float ax, float ay, float az, float dx, float dy, float dz, float *matBuf);
ULONG fpsTickCount = MyGetTickCount();
long nframe=0;

bool scen::play()
{
	long j=0;
	float step,tempf;
	float aX,aY,aZ;		// tempory rotation values

//	--------------- FPS debug
	if(debug())
	{
		if( (MyGetTickCount() - fpsTickCount) >= 250 )	// fps taken all 250 ms
		{
			frameFPS = (nframe*1000) / (MyGetTickCount() - fpsTickCount);
			fpsTickCount = MyGetTickCount();
			nframe = 0;
		}
		else nframe++;
		sprintf(OutputBuffer, "FPS: %i",frameFPS);
		debugPrint->addText(OutputBuffer);
	}

//	---------------
	tempf = (((float)MyGetTickCount()-(float)startTick)/1000)*FPS;
	step = (tempf)-framecpt;

//	printf("start %u, currTime: %u, result:%f\n", startTick, MyGetTickCount(), tempf);

	framecpt=tempf;
	if( (long)framecpt >= frames) 
		return false;	// the scene is ending
	long i;
	for( i=0;i<nb_entity;i++)
	{
	 if(entity[i].anim.endBh == 2)	// repeat endBehavior
	 {
		int last;
		last = entity[i].anim.keys;
		last = entity[i].anim.keylist[last-1].step;

		if( entity[i].Diss.keys != 0)
		{
			if(last == 0) MotionCalcStep(&entity[i].Diss , Dest, 0);
			else MotionCalcStep(&entity[i].Diss , Dest, (((long)framecpt)%last));
			entity[i].dissolve = 1-(float)Dest[0];
		}
//		// check zero division...
		if(last == 0) MotionCalcStep(&entity[i].anim , Dest, 0);
		else MotionCalcStep(&entity[i].anim , Dest, (((long)framecpt)%last));
	 }
	 else 	 if(entity[i].anim.endBh == 1)	// stop endBehavior
	 {
		 float hop = framecpt;
		 float hop2 = framecpt;
		 int last = entity[i].anim.steps;
		 int last2 = entity[i].Diss.steps;
		 if ( framecpt > (float)last ) hop = (float)last;
		 if ( framecpt > (float)last2 ) hop2 = (float)last2;
		 if( entity[i].Diss.keys != 0)
		 {
			 MotionCalcStep(&entity[i].Diss , Dest, hop2);
			 entity[i].dissolve = 1-(float)Dest[0];
		 }
		 MotionCalcStep(&entity[i].anim , Dest, hop);
	 }

	 // check for static to avoid redondant matrix calculations
	 entity[i].flags |= 1;
	 double *cframe = entity[i].currentFrame;
	 long e;
	 for(e=0;e<9;e++)
	 {
		 if( cframe[e] != Dest[e] )
		 {
			entity[i].flags &= ~1;  // clear static flag
			break;
		 }
	 }

	 long h;
	 for(h=0;h<9;h++) entity[i].currentFrame[h] = Dest[h];

	 // calculate matrix for objects
	 if(((entity[i].type == 0) || (entity[i].type == 3)))
	 {
		 entity[i].getCommonMatrix();
//		 entity[i].getCommonMatrixGL();
	 }

	 // object ou null object
	 if((entity[i].type==0) || (entity[i].type==3))
	 {
	 }
	 else if(entity[i].type==1)		// Light
	 {
//		aX=(float)((Dest[4]))*(float)(pi/180);
//		aY=(float)(Dest[3]+180)*(float)(pi/180);
//		aZ=(float)((Dest[5]))*(float)(pi/180);

		// identity matrix for point lights :)
		if( aLight[i-light_at].type == 1 ) setToIdentity(entity[i].matrix_Object);
		else entity[i].getCommonMatrix();
	 }
	 else if(entity[i].type==2)		// camera
	 {
		if(camera.target == -1)
		{
			aY = -(float)((Dest[3]*(pi/180)));
			aX = (float)((Dest[4]*(pi/180)));
			aZ = (float)(Dest[5]*(pi/180));
		}
		// target camera: works perfectly =)
		else
		{
			// first, camera is never static when targeting :)
			entity[i].flags &= ~1;
			// got to build new aX, aY value =|
			aZ = (float)(Dest[5]*(pi/180));	// do not change

			float tx = (float)(Dest[0] - entity[camera.target].currentFrame[0]);
			float ty = (float)(Dest[1] - entity[camera.target].currentFrame[1]);
			float tz = (float)(Dest[2] - entity[camera.target].currentFrame[2]);

			float normaliz = (float)sqrt( (tx*tx)+(ty*ty)+(tz*tz) );
			tx /= normaliz;
			ty /= normaliz;
			tz /= normaliz;

			float tval, addval;
			// pfiou! trigo sux :)
			tval = (float)sqrt( (tx*tx)+(tz*tz) );
			aX = (float)atan(ty/tval);

			tval = tx;
			if(tval == 0) tval = 1;	// check zero division
			if( tval >=0) addval = pi/2;	// fucking arc tangeante propertie
			else addval = -pi/2;
			aY = addval + (float)atan((tz/tval));

			Dest[3] = -(double) aY*(180/pi);
			Dest[4] = (double) aX*(180/pi);
		}
		
		entity[i].getCameraMatrixGL(180+Dest[4], -Dest[3], Dest[5]);

		// camera-child case:
		// works perfectly: camera can be child's child's child's....   :)
		if( entity[i].Parent != -1)
		{
			long p = entity[i].Parent;
			// use matrix_ObjectWorld camera-entity as temp matrix
			glLoadMatrixf(entity[i].matrix_Object);
			while(p != -1)
			{
				glRotated(entity[p].currentFrame[5], 0, 0, 1);
				glRotated(entity[p].currentFrame[4], 1, 0, 0);
				glRotated(-entity[p].currentFrame[3], 0, 1, 0);
				glTranslated(-entity[p].currentFrame[0], entity[p].currentFrame[1],-entity[p].currentFrame[2]);
				p = entity[p].Parent;
			}
			glGetFloatv(GL_MODELVIEW_MATRIX, camG);
		}
	 }
	}

	proceedMatrixsGL();

	// transform directly to camera world points that are particules and lens flare
	int o;
	for( o =0;o<nb_entity;o++)
	{
		if( (entity[o].type == 4) || (entity[o].type == 5) )
		{
			float *matrix = camG;
			float tx = (float)entity[o].currentFrame[0];
			float ty = -(float)entity[o].currentFrame[1];
			float tz = (float)entity[o].currentFrame[2];

			// opengl matrix transformation (in software...)
			entity[o].currentFrame[3] = (double)((tx*matrix[0]) + (ty*matrix[4]) + (tz*matrix[8])  + (matrix[12]));
			entity[o].currentFrame[4] = (double)((tx*matrix[1]) + (ty*matrix[5]) + (tz*matrix[9])  + (matrix[13]));
			entity[o].currentFrame[5] = (double)((tx*matrix[2]) + (ty*matrix[6]) + (tz*matrix[10]) + (matrix[14]));
		}
	}

	return true;	// ok scene is not ending
}


void scen::initHierarchy()
{
	long daChilds[AF_MAX_CHILDS];	// would be enough I think... lets check anyway :)
	long nchild;
	long i;
	for( i=0;i<nb_entity;i++)
	{
		nchild = 0;
		long y;
		for( y=0;y<nb_entity;y++)
		{
			if( entity[y].Parent == i) daChilds[nchild++] = y;
		}

		if(nchild != 0) 
		{
			if( (entity[i].type != 3) && (entity[i].type!=0) ) quitMessage("","waop!");
			if( nchild >= AF_MAX_CHILDS) quitMessage("scen::initHierarchy","Woaw! lots of childs objects in that scene!\nAnyway, it's too much for Attila :(");
			// alloc master parent object childs... :)
			aObject[i].Childs = new long[nchild+1];
			long fofo = 0;
			for(long u=nchild-1;u>=0;u--)
				aObject[i].Childs[fofo++] = daChilds[u];
			aObject[i].Childs[fofo] = -1;// close the lklinks
		}
	}
}


void scen::deleteObjectsNames()
{
	long i;
	for( i =0;i<nobject;i++)
	{
		if( aObject[i].dataLocation ==  &aObject[i] )
		{
			if(aObject[i].objectFileName != NULL)
			{
				delete aObject[i].objectFileName;
				aObject[i].objectFileName = NULL;
			}
		}
		else aObject[i].objectFileName = NULL;
	}
}

void scen::deleteSurfacesNames()
{
	long i;
	for( i=0;i<nsurface;i++)
	{
		if( surface[i].surfName != NULL)
		{
			delete surface[i].surfName;
			surface[i].surfName = NULL;
		}
	}
}

void scen::deleteTexturesNames()
{
	long i;
	for( i = 0;i<ntexture;i++)
	{
		if( texture[i].tName != NULL)
		{
			delete texture[i].tName;
			texture[i].tName = NULL;
		}
	}
}

void scen::releaseAll()
{
	delete [] aObject;
	delete [] aLight;
	delete [] entity;
	cleared = true;
}

scen::~scen()
{
	if(!cleared)
	{
		delete [] aObject;
		delete [] aLight;
		delete [] entity;
	}

	if( bigFace  != NULL)
	{
		delete bigFace;
		bigFace = NULL;
	}
	if( bigPoint != NULL)
	{
		delete bigPoint;
		bigPoint = NULL;
	}
	if( particules != NULL)
	{
		delete particules;
		particules  = NULL;
	}
}


void scen::initNormals()
{
	long n;
	for( n=0;n<nobject;n++)
	{
	 if( !entity[n].type )
	 {
	  if (&aObject[n] == aObject[n].dataLocation) 
	  {
		surf	 *s = surface;
		object *o = &aObject[n];
		ent	 *e = &entity[n];
		bool faceNormals= false;
		char pointsNormals = 0;		//0: no, 1:yes
		long i;

	// little security :)
		if( (o->pNormals != NULL) || (o->fNormals != NULL) ) quitMessage("initNormals","Error managing memory :(");

		for(i=0;i<o->nosurf;i++)
		{
			USHORT val = o->oss[i];
			if( (s[val].flags & AF_FLAGS_GOUR) !=0) pointsNormals |= 1;
		}

		// no!!! faceNormals using in Vertex Culling method ;)
//		if( !faceNormals && !pointsNormals) goto noNormals;	 // :) no normals to calculate
	
		long sur;
		float facevect1x,facevect1y,facevect1z, facevect2x,facevect2y,facevect2z;
		float normalizator;
		long *facett, *ppt, **pptf, index;

		float scal;
		long j=0;

		float *points3D = o->shape3D;
		USHORT *rel = o->rel;
		// store all plane equation, normal + (pointface dotP (Unnormalized normal))
		o->fNormals = new float[o->nbf * 4];
		float *NormalF = o->fNormals;	// see Defs
		for(i=0;i < (o->nbf*4);i+=4)
		{
			if(rel[0]>2)
			{
				facevect1x = points3D[rel[2]] -   points3D[rel[1]];	// take first 3 pts
				facevect1y = points3D[rel[2]+1] - points3D[rel[1]+1];  // to form the normal
				facevect1z = points3D[rel[2]+2] - points3D[rel[1]+2];

				facevect2x = points3D[rel[3]] -   points3D[rel[1]];
				facevect2y = points3D[rel[3]+1] - points3D[rel[1]+1];
				facevect2z = points3D[rel[3]+2] - points3D[rel[1]+2];
			}

			NormalF[i]  =(facevect1y*facevect2z)-(facevect1z*facevect2y);
			NormalF[i+1]=(facevect1z*facevect2x)-(facevect1x*facevect2z);
			NormalF[i+2]=(facevect1x*facevect2y)-(facevect1y*facevect2x);

			// get the distance argument in equation plane
			// all math books will tell you to use the normalized dot product but it wont work!!
			// you must take the UNnormalized normal to get the correct dist argument :|
			normalizator=(float)(1/(
				sqrt(
				(NormalF[i]*NormalF[i])		+
				(NormalF[i+1]*NormalF[i+1]) +
				(NormalF[i+2]*NormalF[i+2])
					)
								)  );

			NormalF[i]   *=normalizator;
			NormalF[i+1] *=normalizator;
			NormalF[i+2] *=normalizator;

			NormalF[i+3] = (NormalF[i]   * points3D[rel[1]]  ) + 
						   (NormalF[i+1] * points3D[rel[1]+1]) +
						   (NormalF[i+2] * points3D[rel[1]+2]);

			rel += rel[0]+1;
		}

//			-------------------- Get point to Face links
		facett = new long[o->nbf];
		ppt = new long[o->nbp];
		pptf = new long*[o->nbp];

		for(i=0;i<o->nbp;i++) ppt[i] =0;
		// get number of adj faces per point
		rel		= o->rel;
		for(i=0;i<o->nbf;i++)
		{
			for(j=1;j<rel[0]+1;j++)
			{
				ppt[rel[j]/3]++;
			}
			rel += rel[0]+1;
		}
		// allocate memory
		for(i=0;i<o->nbp;i++)
		{
			long l=ppt[i];
			pptf[i] = new long[l];
		//	  if(pptf[i] == NULL) error_box("Getnormals","Memory error!");
		}
		for(i=0;i<o->nbp;i++) ppt[i] =0;	// reinit
		rel = o->rel;
		for(i=0;i<o->nbf;i++)	// get offset list
		{
			for(j=1;j<rel[0]+1;j++)
			{
				long s= rel[j]/3;
				pptf[s][ppt[s]] = i;
				ppt[s]++;
			}
			rel += rel[0]+1;
		}
		o->pptf = pptf;
		o->ppt = ppt;
//			---------------------------------



		// calculate points Normals only if needed :)
		// Points normals with maxsmoothing angle
		if( (pointsNormals & 1) != 0 )
		{
			// allocate memory
			o->pNormals = new float[o->allocPF * 3];
			// Optimized normals points calculator with max_smoothing angle by Gozer/CONDENSE
			// use normals face datas

			rel = o->rel;
			float *NormPt = o->pNormals;		// init Points normal ptr
			float *NormalF = o->fNormals;	// see Defs
			USHORT *IDF=o->IDF;

			for(i=0;i<o->nbf;i++)
			{
				sur = o->oss[IDF[i]];
				for(j=1;j<rel[0]+1;j++)
				{
					index = (j-1)*3;
					NormPt[index] = 0;
					NormPt[index+1] = 0;
					NormPt[index+2] = 0;
					long m;
					for( m=0;m<ppt[rel[j]/3];m++)
					{
						long otherp = pptf[rel[j]/3][m];
						scal = (NormalF[otherp*4]*NormalF[(i*4)]) +
								(NormalF[(otherp*4)+1]*NormalF[(i*4)+1]) +
								(NormalF[(otherp*4)+2]*NormalF[(i*4)+2]);

						if(scal > s[sur].maxSmooth)
						{
		 					NormPt[index]   += NormalF[otherp*4];
							NormPt[index+1] += NormalF[(otherp*4)+1];
							NormPt[index+2] += NormalF[(otherp*4)+2];
						}
					}
					normalizator=(float)(1/(
					sqrt(
					(NormPt[index]*NormPt[index])	  +
					(NormPt[index+1]*NormPt[index+1]) +
 					(NormPt[index+2]*NormPt[index+2])
 					)
										)  );
					NormPt[index]   *=normalizator;
					NormPt[index+1] *=normalizator;
					NormPt[index+2] *=normalizator;
				}
				NormPt += rel[0]*3;
				rel += rel[0]+1;
			}
//			for(i=0;i<o->nbp;i++) delete(pptf[i]);
//			delete pptf;
//			delete ppt;
		}

/*
		// no!!! faceNormals using in Vertex Culling method ;)
		if(!faceNormals)
		{
			delete o->fNormals;
			o->fNormals = NULL;
		}
*/
	  }
	  else 
	  {
		  aObject[n].pNormals = aObject[n].dataLocation->pNormals;
		  aObject[n].fNormals = aObject[n].dataLocation->fNormals;
		  aObject[n].ppt = aObject[n].dataLocation->ppt;
		  aObject[n].pptf = aObject[n].dataLocation->pptf;
	  }
	 }

//noNormals:;
	}
}

void scen::proceedMatrixsGL()
{
 long r;
 // first get all rotations matrixs
 for (r=0;r<(nb_entity-1);r++)	// not the camera :)
 {
	 // no need to calcul the camera matrix for child objects :)
	 if(entity[r].Parent == -1) entity[r].getMatrixToWorldGL();
 }



 // first init all non parent entities matrixs execpt camera
 for(r=0;r<nb_entity-1;r++)
 {
	 if( entity[r].Parent == -1)
	 {
		glLoadMatrixf(entity[r].matrix_Object);
		glTranslated(entity[r].currentFrame[0],-entity[r].currentFrame[1],entity[r].currentFrame[2]);
		glGetFloatv(GL_MODELVIEW_MATRIX, entity[r].matrix_OW);

		glLoadIdentity();
		glTranslated(-entity[r].currentFrame[0], entity[r].currentFrame[1], -entity[r].currentFrame[2]);
		glMultMatrixf( entity[r].matrix_iO );
		glGetFloatv(GL_MODELVIEW_MATRIX, entity[r].matrix_iOWorld);

		copyMatrix(entity[r].matrix_NormalW, entity[r].matrix_Normal);
	 }
 }



//		---------- HIERARCHY ----------- a little heavy but correct!
//		matrix calculations are not redondants
 for (r=0;r<nobject;r++)
 {
	 if( (entity[r].Parent == -1) && (aObject[r].Childs != NULL) )	// object is a root parent 
	 {
		glLoadIdentity();
		
		long **childLists= new long*[AF_MAX_CHILDS];
		long **nextChildLists = new long*[AF_MAX_CHILDS];
		void *swap;
		long nchildList = 1;
		childLists[0] = aObject[r].Childs;
		ent *childEnt, **parentEnt = new ent*[AF_MAX_CHILDS];
		ent **nextParentEnt = new ent*[AF_MAX_CHILDS];
		parentEnt[0] = &entity[r];

		while(nchildList)
		{
			long countNextList = 0;
			long pa;
			for(pa=0; pa<nchildList; pa++)
			{
				long a = 0;
				long nob = childLists[pa][a];

				while( nob != -1)
				{ 
					childEnt = &entity[nob];
					glLoadMatrixf(parentEnt[pa]->matrix_ObjectWorld);
					glTranslated(childEnt->currentFrame[0], -childEnt->currentFrame[1], childEnt->currentFrame[2]);
					glMultMatrixf(childEnt->matrix_Object);
					glGetFloatv(GL_MODELVIEW_MATRIX, childEnt->matrix_ObjectWorld);


					glLoadMatrixf(parentEnt[pa]->matrix_OW);
					glTranslated(childEnt->currentFrame[0], -childEnt->currentFrame[1], childEnt->currentFrame[2]);
					glMultMatrixf(childEnt->matrix_Object);
					glGetFloatv(GL_MODELVIEW_MATRIX, childEnt->matrix_OW);


					glLoadMatrixf(childEnt->matrix_iO);
					glTranslated(-childEnt->currentFrame[0], childEnt->currentFrame[1], -childEnt->currentFrame[2]);
					glMultMatrixf(parentEnt[pa]->matrix_iOWorld);
					glGetFloatv(GL_MODELVIEW_MATRIX, childEnt->matrix_iOWorld);

					copyMatrix(childEnt->matrix_NormalW, childEnt->matrix_Normal);

					glLoadMatrixf(parentEnt[pa]->matrix_NormalW);
					glMultMatrixf(childEnt->matrix_NormalW);
					glGetFloatv(GL_MODELVIEW_MATRIX, childEnt->matrix_NormalW);

					if( (childEnt->type == 0) || (childEnt->type == 3) )
					{
						if( aObject[nob].Childs != NULL)
						{
							nextParentEnt[countNextList] = &entity[nob];
							nextChildLists[countNextList++] = aObject[nob].Childs;
						}
					}
					nob = childLists[pa][++a];
				}
			}
			swap = (void*)childLists;
			childLists = nextChildLists;
			nextChildLists = (long**)swap;
			nchildList = countNextList;

			swap = (void*)parentEnt;
			parentEnt = nextParentEnt;
			nextParentEnt = (ent**)swap;
		}
		delete parentEnt;
		delete nextParentEnt;
		delete childLists;
		delete nextChildLists;
	 }
 }
//		--------------------------------
}


// transform lights pos/direction in world space: using 100% cPU
void scen::tLightsGL()
{
	float *matrix, tx, ty, tz;
	long i;
	for(i=0;i<nlight;i++)
	{
		matrix = entity[i+light_at].matrix_OW;
		// transform position
		aLight[i].x =  matrix[12];
		aLight[i].y =  matrix[13];
		aLight[i].z =  matrix[14];

		// rotate distant and spot lights directions
		if( (aLight[i].type == 0) || (aLight[i].type == 2) )
		{
			matrix = entity[i+light_at].matrix_NormalW;
			tx = 0;
			ty = 0;
			tz = 1;
			aLight[i].nx = (tx*matrix[0]) + (ty*matrix[4]) + (tz*matrix[8]);
			aLight[i].ny = (tx*matrix[1]) + (ty*matrix[5]) + (tz*matrix[9]);
			aLight[i].nz = (tx*matrix[2]) + (ty*matrix[6]) + (tz*matrix[10]);
		}
	}
}

void scen::iLights(long n)
{
	float *matrix;
	float tx,ty,tz;
	long l;
	for( l=0;l<nlight;l++)
	{
		// proceed itransform for positions
		if( (aLight[l].type == 1) || (aLight[l].type == 2) )	// point or spot
		{
			matrix = entity[n].matrix_iOWorld;
			tx = aLight[l].x;
			ty = aLight[l].y;
			tz = aLight[l].z;
			aLight[l].fx =  (tx*matrix[0]) + (ty*matrix[4]) + (tz*matrix[8]) + matrix[12];
			aLight[l].fy =  (tx*matrix[1]) + (ty*matrix[5]) + (tz*matrix[9]) + matrix[13];
			aLight[l].fz =  (tx*matrix[2]) + (ty*matrix[6]) + (tz*matrix[10])+ matrix[14];
		}

		// proceed itransform for directions
		if( (aLight[l].type == 0) || (aLight[l].type == 2) )	// distant or spot
		{
			matrix = entity[n].matrix_NormalW;
			tx = aLight[l].nx;
			ty = aLight[l].ny;
			tz = aLight[l].nz;
			aLight[l].fnx =  (tx*matrix[0]) + (ty*matrix[1]) + (tz*matrix[2]);
			aLight[l].fny =  (tx*matrix[4]) + (ty*matrix[5]) + (tz*matrix[6]);
			aLight[l].fnz =  (tx*matrix[8]) + (ty*matrix[9]) + (tz*matrix[10]);

		}
	}
}


float scen::getItPtGL(float *pn, float gloss, float slevel)
{
	float v[3], Oit, dot;
	float spec;
	Oit = AmbientIntensity;		// <---- put ambient here :)
	spec = 0;
	long l;
	for(l=0;l<nlight;l++)
	{
			// proceed distant lights
			if(aLight[l].type == 0)
			{
				dot = (pn[0]*aLight[l].fnx) + (pn[1]*aLight[l].fny) + (pn[2]*aLight[l].fnz);
				if( dot > 0 )
				{
					dot *= aLight[l].intensity;
					Oit += dot;
//					spec += (float)pow(dot,gloss)*slevel;
				}
//				else	// shadow
			}
			// proceed point lights
			else if(aLight[l].type == 1)
			{
				v[0] =  -aLight[l].fx;
				v[1] =  -aLight[l].fy;
				v[2] =  -aLight[l].fz;
				nVector(v);
				dot = (pn[0]*v[0]) + (pn[1]*v[1]) + (pn[2]*v[2]);
				if( dot > 0 )
				{
					dot *= aLight[l].intensity;
					Oit += dot;
//					spec += (float)pow(dot,gloss)*slevel;
				}
			}
	}
	Oit += spec;
	return Oit;
}

float scen::getFaceItGL(float *fn)
{
	float v[3],dot, Oit;
	Oit = AmbientIntensity;	//  <--- put ambient value here :)
	long l;
	for( l=0;l<nlight;l++)
	{
		// proceed distant lights
		if(aLight[l].type == 0)
		{
			dot = (fn[0]*aLight[l].fnx) + (fn[1]*aLight[l].fny) + (fn[2]*aLight[l].fnz);
			if( dot > 0 ) Oit += dot * aLight[l].intensity;
		}
		// proceed point lights
		else if(aLight[l].type == 1)
		{
			v[0] =  -aLight[l].fx;
			v[1] =  -aLight[l].fy;
			v[2] =  -aLight[l].fz;
			nVector(v);
			dot = (fn[0]*v[0]) + (fn[1]*v[1]) + (fn[2]*v[2]);
			if( dot > 0 ) Oit += dot * aLight[l].intensity;
		}
	}
	return Oit;
}

void initMapc(scen *sc, long n, surf *s, textu *t)
{
	object *o = &sc->aObject[n];
	ent	 *e = &sc->entity[n];
	bool calculMC= false;
	char pointsNormals = 0;		//0: no, 1:yes
	long i;

	for(i=0;i<o->nosurf;i++)
	{
		USHORT val = o->oss[i];
		if( (s[val].flags & (AF_FLAGS_FMAP | AF_FLAGS_TMAP)) !=0) calculMC = true;
	}

	if( calculMC )
	{
		long index,j;
		float *map3Dx, *map3Dy, *mapc;
		float surfx,surfy,surfxSize,surfySize;
		mapc = o->mc = new float[o->allocPF<<1];
		USHORT *rel = o->rel;
		float *points3D = o->shape3D;

		for(j=0;j<o->nbf;j++)
		{
		 index = o->oss[o->IDF[j]];
		 if(s[index].surfTexture!=NULL)
		 {
// --------------- Mapping coord -------------------
			if( s[index].surfTexture->axis == 1 )	// AXE X
			{
				map3Dx = points3D +2;
				map3Dy = points3D +1;
				surfx = s[index].surfTexture->Zcenter - (s[index].surfTexture->Zsiz/2);
				surfxSize = s[index].surfTexture->Zsiz;
				surfy = (-s[index].surfTexture->Ycenter) -(s[index].surfTexture->Ysiz/2);
				surfySize = s[index].surfTexture->Ysiz;
			}
			else if( s[index].surfTexture->axis == 2 )	// AXE Y
			{
				map3Dx = points3D;
				map3Dy = points3D +2;
				surfx = s[index].surfTexture->Xcenter - (s[index].surfTexture->Xsiz/2);
				surfxSize = s[index].surfTexture->Xsiz;
				surfy = s[index].surfTexture->Zcenter -(s[index].surfTexture->Zsiz/2);
				surfySize = s[index].surfTexture->Zsiz;
			}
			else if( s[index].surfTexture->axis == 3 )	// AXE Z
			{
				map3Dx = points3D;
				map3Dy = points3D+1;
				surfx = s[index].surfTexture->Xcenter - (s[index].surfTexture->Xsiz/2);
				surfxSize = s[index].surfTexture->Xsiz;
				surfy = (-s[index].surfTexture->Ycenter) -(s[index].surfTexture->Ysiz/2);
				surfySize = s[index].surfTexture->Ysiz;
			}

			if( s[index].bitmap != -1)
			{
				textu *tempt;					// address of class texture
				long scnNb = s[index].bitmap>>16;	// get scene number of that texture
				if( &scene[scnNb] == sc) tempt = t;	// texture class is in current loading scene so use tempory buffer
				else tempt = scene[scnNb].texture;	// txt class is in a loaded scene, use scene member...
				long k = s[index].bitmap & 0x0ffff;
				long h;
				for( h=0;h<rel[0];h++)
				{
	  				mapc[(h<<1)]= tempt[k].sizex *(
								(map3Dx[rel[h+1]]- surfx)/
								(surfxSize)
												);

					mapc[(h<<1)+1]=(
									tempt[k].sizey -(
									tempt[k].sizey *(
								(map3Dy[rel[h+1]]-surfy)/
								(surfySize)
												)
												)
									);

					mapc[(h<<1)]   /= tempt[k].sizex;
					mapc[(h<<1)+1] /= tempt[k].sizey;
					if( s[index].surfTexture->axis == 2) mapc[(h<<1)+1] *= -1;	// AXE Y
				}
			}
// ---------------------------------------------------
		 }
		mapc += rel[0]<<1;
		rel += rel[0] +1;
		}
	}
}




long loadLWO(scen *, long, surf *, textu *);

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


	     ***************   class de recherche de mots ascii ***************


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

class reader
{
#define GRP_SIZE  512
public:
	char *hop;
	long end, walk;
	char *fdata;

	reader(long z)
	{
		hop = new char[GRP_SIZE];
		walk = 0;
		end = z;
		fdata = NULL;
	}

	bool cmpstring(char *strone, char *strtwo, long length)
	{
		long i=0;
		bool match=TRUE;
		if(length == 0)
		{
			while( (strone[i]!=0) && (strtwo[i]!=0) )
			{
				if( strone[i] != strtwo[i]) 
				{
					match=FALSE;
					break;
				}
				i++;
			}
		}
		else
		{
			while( i<length )
			{
				if( strone[i] != strtwo[i])
				{
					match=FALSE;
					break;
				}
				i++;
			}
		}
		return match;
	}

	bool getWord()	// get the next word...
	{
		// skip undesired characters....
		while(  (fdata[walk] == ' ') ||
				(fdata[walk] == 10)  ||
				(fdata[walk] == 13) ) walk++;

		long toO = GRP_SIZE;
		if( (toO+walk) >= end) toO -= (toO+walk)-end;	// clip to end of buffer

		long i;
		for( i=0;i<toO;i++)
		{
			hop[i] = fdata[walk+i];
			if( (hop[i] == ' ') || (hop[i] == 13) )
			{
				hop[i] = 0;
				walk += i;	// word was found so no need to re-read this data :)
				break;
			}
		}
		if( (toO!=GRP_SIZE) && (i==toO) ) return true;	// end of buffer
		else return false;
	}

	bool getWordName()	// get the next word...
	{
		// skip undesired characters....
		while(	(fdata[walk] == ' ') ||
				(fdata[walk] == 10)  ||
				(fdata[walk] == 13) ) walk++;

		long toO = GRP_SIZE;
		if( (toO+walk) >= end) toO -= (toO+walk)-end;	// clip to end of buffer

		long i;
		for( i=0;i<toO;i++)
		{
			hop[i] = fdata[walk+i];
			if( (hop[i] == 13) )
			{
				hop[i] = 0;
				walk += i;	// word was found so no need to re-read this data :)
				break;
			}
		}
		if( (toO!=GRP_SIZE) && (i==toO) ) return true;	// end of buffer
		else return false;
	}


	// note: the offset stay at the beginning of the founded word...
	// find a word until another word has been found...
	bool findWord(char *hopla, char *hop2, char *endOfSection)
	{
		while(  !cmpstring(hopla, fdata + walk, 0) &&
				!cmpstring(hop2,fdata + walk, 0)
			 ) 
		{
			 if (cmpstring(endOfSection,fdata + walk, 0)) return true;
			 walk++;
		}
		long i=0;
		while(hopla[i++]!=0);
//		walk += i;
		return false;
	}

	// this function search only one word and add the offset to the end of that word
	// find a word until another word has been found...
	bool findWord(char *hopla, char *endOfSection)
	{
		while(  !cmpstring(hopla, fdata + walk, 0) )
		{
			 if (cmpstring(endOfSection,fdata + walk, 0)) return true;
			 walk++;
		}
		long i=0;
		while(hopla[i++]!=0);
		walk += i-1;
		return false;
	}

	// this function search only one word and add the offset to the end of that word
	bool findWord(char *hopla)// find a word until the end of the file
	{
		while(  !cmpstring(hopla, fdata + (walk++), 0) ) if (walk >= end) return true;
		long i=0;
		while(hopla[i++]!=0);
		walk += i-1;
		return false;
	}

	bool nextWord()
	{
		while( (fdata[walk] != ' ') && (fdata[walk++] != 10) )
		{
			if(walk >= end) return true;
		}
		return false;
	}

	void getDissolve(ent *tempEnt)
	{
	 if(checkWord("ObjDissolve"))
	 {
		if(checkWord("(envelope)"))
		{
			findWord("1");
			getWord();
			tempEnt->Diss.keys = atoi(hop);
			tempEnt->Diss.keylist = new KeyFrame[tempEnt->Diss.keys];
			long i;
			for(i=0;i<tempEnt->Diss.keys;i++)
			{
				// get dissolve value
				getWord();
				tempEnt->Diss.keylist[i].cv[0] = (float) atof(hop);
				for(long j=1;j<9;j++) tempEnt->Diss.keylist[i].cv[j] = 0;

				getWord();
				tempEnt->Diss.keylist[i].step   = (long) atoi(hop);

				getWord();
				tempEnt->Diss.keylist[i].linear = (long) atoi(hop);

				getWord();
				tempEnt->Diss.keylist[i].tens = (float) atof(hop);

				getWord();
				tempEnt->Diss.keylist[i].cont = (float) atof(hop);

				getWord();
				tempEnt->Diss.keylist[i].bias = (float) atof(hop);

			}
			tempEnt->Diss.steps = tempEnt->Diss.keylist[i-1].step; 
			findWord("EndBehavior");
			getWord();
			tempEnt->Diss.endBh = (long) atoi(hop);
		}
		else
		{
		}
	 }
	}

	void checkParticle(scen *daScen, ent *e)
	{
	 if(checkWord("ObjPolygonEdges"))
	 {
		 getWord();
		 if ( atoi(hop) != 0 )
		 {
			 daScen->particules = new spart[NPART];
			 daScen->initParticules();
			 e->type = 4;
		 }
	 }
	}

	void checkBGImage(scen *daScen)
	{
	 long where,back;
	 if( (where = checkWordAll("BGImage")))
	 {
		 back = walk;
		 walk = where+1;
		 nextWord();
		 getWord();
		 walk = back;
		 daScen->bgImage = new textu[1];
		 daScen->bgImage->tName = hop;
		 if ( daScen->bgImage->loadIMG(0) ) quitMessage("checkBGImage","couldn't load background image");
		 daScen->bgImage->tName = NULL;
	 }

	}

	void checkQuad(scen *daScen, ent *e)
	{
	 if(checkWord("UnaffectedByFog 1"))
	 {
		 e->sousType = 1;
	 }

	}

	void checkLens(scen *daScen, ent *e)
	{
	 if(checkWord("UnseenByRays 1"))
	 {
		 e->type = 5;
	 }

	}
	void getAnim(ent *tempEnt)
	{
		findWord("9");
		getWord();
		tempEnt->anim.keys = atoi(hop);
		tempEnt->anim.keylist = new KeyFrame[tempEnt->anim.keys];
		long i;
		for( i=0;i<tempEnt->anim.keys;i++)
		{
			long j;
			for(j=0;j<9;j++)
			{
				getWord();
				tempEnt->anim.keylist[i].cv[j] = (float) atof(hop);
			}
			getWord();
			tempEnt->anim.keylist[i].step   = (long) atoi(hop);

			getWord();
			tempEnt->anim.keylist[i].linear = (long) atoi(hop);

			getWord();
			tempEnt->anim.keylist[i].tens = (float) atof(hop);

			getWord();
			tempEnt->anim.keylist[i].cont = (float) atof(hop);

			getWord();
			tempEnt->anim.keylist[i].bias = (float) atof(hop);
		}
		// total nb of steps for that entity
		tempEnt->anim.steps = tempEnt->anim.keylist[i-1].step; 
		findWord("EndBehavior");
		getWord();
		tempEnt->anim.endBh = (long) atoi(hop);
	}

	// check up to the end of the current entity
	// do not modify the walker
	// used for non-required identifiers
	// return true if id exist and change the position of the walker to the id's data
	// return false if id doesn t exist, then the walker is not modified

	void checkParent(ent *tempEnt)
	{

		if(checkWord("ParentObject"))
		{
			getWord();
			tempEnt->Parent = (long)atoi(hop) -1;
		}
		else tempEnt->Parent = -1;
	}

	void checkPivot(ent *tempEnt)
	{
		// check for pivot infos
		if( checkWord("PivotPoint") )
		{
			getWord();
			tempEnt->pivotx = -(float)atof(hop);
			getWord();
			tempEnt->pivoty = (float)atof(hop);
			getWord();
			tempEnt->pivotz = -(float) atof(hop);
		}
		//else pivots initialized in entity constructor :)
	}

	bool checkWord(char *daID)
	{
		long lastWalk = walk;
		while(1)
		{
			// check end of entity
			if( (fdata[walk] == 10) && (fdata[walk+1] == 13) ) break;
			if( cmpstring(daID, fdata + (walk++), 0) )
			{
				nextWord();
				return true;
			}
		}
		walk = lastWalk;
		return false;
	}

	// check threw all datas if a word match
	long checkWordAll(char *daID)
	{
		long lastWalk = walk, retWalk;
		while(1)
		{
			if( walk >= end ) break;
			// check end of entity
			if( cmpstring(daID, fdata + (walk++), 0) )
			{
				if( (fdata + walk)[-2]  == 10 )
				{
					retWalk = walk;
					walk = lastWalk;
					return retWalk;
				}
			}
		}
		walk = lastWalk;
		return 0;
	}

	void getAllocation(long & objects, long & lights)
	{
		long lastWalk = walk;
		walk = 0;
		while(!findWord("LoadObject", "AddNullObject", "AmbientColor") )
		{
				nextWord();
				objects++;
		}
		while(!findWord("AddLight", "CameraMotion"))
				lights++;
		walk = lastWalk;
	}

	~reader()
	{
		delete hop;
		if(fdata != NULL) 
		{
			delete fdata;
			fdata = NULL;
		}
	}
};

#include "sceneManager.h"

long surfaceExist(char *sName, surf *s, long nsurf);

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


			***************   lws scene format loader procedure ***************


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

void scen::loadScene(char *filename)
{
// -------------------- LWS LOADER ROUTINE ----------------------
 long n=0;
 fileOperations sceneFile(filename);
 reader rLWS(sceneFile.getfilesize());
 rLWS.fdata = (char*)sceneFile.qloadfile();// will be deleted in destroyer's rLWS
 if (rLWS.fdata == NULL) quitMessage("scen constructor","Can't load scene:");

 // get scene section
 rLWS.findWord("LastFrame");
 rLWS.getWord();
 frames=atoi(rLWS.hop);
 if( rLWS.checkWord("PreviewLastFrame") )
 {
	rLWS.getWord();
	frames=atoi(rLWS.hop);
 }

 rLWS.findWord("FramesPerSecond");
 rLWS.getWord();
 FPS=(long)(atof(rLWS.hop));
 // --------------------$
 long allocObj=0;
 long allocL=0;
 rLWS.getAllocation(allocObj, allocL);
 entity = new ent[allocObj+allocL+1];
 aObject = new object[allocObj];
 aLight = new light[allocL];

// sprintf(OutputBuffer, "there is %i bytes of memory used.",(sizeof(entity)*(allocObj+allocL+1))+(sizeof(object)*allocObj)+(sizeof(light)*allocL) );
// MessageBox(0,OutputBuffer,"information",MB_OK);

 // alloc a tempory surfaces & textures buffers
 surf *Tsurface = new surf[AF_MAX_SURFACES];
 textu *Ttexture = new textu[AF_MAX_TEXTURES];

 // get objects section
 while(!rLWS.findWord("LoadObject", "AddNullObject", "AmbientColor") )
 {
	if(rLWS.fdata[rLWS.walk] == 'L')	// file object
	{
		rLWS.nextWord();
		rLWS.getWordName();	// here is the filename of the object
		bool found = false;

		// search for mactching name threw all scenes!!!!
		long u;
		for(u=0;u<scnMan.nbs;u++)
		{
			long i;
			for(i=0;i<scene[u].nobject;i++)
			{
				if( scene[u].entity[i].type == 0)
				{
					if( rLWS.cmpstring(scene[u].aObject[i].objectFileName, rLWS.hop,0) )
					{
						scene[u].aObject[i].COMValue++;
						aObject[nobject].dataLocation = &scene[u].aObject[i];
						found = true;
						break;
					}
				}
			}
			if(found) break;
		}
		// ------------------------------------------------

		if (!found)
		{
			long o=0;
			while(rLWS.hop[o++]!=0);
			aObject[nobject].whichScene = this;
			aObject[nobject].objectFileName = new char[o];
			strcpy(aObject[nobject].objectFileName, rLWS.hop);
			loadLWO(this, nobject, Tsurface, Ttexture);
//			initMapc(this, nobject, Tsurface, Ttexture);
			totalface += aObject[nobject].nbf;	// get totalnumber of faces
		}
		else// object exist already in memory, link is in dataLocation member
		{
			//  copy object: first save dataLocation-> which will be erased :(
			object *saveLocation = aObject[nobject].dataLocation;
			//	copy all members of the object
			aObject[nobject] = *aObject[nobject].dataLocation;
			//  restore location of the original object
			aObject[nobject].dataLocation = saveLocation;
			aObject[nobject].whichScene = this;
			aObject[nobject].initClone();
			if( saveLocation->whichScene != this)
			{
				long localNS = 0;
				long f;
				for(f=0;f<saveLocation->nosurf;f++)
				{
					long whichSRF = saveLocation->oss[f];
					long yo;
					if (-1 == (yo=surfaceExist(saveLocation->whichScene->surface[whichSRF].surfName,
									  Tsurface, nsurface)) )
					{
						aObject[nobject].oss[localNS++] = (USHORT)nsurface;
						Tsurface[nsurface] = saveLocation->whichScene->surface[whichSRF];
						// texture COM management
						if( Tsurface[nsurface].bitmap != -1) scene[Tsurface[nsurface].bitmap>>16].texture[Tsurface[nsurface].bitmap & 0x0ffff].COMval++;
						long a=0;
						while(saveLocation->whichScene->surface[whichSRF].surfName[a++] !=0);
						Tsurface[nsurface].surfName = new char[a];
						strcpy(Tsurface[nsurface++].surfName, saveLocation->whichScene->surface[whichSRF].surfName);
					}
					else 
					{
						aObject[nobject].oss[localNS++] = (USHORT)yo;

						Tsurface[yo] = saveLocation->whichScene->surface[whichSRF];
						// texture COM management
						if( Tsurface[yo].bitmap != -1) scene[Tsurface[yo].bitmap>>16].texture[Tsurface[yo].bitmap & 0x0ffff].COMval++;
						long a=0;
						while(saveLocation->whichScene->surface[whichSRF].surfName[a++] !=0);
						Tsurface[yo].surfName = new char[a];
						strcpy(Tsurface[yo].surfName, saveLocation->whichScene->surface[whichSRF].surfName);
					}
				}
			}
			// ------------------------

			totalface += aObject[nobject].nbf;	// get totalnumber of faces
		}
		entity[nb_entity].type = 0;
		rLWS.getAnim(&entity[nb_entity]);
		rLWS.checkQuad(this,&entity[nb_entity]);
		rLWS.getDissolve(&entity[nb_entity]);
		rLWS.checkPivot(&entity[nb_entity]);
		rLWS.checkParent(&entity[nb_entity]);
		aObject[nobject].init();
		nb_entity++;
		nobject++;
	}
	else	// null object
	{
		entity[nb_entity].type = 3;
		rLWS.nextWord();
		rLWS.getAnim(&entity[nb_entity]);
		// init null object alone point
		aObject[nobject].nbp = 1;
		aObject[nobject].allocPoints(1);
		ZeroMemory(aObject[nobject].shape3D, 3 * sizeof(float));
		rLWS.checkLens(this, &entity[nb_entity]);
		rLWS.checkParticle(this, &entity[nb_entity]);
		rLWS.checkPivot(&entity[nb_entity]);
		rLWS.checkParent(&entity[nb_entity]);
		nb_entity++;
		nobject++;
	}
 }

//	------------- arrange buffers --------------
 surface = new surf[nsurface];
 long i;
 for(i=0;i<nsurface;i++)
 {
	 surface[i] = Tsurface[i];
	 Tsurface[i].surfTexture = NULL;	// to avoid deletion
	 surface[i].initPtr();	// set all unused ptr to zero + names
 }
 //	note: names of surfaces are deleted during this operation...
 delete [] Tsurface;

 texture = new textu[ntexture];
 for(i=0;i<ntexture;i++) 
 {
	 texture[i] = Ttexture[i];
	 texture[i].initPtr();	// set all unused ptr to zero
	 Ttexture[i].data = NULL;	// this will avoid texture datas deletion :)
	 Ttexture[i].tName = NULL;	// this will avoid texture names deletion :)
 }
 // note: names of textures are NOT deleted during this operation...

 // got to init coord texture here!!!
 // because after the delete the X,Y,Zcenter and X,Y,Z size would be out!!!
 delete [] Ttexture;
//  --------------------------------------------

 // get ambient light
 rLWS.findWord("AmbientColor");
 rLWS.getWord();
 Ambient.iRedValue = (USHORT) atoi(rLWS.hop);
 rLWS.getWord();
 Ambient.iGreenValue = (USHORT) atoi(rLWS.hop);
 rLWS.getWord();
 Ambient.iBlueValue = (USHORT) atoi(rLWS.hop);
 Ambient.toFloat();
 Ambient.to16Bits();
 rLWS.findWord("AmbIntensity");
 rLWS.getWord();
 AmbientIntensity = (float)atof(rLWS.hop);

 // get lights section
 light_at = nb_entity;
 while(!rLWS.findWord("AddLight", "CameraMotion"))
 {
	rLWS.getAnim(&entity[nb_entity]);
	rLWS.checkParent(&entity[nb_entity]);
	rLWS.findWord("LightColor");

	// get Light color
	rLWS.getWord();
	aLight[nlight].lCol.iRedValue = (USHORT)atoi(rLWS.hop);
	rLWS.getWord();
	aLight[nlight].lCol.iGreenValue = (USHORT)atoi(rLWS.hop);
	rLWS.getWord();
	aLight[nlight].lCol.iBlueValue = (USHORT)atoi(rLWS.hop);
	aLight[nlight].lCol.toFloat();
	aLight[nlight].lCol.to16Bits();

	// get Light intensity
	rLWS.findWord("LgtIntensity");
	rLWS.getWord();
	aLight[nlight].intensity = (float) atof(rLWS.hop);

	// get Light type
	rLWS.findWord("LightType");
	rLWS.getWord();
	aLight[nlight].type = (long) atoi(rLWS.hop);

	entity[nb_entity].type = 1;
	nb_entity++;
	nlight++;
 }

 rLWS.checkBGImage(this);
 camera_at = nb_entity;
 // get camera section
 while(!rLWS.findWord("CameraMotion", "SolidBackdrop"))
 {
	rLWS.getAnim(&entity[nb_entity]);
	rLWS.checkParent(&entity[nb_entity]);//dont know if its possible, check it anyway

	// check for targeted object
	if(rLWS.checkWord("TargetObject"))
	{
		rLWS.getWord();
		camera.target = (long)atoi(rLWS.hop) -1;
	}

	// get the focal
	rLWS.findWord("ZoomFactor");
	rLWS.getWord();
	camera.focal = (float)(res_x+res_y)*((float)atof(rLWS.hop))/5;
	camera.LWfocal = (float)atof(rLWS.hop);
	
	entity[nb_entity].type = 2;
	nb_entity++;
 }

 initHierarchy();
 initNormals();

 // get background color
 rLWS.findWord("BackdropColor");
 rLWS.getWord();
 Background.iRedValue = (USHORT) atoi(rLWS.hop);
 rLWS.getWord();
 Background.iGreenValue = (USHORT) atoi(rLWS.hop);
 rLWS.getWord();
 Background.iBlueValue = (USHORT) atoi(rLWS.hop);
 Background.toFloat();
 Background.to16Bits();

 // scene resize
 rLWS.findWord("GridSize");
 rLWS.getWord();
 gridSize = (float)atof(rLWS.hop);
 gridSize /= 2;
}
