#include "project.h"

tPrimitive::tPrimitive()
{
	NumVertices=NumFaces=0;
	Faces=NULL;
	Vertices=NULL;
	VertexNormals=NULL;
	smooth=true;
	//tmxIdentity(transform);
}

tPrimitive::~tPrimitive()
{
	NumFaces=NumVertices=0;
	if (Vertices!=NULL) delete [] Vertices;
	if (VertexNormals!=NULL) delete [] VertexNormals;
	if (Faces!=NULL) delete [] Faces;
	Vertices=NULL;
	VertexNormals=NULL;
	Faces=NULL;
}

void tPrimitive::Allocate()
{
	Faces=new tFace [NumFaces];
	Vertices=new t3DVector [NumVertices];
	VertexNormals=new t3DVector [NumVertices];
	memset(Faces,0,NumFaces*sizeof(tFace));
	memset(Vertices,0,NumVertices*sizeof(t3DVector));
	memset(VertexNormals,0,NumVertices*sizeof(t3DVector));

	//tmxIdentity(transform);
}

void tPrimitive::SetFace(int faceNum, int a, int b, int c, float px, float py, float qx, float qy, float rx, float ry)
{
	Faces[faceNum].a=a; Faces[faceNum].b=b; Faces[faceNum].c=c;
	Faces[faceNum].px=px; Faces[faceNum].py=py;
	Faces[faceNum].qx=qx; Faces[faceNum].qy=qy;
	Faces[faceNum].rx=rx; Faces[faceNum].ry=ry;
}

void tPrimitive::Draw()
{
	if (Faces!=NULL)
	{
		int i;
		tFace *f = &Faces[0];

		//int i;
		glBegin(GL_TRIANGLES);
			if (smooth)
			{
				for (i=0; i<NumFaces; i++, f++)
				{
					glNormal3fv(VertexNormals[f->a]); glVertex3fv(Vertices[f->a]);
					glNormal3fv(VertexNormals[f->b]); glVertex3fv(Vertices[f->b]);
					glNormal3fv(VertexNormals[f->c]); glVertex3fv(Vertices[f->c]);
				}
			} else {
				for (i=0; i<NumFaces; i++, f++)
				{
					glNormal3fv(f->n); 
					glVertex3fv(Vertices[f->a]);
					glVertex3fv(Vertices[f->b]);
					glVertex3fv(Vertices[f->c]);
				}
			}
		glEnd();
	}
}

void tPrimitive::TexDraw(float tilex, float tiley)
{
	if (Faces!=NULL)
	{
		int i;
		tFace *f = &Faces[0];

		//int i;
		glBegin(GL_TRIANGLES);
			if (smooth)
			{
				for (i=0; i<NumFaces; i++, f++)
				{
					glTexCoord2f(tilex*f->px,tiley*f->py); glNormal3fv(VertexNormals[f->a]); glVertex3fv(Vertices[f->a]);
					glTexCoord2f(tilex*f->qx,tiley*f->qy); glNormal3fv(VertexNormals[f->b]); glVertex3fv(Vertices[f->b]);
					glTexCoord2f(tilex*f->rx,tiley*f->ry); glNormal3fv(VertexNormals[f->c]); glVertex3fv(Vertices[f->c]);
				}
			} else {
				for (i=0; i<NumFaces; i++, f++)
				{
					glNormal3fv(f->n); 
					glTexCoord2f(tilex*f->px,tiley*f->py); glVertex3fv(Vertices[f->a]);
					glTexCoord2f(tilex*f->qx,tiley*f->qy); glVertex3fv(Vertices[f->b]);
					glTexCoord2f(tilex*f->rx,tiley*f->ry); glVertex3fv(Vertices[f->c]);
				}
			}
		glEnd();
	}
}

// this is slow and unoptimized. sorry.
void tPrimitive::CalculateVertexNormals()
{
	for (int i=0; i<NumVertices; i++)
	{
		int k=0;
		t3DVector n = {0,0,0};

		// get the faces this vertex is involved in
		for (int j=0; j<NumFaces; j++)
		{
			if ((Faces[j].a==i) || (Faces[j].b==i) || (Faces[j].c==i))
			{
				t3DVector_Add(n,Faces[j].n,n);
				k++;
			}
		}

		VertexNormals[i][0]=n[0]/(float)k;
		VertexNormals[i][1]=n[1]/(float)k;
		VertexNormals[i][2]=n[2]/(float)k;

		t3DVector_Normalize(VertexNormals[i]);
	}
}

// Affect: vertices
void tPrimitive::Translate(float tx, float ty, float tz)
{
	tmxMatrix m;
	tmxIdentity(m);
	tmxTranslate(m,tx,ty,tz);

	t3DVector dst,*v=&Vertices[0];
	int i;
	for (i=0; i<NumVertices; i++, v++)
	{
		tmxMulMxVec(m,*v,dst);
		t3DVector_Copy(dst,*v);
	}
}

// Affect: vertices, facenormals, vertexnormals
void tPrimitive::Scale(float sx, float sy, float sz)
{
	tmxMatrix m;
	tmxIdentity(m);
	tmxScale(m,sx,sy,sz);

	t3DVector dst,*v=&Vertices[0],*vn=&VertexNormals[0];
	int i;
	for (i=0; i<NumVertices; i++, v++, vn++)
	{
		tmxMulMxVec(m,*v,dst);
		t3DVector_Copy(dst,*v);
		tmxMulMxVec(m,*vn,dst);
		t3DVector_Copy(dst,*vn);
		t3DVector_Normalize(*vn);
	}
	tFace *f=&Faces[0];
	for (i=0; i<NumVertices; i++, f++)
	{
		tmxMulMxVec(m,f->n,dst);
		t3DVector_Copy(dst,f->n);
		t3DVector_Normalize(f->n);
	}
}

// Affect: vertices, facenormals, vertexnormals
void tPrimitive::Rotate(float rx, float ry, float rz)
{
	tmxMatrix m;
	tmxIdentity(m);
	tmxRotate(m,rx,ry,rz);

	t3DVector dst,*v=&Vertices[0],*vn=&VertexNormals[0];
	int i;
	for (i=0; i<NumVertices; i++, v++, vn++)
	{
		tmxMulMxVec(m,*v,dst);
		t3DVector_Copy(dst,*v);
		tmxMulMxVec(m,*vn,dst);
		t3DVector_Copy(dst,*vn);
		t3DVector_Normalize(*vn);
	}
	tFace *f=&Faces[0];
	for (i=0; i<NumVertices; i++, f++)
	{
		tmxMulMxVec(m,f->n,dst);
		t3DVector_Copy(dst,f->n);
		t3DVector_Normalize(f->n);
	}
}



void tPrimitive::Box(float wx, float wy, float wz)
{
	NumFaces=12;
	NumVertices=8;
	Allocate();

	float hx = wx/2.0f;
	float hz = wz/2.0f;

	float *verts = &(Vertices[0][0]);
	// TO BE OPTIMIZED
	*verts++=-hx; *verts++=wy; *verts++= hz; // bfe
	*verts++=-hx; *verts++= 0; *verts++= hz; // ble
	*verts++= hx; *verts++= 0; *verts++= hz; // jle
	*verts++= hx; *verts++=wy; *verts++= hz; // jfe
	*verts++=-hx; *verts++=wy; *verts++=-hz; // bfh
	*verts++=-hx; *verts++= 0; *verts++=-hz; // blh
	*verts++= hx; *verts++= 0; *verts++=-hz; // jlh
	*verts++= hx; *verts++=wy; *verts++=-hz; // jfh

	SetFace( 0, 0,1,2, 0,0,0,1,1,1); SetFace( 1, 2,3,0, 1,1,1,0,0,0);
	SetFace( 2, 7,6,5, 0,0,0,1,1,1); SetFace( 3, 5,4,7, 1,1,1,0,0,0);
	SetFace( 4, 4,5,1, 0,0,0,1,1,1); SetFace( 5, 1,0,4, 1,1,1,0,0,0);
	SetFace( 6, 3,2,6, 0,0,0,1,1,1); SetFace( 7, 6,7,3, 1,1,1,0,0,0);
	SetFace( 8, 4,0,3, 0,0,0,1,1,1); SetFace( 9, 3,7,4, 1,1,1,0,0,0);
	SetFace(10, 1,5,6, 0,0,0,1,1,1); SetFace(11, 6,2,1, 1,1,1,0,0,0);

	for (int i=0; i<NumFaces; i++)
		t3DVector_GetNormal(Vertices[Faces[i].a],Vertices[Faces[i].b],Vertices[Faces[i].c],Faces[i].n);
	CalculateVertexNormals();
}

void tPrimitive::Grid(float wx, float wy, int segsx, int segsy)
{
	NumFaces=segsx*segsy*2;
	NumVertices=(segsx+1)*(segsy+1);
	Allocate();

	float hx = wx/2.0f;
	float hy = wy/2.0f;

	int i,j;
	for (j=0; j<=segsy; j++)
	{
		for (i=0; i<=segsx; i++)
		{
			// 0,0 is the upper left corner
			Vertices[i+j*(segsx+1)][0]=wx*(i/(float)segsx)-hx;
			Vertices[i+j*(segsx+1)][1]=hy-wy*(j/(float)segsy);
			Vertices[i+j*(segsx+1)][2]=0;
		}
	}
	for (j=0; j<segsy; j++)
	{
		for (i=0; i<segsx; i++)
		{
			// 0,0 is the upper left corner
			SetFace(2*(i+j*segsx),
					i+   j   *(segsx+1),
					i+  (j+1)*(segsx+1),
					i+1+(j+1)*(segsx+1),
					i/(float)segsx,j/(float)segsy,
					i/(float)segsx,(j+1)/(float)segsy,
					(i+1)/(float)segsx,(j+1)/(float)segsy);
			SetFace(2*(i+j*segsx)+1,
					i+1+(j+1)*(segsx+1),
					i+1+j    *(segsx+1),
					i+  j    *(segsx+1),
					(i+1)/(float)segsx,(j+1)/(float)segsy,
					(i+1)/(float)segsx,j/(float)segsy,
					i/(float)segsx,j/(float)segsy);
			t3DVector_GetNormal(Vertices[Faces[2*(i+j*segsx)].a],Vertices[Faces[2*(i+j*segsx)].b],Vertices[Faces[2*(i+j*segsx)].c],Faces[2*(i+j*segsx)].n);
			t3DVector_GetNormal(Vertices[Faces[2*(i+j*segsx)+1].a],Vertices[Faces[2*(i+j*segsx)+1].b],Vertices[Faces[2*(i+j*segsx)+1].c],Faces[2*(i+j*segsx)+1].n);
		}
	}

	CalculateVertexNormals();
}

void tPrimitive::Sphere(float radius, int slices, int segments)
{
	tPointSet c;
	c.numPts=segments+1;
	c.points=new t3DVector [c.numPts];
	for (int i=0; i<=segments; i++)
	{
		// kup
		//c.points[i][0]=my_sin(my_pi*i/(float)segments)*my_sin(my_pi*i/(float)segments)/2.0f;
		//c.points[i][1]=my_cos(-0.1f+my_pi*i/(float)segments)*my_cos(my_pi*i/(float)segments)/2.0f;

		// majdnem torusz
		//c.points[i][0]=my_sin(my_pi*i/(float)segments)*my_sin(my_pi*i/(float)segments)/2.0f;
		//c.points[i][1]=my_sin(my_pi*i/(float)segments)*my_cos(my_pi*i/(float)segments)/2.0f;

		// ?
		//c.points[i][0]=my_sin(my_pi*i/(float)segments)*my_sin(my_pi*i/(float)segments)/2.0f;
		//c.points[i][1]=my_cos(my_pi*i/(float)segments)/2.0f;

		// kind of torus
		//c.points[i][0]=my_sin(my_pi*i/(float)segments)/2.0f;
		//c.points[i][1]=my_sin(my_pi*i/(float)segments)*my_cos(my_pi*i/(float)segments)/2.0f;

		// csucsos cukorka
		//c.points[i][0]=pow(my_sin(my_pi*i/(float)segments)/2.0f,3);
		//c.points[i][1]=my_cos(my_pi*i/(float)segments)/2.0f;

		// bugocsiga
		//c.points[i][0]=pow(my_sin(my_pi*i/(float)segments),3)/2.0f;
		//c.points[i][1]=my_cos(my_pi*i/(float)segments)/2.0f;

		// ?
		//c.points[i][0]=my_sin(my_pi*i/(float)segments)/2.0f;
		//c.points[i][1]=pow(my_cos(my_pi*i/(float)segments),5)/2.0f;

		// ufo
		//c.points[i][0]=0.001f+my_sin(my_pi*i/(float)segments)/2.0f;
		//c.points[i][1]=pow(my_cos(my_pi*i/(float)segments)/2.0f,3);

		// sphere
		c.points[i][0]=radius*my_sin(my_pi*i/(float)segments);
		c.points[i][1]=radius*my_cos(my_pi*i/(float)segments);

	}
	Lathe(c,slices,false);
	// fix the top part's normals
	/*tFace *q;
	for (i=0; i<slices; i++)
	{
		q=&Faces[i*(segments)];
		t3DVector_GetNormal(Vertices[q->a],Vertices[q->b],Vertices[q->c],q->n);
	}*/
	CalculateVertexNormals();
	delete [] c.points;
}

void tPrimitive::Tube(float radius1, float radius2, float height, int slices)
{
	tPointSet c;
	c.numPts=4;
	c.points=new t3DVector [c.numPts];
	c.points[0][0]=radius2; c.points[0][1]=height; c.points[0][2]=0;
	c.points[1][0]=radius1; c.points[1][1]=height; c.points[1][2]=0;
	c.points[2][0]=radius1; c.points[2][1]=0; c.points[2][2]=0;
	c.points[3][0]=radius2; c.points[3][1]=0; c.points[3][2]=0;
	
	Lathe(c,slices,true);
	CalculateVertexNormals();
	delete [] c.points;
}

void tPrimitive::Lathe(tPointSet shape, int segs, bool close_surface)
{
	NumVertices=shape.numPts*segs;
	NumFaces=2*(close_surface?shape.numPts:(shape.numPts-1))*segs;
	Allocate();

	int i,j;

	for (j=0; j<segs; j++)
	{
		for (i=0; i<shape.numPts; i++)
		{
			Vertices[i+j*shape.numPts][0]=shape.points[i][0]*my_cos(2*my_pi*j/(float)segs);
			Vertices[i+j*shape.numPts][1]=shape.points[i][1];
			Vertices[i+j*shape.numPts][2]=shape.points[i][0]*-my_sin(2*my_pi*j/(float)segs);
		}
	}

	int szorzo = close_surface?shape.numPts:(shape.numPts-1);

	for (j=0; j<segs-1; j++)
	{
		for (i=0; i<shape.numPts-1; i++)
		{
			SetFace(2*(i+j*szorzo),
					i+j*shape.numPts,
					i+1+j*shape.numPts,
					i+1+(j+1)*shape.numPts,

					j/(float)segs,    i/(float)(szorzo),
					j/(float)segs,    (i+1)/(float)(szorzo),
					(j+1)/(float)segs,(i+1)/(float)(szorzo));
			SetFace(2*(i+j*szorzo)+1,
					i+1+(j+1)*shape.numPts,
					i+(j+1)*shape.numPts,
					i+j*shape.numPts,

					(j+1)/(float)segs,(i+1)/(float)(szorzo),
					(j+1)/(float)segs,i/(float)(szorzo),
					j/(float)segs,    i/(float)(szorzo));
		}
		if (close_surface)
		{
			SetFace(2*(shape.numPts-1+j*szorzo),
					shape.numPts-1+j*shape.numPts,
					j*shape.numPts,
					(j+1)*shape.numPts,
					j/(float)segs,    (szorzo-1)/(float)(szorzo),
					j/(float)segs,    1,
					(j+1)/(float)segs,1);
			SetFace(2*(shape.numPts-1+j*szorzo)+1,
					(j+1)*shape.numPts,
					shape.numPts-1+(j+1)*shape.numPts,
					shape.numPts-1+j*shape.numPts,
					(j+1)/(float)segs,1,
					(j+1)/(float)segs,(szorzo-1)/(float)(szorzo),
					j/(float)segs,    (szorzo-1)/(float)(szorzo));
		}
	}

	for (i=0; i<shape.numPts-1; i++)
	{
		SetFace(2*(i+(segs-1)*szorzo),
				i+(segs-1)*shape.numPts,
				i+1+(segs-1)*shape.numPts,
				i+1,
				(segs-1)/(float)segs,i/(float)(szorzo),
				(segs-1)/(float)segs,(i+1)/(float)(szorzo),
				1,                   (i+1)/(float)(szorzo));
		SetFace(2*(i+(segs-1)*szorzo)+1,
				i+1,
				i,
				i+(segs-1)*shape.numPts,
				1,                   (i+1)/(float)(szorzo),
				1,                   i/(float)(szorzo),
				(segs-1)/(float)segs,i/(float)(szorzo));
	}
	if (close_surface)
	{
		SetFace(2*(shape.numPts-1+(segs-1)*szorzo),
				shape.numPts-1+(segs-1)*shape.numPts,
				(segs-1)*shape.numPts,
				0,
				(segs-1)/(float)segs,(szorzo-1)/(float)(szorzo),
				(segs-1)/(float)segs,1,
				1,                   1);
		SetFace(2*(shape.numPts-1+(segs-1)*szorzo)+1,
				0,
				shape.numPts-1,
				shape.numPts-1+(segs-1)*shape.numPts,
				1,                   1,
				1,                   (szorzo-1)/(float)(szorzo),
				(segs-1)/(float)segs,(szorzo-1)/(float)(szorzo));
	}

	tFace *f = &Faces[0];

	for (i=0; i<NumFaces; i++, f++)
	{
		t3DVector_GetNormal(
			Vertices[f->a],
			Vertices[f->b],
			Vertices[f->c],
			f->n);
	}

	this->CalculateVertexNormals();

}

/*void tPrimitive::Lathe2(tPointSet shape, float startangle, float endangle, int segs, bool close_surface)
{
	NumVertices=shape.numPts*(segs+1);
	NumFaces=2*(close_surface?shape.numPts:(shape.numPts-1))*segs;
	Allocate();

	int i,j;

	startangle*=my_pi/180.0f;
	endangle*=my_pi/180.0f;

	for (j=0; j<=segs; j++)
	{
		for (i=0; i<shape.numPts; i++)
		{
			Vertices[i+j*shape.numPts][0]=shape.points[i][0]*my_cos(startangle + endangle*j/(float)segs);
			Vertices[i+j*shape.numPts][1]=shape.points[i][1];
			Vertices[i+j*shape.numPts][2]=shape.points[i][0]*-my_sin(startangle + endangle*j/(float)segs);
		}
	}

	int szorzo = close_surface?shape.numPts:(shape.numPts-1);

	for (j=0; j<segs; j++)
	{
		for (i=0; i<shape.numPts-1; i++)
		{
			SetFace(2*(i+j*szorzo),
					i+j*shape.numPts,
					i+1+j*shape.numPts,
					i+1+(j+1)*shape.numPts,

					j/(float)segs,    i/(float)(szorzo),
					j/(float)segs,    (i+1)/(float)(szorzo),
					(j+1)/(float)segs,(i+1)/(float)(szorzo));
			SetFace(2*(i+j*szorzo)+1,
					i+1+(j+1)*shape.numPts,
					i+(j+1)*shape.numPts,
					i+j*shape.numPts,

					(j+1)/(float)segs,(i+1)/(float)(szorzo),
					(j+1)/(float)segs,i/(float)(szorzo),
					j/(float)segs,    i/(float)(szorzo));
		}
		if (close_surface)
		{
			SetFace(2*(shape.numPts-1+j*szorzo),
					shape.numPts-1+j*shape.numPts,
					j*shape.numPts,
					(j+1)*shape.numPts,
					j/(float)segs,    (szorzo-1)/(float)(szorzo),
					j/(float)segs,    1,
					(j+1)/(float)segs,1);
			SetFace(2*(shape.numPts-1+j*szorzo)+1,
					(j+1)*shape.numPts,
					shape.numPts-1+(j+1)*shape.numPts,
					shape.numPts-1+j*shape.numPts,
					(j+1)/(float)segs,1,
					(j+1)/(float)segs,(szorzo-1)/(float)(szorzo),
					j/(float)segs,    (szorzo-1)/(float)(szorzo));
		}
	}

	tFace *f = &Faces[0];

	for (i=0; i<NumFaces; i++, f++)
	{
		t3DVector_GetNormal(
			Vertices[f->a],
			Vertices[f->b],
			Vertices[f->c],
			f->n);
	}

	this->CalculateVertexNormals();

}*/

// the shape lies in the XY plane
void tPrimitive::Loft(tPointSet shape, tPointSet path, bool close_shape, bool close_path)
{
	int i,j;

	tPointSet lft_temppath;
	lft_temppath.points = new t3DVector [path.numPts+2];

	for (i=0; i<path.numPts; i++)
		t3DVector_Copy(path.points[i],lft_temppath.points[i+1]);

	if (close_path)
	{
		t3DVector_Copy(lft_temppath.points[path.numPts],lft_temppath.points[0]);
		t3DVector_Copy(lft_temppath.points[1],lft_temppath.points[path.numPts+1]);
	} else {
		t3DVector_Copy(lft_temppath.points[path.numPts],lft_temppath.points[path.numPts+1]);
		t3DVector_Copy(lft_temppath.points[1],lft_temppath.points[0]);
	}

	path.numPts+=2;
	
	float lft_texdx = (close_path)?(path.numPts-2):(path.numPts-3);
	float lft_texdy = (close_shape)?(shape.numPts):(shape.numPts-1);

	this->~tPrimitive();
	NumVertices=shape.numPts*path.numPts;
	NumFaces=2*shape.numPts*(close_path?path.numPts:path.numPts-1); // [+1]
	Allocate();

	t3DVector a1,a2,normal,pi,pj;
	t3DVector up = {0,1,0};

	for (j=1; j<path.numPts-1; j++)
	{
		t3DVector_Sub(lft_temppath.points[j],lft_temppath.points[j-1],a1); t3DVector_Normalize(a1);
		t3DVector_Sub(lft_temppath.points[j+1],lft_temppath.points[j],a2); t3DVector_Normalize(a2);

		t3DVector_Add(a1,a2,normal); t3DVector_Normalize(normal);

		t3DVector_Cross(up,normal,pi); t3DVector_Normalize(pi);
		t3DVector_Cross(normal,pi,pj); t3DVector_Normalize(pj);

		for (i=0; i<shape.numPts; i++)
		{
			Vertices[i+(j-1)*shape.numPts][0] = lft_temppath.points[j][0] + shape.points[i][0]*pi[0] + shape.points[i][1]*pj[0];// + shape.points[i][2]*normal[0];
			Vertices[i+(j-1)*shape.numPts][1] = lft_temppath.points[j][1] + shape.points[i][0]*pi[1] + shape.points[i][1]*pj[1];// + shape.points[i][2]*normal[1];
			Vertices[i+(j-1)*shape.numPts][2] = lft_temppath.points[j][2] + shape.points[i][0]*pi[2] + shape.points[i][1]*pj[2];// + shape.points[i][2]*normal[2];
		}
	}

	for (j=0; j<path.numPts-1; j++)
	{
		for (i=0; i<shape.numPts-1; i++)
		{
			SetFace(
				2*(i+j*shape.numPts),

				i  + j   *shape.numPts,
				i+1+ j   *shape.numPts,
				i+1+(j+1)*shape.numPts,

				(j  )/lft_texdx,(i  )/lft_texdy,
				(j  )/lft_texdx,(i+1)/lft_texdy,
				(j+1)/lft_texdx,(i+1)/lft_texdy

				);

			SetFace(
				2*(i+j*shape.numPts)+1,

				i+1+(j+1)*shape.numPts,
				i  +(j+1)*shape.numPts,
				i  +(j  )*shape.numPts,

				(j+1)/lft_texdx,(i+1)/lft_texdy,
				(j+1)/lft_texdx,(i  )/lft_texdy,
				(j  )/lft_texdx,(i  )/lft_texdy

				);
		}

		if (close_shape)
		{
			SetFace(
				2*(shape.numPts-1+j*shape.numPts),

				shape.numPts-1+j*shape.numPts,
				j*shape.numPts,
				(j+1)*shape.numPts,

				(j  )/lft_texdx,(lft_texdy-1)/lft_texdy,
				(j  )/lft_texdx,1,
				(j+1)/lft_texdx,1);

			SetFace(
				2*(shape.numPts-1+j*shape.numPts)+1,

				(j+1)*shape.numPts,
				shape.numPts-1+(j+1)*shape.numPts,
				shape.numPts-1+j*shape.numPts,

				(j+1)/lft_texdx,1,
				(j+1)/lft_texdx,(lft_texdy-1)/lft_texdy,
				(j  )/lft_texdx,(lft_texdy-1)/lft_texdy);
		}
	}


	/*if (close_path)
	{
		j=path.numPts-3;
		for (i=0; i<shape.numPts-1; i++)
		{
			SetFace(
				2*(i+j*shape.numPts),

				i  +(path.numPts-3)*shape.numPts,
				i+1+(path.numPts-3)*shape.numPts,
				i+1,

				(lft_texdx-1)/lft_texdx,(i  )/lft_texdy,
				(lft_texdx-1)/lft_texdx,(i+1)/lft_texdy,
				1,(i+1)/lft_texdy);

			SetFace(
				2*(i+j*shape.numPts)+1,

				i+1,
				i,
				i  +(path.numPts-3)*shape.numPts,

				1,(i+1)/lft_texdy,
				1,(i  )/lft_texdy,
				(lft_texdx-1)/lft_texdx,(i  )/lft_texdy);
		}

		if (close_shape)
		{
			SetFace(
				2*(shape.numPts-1+j*shape.numPts),

				shape.numPts-1+(path.numPts-3)*shape.numPts,
				(path.numPts-3)*shape.numPts,
				0,

				(lft_texdx-1)/lft_texdx,(lft_texdy-1)/lft_texdy,
				(lft_texdx-1)/lft_texdx,1,
				1,1);

			SetFace(
				2*(shape.numPts-1+j*shape.numPts)+1,

				0,
				shape.numPts-1,
				shape.numPts-1+(path.numPts-3)*shape.numPts,

				1,1,
				1,(lft_texdy-1)/lft_texdy,
				(lft_texdx-1)/lft_texdx,(lft_texdy-1)/lft_texdy);
		}
	}*/



	for (j=0; j<path.numPts-3; j++)
	{
		for (i=0; i<shape.numPts; i++)
		{
			t3DVector_GetNormal(
				Vertices[Faces[2*(i+j*shape.numPts)].a],
				Vertices[Faces[2*(i+j*shape.numPts)].b],
				Vertices[Faces[2*(i+j*shape.numPts)].c],
				Faces[2*(i+j*shape.numPts)].n);
			t3DVector_GetNormal(
				Vertices[Faces[2*(i+j*shape.numPts)+1].a],
				Vertices[Faces[2*(i+j*shape.numPts)+1].b],
				Vertices[Faces[2*(i+j*shape.numPts)+1].c],
				Faces[2*(i+j*shape.numPts)+1].n);
		}
	}

	this->CalculateVertexNormals();

	delete [] lft_temppath.points;
}


void LoadMesh(tPrimitive *target, char filename[])
{
	FILE *f = fopen(filename,"rb");
	if (f==NULL)
	{
		MessageBox(NULL,"Fuck! A file is missing!","",MB_OK);
		exit(1);
	}

	__int16 numvx,numfc;

	fread(&numvx,2,1,f);
	fread(&numfc,2,1,f);

	target->NumFaces=numfc;
	target->NumVertices=numvx;
	target->Allocate();

	int i;

	for (i=0; i<numvx; i++)
	{
		fread(&(target->Vertices[i][0]),sizeof(float),1,f);
		fread(&(target->Vertices[i][1]),sizeof(float),1,f);
		fread(&(target->Vertices[i][2]),sizeof(float),1,f);
	}

	for (i=0; i<numfc; i++)
	{
		fread(&(target->Faces[i].a),2,1,f);
		fread(&(target->Faces[i].b),2,1,f);
		fread(&(target->Faces[i].c),2,1,f);
	}

	for (i=0; i<numfc; i++)
	{
		fread(&(target->Faces[i].n[0]),sizeof(float),1,f);
		fread(&(target->Faces[i].n[1]),sizeof(float),1,f);
		fread(&(target->Faces[i].n[2]),sizeof(float),1,f);
	}

	for (i=0; i<numvx; i++)
	{
		fread(&(target->VertexNormals[i][0]),sizeof(float),1,f);
		fread(&(target->VertexNormals[i][1]),sizeof(float),1,f);
		fread(&(target->VertexNormals[i][2]),sizeof(float),1,f);
	}

	fclose(f);
}

void LoadCurve(tPointSet *target, char filename[])
{
	FILE *f = fopen(filename,"rb");
	if (f==NULL)
	{
		MessageBox(NULL,"Fuck! A file is missing!","",MB_OK);
		exit(1);
	}

	__int16 numvx;
	byte mode;

	fread(&numvx,2,1,f);
	fread(&mode,1,1,f);

	target->numPts=numvx;
	delete [] target->points;
	target->points=new t3DVector [numvx];

	int i;

	for (i=0; i<numvx; i++)
	{
		fread(&(target->points[i][0]),sizeof(float),1,f);
		fread(&(target->points[i][1]),sizeof(float),1,f);
		target->points[i][2]=0;
	}

	fclose(f);
}

// planar UV mapping
void UVMap(tPrimitive *target)
{
	int i;
	t3DVector topleft,bottomright;

	t3DVector_Copy(target->Vertices[0],topleft);
	t3DVector_Copy(target->Vertices[0],bottomright);

	for (i=0; i<target->NumVertices; i++)
	{
		if (target->Vertices[i][0]<topleft[0]) topleft[0]=target->Vertices[i][0];
		if (target->Vertices[i][1]>topleft[1]) topleft[1]=target->Vertices[i][1];
		if (target->Vertices[i][0]>bottomright[0]) bottomright[0]=target->Vertices[i][0];
		if (target->Vertices[i][1]<bottomright[1]) bottomright[1]=target->Vertices[i][1];
	}

	for (i=0; i<target->NumFaces; i++)
	{
		target->Faces[i].px=((target->Vertices[target->Faces[i].a][0])-topleft[0])/(bottomright[0]-topleft[0]);
		target->Faces[i].py=((target->Vertices[target->Faces[i].a][1])-topleft[1])/(bottomright[1]-topleft[1]);

		target->Faces[i].qx=((target->Vertices[target->Faces[i].b][0])-topleft[0])/(bottomright[0]-topleft[0]);
		target->Faces[i].qy=((target->Vertices[target->Faces[i].b][1])-topleft[1])/(bottomright[1]-topleft[1]);

		target->Faces[i].rx=((target->Vertices[target->Faces[i].c][0])-topleft[0])/(bottomright[0]-topleft[0]);
		target->Faces[i].ry=((target->Vertices[target->Faces[i].c][1])-topleft[1])/(bottomright[1]-topleft[1]);
	}

}