#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <time.h>

#include <exec/types.h>

#include <proto/exec.h>
#include <exec/memory.h>

#include "/Shared/SH_view.h"
#include "TM_structures.h"
#include "TM_reader.h"
#include "TM_render.h"

#include "/tools.h"

typedef
	struct Normal
	{
		double x, y, z;
		double xn, yn, zn;
		int ncntr;
	} NORMAL;

void CalcNormals(FACE *Faces, LONG FacesNumber,
								 VERTEX *Vertices, LONG VerticesNumber,
								 NORMAL *Normals);


SCENE *EM_RelocScene(UBYTE *Data)
{
NORMAL *Normals;
POINT3D *Points;
SFACE *SFaces;
SCENE *Scene;
OBJECT *Objects;
LONG VNumber;
LONG FNumber;
LONG V1, V2, V3,x,y,z;
LONG i,j;

	if((Scene = AllocVec(sizeof(SCENE),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
		return NULL;

	Scene->ONumber = ((LONG *)Data)[0];
		Data += 4;

	if((Objects = AllocVec(Scene->ONumber * sizeof(OBJECT),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	Scene->Objects = Objects;

     for(j=0;j<Scene->ONumber;j++)
     {
		VNumber = ((LONG *)Data)[0];
		FNumber = ((LONG *)Data)[1];
		Data += 8;

	if((Objects[j].Faces = AllocVec((FNumber+1) * sizeof(FACE),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

     if((Normals = AllocVec((VNumber+1) * sizeof(NORMAL),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
     {
		EM_FreeScene(Scene);
		return NULL;
     }

	if((Objects[j].Vertices = AllocVec((VNumber+1) * sizeof(VERTEX),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

     	Scene->FNumber += FNumber;

		Objects[j].VNumber = VNumber;
		Objects[j].FNumber = FNumber;

		Points = &((POINT3D *)Data)[0];
		Data += (VNumber*sizeof(POINT3D));

		SFaces = &((SFACE *)Data)[0];
		Data += (FNumber*sizeof(SFACE));

          for(i=0;i<FNumber;i++)
          {
          Objects[j].Faces[i].V1=(VERTEX *)SFaces[i].v1;
          Objects[j].Faces[i].V2=(VERTEX *)SFaces[i].v2;
          Objects[j].Faces[i].V3=(VERTEX *)SFaces[i].v3;
          }

          for(i=0;i<VNumber;i++)
          {
          x=(LONG)Points[i].x;
          y=(LONG)Points[i].y;
          z=(LONG)Points[i].z;
          Objects[j].Vertices[i].x=x;
          Objects[j].Vertices[i].y=y;
          Objects[j].Vertices[i].z=z;
          Normals[i].x=(DOUBLE)x;
          Normals[i].y=(DOUBLE)y;
          Normals[i].z=(DOUBLE)z;
          }

          CalcNormals(Objects[j].Faces,FNumber,Objects[j].Vertices,VNumber,Normals);

		for(i=0; i<FNumber; i++)
		{
			V1 = (LONG)Objects[j].Faces[i].V1;
			V2 = (LONG)Objects[j].Faces[i].V2;
			V3 = (LONG)Objects[j].Faces[i].V3;
			Objects[j].Faces[i].V1 = &Objects[j].Vertices[V1];
			Objects[j].Faces[i].V2 = &Objects[j].Vertices[V2];
			Objects[j].Faces[i].V3 = &Objects[j].Vertices[V3];
		}

     MapObject(&Objects[j]);
     FreeVec(Normals);
     }

	if((Scene->DeptBuffor = AllocVec((Scene->FNumber+1) * sizeof(FACE *),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	return Scene;
}

void CalcNormals(FACE *Faces, LONG FacesNumber,
								 VERTEX *Vertices, LONG VerticesNumber,
								 NORMAL *Normals)
{
int i;
LONG V1, V2, V3;
double u[3], v[3], n[3], nlen;
int ncntr;

	for(i=0; i<FacesNumber; i++)
	{
		V1 = (LONG)Faces[i].V1;
		V2 = (LONG)Faces[i].V2;
		V3 = (LONG)Faces[i].V3;

		u[0] = Normals[V2].x - Normals[V1].x;
		u[1] = Normals[V2].y - Normals[V1].y;
		u[2] = Normals[V2].z - Normals[V1].z;

		v[0] = Normals[V3].x - Normals[V1].x;
		v[1] = Normals[V3].y - Normals[V1].y;
		v[2] = Normals[V3].z - Normals[V1].z;

		n[0] = u[1]*v[2] - u[2]*v[1]; 
		n[1] = u[2]*v[0] - u[0]*v[2]; 
		n[2] = u[0]*v[1] - u[1]*v[0]; 

		nlen = sqrt(n[0]*n[0] + n[1]*n[1] + n[2]*n[2]);

		if(nlen != 0.0)
		{
			n[0] /= nlen;
			n[1] /= nlen;
			n[2] /= nlen;
		}

		Normals[V1].xn += n[0];
		Normals[V1].yn += n[1];
		Normals[V1].zn += n[2];
		Normals[V1].ncntr++;

		Normals[V2].xn += n[0];
		Normals[V2].yn += n[1];
		Normals[V2].zn += n[2];
		Normals[V2].ncntr++;

		Normals[V3].xn += n[0];
		Normals[V3].yn += n[1];
		Normals[V3].zn += n[2];
		Normals[V3].ncntr++;
	}

	for(i=0; i<VerticesNumber; i++)
	{
		ncntr = Normals[i].ncntr;

		Vertices[i].xn = (LONG)(Normals[i].xn*127.0/ncntr);
		Vertices[i].yn = (LONG)(Normals[i].yn*127.0/ncntr);
		Vertices[i].zn = (LONG)(Normals[i].zn*127.0/ncntr);
	}
}


VOID EM_FreeScene(SCENE *Scene)
{

int i;
OBJECT *Objects;

	if(Scene)
	{

  if(Scene->DeptBuffor)
		 FreeVec(Scene->DeptBuffor);

  if(Scene->Objects)
     {
          Objects=Scene->Objects;

          for(i=0;i<Scene->ONumber;i++)
          {
          if(Objects[i].Vertices) FreeVec(Objects[i].Vertices);
          if(Objects[i].Faces) FreeVec(Objects[i].Faces);
          }
     	FreeVec(Scene->Objects);
     }
		FreeVec(Scene);
	}
}

SCENE *RelocExplodeScene(SCENE *OrgScene)
{
     SCENE *Scene;
     LONG ONumber,VNumber,FNumber;
     LONG i,j,k;
     FACE *OrgFaces,*Faces;
     VERTEX *Vertices;
     LONG tmpx,tmpy,tmpz;

     ONumber = OrgScene -> ONumber;

	if((Scene = AllocVec(sizeof(SCENE),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
		return NULL;

	Scene->ONumber = ONumber;

	if((Scene->Objects = AllocVec(ONumber * sizeof(OBJECT),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

     for(i=0;i<ONumber;i++)
     {
        FNumber = OrgScene -> Objects[i].FNumber;
        VNumber = OrgScene -> Objects[i].FNumber * 3;
        Scene -> Objects[i].FNumber = FNumber;
        Scene -> Objects[i].VNumber = VNumber;
        Scene -> FNumber += FNumber;
        if((Scene->Objects[i].Faces = AllocVec((FNumber+1) * sizeof(FACE),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	     {
		EM_FreeScene(Scene);
		return NULL;
	     }

	   if((Scene->Objects[i].Vertices = AllocVec((VNumber+1) * sizeof(VERTEX),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	     {
		EM_FreeScene(Scene);
		return NULL;
	     }

          OrgFaces = OrgScene->Objects[i].Faces;
          Faces = Scene->Objects[i].Faces;
          Vertices = Scene->Objects[i].Vertices;

        k=0;
        for(j=0;j<FNumber;j++)
          {
             MemCpy(OrgFaces[j].V1,&Vertices[k],sizeof(VERTEX));
             Faces[j].V1 = &Vertices[k];
             tmpx = Vertices[k].xn;
             tmpy = Vertices[k].yn;
             tmpz = Vertices[k].zn;
             k++;
             MemCpy(OrgFaces[j].V2,&Vertices[k],sizeof(VERTEX));
             Faces[j].V2 = &Vertices[k];
             tmpx += Vertices[k].xn;
             tmpy += Vertices[k].yn;
             tmpz += Vertices[k].zn;
             k++;
             MemCpy(OrgFaces[j].V3,&Vertices[k],sizeof(VERTEX));
             Faces[j].V3 = &Vertices[k];
             tmpx += Vertices[k].xn;
             tmpy += Vertices[k].yn;
             tmpz += Vertices[k].zn;
             k++;
             Faces[j].DPosX = (tmpx/3)>>3;
             Faces[j].DPosY = (tmpy/3)>>3;
             Faces[j].DPosZ = (tmpz/3)>>3;
          }
     }

	if((Scene->DeptBuffor = AllocVec((Scene->FNumber+1) * sizeof(FACE *),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}
     return Scene;
}

SCENE *RellocAnimScene(UBYTE *Data)
{
/*
     Structure of scene:
     UWORD ONumber;
     UWORD VNumber;
     UWORD FNumber;
     Point3D * VNumber * ONumber
     SFace * FNumber
     UVCoords * VNumber
*/
SCENE *Scene;
POINT3D *Points;
SFACE *SFaces;
OBJECT *Objects;
UVCOORDS *UV;
LONG VNumber;
LONG FNumber;
LONG ONumber;
LONG i,j;
LONG V1,V2,V3;
LONG x,y,z;
LONG tmp;

	if((Scene = AllocVec(sizeof(SCENE),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
		return NULL;

	ONumber = ((UWORD *)Data)[0];
	Data += 2;

     Scene->ONumber = 1;

     Scene -> FramesNumber = ONumber;

	if((Objects = AllocVec(Scene->ONumber * sizeof(OBJECT),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	Scene->Objects = Objects;
		VNumber = ((UWORD *)Data)[0];
		FNumber = ((UWORD *)Data)[1];
		Data += 4;

          Scene -> FNumber = FNumber;

		Points = &((POINT3D *)Data)[0];
		Data += (VNumber*ONumber*sizeof(POINT3D));

		SFaces = &((SFACE *)Data)[0];
		Data += (FNumber*sizeof(SFACE));

		UV = &((UVCOORDS *)Data)[0];

	if((Objects[0].Faces = AllocVec((FNumber+1) * sizeof(FACE),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	if((Objects[0].Vertices = AllocVec(((ONumber+1)*VNumber) * sizeof(VERTEX),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	Objects[0].VNumber = VNumber;
	Objects[0].FNumber = FNumber;


		for(i=0; i<FNumber; i++)
		{
			V1 = (LONG)SFaces[i].v1;
			V2 = (LONG)SFaces[i].v2;
			V3 = (LONG)SFaces[i].v3;
			Objects[0].Faces[i].V1 = &Objects[0].Vertices[V1];
			Objects[0].Faces[i].V2 = &Objects[0].Vertices[V2];
			Objects[0].Faces[i].V3 = &Objects[0].Vertices[V3];
		}

          for(i=0;i<VNumber;i++)
          {
          x=(LONG)Points[i].x;
          y=(LONG)Points[i].y;
          z=(LONG)Points[i].z;
          Objects[0].Vertices[i].x=x;
          Objects[0].Vertices[i].y=y;
          Objects[0].Vertices[i].z=z;
          tmp = (LONG) UV[i].u;
          Objects[0].Vertices[i].v = tmp;
          tmp = (LONG) UV[i].v;
          Objects[0].Vertices[i].u = tmp;
          }

       for(j=1;j<ONumber+1;j++)
          for(i=0;i<VNumber;i++)
          {
          x=(LONG)Points[(j*VNumber)+i].x;
          y=(LONG)Points[(j*VNumber)+i].y;
          z=(LONG)Points[(j*VNumber)+i].z;
          Objects[0].Vertices[(j*VNumber)+i].x=x;
          Objects[0].Vertices[(j*VNumber)+i].y=y;
          Objects[0].Vertices[(j*VNumber)+i].z=z;
          }

	if((Scene->DeptBuffor = AllocVec((Scene->FNumber+1) * sizeof(FACE *),MEMF_PUBLIC|MEMF_CLEAR)) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}
     return Scene;
}

/* Object maping functions (LW rewritten by NOE*/

void xyztohp(float x,float y,float z,float *h,float *p)
{
    if (x == 0.0 && z == 0.0) {
        *h = 0.0;
        if (y != 0.0)
            *p = (y < 0.0) ? -HALFPI : HALFPI;
        else
            *p = 0.0;
    }
    else {
        if (z == 0.0)
            *h = (x < 0.0) ? HALFPI : -HALFPI;
        else if (z < 0.0)
            *h = -atan(x / z) + PI;
        else
            *h = -atan(x / z);
        x = sqrt(x * x + z * z);
        if (x == 0.0)
            *p = (y < 0.0) ? -HALFPI : HALFPI;
        else
            *p = atan(y / x);
    }
}

float fract(float x)
{
	return (x - (FLOAT)((LONG)x));
}


VOID XYZ2UV(FLOAT x, FLOAT y, FLOAT z, FLOAT *u, FLOAT *v)
{
FLOAT lon, lat;

        xyztohp(-x,z,-y,&lon,&lat);
        lon = 1.0 - lon / TWOPI;
        lat = .5 - lat / PI;
        lon = fract(lon) * 2.0;
        *u = fract(lon);
        *v = fract(lat);
}


VOID MapObject(OBJECT *Object)
{
FACE *Faces = Object->Faces;
ULONG FNumber = Object->FNumber;
LONG i;
FLOAT u, v;

     for(i=0;i<FNumber;i++)
		 {
				XYZ2UV((FLOAT)Faces[i].V1->x, (FLOAT)Faces[i].V1->y, (FLOAT)Faces[i].V1->z, &u, &v);
				Faces[i].u1 = u*256;
				Faces[i].v1 = v*256;

				XYZ2UV((FLOAT)Faces[i].V2->x, (FLOAT)Faces[i].V2->y, (FLOAT)Faces[i].V2->z, &u, &v);
				Faces[i].u2 = u*256;
				Faces[i].v2 = v*256;

				XYZ2UV((FLOAT)Faces[i].V3->x, (FLOAT)Faces[i].V3->y, (FLOAT)Faces[i].V3->z, &u, &v);
				Faces[i].u3 = u*256;
				Faces[i].v3 = v*256;

				if(labs(Faces[i].u1-Faces[i].u2) > 128)
					if(Faces[i].u1 > Faces[i].u2)
						Faces[i].u1 -= 256;
					else
						Faces[i].u2 -= 256;

				if(labs(Faces[i].u2-Faces[i].u3) > 128)
					if(Faces[i].u2 > Faces[i].u3)
						Faces[i].u2 -= 256;
					else
						Faces[i].u3 -= 256;

				if(labs(Faces[i].u3-Faces[i].u1) > 128)
					if(Faces[i].u3 > Faces[i].u1)
						Faces[i].u3 -= 256;
					else
						Faces[i].u1 -= 256;

				if(labs(Faces[i].v1-Faces[i].v2) > 128)
					if(Faces[i].v1 > Faces[i].v2)
						Faces[i].v1 -= 256;
					else
						Faces[i].v2 -= 256;

				if(labs(Faces[i].v2-Faces[i].v3) > 128)
					if(Faces[i].v2 > Faces[i].v3)
						Faces[i].v2 -= 256;
					else
						Faces[i].v3 -= 256;

				if(labs(Faces[i].v3-Faces[i].v1) > 128)
					if(Faces[i].v3 > Faces[i].v1)
						Faces[i].v3 -= 256;
					else
						Faces[i].v1 -= 256;

//				Faces[i].V1->u = Faces[i].u1;
//				Faces[i].V1->v = Faces[i].v1;
//				Faces[i].V2->u = Faces[i].u2;
//				Faces[i].V2->v = Faces[i].v2;
//				Faces[i].V3->u = Faces[i].u3;
//				Faces[i].V3->v = Faces[i].v3;
		 }
}
