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

#include <exec/types.h>

#include "/Shared/EE_view.h"
#include "EM_structures.h"
#include "EM_reader.h"
#include "EM_render.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);


NORMAL NormalS[10000];

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

	if((Scene = malloc(sizeof(SCENE))) == NULL)
		return NULL;

	memset(Scene, 0, sizeof(SCENE));

	if((Scene->Camera = malloc(sizeof(CAMERA))) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	memset(Scene->Camera, 0, sizeof(CAMERA));

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

     if(ObjN!=0) Scene->ONumber = ObjN;

	if((Objects = calloc(Scene->ONumber, sizeof(OBJECT))) == 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 = calloc(FNumber+1, sizeof(FACE))) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	if((Objects[j].Vertices = calloc(VNumber+1, sizeof(VERTEX))) == NULL)
	{
		EM_FreeScene(Scene);
		return NULL;
	}

	Scene->Vertices = Objects[j].Vertices;
	Scene->Faces = Objects[j].Faces;

     	Scene->FNumber += FNumber;
	     Scene->VNumber += VNumber;

		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];
		}

          if(ObjN!=0)
               {
     		Data -= 8;
     		Data -= (VNumber*sizeof(POINT3D));
	     	Data -= (FNumber*sizeof(SFACE));
               }
     
     }

     CalculateUV(Objects[0].Vertices,Objects[0].VNumber);

	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->Camera)
			free(Scene->Camera);

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

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