/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
////																					 ////
////																					 ////
////								- SCOL3dSound.cpp -									 ////
////																					 ////
////																					 ////
////				Implémentation des fonctions SCOL de la librairie sonore			 ////
////									 Version  1.0									 ////
////																					 ////
////								  Hilaire Verschuere								 ////
////																					 ////
////																					 ////
/////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////
#include "..\SCOL\ZooSCOL.h"
#include "..\SCOL\SCOLsound.h"




//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndCreate														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d AsSnd I] H3d
int as3dSndCreate(mmachine m)
{
	int H3dLinkedToSound = MTOI( MMpull(m) ) ;
	int	asSnd			 = MTOP( MMpull(m) ) ;
	int	s3d				 = MTOP( MMget(m,0) ) ;
	if( s3d==NIL || asSnd==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	WSound*	pWSound = (WSound*)MMfetch(m, asSnd, 0) ;
	ZScene*	pZScene	= (ZScene*)MMfetch(m, s3d, 0);       
    if( !pZScene || !pWSound || !(pWSound->flag & DSBCAPS_3D) ) { MMset(m, 0, NIL) ; return 0 ; }

	int hash_tab = MMfetch(m, s3d, 1) ;
	MMstore( m, asSnd, 1, hash_tab ) ;
	hash_tab = MTOP( hash_tab ) ;

	int h3d ;

	if( !pWSound->pZSound )
	{
		ZSound* pZSound = new ZSound( (int)pZScene, H3dLinkedToSound ) ;
		pWSound->pZSound = pZSound ;
		pWSound->pZScene = pZScene ;
		pZSound->pWSound = pWSound ;
		pZSound->nbRef = 0 ;
		pZSound->InsertAsChildOf(pZScene->World) ;

		h3d = createH3D( m, (int)pZSound, hash_tab ) ;

		pWSound->m_3dEnable = true ;
		if( HListener::activeScene && pWSound->pHSound ) pWSound->pHSound->Set3dMode( pZScene == HListener::activeScene ) ;
	}
	else
	{
		h3d = NodeTOHandle(m, hash_tab, (int)pWSound->pZSound ) ;
	}
	
	if( h3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	MMset( m, 0, PTOM( h3d ) );
	return 0;
}





//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndSetDistance
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I I] H3d
int as3dSndSetDistance(mmachine m)
{
	int max		 = MTOI( MMpull(m) ) ;
	int min		 = MTOI( MMpull(m) ) ;
	int h3d		 = MTOP( MMpull(m) ) ;
	int s3d		 = MTOP( MMget(m, 0) ) ;	
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound*	pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound || !pZSound->pWSound->pHSound ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->pHSound->m_p3DBuffer->SetMinDistance( min==NIL ? DS3D_DEFAULTMINDISTANCE : ( min<=0 ? 0.0001 : ((float)min)/100.0 ), DS3D_IMMEDIATE ) ;
	pZSound->pWSound->pHSound->m_p3DBuffer->SetMaxDistance( max==NIL ? DS3D_DEFAULTMAXDISTANCE : ( max<=0 ? 0.0001 : ((float)max)/100.0 ), DS3D_IMMEDIATE ) ;

	MMset( m, 0, PTOM(h3d) ) ;
	return 0 ;
}

	


//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndGetDistance
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I]
int as3dSndGetDistance(mmachine m)
{
	float minf ;
	float maxf ;
	int h3d	= MTOP( MMpull(m) ) ;
	int s3d	= MTOP( MMget(m, 0) ) ;	
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound*	pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound || !pZSound->pWSound->pHSound ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->pHSound->m_p3DBuffer->GetMinDistance( &minf ) ;
	pZSound->pWSound->pHSound->m_p3DBuffer->GetMaxDistance( &maxf ) ;
	
	int res = MMmalloc(m,2,TYPETAB) ;
	if ( res == NIL )	{ MMset(m,0,NIL) ;	return MERRMEM ; }

	MMstore(m, res, 0, ITOM(AROUNDINT(minf*100.0)) ) ;
	MMstore(m, res, 1, (maxf == DS3D_DEFAULTMAXDISTANCE) ? NIL : ITOM(AROUNDINT(maxf*100.0)) ) ;

	MMset(m, 0, PTOM(res)) ;

	return 0 ;
}


	

//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndSetCone														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d [I I] I] H3d
int as3dSndSetCone(mmachine m)
{
	int	volumeOutside = MTOI( MMpull(m) ) ;
	int angle         = MTOP( MMpull(m) ) ;
	int h3d			  = MTOP( MMpull(m) ) ;
	int s3d			  = MTOP( MMget(m,0) ) ;
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound*	pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound || !pZSound->pWSound->pHSound ) { MMset(m, 0, NIL) ; return 0 ; }
	
	if( angle!=NIL )
	{
		int angleInside	 = MTOI( MMfetch(m, angle, 0) ) ;
		int angleOutside = MTOI( MMfetch(m, angle, 1) ) ;		
		if( angleOutside!=NIL && angleInside!=NIL )
		{
			if( angleOutside < 0   ) angleOutside = 0 ;
			if( angleInside  < 0   ) angleInside  = 0 ;
			if( angleOutside > 360 ) angleOutside = 360 ;
			if( angleInside  > 360 ) angleInside  = 360 ;
			pZSound->pWSound->pHSound->m_p3DBuffer->SetConeAngles( (float)angleInside, (float)angleOutside, DS3D_IMMEDIATE ) ;
		}
	}
	
	if( volumeOutside!=NIL ) pZSound->pWSound->pHSound->SetVolumeCone( volumeOutside ) ;
	
	MMset( m, 0, PTOM(h3d) ) ;
	return 0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndGetCone														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] [I I I]
int as3dSndGetCone(mmachine m)
{
	long volumeOutside ;
	unsigned long angleInside ;
	unsigned long angleOutside ;
	int h3d    = MTOP( MMpull(m) ) ;
	int s3d	   = MTOP( MMget(m,0) ) ;
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound*	pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound || !pZSound->pWSound->pHSound ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->pHSound->m_p3DBuffer->GetConeAngles( &angleInside, &angleOutside ) ;
	volumeOutside = pZSound->pWSound->pHSound->GetVolumeCone() ;

	int res = MMmalloc(m,3,TYPETAB) ;
	if ( res == NIL )	{ MMset(m,0,NIL) ;	return MERRMEM ; }

	MMstore(m, res, 0, ITOM(angleInside) ) ;
	MMstore(m, res, 1, ITOM(angleOutside) ) ;
	MMstore(m, res, 2, ITOM(volumeOutside) ) ;

	MMset(m, 0, PTOM(res)) ;

	return 0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndEnable														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] H3d
int as3dSndEnable(mmachine m)
{
	int h3d    = MTOP( MMpull(m) ) ;
	int s3d	   = MTOP( MMget(m,0) ) ;
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound*	pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound || !pZSound->pWSound->pHSound ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->m_3dEnable = true ;
	if( pZSound->pWSound->pZScene == HListener::activeScene ) pZSound->pWSound->pHSound->Set3dMode( true ) ;

	MMset( m, 0, PTOM(h3d) ) ;
	return  0 ;
}



//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dSndDisable														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] H3d
int as3dSndDisable(mmachine m)
{
	int h3d    = MTOP( MMpull(m) ) ;
	int s3d	   = MTOP( MMget(m,0) ) ;
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound*	pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound || !pZSound->pWSound->pHSound ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->m_3dEnable = false ;
	pZSound->pWSound->pHSound->Set3dMode( false ) ;

	MMset( m, 0, PTOM(h3d) ) ;
	return  0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dListenerCreate 														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d] H3d
int as3dListenerCreate (mmachine m)
{
	if( !initDirectSound() ) { MMset(m,0,NIL) ; return 0 ; }

	int s3d = MTOP( MMget(m,0) ) ;
	if( s3d==NIL ) { MMset(m,0,NIL) ; return 0 ; }
	
	ZScene*	pZScene = (ZScene*)MMfetch(m, s3d, 0);
	if( !pZScene ) { MMset(m,0,NIL) ;	return 0 ; }

	ZSound* pZSound = new ZSound((int)pZScene, 0 ) ;
	WSound* pWSound = new WSound( 0 ) ;

	pWSound->load( new HListener() ) ;
	pWSound->pZSound = pZSound ;
	pWSound->pZScene = pZScene ;
	pZSound->pWSound = pWSound ;
	
	pZSound->InsertAsChildOf( pZScene->World ) ;

	int hash_tab = MTOP( MMfetch(m, s3d, 1) );
	int h3d = createH3D(m, (int)pZSound, hash_tab);
	if( h3d==NIL ) { MMset(m,0,NIL) ; return 0 ; }

    MMset( m, 0, PTOM(h3d) );
	return 0;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dListenerSetActive														
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] H3d
int as3dListenerSetActive(mmachine m)
{
	int h3d = MTOP( MMpull(m) ) ;
	int s3d = MTOP( MMget(m, 0) ) ;
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound* pZSound = (ZSound*)MMfetch(m, h3d, 0) ;
	ZScene*	pZScene = (ZScene*)MMfetch(m, s3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound->pHListener ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->pHListener->SetActive( pZScene, pZSound ) ;	
	
	MMset(m, 0, PTOM(h3d) ) ;
	return 0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dListenerSetRollOff													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d I] H3d
int as3dListenerSetRollOff(mmachine m)
{
	int factor = MTOI( MMpull(m) ) ;
	int h3d    = MTOP( MMpull(m) ) ;
	int s3d	   = MTOP( MMget(m,0) ) ;
	if( h3d==NIL || s3d==NIL || factor==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound* pZSound  = (ZSound*)MMfetch(m, h3d, 0) ;
	ZScene*	pZScene = (ZScene*)MMfetch(m, s3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound->pHListener ) { MMset(m, 0, NIL) ; return 0 ; }

	if(factor<0) factor = 0 ;
	else if(factor>1000) factor = 1000 ;
	
	pZSound->pWSound->pHListener->m_pListener->SetRolloffFactor( ((float)factor)/100, DS3D_IMMEDIATE ) ;

	MMset( m, 0, PTOM(h3d) ) ;
	return 0 ;
}




//////////////////////////////////////////////////////////////////////////////////////////////
///		as3dListenerGetRollOff													
//////////////////////////////////////////////////////////////////////////////////////////////
// fun [S3d H3d] I
int as3dListenerGetRollOff(mmachine m)
{
	float factor ;
	int h3d    = MTOP( MMpull(m) ) ;
	int s3d	   = MTOP( MMget(m,0) ) ;
	if( h3d==NIL || s3d==NIL ) { MMset(m, 0, NIL) ; return 0 ; }

	ZSound* pZSound  = (ZSound*)MMfetch(m, h3d, 0) ;
	ZScene*	pZScene = (ZScene*)MMfetch(m, s3d, 0) ;
	if( !pZSound || pZSound->type!=SND_TYPE_ID || !pZSound->pWSound->pHListener ) { MMset(m, 0, NIL) ; return 0 ; }

	pZSound->pWSound->pHListener->m_pListener->GetRolloffFactor( &factor ) ;

	MMset(m, 0, ITOM(AROUNDINT(factor*100)));

	return 0 ;
}



/////////////////////////////////////////////////////// DEFINITIONS
#define NBSOUND3DPKG 12

char* SOUND3Dname [ NBSOUND3DPKG ] = 
{
	"AS_SND_LINKED_TO_H3D",			// AS_SND_LINKED_TO_H3D

	// Son 3D				
	"as3dListenerCreate",			// as3dListenerCreate 
	"as3dListenerSetActive",		// as3dListenerSetActive
	"as3dListenerSetRollOff",		// as3dListenerSetRollOff
	"as3dListenerGetRollOff",		// as3dListenerGetRollOff
	"as3dSndCreate",				// as3dSndCreate,
	"as3dSndSetCone",				// as3dSndSetCone
	"as3dSndGetCone",				// as3dSndGetCone
	"as3dSndSetDistance",			// as3dSndSetDistance
	"as3dSndGetDistance",			// as3dSndGetDistance
	"as3dSndEnable",				// as3dSndEnable
	"as3dSndDisable",				// as3dSndDisable
} ;

char * SOUND3Dtype [ NBSOUND3DPKG ] = 
{
	"I",																	// AS_SND_LINKED_TO_H3D
																																						
	// Son 3D																	
	"fun [S3d] H3d",														// as3dListenerCreate 
	"fun [S3d H3d] H3d",													// as3dListenerSetActive
	"fun [S3d H3d I] H3d",													// as3dListenerSetRollOff
	"fun [S3d H3d] I",														// as3dListenerGetRollOff
	"fun [S3d AsSnd I] H3d",												// as3dSndCreate,
	"fun [S3d H3d [I I] I] H3d",											// as3dSndSetCone,
	"fun [S3d H3d] [I I I]",												// as3dSndGetCone
	"fun [S3d H3d I I] H3d",												// as3dSndSetDistance,
	"fun [S3d H3d] [I I]",													// as3dSndGetDistance,
	"fun [S3d H3d] H3d",													// as3dSndEnable
	"fun [S3d H3d] H3d",													// as3dSndDisable																			
} ;


int SOUND3Dnarg [ NBSOUND3DPKG ] = 
{
	TYPVAR,							// AS_SND_LINKED_TO_H3D

	// Son 3D
	1,								// as3dListenerCreate 
	2,								// as3dListenerSetActive
	3,								// as3dListenerSetRollOff,
	2,								// as3dListenerGetRollOff,
	3,								// as3dSndCreate,
	4,								// as3dSndSetCone
	2,								// as3dSndGetCone
	4,								// as3dSndSetDistance
	2,								// as3dSndGetDistance
	2,								// as3dSndEnable
	2,								// as3dSndDisable

} ;


int (*SOUND3Dfun[NBSOUND3DPKG])(mmachine m)= 
{
	(int (__cdecl *)(struct Mmachine *))(2*AS_SND_LINKED_TO_H3D),	// AS_SND_LINKED_TO_H3D
 
	// Son 3D														
	as3dListenerCreate ,											// as3dListenerCreate 
	as3dListenerSetActive,											// as3dListenerSetActive
	as3dListenerSetRollOff,											// as3dListenerSetRollOff
	as3dListenerGetRollOff,											// as3dListenerGetRollOff
	as3dSndCreate,													// as3dSndCreate,
	as3dSndSetCone,													// as3dSndSetCone
	as3dSndGetCone,													// as3dSndGetCone
	as3dSndSetDistance,												// as3dSndSetDistance
	as3dSndGetDistance,												// as3dSndGetDistance
	as3dSndEnable,													// as3dSndEnable
	as3dSndDisable,													// as3dSndDisable

} ;



int SCOLload3dSound(mmachine m,cbmachine w)
{	
	return PKhardpak( m, "3D Sound", NBSOUND3DPKG, SOUND3Dname, SOUND3Dfun, SOUND3Dnarg, SOUND3Dtype ) ;
}


int SCOLfree3dSound()
{
	return 0;
}

