/*****************************/
/* Inside The Machine - MKS  */
/*****************************/

//Includes
#include "Engine.h"
 
int uGetMapPixel(UL_MAP* m, int x, int y, u16* vid, int* bx, int* by)
{
	//1 : x et y sont les coordonnées à l'écran (en pixels)
	//2 : mx et my sont les coordonnées de x et y sur la map (en pixels)
	int mx, my, bmx, bmy, ttX=0, tX=0, tY=0, i, u0, v0, diffx, diffy;
	u16 v;
	u16 *map = (u16*)m->map;
	
	mx = x;
	my = y;
	
	//On réduit alors mx et my a des coord en blocs (16*16)
	*bx = bmx = mx >> 4;
	*by = bmy = my >> 4;
	
	//On récupère ensuite l'indice de chipset du bloc
	v = map[m->mapSizeX * bmy + bmx];
	*vid = v;
	
	for (i=3;i<=9;i++)			{
		if (ttX == 0 && m->img->sysSizeX <= 1 << i)
			ttX = i;
		if (tX == 0 && m->tileX <= 1 << i)
			tX = i;
		if (tY == 0 && m->tileY <= 1 << i)
			tY = i;
	}
	
	//On recupère ensuite les coordonnées du pixel sur le chipset
	if(v)
	{
		 //Calcul des coord. UV
		 u0 = ((v << tX) & ((1 << ttX) - 1));
		 v0 = ((v << tX) >> ttX) << tY;
		 
		 //Différence entre l'arrondi en blocs et le point réel
		 diffx = mx - (bmx << 4);
		 diffy = my - (bmy << 4);
		 
		 //Calcul des coord. du point sur le chipset
		 u0 += diffx;
		 v0 += diffy;
	}
	
	//Récuperation de la couleur du pixel (normalement le chipset de collision reste en RAM)
	//Ne marche que sur une image en PAL8
	//ulUnrealizeImage(m->img);
	void *pPixel = ulGetImageLineAddr(m->img, v0);
	//ulRealizeImage(m->img);
	//ulPrintf_xy(40, 60, "pixcol:%d", ((u8*)pPixel)[u0]); //debug
	//ulPrintf_xy(40, 70, "v:%d", v); //debug
	//ulPrintf_xy(40, 80, "u0:%d v0:%d", u0, v0); //debug
	return ((u8*)pPixel)[u0];
}

u16 uGetTile(UL_MAP* m, int x, int y)
{
   //1 : x et y sont les coordonnées à l'écran (en pixels)
	//2 : mx et my sont les coordonnées de x et y sur la map (en pixels)
	int mx, my, bmx, bmy;
	u16 *map = (u16*)m->map;
	
	mx = x;
	my = y;
	
	//On réduit alors mx et my a des coord en blocs (16*16)
	bmx = mx >> 4;
	bmy = my >> 4;
	
	//On recupère ensuite les coordonnées du pixel sur le chipset
	return map[m->mapSizeX * bmy + bmx];
}

//Fonctions
bool uStylusInZone(u16 x1, u16 y1, u16 x2, u16 y2)
{
   if(ul_keys.touch.x  < x1)
   	return 0;
   if(ul_keys.touch.x  > x1 + (x2-x1))
   	return 0;
   if(ul_keys.touch.y  < y1)
   	return 0;
   if(ul_keys.touch.y  > y1 + (y2-y1))
   	return 0;
   	
   return 1;
}

//mu [0;32]
u16 uInterpolate(float v1, float v2, float mu)
{
   //A optimiser
   return(v1*(1-mu)+v2*mu);
}

void drawTriangle(int x0, int y0, int x1, int y1, int x2, int y2, UL_COLOR color)
{
   //We're drawing a simple colored triangle (untextured)
   ulDisableTexture();

   //Begins drawing quadliterals
   ulVertexBegin(GL_TRIANGLES);
        
   //You can define the color of each vertex before issuing the vertex command, or once for all, like here. If the vertices have different colors, a gradient will appear between each corner.
   ulVertexColor(color);

   //Draw our triangle (3 vertices)
   ulVertexXY(x0, y0);
   ulVertexXY(x1, y1);
   ulVertexXY(x2, y2);

   //End our drawing.
   ulVertexEnd();

   //Don't forget to auto-increment depth
   ulVertexHandleDepth();
   return;
}

void drawQuad(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3, UL_COLOR color)
{
   //We're drawing a simple colored triangle (untextured)
   ulDisableTexture();

   //Begins drawing quadliterals
   ulVertexBegin(GL_QUADS);
        
   //You can define the color of each vertex before issuing the vertex command, or once for all, like here. If the vertices have different colors, a gradient will appear between each corner.
   ulVertexColor(color);

   //Draw our triangle (3 vertices)
   ulVertexXY(x0, y0);
   ulVertexXY(x1, y1);
   ulVertexXY(x2, y2);
	ulVertexXY(x3, y3);
	
   //End our drawing.
   ulVertexEnd();

   //Don't forget to auto-increment depth
   ulVertexHandleDepth();
   return;
}

//Le float doit être viré tôt ou tard ...
int myRand(int min, int max)
{
    return (int) (min + ((float) rand() / RAND_MAX * (max - min )));
    //return (min + rand()%(max - min));
}

//bool BoxCollision(CGraphic a, int ax, int ay, CGraphic b, int bx, int by)
bool RectCollision(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
{
    if(bx1 + ulAbs(bx2-bx1) < ax1)
        return false;
    if(bx1 > ax1 + ulAbs(ax2-ax1))
        return false;

    if(by1 + ulAbs(by2-by1) < ay1)
        return false;
    if(by1 > ay1 + ulAbs(ay2-ay1))
        return false;

    return true;
}

bool RectCollision(int px1, int py1, sHitBoxRect * a, int px2, int py2, sHitBoxRect * b)
{
   if((px2 + b->x1) + (px2 + b->x2)-(px2 + b->x1) < (px1 + a->x1))
      return false;
   if((px2 + b->x1) > (px1 + a->x1) + (px1 + a->x2)-(px1 + a->x1))
      return false;

   if((py2 + b->y1) + (py2 + b->y2)-(py2 + b->y1) < (py1 + a->y1))
      return false;
   if((py2 + b->y1) > (py1 + a->y1) + (py1 + a->y2)-(py1 + a->y1))
      return false;

   return true;
}   

UL_IMAGE* ulEFSLoadPNG(char* filename, int location, int pixelFormat)
{
   //On définit quelques variables
   FILE* file;
   UL_IMAGE* img;
   char* buffer;
   int size;
   
   //On ouvre le fichier
   file = fopen(filename, "rb");
   
   if(file != NULL)
   {
	   //Cn charge le fichier en mémoire
	   fseek(file, 0, SEEK_END);
	   size = ftell(file); 
	   fseek(file, 0, SEEK_SET);
	   
	   //On alloue de la mémoire
	   buffer = (char*)malloc(sizeof(char)*size);
	   
	   if(buffer == NULL)
	   {
	    	ulDebug("buffer break!");  
	   } 
	   
	   int result = fread(buffer, 1, size, file);
	   
	   if(result != size)
	   {
	      ulDebug("read break!");  
	   }
	   fclose (file);
	   //On charge le png
	   ulSetLoadUtilitySource(VF_MEMORY);
	   img = ulLoadImageFilePNG((const char*)buffer, size, location, pixelFormat);
	   free(buffer);
	   return img;
	}
	else
		return NULL;
}

sMusic LoadMusic(char* filename)
{
	//On charge le fichier en mémoire
	//On vide le buffer mémoire (spéficique a ITM atttention)
	//*memset(soundData, 0, 1024*1024);*/

	//On définit quelques variables
   FILE* file;
   sMusic music;
   
   //On ouvre le fichier
   file = fopen(filename, "rb");
   
   if(file != NULL)
   {
	   //Cn charge le fichier en mémoire
	   fseek(file, 0, SEEK_END);
	   music.size = ftell(file); 
	   fseek(file, 0, SEEK_SET);
	   
	   //On alloue de la mémoire
	   //music.data = (u8*)malloc(sizeof(u8)*music.size);
	   music.data = soundData;
	   
	   int result = fread(music.data, 1, music.size, file);
	   music.loaded = true;
	   fclose(file);
	}
	
	return music;
}

void LoadSnd(char* filename, u8* buf)
{
	//On charge le fichier en mémoire
	//On vide le buffer mémoire (spéficique a ITM atttention)
	//*memset(soundData, 0, 1024*1024);*/

	//On définit quelques variables
   FILE* file;
   
   //On ouvre le fichier
   file = fopen(filename, "rb");
   
   if(file != NULL)
   {
	   //Cn charge le fichier en mémoire
	   fseek(file, 0, SEEK_END);
	   int size = ftell(file); 
	   fseek(file, 0, SEEK_SET);
	   
	   //On alloue de la mémoire
	   int result = fread(buf, 1, size, file);
	   fclose(file);
	}
}

void FreeMusic(sMusic music)
{
	//On libère la mémoire
	memset(music.data, 0, music.size);
	music.data = NULL;
	music.size = 0;
	music.loaded = false;
}   
   
//Sqrt hardware
s32 hwSqrt64(int64 a)
{
	SQRT_CR = SQRT_64;
	while(SQRT_CR & SQRT_BUSY);
	SQRT_PARAM64 = a;
	while(SQRT_CR & SQRT_BUSY);
	return SQRT_RESULT32;
}

//Sqrt software "code de Nrx, merci ! :)"
s32 quickSqrt(s32 a)
{
	signed long n,m,q,d;
 
	for(n=0,m=a;m>3;m>>=2,++n);
 
	for(q=0,m=1<<n;m;--n,m>>=1)
	{
		d=(q|m)<<n;
		if(a>=d)
		{
			a-=d;
			q|=m<<1;
		}
	}
	return(q>>1);
}

// Calcul de la racine carrée par approximation successives
u16 getSQRT(u32 carre) 
{
	// Calcul de la racine carree (algorithme de Heron d'Alexandrie)
	u32 x=carre;
	s32 precision;
	do
	{
		precision=x;
		x=(x+carre/x)>>1; // Note : on n'utilise pas INVERSE_TABLE[x] car x peut etre superieur a INVNB...
		precision-=x;
	}
	while(precision>1);
	return (u16) x;
} 
