/*
 *
 * hiatus - 64k by calodox 
 *
 * 3d.c - H3D 3dengine main routines. 
 *
 * dake
 *
 */

 #include "main.h"
 #include "3d.h"
 #include "vectors.h"
 #include <math.h>

 #define  myalloc       malloc


 float H3D_fsin[256], H3D_fcos[256];

 void H3D_precalc()
 {

	 for (int i=0;i<256;i++)
	 {
		H3D_fsin[i]=sin(i*3.1416/128.0);
		H3D_fcos[i]=cos(i*3.1416/128.0);
	 }

 }


 /*----------------------------------------------------------------------*/

 void H3D_allocate_obj(Object_Data *o, int nbfaces, int nbvtx)
      {

       o->f=(Face_Data*) myalloc(nbfaces*sizeof(Face_Data));

       o->v_original=(Vect3D*) myalloc(nbvtx*sizeof(Vect3D));
       o->v_rotated=(Vect3D*) myalloc(nbvtx*sizeof(Vect3D));
	   o->v_intermed=(Vect3D*) myalloc(nbvtx*sizeof(Vect3D));
       o->uvw=(Vect3D*) myalloc(nbvtx*sizeof(Vect3D));

       o->nbfaces=nbfaces;
       o->nbvtx=nbvtx;

	   MAT_ident(o->m);
      }

 
 /*----------------------------------------------------------------------*/


 void H3D_transform_normal(Object_Data *o, Matrix m, unsigned char active)
 {
		for (int i=0;i<o->nbfaces;i++)
		{
			Vect3D nrm, newnrm;

			nrm=o->f[i].nrm;

			if (active==1)
			{
			MAT_rotate_pt(nrm, (Vect3D*) &newnrm, m);
			o->f[i].trmnrm=newnrm;
			}
			else
			{

			o->f[i].trmnrm=nrm;
			}
		}
 }


 void H3D_transform_obj_matrix(Object_Data *o, Matrix m)
      {
      int  n;
      Vect3D temp;

       for (n=o->nbvtx-1;n>=0;n--)
           {
           MAT_rotate_pt(o->v_original[n], (Vect3D*) &o->v_rotated[n], m);
           }
      }


  void H3D_transform_intermed_obj_matrix(Object_Data *o, Matrix m)
      {
      int  n;
      Vect3D temp;

       for (n=o->nbvtx-1;n>=0;n--)
           {
		   MAT_rotate_pt(o->v_intermed[n], (Vect3D*) &o->v_rotated[n], m);
           }
      }


  
  void H3D_transform_blobby_obj(Object_Data *o, int fxtype, float scale, float param1)
      {
      int  n;
      Vect3D temp;
	  float fact1=1.0;

       for (n=o->nbvtx-1;n>=0;n--)
           {
		   temp=o->v_original[n];
			
		     if (fxtype==0) {  
				 fact1=1.5*fabs(sin(temp.x*temp.y+param1)); 
				  temp=Vect3D_MulScalar(temp, fact1*scale);
			 
				}
			
			 
			  if (fxtype==1)												//effet meduse
			  {  
				  if (temp.y<0.0)
				  {
					temp.y+=-temp.y*fabs(sin(ACCURATE_TIMER*0.001+temp.y*3.14*0.5));
				  }
				  else
				  {
					temp.y*=0.8+fabs(sin(ACCURATE_TIMER*0.001))*0.2;
				  }

				   temp=Vect3D_MulScalar(temp, scale);
			  }

			  if (fxtype==2)				//queue de la meduse
			  {

				  Vect3D add;
				  add.x=1.5*(sin(temp.z+param1));

				  add.y=0.0;//1.5*(sin(temp.z*0.3+param1));
				  add.z=1.5*(cos(temp.x+param1*2.0));
				  temp=Vect3D_Add(temp, add);
			  }

			  	if (fxtype==3)		//machin transparent dans la mer
			  {

					
				  Vect3D add;
				  add.x=1.5*(sin(temp.y+param1));

				  add.y=1.5*(sin(temp.z*0.3+param1));
				  add.z=1.5*(cos(temp.x*temp.y+param1*2.0));
				  temp=Vect3D_Add(temp, add);

				  //fact1=1.5*(0.5+fabs(sin(temp.x*0.4*temp.z*0.4))*cos(temp.x*0.6)); 
				  //temp=Vect3D_MulScalar(temp, fact1*scale);
			  }
			
			  


			 o->v_intermed[n]=temp;
			 
           }
      }


  	


 /*----------------------------------------------------------------------*/


void H3D_render_object(Object_Data *o, long rendering_flags, GLuint texture_id, float alpha)
{


	glBindTexture(GL_TEXTURE_2D, texture_id);
	glLoadIdentity();   
	
	if (rendering_flags==2) { glBlendFunc(GL_SRC_ALPHA,GL_ONE); }
	if (rendering_flags==4) { glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); }

	if (rendering_flags==2 || rendering_flags==4) {glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST);}


	for (int i=0;i<o->nbfaces;i++)
	{

		int idx1, idx2, idx3;
		Vect3D p1, p2, p3;
		Vect3D n1, n2, n3;

		idx1=o->f[i].idx[0];
		idx2=o->f[i].idx[1];
		idx3=o->f[i].idx[2];

		p1=o->v_rotated[idx1];
		p2=o->v_rotated[idx2];
		p3=o->v_rotated[idx3];


		n1=o->uvw[idx1];
		n2=o->uvw[idx2];
		n3=o->uvw[idx3];

		Vect3D normal=o->f[i].trmnrm;

		glBegin(GL_TRIANGLES);

		glNormal3f(normal.x, normal.y, normal.z);
		glColor4f(1.0, 1.0, 1.0, alpha);	
		glTexCoord2f(n1.x, n1.y); glVertex3f(p1.x, p1.y, p1.z);	// Bottom Left Of The Texture and Quad
		glTexCoord2f(n2.x, n2.y); glVertex3f(p2.x, p2.y, p2.z);	// Bottom Right Of The Texture and Quad
		glTexCoord2f(n3.x, n3.y); glVertex3f(p3.x, p3.y, p3.z);	// Top Right Of The Texture and Quad
	
        glEnd();
	}

	if (rendering_flags==2 || rendering_flags==4)
	{
		glEnable(GL_DEPTH_TEST);
		glDisable(GL_BLEND);
	}

}


void H3D_render_volumetric(Object_Data *o, Vect3D color)
{


	glLoadIdentity();   
	
	glBlendFunc(GL_SRC_ALPHA,GL_ONE); 
	glEnable(GL_BLEND);
	glDisable(GL_TEXTURE_2D);
//	glDisable(GL_DEPTH_TEST);


	for (int i=0;i<o->nbfaces;i++)
	{

		int idx1, idx2, idx3;
		Vect3D p1, p2, p3;
		Vect3D n1, n2, n3;

		idx1=o->f[i].idx[0];
		idx2=o->f[i].idx[1];
		idx3=o->f[i].idx[2];

		p1=o->v_rotated[idx1];
		p2=o->v_rotated[idx2];
		p3=o->v_rotated[idx3];

		n1=o->uvw[idx1];
		n2=o->uvw[idx2];
		n3=o->uvw[idx3];

		glBegin(GL_TRIANGLES);

		glColor4f(color.x*n1.x, color.y*n1.x, color.z*n1.x, 1.0);	
		glVertex3f(p1.x, p1.y, p1.z);	// Bottom Left Of The Texture and Quad
		glColor4f(color.x*n2.x, color.y*n2.x, color.z*n2.x, 1.0);	
		glVertex3f(p2.x, p2.y, p2.z);	// Bottom Right Of The Texture and Quad
		glColor4f(color.x*n3.x, color.y*n3.x, color.z*n3.x, 1.0);	
		glVertex3f(p3.x, p3.y, p3.z);	// Top Right Of The Texture and Quad
	
        glEnd();
	}

	//glEnable(GL_DEPTH_TEST);
		glEnable(GL_TEXTURE_2D);
	glDisable(GL_BLEND);

}

void H3D_render_tv(Object_Data *o, float alpha, GLuint texture_id)
{


	glLoadIdentity();   
	
	glBindTexture(GL_TEXTURE_2D, texture_id);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE); 
	glEnable(GL_BLEND);
	glDisable(GL_DEPTH_TEST);


	for (int i=0;i<o->nbfaces;i++)
	{

		int idx1, idx2, idx3;
		Vect3D p1, p2, p3;
		Vect3D n1, n2, n3;

		idx1=o->f[i].idx[0];
		idx2=o->f[i].idx[1];
		idx3=o->f[i].idx[2];

		p1=o->v_rotated[idx1];
		p2=o->v_rotated[idx2];
		p3=o->v_rotated[idx3];

		n1=o->uvw[idx1];
		n2=o->uvw[idx2];
		n3=o->uvw[idx3];

		glColor4f(1.0, 1.0, 1.0, alpha);

		glBegin(GL_TRIANGLES);
		glTexCoord2f(n1.x, n1.y);

		glVertex3f(p1.x, p1.y, p1.z);	// Bottom Left Of The Texture and Quad
		glTexCoord2f(n2.x, n2.y);
		glVertex3f(p2.x, p2.y, p2.z);	// Bottom Right Of The Texture and Quad
		glTexCoord2f(n3.x, n3.y);
		glVertex3f(p3.x, p3.y, p3.z);	// Top Right Of The Texture and Quad
	
        glEnd();
	}

	glEnable(GL_DEPTH_TEST);
	glDisable(GL_BLEND);

}

void H3D_render_sea(Object_Data *o, float alpha, GLuint texture_id)
{


	glLoadIdentity();   
	
	glBindTexture(GL_TEXTURE_2D, texture_id);
	glBlendFunc(GL_ONE,GL_ONE); 
//		glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); 
	glEnable(GL_BLEND);


	for (int i=0;i<o->nbfaces;i++)
	{

		int idx1, idx2, idx3;
		Vect3D p1, p2, p3;
		Vect3D n1, n2, n3;

		idx1=o->f[i].idx[0];
		idx2=o->f[i].idx[1];
		idx3=o->f[i].idx[2];

		p1=o->v_rotated[idx1];
		p2=o->v_rotated[idx2];
		p3=o->v_rotated[idx3];

		n1=o->uvw[idx1];
		n2=o->uvw[idx2];
		n3=o->uvw[idx3];

		glColor3f(1.0*alpha, 1.0*alpha, 1.0*alpha);

		glBegin(GL_TRIANGLES);
		glTexCoord2f(n1.x, n1.y);

		glVertex3f(p1.x, p1.y, p1.z);	// Bottom Left Of The Texture and Quad
		glTexCoord2f(n2.x, n2.y);
		glVertex3f(p2.x, p2.y, p2.z);	// Bottom Right Of The Texture and Quad
		glTexCoord2f(n3.x, n3.y);
		glVertex3f(p3.x, p3.y, p3.z);	// Top Right Of The Texture and Quad
	
        glEnd();
	}

	glDisable(GL_BLEND);

}




