/*
//////////////////////////////////////////////////////
//	SNDREAL.CXX - Librairie SOUNDxd version 2.0		//
//////////////////////////////////////////////////////
//	Fonctions de gestion des pseudo-reels			//
//////////////////////////////////////////////////////
*/
 
#include "SND\snddef.h"
 
#include "SNDinc.h"  
#ifdef U64
#include <ultra.h>
#else
#ifdef PSX
#include <stddef.h>
#include <libgte.h>
#else
#include <math.h>
#endif
#endif
#include "sndvect.h"
 
/*---------------------------------------------------------*/
/*	MulRealRealSnd: multiplication exacte de 2 SndReal*/
/*	Entrees:r1,r2=reels à multiplier*/
/*	Sortie:resultat (r1*r2)*/
/*--------------------------------------------------------*/
SndReal SND_CALL SND_fn_rMulRealRealSnd(SndReal r1,SndReal r2)
{
	unsigned long r1p,r2p,t1,t2,t3,t4,r3p;
 
	r1p=abs(r1);
	r2p=abs(r2);
 
	if ((r1p<0x800) && (r2p<0x800) && (r1p>0xFF) && (r2p>0xFF))
		return ((r1>>8)*(r2>>8));
 
	if (r1p<0x7F)
		return ((r1 * (r2>>8))>>8);
 
	if (r2p<0x7F)
		return ((r2 * (r1>>8))>>8);
 
	t1=(r1p & 0xFFFF) * (r2p & 0xFFFF);
	t2=(r1p & 0xFFFF) * (r2p>>16);
	t3=(r1p>>16) * (r2p & 0xFFFF);
	t4=(r1p>>16) * (r2p >>16);
 
	r3p=(t1>>16)+t2+t3+(t4<<16);
 
	if ((r1<0)^(r2<0))
		return (SndReal)(0-r3p);
	else
		return (SndReal)r3p;
}
 
/*---------------------------------------------------------*/
/*	MulRealRealQuickSnd: multiplication rapide de 2 SndReal*/
/*	Entrees:r1,r2=reels à multiplier*/
/*	Sortie:resultat (r1*r2)*/
/*	Valide ssi -abs(ri)>0x800; octet de poid faible non valide*/
/*--------------------------------------------------------*/
SndReal SND_CALL SND_fn_rMulRealRealQuickSnd(SndReal r1,SndReal r2)
{
	return ((r1>>8)*(r2>>8));
}
 
/*---------------------------------------------------------*/
/*	SqrtRealSnd: racine carre d'un SndReal*/
/*	Entrees:r dont il faut extraire la racine*/
/*	Sortie:racine carre de r*/
/*--------------------------------------------------------*/
SndReal SND_CALL SND_fn_rSqrtRealSnd(SndReal r)
{
#ifdef U64
	return M_DoubleToRealSnd(sqrtf(M_RealToDoubleSnd(r)));
#else
#ifdef PSX
	return M_DoubleToRealSnd(csqrt(M_RealToDoubleSnd(r)));	
#else
	return M_DoubleToRealSnd(sqrt(M_RealToDoubleSnd(r)));
#endif
#endif
}
 
 
/*---------------------------------------------------------*/
/*	DivRealRealSnd: division d'un SndReal par un autre SndReal*/
/*		avec peut de precision (1/65000 à 1/256)*/
/*	Entrees:r1=dividente*/
/*		r2=diviseur*/
/*	Sortie:resultat de r1/r2*/
/*--------------------------------------------------------*/
SndReal SND_CALL SND_fn_rDivRealRealQuickSnd(SndReal r1,SndReal r2)
{
	/*il faut retourner 2^16*r1/r2, c.a.d.*/
	/*	r1	!0 7f	!80		!8000	!800000 */
	/*r2	!		!		!		!	*/
	/*------+----------------------------------------*/
	/*0 7f	!	r1<<16		!	?	!r2>>16	*/
	/*80	!	.	.		!r1<<8	!.*/
	/*8000	!	.	.		!r1<<8	!.*/
	/*800000!	.	.		!r1<<8	!.*/
	if (SND_fn_rAbsRealSnd(r1)<0x8000)
	{/*r1 suffisament petit*/
		snd_assert(r2);
		/*r2 null -> division by zero*/
		return ((r1<<16)/r2);
	}
	if (SND_fn_rAbsRealSnd(r1)<0x800000)
	{/*r1 moyen*/
		snd_assert(r2>>8);/* trop grand e=ecart entre r1 et r2*/
		return ((r1<<8)/(r2>>8));
	}
	/*r1 grand*/
	if (SND_fn_rAbsRealSnd(r2)>0x8000)
	{/*r2 grand*/
		snd_assert(r2>>8);
		return ((r1/(r2>>8))<<8);
	}
	/*vaillle que vaille*/
	snd_assert(r2);
	return (r1/r2)<<16;
}
 
/*---------------------------------------------------------*/
/*	DivRealRealSnd: division d'un SndReal par un autre SndReal*/
/*		avec precision */
/*	Entrees:r1=dividente*/
/*		r2=diviseur*/
/*	Sortie:resultat de r1/r2*/
/*--------------------------------------------------------*/
SndReal SND_CALL SND_fn_rDivRealRealSnd(SndReal r1,SndReal r2)
{
#ifdef PSX
	return SND_fn_rDivRealRealQuickSnd(r1,r2);
#else
	/*il faut retourner 2^16*r1/r2, c.a.d.*/
	return M_DoubleToRealSnd(
		(float)r1
		/(float)r2);
#endif
}
 
/*-----------------------------------*/
/* Valeur absolu*/
/*-----------------------------------*/
SndReal SND_CALL SND_fn_rAbsRealSnd(SndReal r)
{
	return abs(r);
}
 
/*------------------------------------------------*/
/*	Calcul rapide et approche de sqrt(a^2+b^2+c^2)*/
/*------------------------------------------------*/
SndReal SND_CALL SND_fn_rPseudoNormeRealSnd(SndReal r1,SndReal r2,SndReal r3)
{
	SndVector v;
 
	v.x=r1;
	v.y=r2;
	v.z=r3;
 
	return SND_fn_rPseudoNormeVectorSnd(&v);
}
 
void SND_CALL SND_fn_vSndRealTwinToSndReal(SndRealTwin rtwin,SndReal* pr1,SndReal* pr2)
{
	if (pr1)
		*pr1=(rtwin>>16)<<8;
 
	if (pr2)
		*pr2=(rtwin<<16)>>8;
}
 
SndRealTwin	SND_CALL SND_fn_rtSndRealToSndRealTwin(SndReal r1,SndReal r2)
{
	snd_assert(r1<M_DoubleToRealSnd(127.0));snd_assert(r2<M_DoubleToRealSnd(127.0));
 
	return ((r1<<8)&0xFFFF0000) | ((r2>>8)&0xFFFF);
}
 
