#include "commun.h"

unsigned short EWRAM_DATA PaletteNormale[512], PaletteEau[512];
unsigned short EWRAM_DATA PaletteNormaleSauv[512], PaletteEauSauv[512];

unsigned char EWRAM_DATA save_sd[2048];
int niveau_reel_eau = 10000, niveau_reel = 500;
int fadeLength = 4;

//char EWRAM_DATA save_buffer[16384];
//int save_car=0, save_largeur=0;
int sauve_saved = 0;
int sauve_sonX, sauve_sonY, sauve_temps;

/*
void IWRAM_CODE EcritCarSave(int c)         {
    if (save_car<16384)
        save_buffer[save_car++]=c;
}

void EcritDataSave(void *donnees, int taille)         {
    while (save_car<16384 && taille--)      {
        save_buffer[save_car++]=*(char*)donnees;
        donnees++;
    }
}

void IWRAM_CODE LitDataSave(void *donnees, int taille)         {
    while (save_car<16384 && taille--)      {
        *(char*)donnees=save_buffer[save_car++];
        donnees++;
    }
}*/
void SaveState(SONIC *s)
{
        int i, j, k, v, n;

        sauve_saved = 1;
        memcpy(save_sd, sdUsed, sizeof(sdUsed));
        sauve_sonX = s->x;
        sauve_sonY = s->y;
        sauve_temps = gblTemps;

        /*        for (j=0;j<TABLE_Y;j++)                {
                for (i=0;i<TABLE_X/8;)                {
                        v=tableauMap[j][i++];
                        if (v==0)            {
                            for (k=i;k<TABLE_X/8;k++)
                                    if (tableauMap[j][k]!=v)
                                            break;
                            if (k==TABLE_X/8)
                                    break;
                            n=k-i;
                                //Essayer avec >=2
                                if (n>2)                {
                                    EcritCarSave(0xfe);
                                    EcritCarSave(n);
                                        i=k-1;
//                                    Debug("%i %i %i",i,j,save_car);
                                        continue;
                                }
                        }
                        if (v>=0xfc)             {
                            EcritCarSave(0xfc);
                            EcritCarSave(v);
            }
            else            {
                EcritCarSave(v);
            }
//            i++;
                }
                EcritCarSave(0xfd);
        }
        Exec(EcritDataSave,&s->x,sizeof(s->x));
        Exec(EcritDataSave,&s->y,sizeof(s->y));
//        Exec(EcritDataSave,s,sizeof(SONIC));*/

        //        save_largeur=save_car;
}

void LoadState(SONIC *s)
{
        int i, j, n, v, c = 0;

        //    save_car=0;
        memcpy(sdUsed, save_sd, sizeof(sdUsed));
        s->x = sauve_sonX;
        s->y = sauve_sonY;
        gblTemps = sauve_temps;

        /*        for (j=0;j<TABLE_Y;j++)                {
            if (save_car>=save_largeur)            {
                Debug("Erreur de decompression");
            break;
        }
                for (i=0;i<TABLE_X/8;)          {
                    c=save_buffer[save_car++];
                    if (c==0xfc)
                tableauMap[j][i++]=save_buffer[save_car++];
            else if (c==0xfd)           {
                for (;i<TABLE_X/8;)
                    tableauMap[j][i++]=0;
                break;
            }
            else if (c==0xfe)           {
                n=save_buffer[save_car++];
                for (;n--;i++)
                    tableauMap[j][i]=0;
//                Debug("%i %i %i",i,j,save_car);
                continue;
            }
            else
                tableauMap[j][i++]=c;
        }
        if (c!=0xfd && save_buffer[save_car]==0xfd)
            save_car++;
    }
        Exec(LitDataSave,&s->x,sizeof(s->x));
        Exec(LitDataSave,&s->y,sizeof(s->y));
    if (save_car<save_largeur)
        Debug("Erreur de decompression");*/
}

/*int min3(int x, int y, int z)                {
        if (x<=y && x<=z)
                return x;
        if (y<=x && y<=z)
                return y;
        if (z<=x && z<=y)
                return z;
        return z;
}

int max3(int x, int y, int z)                {
        if (x>=y && x>=z)
                return x;
        if (y>=x && y>=z)
                return y;
        if (z>=x && z>=y)
                return z;
        return z;
}

void RVB_TSL (int R,int V, int B, int *H, int *S, int *L)                        {
        int var_R, var_G, var_B;
        int var_Min, var_Max, del_Max;
        int del_R, del_G, del_B;

        var_R = R;
        var_G = V;
        var_B = B;

        var_Min = min3( var_R, var_G, var_B );    //Min. value of RGB
        var_Max = max3( var_R, var_G, var_B );    //Max. value of RGB
        del_Max = var_Max - var_Min;             //Delta RGB value

        *L = ( var_Max + var_Min ) / 2;

        if ( del_Max == 0 )                     //This is a gray, no chroma...
        {
           *H = 0;                                //HSL results = 0 ÷ 1
           *S = 0;
        }
        else                                    //Chromatic data...
        {
           if ( *L < 1<<7 ) *S = (del_Max<<8) / ( var_Max + var_Min );
           else              *S = (del_Max<<8) / ( (2<<8) - var_Max - var_Min );

           del_R = (( ( ( var_Max - var_R ) / 6 ) + ( del_Max / 2 ) )<<8) / del_Max;
           del_G = (( ( ( var_Max - var_G ) / 6 ) + ( del_Max / 2 ) )<<8) / del_Max;
           del_B = (( ( ( var_Max - var_B ) / 6 ) + ( del_Max / 2 ) )<<8) / del_Max;

           if      ( var_R == var_Max ) *H = del_B - del_G;
           else if ( var_G == var_Max ) *H = ( 1 / 3 ) + del_R - del_B;
           else if ( var_B == var_Max ) *H = ( 2 / 3 ) + del_G - del_R;

           if ( *H < 0 ) *H += (1<<8);
           if ( *H > (1<<8) ) *H -= (1<<8);
        }
}

void CreePaletteSousEau()           {
    int i, temp, rouge, vert, bleu;
    int rdest, vdest, bdest, alpha;
    int t, l, s;
    bdest=(gblLI->couleur_eau>>10)&31;
    vdest=(gblLI->couleur_eau>>5)&31;
    rdest=(gblLI->couleur_eau)&31;
    alpha=gblLI->alpha_eau;

    for (i=0;i<512;i++)         {
        temp=PaletteNormale[i];
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        PaletteNormale[i]=RVB(rouge,vert,bleu);
        RVB_TSL(rouge<<3,vert<<3,bleu<<3,&t,&s,&l);
        s-=ABS(128-l);
        alpha=(31-(s>>3));
        if (alpha>31)
            alpha=31;
        if (alpha<0)
            alpha=0;
        rouge=(alpha*rouge+(31-alpha)*rdest)/31;
        vert=(alpha*vert+(31-alpha)*vdest)/31;
        bleu=(alpha*bleu+(31-alpha)*bdest)/31;
        PaletteEau[i]=RVB(rouge,vert,bleu);
    }
}*/

//Méthode: Alpha-blend

/*void CreePaletteSousEau()           {
    int i, temp, rouge, vert, bleu;
    int rdest, vdest, bdest, alpha;
    bdest=(gblLI->couleur_eau>>10)&31;
    vdest=(gblLI->couleur_eau>>5)&31;
    rdest=(gblLI->couleur_eau)&31;
    alpha=gblLI->alpha_eau;

    for (i=0;i<512;i++)         {
        temp=PaletteNormale[i];
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        PaletteNormale[i]=RVB(rouge,vert,bleu);
        rouge=(alpha*rouge+(31-alpha)*rdest)/31;
        vert=(alpha*vert+(31-alpha)*vdest)/31;
        bleu=(alpha*bleu+(31-alpha)*bdest)/31;
        PaletteEau[i]=RVB(rouge,vert,bleu);
    }
}*/
void CreePaletteSousEau(unsigned short *src, unsigned short *dst1, unsigned short *dst2, int taille)
{
        int i, temp, rouge, vert, bleu;
        int rdest, vdest, bdest;
        bdest = (gblLI->couleur_eau >> 10) & 31;
        vdest = (gblLI->couleur_eau >> 5) & 31;
        rdest = (gblLI->couleur_eau) & 31;
        if (gblLI->alpha_eau & 0x1000)
        {        //Effet par addition
                if (gblLI->alpha_eau & 1)
                        bdest = -bdest;
                if (gblLI->alpha_eau & 2)
                        vdest = -vdest;
                if (gblLI->alpha_eau & 4)
                        rdest = -rdest;
        }

        while (taille--)
        {
                temp = *src;
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                *dst1 = RVB(rouge, vert, bleu);
                rouge += rdest;
                vert += vdest;
                bleu += bdest;
                if (rouge > 31)
                        rouge = 31;
                if (rouge < 0)
                        rouge = 0;
                if (vert > 31)
                        vert = 31;
                if (vert < 0)
                        vert = 0;
                if (bleu > 31)
                        bleu = 31;
                if (bleu < 0)
                        bleu = 0;
                *dst2 = RVB(rouge, vert, bleu);
                src++, dst1++, dst2++;
        }
}

void AlphaBlendPalette(unsigned short *dst, const unsigned short *src, u32 taille, u32 couleur, u32 alpha)
{
        int i, temp, rouge, vert, bleu;
        int rdest, vdest, bdest;
        bdest = (couleur >> 10) & 31;
        vdest = (couleur >> 5) & 31;
        rdest = (couleur) & 31;
        for (i = 0; i < taille; i++)
        {
                temp = src[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                rouge = (alpha * rouge + (31 - alpha) * rdest) / 31;
                vert = (alpha * vert + (31 - alpha) * vdest) / 31;
                bleu = (alpha * bleu + (31 - alpha) * bdest) / 31;
                dst[i] = RGB(rouge, vert, bleu);
        }
}

unsigned short *adresse_palettes[12] EWRAM_DATA;
char pal_utilisees[12] EWRAM_DATA;
int nbPalettes;

void GestionnairePalette()
{
	u32 i;
	for (i = 0; i < 12; i++)
	{
		if (pal_utilisees[i] > 0)
			pal_utilisees[i]--;
	}
}

u32 CreeNouvellePalette(unsigned short *palette, int place)
{
	u32 libre = 0, i;
	if (place == -1)
	{

		//La palette n'existe pas, on en cherche une qui soit libre
		for (i = 0; i < 12; i++)
		{
			if (pal_utilisees[i] == 0)
			{
				libre = i;
				break;
			}
		}

		nbPalettes++;
	}
	else
		libre = place;
	adresse_palettes[libre] = palette;
	pal_utilisees[libre] = 2;
	i = 256 + 16 * libre;
	if (!fade)
	{
		CreePaletteSousEau(palette, PaletteNormale + i, PaletteEau + i, 16);
	}
	else
	{
		CreePaletteSousEau(palette, PaletteNormaleSauv + i, PaletteEauSauv + i, 16);
	}

	return libre;
}

void InitSysPalettes()
{
	InitZero(adresse_palettes);
	InitZero(pal_utilisees);
	nbPalettes = 0;
}

void MajSysPalettes()
{
	u32 i;
	for (i = 0; i < 12; i++)
	{
		if (pal_utilisees[i])
			CreeNouvellePalette(adresse_palettes[i], i);
	}
}

//Méthode: Addition

/*void CreePaletteSousEau()           {
    int i, temp, rouge, vert, bleu;
    const int rdest=0, vdest=8, bdest=16;

    for (i=0;i<512;i++)         {
        temp=Palette[i];
            PaletteNormale[i]=temp;
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        if (rouge+rdest>31)             rouge=31;
        else                            rouge+=rdest;
        if (vert+vdest>31)              vert=31;
        else                            vert+=vdest;
        if (bleu+bdest>31)              bleu=31;
        else                            bleu+=bdest;
        PaletteEau[i]=RGB(rouge,vert,bleu);
    }
}*/

//Méthode: Soustraction

/*void CreePaletteSousEau()           {
    int i, temp, rouge, vert, bleu;
    const int rdest=16, vdest=8, bdest=0;

    for (i=0;i<512;i++)         {
        temp=Palette[i];
            PaletteNormale[i]=temp;
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        if (rouge-rdest<0)              rouge=0;
        else                            rouge-=rdest;
        if (vert-vdest<0)               vert=0;
        else                            vert-=vdest;
        if (bleu-bdest<0)               bleu=0;
        else                            bleu-=bdest;
        PaletteEau[i]=RGB(rouge,vert,bleu);
    }
}*/
void GereSonicMort(SONIC *s)
{
        s->y += vDIV(s->vy);
        s->vy += 32;
}

int fade;
void Quitte()
{
        if (!fade)
                fade = 24;
}

/*void GereFade()         {
    if (fade)         {
        REG_COLEY=ABS(fade);
        REG_BLDMOD = 0x3fff;
        if ((nTimer&1)==0)
            fade++;
    }
    else
        REG_BLDMOD=0;
}*/
void AssombritPalette(unsigned short *dst, unsigned short *src, s32 valeur)
{
        s32 i, rouge, vert, bleu, temp;
        s32 vr, vb, vg;

        //    vr=valeur*1.5, vg=valeur*1.25, vb=valeur;

        /*    for (i=0;i<504;i++)         {
        temp=src[i];
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        if (rouge-vr<0)                 rouge=0;
        else                            rouge-=vr;
        if (vert-vg<0)                  vert=0;
        else                            vert-=vg;
        if (bleu-vb<0)                  bleu=0;
        else                            bleu-=vb;
        dst[i]=RGB(rouge,vert,bleu);
    }*/
        if (valeur > 24)
                valeur = 24;
        valeur = 24 - valeur;
        if (valeur < 8)
                vr = 0, vg = 0, vb = valeur * 2;
        else if (valeur < 16)
                vr = 0, vg = (valeur - 8) * 2, vb = 16 + (valeur - 8);
        else
                vr = (valeur - 16) * 4, vg = 16 + (valeur - 16) * 2, vb = 24 + (valeur - 16);

        //    valeur=32-valeur;
        for (i = 0; i < 496; i++)
        {
                temp = src[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                rouge = (vr * rouge) >> 5;
                vert = (vg * vert) >> 5;
                bleu = (vb * bleu) >> 5;
                dst[i] = RGB(rouge, vert, bleu);
        }
}

void FadeOut(unsigned short *dst, unsigned short *src, s32 taille)
{
        s32 i, rouge, vert, bleu, temp;
        for (i = 0; i < taille; i++)
        {
                temp = dst[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                if (rouge)
                        rouge -= fadeLength;
                else if (vert)
                        vert -= fadeLength;
                else if (bleu)
                        bleu -= fadeLength;
                if (rouge < 0)
                        rouge = 0;
                if (vert < 0)
                        vert = 0;
                if (bleu < 0)
                        bleu = 0;
                dst[i] = RGB(rouge, vert, bleu);
        }
}

void FadeOutBlanc(unsigned short *dst, unsigned short *src, s32 taille)
{
        s32 i, rouge, vert, bleu, temp;
        for (i = 0; i < taille; i++)
        {
                temp = dst[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                if (rouge < 31)
                        rouge += fadeLength;
                else if (vert < 31)
                        vert += fadeLength;
                else if (bleu < 31)
                        bleu += fadeLength;
                if (rouge > 31)
                        rouge = 31;
                if (vert > 31)
                        vert = 31;
                if (bleu > 31)
                        bleu = 31;
                dst[i] = RGB(rouge, vert, bleu);
        }
}

/*void  FadeOut(unsigned short *dst, unsigned short *src)          {
    s32 i, rouge, vert, bleu, temp, j;
    for (i=0;i<504;i++)         {
        temp=dst[i];
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        j=nImages%3;
        if (j==0)           {
            if (rouge)              rouge-=4;
            if (rouge<0)            rouge=0;
        }
        else if (j==1)          {
            if (vert)          vert-=4;
            if (vert<0)        vert=0;
        }
        else if (j==2)      {
            if (bleu)               bleu-=4;
            if (bleu<0)             bleu=0;
        }
        dst[i]=RGB(rouge,vert,bleu);
    }
}*/
void FadeIn(unsigned short *dst, unsigned short *src, s32 taille)
{
        s32 i, rouge, vert, bleu, temp;
        for (i = 0; i < taille; i++)
        {
                temp = dst[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                if (bleu < ((src[i] >> 10) & 0x1F))
                        bleu += fadeLength;
                else if (vert < ((src[i] >> 5) & 0x1F))
                        vert += fadeLength;
                else if (rouge < (src[i] & 0x1F))
                        rouge += fadeLength;
                if (rouge > (src[i] & 0x1F))
                        rouge = (src[i] & 0x1F);
                if (vert > ((src[i] >> 5) & 0x1F))
                        vert = ((src[i] >> 5) & 0x1F);
                if (bleu > ((src[i] >> 10) & 0x1F))
                        bleu = ((src[i] >> 10) & 0x1F);
                dst[i] = RGB(rouge, vert, bleu);
        }
}

void FadeInBlanc(unsigned short *dst, unsigned short *src, s32 taille)
{
        s32 i, rouge, vert, bleu, temp;
        for (i = 0; i < taille; i++)
        {
                temp = dst[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);
                if (bleu > ((src[i] >> 10) & 0x1F))
                        bleu -= fadeLength;
                else if (vert > ((src[i] >> 5) & 0x1F))
                        vert -= fadeLength;
                else if (rouge > (src[i] & 0x1F))
                        rouge -= fadeLength;
                if (rouge < (src[i] & 0x1F))
                        rouge = (src[i] & 0x1F);
                if (vert < ((src[i] >> 5) & 0x1F))
                        vert = ((src[i] >> 5) & 0x1F);
                if (bleu < ((src[i] >> 10) & 0x1F))
                        bleu = ((src[i] >> 10) & 0x1F);
                dst[i] = RGB(rouge, vert, bleu);
        }
}

/*void  FadeIn(unsigned short *dst, unsigned short *src)          {
    s32 i, rouge, vert, bleu, temp, j;
    for (i=0;i<504;i++)         {
        temp=dst[i];
        bleu=(temp&0x7C00)>>10;
        vert=(temp&0x3E0)>>5;
        rouge=(temp&0x1F);
        j=nImages%3;
        if (j==0)       {
            if (rouge<(src[i]&0x1F))
                rouge+=4;
            if (rouge>(src[i]&0x1F))
                rouge=(src[i]&0x1F);
        }
        else if (j==1)      {
            if (vert<((src[i]>>5)&0x1F))
                vert+=4;
            if (vert>((src[i]>>5)&0x1F))
                vert=((src[i]>>5)&0x1F);
        }
        else if (j==2)          {
            if (bleu<((src[i]>>10)&0x1F))
                bleu+=4;
            if (bleu>((src[i]>>10)&0x1F))
                bleu=((src[i]>>10)&0x1F);
        }
        dst[i]=RGB(rouge,vert,bleu);
    }
}*/
char EWRAM_DATA fadedata[2][512 >> 2];
#define GET_FD(i)                ((fd[(i) >> 2] & (0x3 << (((i) & 3) << 1))) >> ((i & 3) << 1))
#define CLR_FD(i)                (fd[(i) >> 2] &= ~(0x3 << (((i) & 3) << 1)))
#define SET_FD(i, val)        (fd[(i) >> 2] |= ((val) << (((i) & 3) << 1)))

void InitFadeOutLong()
{
        InitZero(fadedata);
}

void FadeOutTresLong(int no_buffer, unsigned short *dst, unsigned short *src, s32 taille)
{
        s32 i, rouge, vert, bleu, temp;
        char *fd = fadedata[no_buffer];
        for (i = 0; i < taille; i++)
        {
                temp = dst[i];
                bleu = (temp & 0x7C00) >> 10;
                vert = (temp & 0x3E0) >> 5;
                rouge = (temp & 0x1F);

                if (rouge == 0 && vert == 0 && bleu == 0)
                        continue;

ici:
                if (GET_FD(i) == 0)
                {
                        CLR_FD(i);
                        SET_FD(i, 1);
                        if (rouge > 0)
                                rouge -= fadeLength;
                        else
                                goto ici;
                        goto apres;
                }

                if (GET_FD(i) == 1)
                {
                        CLR_FD(i);
                        SET_FD(i, 2);
                        if (vert > 0)
                                vert -= fadeLength;
                        else
                                goto ici;
                        goto apres;
                }

                if (GET_FD(i) == 2)
                {
                        CLR_FD(i);
                        SET_FD(i, 0);
                        if (bleu > 0)
                                bleu -= fadeLength;
                        else
                                goto ici;
                        goto apres;
                }

apres:
                if (rouge < 0)
                        rouge = 0;
                if (vert < 0)
                        vert = 0;
                if (bleu < 0)
                        bleu = 0;
                dst[i] = RGB(rouge, vert, bleu);
        }
}

void GereFade()
{
        u32 fadetype = 0;
        fadeLength = 96 / ABS(fade);
        while (fade)
        {
                if (fade > 0)
                {
                        FadeOut(PaletteNormale, PaletteNormaleSauv, 512);
                        FadeOut(PaletteEau, PaletteEauSauv, 512);
                        fade--;
                        fadetype = 1;
                }
                else if (fade < 0)
                {
                        FadeIn(PaletteNormale, PaletteNormaleSauv, 504);
                        FadeIn(PaletteEau, PaletteEauSauv, 504);
                        fade++;
                        fadetype = 0;
                }

                /*        if (nTimer&1)
            AssombritPalette(PaletteNormale,PaletteNormaleSauv,ABS(fade));
        else
            AssombritPalette(PaletteEau,PaletteEauSauv,ABS(fade));*/

                //        REG_COLEY=ABS(fade);
                //        REG_BLDMOD = 0x3fff;
                //        if ((nTimer&1)==0)
                if (fade == 0 && fadetype == 0)
                {
                        CopieDMA(PaletteNormaleSauv, PaletteNormale, 512, DMA_16im);
                        CopieDMA(PaletteEauSauv, PaletteEau, 512, DMA_16im);
                }

                AttendVSync();
        }
}

void GereFadeBlanc()
{
        fadeLength = 96 / ABS(fade);
        while (fade)
        {
                if (fade > 0)
                {
                        FadeOutBlanc(PaletteNormale, PaletteNormaleSauv, 504);
                        FadeOutBlanc(PaletteEau, PaletteEauSauv, 504);
                        fade--;
                }
                else if (fade < 0)
                {
                        FadeInBlanc(PaletteNormale, PaletteNormaleSauv, 504);
                        FadeInBlanc(PaletteEau, PaletteEauSauv, 504);
                        fade++;
                        if (fade == 0)
                        {
                                CopieDMA(PaletteNormaleSauv, PaletteNormale, 512, DMA_16im);
                                CopieDMA(PaletteEauSauv, PaletteEau, 512, DMA_16im);
                        }
                }

                AttendVSync();
        }
}
