#include "commun.h"

extern u16 map_nTiles;
extern u32 map_nEtape;

//Interne
void IWRAM_CODE ClearBloc_16(u32 x, u32 y)
{
	u32 *ptr;

	//	ptr=(u32*)(&tableau[y<<1][x<<1]);
	ptr = (u32 *) tableau + (y << 5) + (x);
	*ptr = 0;
	*(ptr + 16) = 0;
}

extern int fromlasttime;

int IWRAM_CODE ChercheTile(int val)
{
	u32 i;
	while (copieTiles[numTiles[map_nTiles]] == map_nEtape)
		map_nTiles++;

	//Pas que pour le débogage!
	if (map_nTiles >= map_maxTiles)
	{

		//Pour le débogage
		if (depassement)
		{        //Pour le débogage seulement: détection de boucle infinie
			//            map_nTiles=map_maxTiles-1;
			return 0;
		}
		else
			return 1;
	}

	//Effacement des anciennes références
	i = numTiles[map_nTiles];
	numTiles[utilTiles[val]] = 0;
	utilTiles[i] = 0;        //L'ancienne n'est plus valide

	//Nouvelles références
	utilTiles[val] = map_nTiles;
	numTiles[map_nTiles] = val;

	//Tile à jour
	copieTiles[val] = map_nEtape;

	CopieTile(val, map_nTiles);
	map_nTiles++;
	return 0;
}

//Copie un bloc de 16x16 pixels sur une map de 8x8
void IWRAM_CODE CopieBloc_16(int x, int y, unsigned short bloc, unsigned short flags)
{
	u32 *ptr, valeur;

	if (bloc == 0)
	{

		//        bloc=0;
		goto ici;
	}

rechercheTile:
	if (map_nTiles >= map_maxTiles)
	{
		OptTiles();

		//        val=bloc;
	}

	if (copieTiles[bloc] != map_nEtape)
	{
		if (ChercheTile(bloc))
			goto rechercheTile;
	}
	else if (utilTiles[bloc] == 0)
		ErreurFatale("CopieBloc_16 #1", "%i %i", copieTiles[bloc], bloc);

	bloc = utilTiles[bloc];
	bloc <<= 2;

ici:

	//Ceci est une version "optimisée" (en tous cas ça jette!) de l'horreur qui se trouve ci-dessous, ça me permet d'économiser un peu de CPU ;)
	ptr = (u32 *) (&tableau[y << 1][x << 1]);

	//AJOUT POUR LES PALETTES MULTIPLES
	bloc |= flags;
	valeur = bloc | ((bloc | 1) << 16);
	*ptr = valeur;
	*(ptr + 16) = valeur | 0x20002;

	/*    tableau[2*y][2*x]=bloc;
	tableau[2*y][2*x+1]=bloc+1;
	tableau[2*y+1][2*x]=bloc+2;
	tableau[2*y+1][2*x+1]=bloc+3;*/
}

void IWRAM_CODE DessineRect(int rLeft, int rTop, int rRight, int rBottom)
{
	unsigned short *ptr;
	unsigned int x, y;
	unsigned int i;

	for (y = rTop; y < rBottom; y++)
	{
		ptr = (unsigned short *) MapGfx[y] + rLeft;
		for (x = rLeft; x < rRight; x++)
		{
			i = *ptr++;

			if (i & 2048)
			{
				tableau = tableau1;
				ClearBloc_16(x, y);

				//AJOUT DE FLAGS POUR LES PALETTES MULTIPLES
				tableau = tableau3;
				CopieBloc_16(x, y, i & 2047, i & 0xf000);
			}
			else
			{
				//AJOUT DE FLAGS POUR LES PALETTES MULTIPLES
				tableau = tableau1;
				CopieBloc_16(x, y, i & 0xf7ff, i & 0xf000);

				tableau = tableau3;
				ClearBloc_16(x, y);
			}
		}
	}
}

void IWRAM_CODE ClipSpriteXY(int no_objet, int posX, int posY)
{
	if (posX > 240)
		posX = 240;
	if (posX < 0 && posX > -64)
		posX = 512 + posX;
	if (posY > 160)
		posY = 160;
	if (posY < 0 && posY > -64)
		posY = 256 + posY;
	if (posX < 0)
		posX = 240;
	if (posY < 0)
		posY = 160;
	PlaceObjetXY(no_objet, posX, posY);
}

int lastNoSprite;

#if 0
void AnalyseRectPasEnIwram(int rLeft, int rTop, int rRight, int rBottom, int departX, int departY)
{
	int nbEle = *gblLI->spi.nbEle;
	SPRITE_LISTE *sl = gblLI->spi.liste;
	int i;

	if (premFois)
		lastNoSprite = 0;

	rLeft += departX;
	rTop += departY;
	rRight += departX;
	rBottom += departY;
	rLeft <<= 4, rTop <<= 4, rRight <<= 4, rBottom <<= 4;

	/*   if (rLeft+4<0)
	rLeft=-(departX+4);
	if (departY+rTop+4<0)
	rTop=-(departY+4);*/
	i = lastNoSprite;
	while (sl[i].x >= rLeft && i > 0)
		i--;
	while (sl[i].x < rLeft && i < nbEle)
		i++;
	lastNoSprite = i;

	/*   for (i=0;;i++)       {
	if (sl[i].x>=rLeft)
	break;
	}*/
	for (; i < nbEle; i++)
	{
		if (sl[i].x > rRight)
			break;
		if (sl[i].y >= rBottom)
		{
			do
			{
				i++;
			}
			while ((sl[i].y >= rBottom || sl[i].y < rTop) && i < nbEle);
		}

		if (sl[i].y >= rTop && sl[i].y <= rBottom)
		{

			//         xMap=x, yMap=y;
			gblNoObjet = i;
			if (!sdUsed[i])
				ExecHandler(&sl[i]);
			sdUsed[i] = 1;
		}
	}

	//   Debug("%i %i %i %i %i %i",rLeft,rTop,rRight,rBottom,departX,departY);
	/*    for (y=rTop;y<rBottom;y++)     {
	xx=departX+rLeft+4;
	yy=y+departY+4;
	//        ptr=(unsigned short *)(map+yy*tailleMapX+xx);
	for (x=rLeft;x<rRight;x++)     {
	i=Map[y+4][x+4];
	if (LIT_TABLEAU(xx,yy))      {
	Map[y+4][x+4]=0;
	xx++;
	continue;
	}
	if (i&32768)      {            //i&32768 optionnel
	//                CopieBloc_16_2(x,y,0);
	xx++;
	continue;
	}
	//            i&=1023;
	if (i>=0x2000 && i<0x4000)       {
	xxx=departX+x+4;
	yyy=departY+y+4;
	xMap=x, yMap=y;
	ExecHandler(i,xxx,yyy);
	}
	xx++;
	}
	}*/
}
#endif

// Crée tous les nouveaux objets dans un rectangle donné
void IWRAM_CODE AnalyseRect(int rLeft, int rTop, int rRight, int rBottom, int departX, int departY)
{
	int nbEle = *gblLI->spi.nbEle;
	const SPRITE_LISTE *sl = gblLI->spi.liste;
	int i;

	if (premFois)
		lastNoSprite = 0;

	rLeft += departX;
	rTop += departY;
	rRight += departX;
	rBottom += departY;
	rLeft <<= 4, rTop <<= 4, rRight <<= 4, rBottom <<= 4;

	i = lastNoSprite;
	while (sl[i].x >= rLeft && i > 0)
		i--;
	while (sl[i].x < rLeft && i < nbEle)
		i++;
	lastNoSprite = i;
	if (lastNoSprite >= nbEle)
		lastNoSprite--;

	for (; i < nbEle; i++)
	{
		if (sl[i].x > rRight)
			break;
		if (sl[i].y >= rBottom)
		{
			do
			{
				i++;
			}
			while ((sl[i].y >= rBottom || sl[i].y < rTop) && i < nbEle);
		}

		if (sl[i].x > rRight)
			return;
		if (sl[i].y >= rTop && sl[i].y <= rBottom)
		{

			//         xMap=x, yMap=y;
			gblNoObjet = i;
			if (!sdUsed[i])
				ExecHandler(&sl[i]);
			gblNoObjet = 0x7fff;                //Pour détecter les erreurs (#3)
			sdUsed[i] = 1;
		}
	}

	//   Exec(AnalyseRectPasEnIwram,rLeft,rTop,rRight,rBottom,departX,departY);
}


// Laissée en THUMB car un problème d'optimisation la rend plus lente en ARM
void IWRAM_CODE CopieMapBG(int scrlX, int scrlY)
{
	int largeurMapSource = gblLI->bgmi.bgLargeur;
	const u16 (*mapSource)[largeurMapSource] = (const u16 (*)[largeurMapSource])gblLI->bgmi.BGmap;
	u16 (*mapDestination)[LARGEUR_MAP_BG] = SCREEN_BASE_BLOCK(29);
	int i, j, offsetVertical;
	u32 nb = 0;

	bgmap_scrlX = scrlX;

	// Calcule l'offset vertical
	bgmap_scrlY = (scrlY * gblLI->bgmi.scrollY) >> 8;
	// S'assure qu'on ne va pas plus bas que le fond
	// << 3: tiles de 8x8
	if (bgmap_scrlY + ((HAUTEUR_MAP_BG_VISIBLE - 1) << 3) >= gblLI->bgmi.bgHauteur << 3)
		bgmap_scrlY = (gblLI->bgmi.bgHauteur - (HAUTEUR_MAP_BG_VISIBLE - 1)) << 3;
	offsetVertical = bgmap_scrlY >> 3;

	// Trouve le premier élément de script correspondant au haut de l'écran
	while (gblLI->bgmi.linescrollScript[nb] <= bgmap_scrlY)
		nb += 2;
	if (nb > 0)
		nb -= 2;

	for (j = 0; j < HAUTEUR_MAP_BG_VISIBLE; j++)
	{
		int k;

		if (gblLI->bgmi.linescrollScript[nb + 2] <= bgmap_scrlY + (j << 3))
			nb += 2;
		if (gblLI->bgmi.linescrollScript[nb + 1] & 0x8000)
			k = 0;
		else
		{
			// Calcule le n° de tile tout à droite (>> 8 pour unfixer, >> 3 pour diviser par 8, taille d'une tile)
			k = ((bgmap_scrlX * gblLI->bgmi.linescrollScript[nb + 1]) >> 11) + LARGEUR_MAP_BG_VISIBLE - 1;

			//Le but est de faire un modulo largeurMapSource, mais c'est trop lent
			while (k >= (largeurMapSource << 6)) //Par étapes de 64 * largeurMapSource
				k -= largeurMapSource << 6;
			while (k >= (largeurMapSource << 3)) //Par étapes de 8 * largeurMapSource
				k -= largeurMapSource << 3;
			while (k >= largeurMapSource)
				k -= largeurMapSource;
		}

		for (i = LARGEUR_MAP_BG_VISIBLE - 1; i >= 0; i--)
		{
			mapDestination[j][i] = mapSource[j + offsetVertical][k--];
			if (k < 0)
				k += largeurMapSource;
		}
	}
}

/*void IWRAM_CODE CopieMapBG(int scrlX, int scrlY)
{
	int largeurMapSource = gblLI->bgmi.bgLargeur;
	const u16 (*mapSource)[largeurMapSource] = (const u16 (*)[largeurMapSource])gblLI->bgmi.BGmap;
	u16 (*mapDestination)[LARGEUR_MAP_BG] = SCREEN_BASE_BLOCK(29);
	int i, j, offsetVertical;
	u32 nb = 0;
	static int lastTilePosition[HAUTEUR_MAP_BG_VISIBLE];

	bgmap_scrlX = scrlX;

	// Calcule l'offset vertical
	bgmap_scrlY = (scrlY * gblLI->bgmi.scrollY) >> 8;
	// S'assure qu'on ne va pas plus bas que le fond
	// << 3: tiles de 8x8
	if (bgmap_scrlY + ((HAUTEUR_MAP_BG_VISIBLE - 1) << 3) >= gblLI->bgmi.bgHauteur << 3)
		bgmap_scrlY = (gblLI->bgmi.bgHauteur - (HAUTEUR_MAP_BG_VISIBLE - 1)) << 3;
	offsetVertical = bgmap_scrlY >> 3;

	// Trouve le premier élément de script correspondant au haut de l'écran
	while (gblLI->bgmi.linescrollScript[nb] <= bgmap_scrlY)
		nb += 2;
	if (nb > 0)
		nb -= 2;

	for (j = 0; j < HAUTEUR_MAP_BG_VISIBLE; j++)
	{
		int noTile;

		if (gblLI->bgmi.linescrollScript[nb + 1] & 0x8000)
			noTile = 0;
		else
		{
			// Calcule le n° de tile à gauche (>> 8 pour unfixer, >> 3 pour diviser par 8, taille d'une tile)
			noTile = ((bgmap_scrlX * gblLI->bgmi.linescrollScript[nb + 1]) >> 11);

			//Le but est de faire un modulo largeurMapSource, mais c'est trop lent
			while (noTile >= (largeurMapSource << 6)) //Par étapes de 64 * largeurMapSource
				noTile -= largeurMapSource << 6;
			while (noTile >= (largeurMapSource << 3)) //Par étapes de 8 * largeurMapSource
				noTile -= largeurMapSource << 3;
			while (noTile >= largeurMapSource)
				noTile -= largeurMapSource;
		}

		if (!premFois)
		{
			int differenceScroll = noTile - lastTilePosition[j];
			int noTileStart;

			// Au cas où on se déplace vers la gauche
			if (differenceScroll < 0)
			{
				differenceScroll = -differenceScroll;
				noTileStart = i = noTile - 1;

				while (differenceScroll-- > 0)
				{
					if (noTileStart >= largeurMapSource)
						noTileStart -= largeurMapSource;
					mapDestination[j][(i--) & (LARGEUR_MAP_HARDWARE - 1)] =
						mapSource[j + offsetVertical][noTileStart++];
				}
			}
			// Si on a bougé, alors il faut remplir les tiles à gauche ou à droite
			else if (differenceScroll > 0)
			{
				// Numéro de la première tile tout à droite de l'écran, utilise le "WRAP" du BG pour recommencer à gauche une fois tout à droite
				noTileStart = i = noTile + LARGEUR_MAP_BG_VISIBLE - differenceScroll;

				// Copie les tiles sur la map
				while (differenceScroll-- > 0)
				{
					if (noTileStart >= largeurMapSource)
						noTileStart -= largeurMapSource;
					mapDestination[j][(i++) & (LARGEUR_MAP_HARDWARE - 1)] =
						mapSource[j + offsetVertical][noTileStart++];
				}
			}
		}

		// Garde le n° de tile pour la prochaine fois
		lastTilePosition[j] = noTile;
	}
}*/

