/**********************************************************
 *                                                        *
 *                   Magnet                               *
 *                                                        *
 * Author : Ubi China - Marc Trabucato                    *
 *                                                        *
 **********************************************************/
 
#include "acp_base.h"
 
#define D_MSMagnet_StructureDefine
 
#include "MTH.h"
#include "GEO.h"
#include "GLI.h"
 
/*XB980506*/
/*#include "incGAM.h"*/
#include "mec.h"
#include "fil.h"
#include "snd.h"
#include "pcs.h"
#include "gld.h"
#include "lst.h"
#ifdef USE_IPT_DX5
#include "IPT_DX5.h" /* InPuT (absolutely before GAM.h)*/
#else /* USE_IPT_WIN */
#include "IPT.h" /* InPuT (absolutely before GAM.h)*/
#endif /* USE_IPT_WIN */
/*#include "srf.h"*/
/*#include "env.h"*/
#include "sct.h"
#include "prt.h"
#include "gam.h"
 
/*#include "incSPO.h"*/
#include "pos.h"
#include "spo.h"
 
/*#include "incIPO.h"*/
#include "po.h"
/*XB980821*/
#ifndef D_THROW_IPO
#include "ipo.h"
#endif /* D_THROW_IPO */
/*End XB*/
/*End XB*/
 
#include "COL.h"
 
#include "MGT\MGTStruc.h"
#include "MGTInit.h"
#include "MGTMain.h"
#include "MGTmm.h"
#include "MGTmo.h"
 
#ifdef MGT_RASTER
#include "MGTRast.h"
#endif
 
#define MGT_C_NoMoveDistanceSqr       MTH_M_xFloatToReal( 0.04 )
 
EXTERN HIE_tdxHandleToSuperObject		SECT_hFatherSector;
 
/*************************************************************************************************/
#define MGT_M_bIsSetBit( p_cTab , xIndex )	( p_cTab[ xIndex >> 3 ] & ( 1 << (xIndex & 0x00000007) ) )
#define MGT_M_vSetBit( p_cTab , xIndex )	( p_cTab[ xIndex >> 3 ] |= ( 1 << (xIndex & 0x00000007) ) )
#define MGT_M_vUnSetBit( p_cTab , xIndex )	( p_cTab[ xIndex >> 3 ] &= ~((char)( 1 << (xIndex & 0x00000007) )) )
/*
INLINE
ACP_tdxBool MGT_M_bIsSetBit( char *p_cTab , ACP_tdxIndex xIndex )
{
	ACP_tdxIndex xDiv , xMod;
 
	xDiv = xIndex >> 3;
	xMod = ( xIndex & 0x00000007 );
 
	return ( p_cTab[ xDiv ] & ( 1 << xMod ) );
}
 
INLINE
void MGT_M_vSetBit( char *p_cTab , ACP_tdxIndex xIndex )
{
	ACP_tdxIndex xDiv , xMod;
 
	xDiv = xIndex >> 3;
	xMod = ( xIndex & 0x00000007 );
 
	p_cTab[ xDiv ] |= ( 1 << xMod );
}
 
INLINE
void MGT_M_vUnSetBit( char *p_cTab , ACP_tdxIndex xIndex )
{
	ACP_tdxIndex xDiv , xMod;
	char cValue;
 
	xDiv = xIndex >> 3;
	xMod = ( xIndex & 0x00000007 );
	cValue = ~((char)( 1 << xMod ));
	p_cTab[ xDiv ] &= cValue;
}
*/
 
/*
===================================================================================================
 * The main loop in Game Engine to deal with magnet morph.
 *
 *	QZY 1997.11.18
===================================================================================================
*/
void MGT_fn_vTreatMagnets(void)
{
    ACP_tdxIndex						xMagnetIndex , xObjectIndex;
    HIE_tdxHandleToSuperObject          *p_h_SOMagnet;
    MS_tdxHandleToMSMagnet				h_Magnet;
    MTH3D_tdstVector					*p_stPreviousPosition , stCurrentPosition , stMove;
	MTH_tdxReal							xDistance;
    MGT_tdxHandleToModifiedObject       *p_h_ModifiedObject;
    MGT_tdxHandleToMagnetModification   *p_h_MagnetModif;
	ACP_tdxBool							bObjectChanged ;
	unsigned char						ucStatus;
 
	/* update list of influenced points*/
	if( MGT_g_xMaxIndexOfModifiedObject )
	{
		MGT_fn_vInitTreatement();
	}
    for ( xMagnetIndex = 0 , p_h_SOMagnet = MGT_g_aDEF_hActivatedMagnets ;
          xMagnetIndex < MGT_g_xMaxIndexOfActivatedMagnet ; xMagnetIndex++, p_h_SOMagnet++ )
    {
		h_Magnet = (*p_h_SOMagnet) ? M_GetMSHandle( (*p_h_SOMagnet), MSMagnet) : NULL ;
 
        if( h_Magnet )
        {
			ucStatus = fn_lMSMagnetGetStatus( h_Magnet );
 
			if( fn_bMSMagnetIsNearFarModified( h_Magnet ) )
			{
				POS_fn_vGetTranslationVector( HIE_fn_hGetSuperObjectGlobalMatrix( (*p_h_SOMagnet) ), & stCurrentPosition );
				p_stPreviousPosition = fn_hMSMagnetGetPosition( h_Magnet );
				MTH3D_M_vSubVector( & stMove , & stCurrentPosition , p_stPreviousPosition );
				fn_vMSMagnetSetPosition( h_Magnet, & stCurrentPosition );
                MGT_fn_vComputeInfluence( (*p_h_SOMagnet), h_Magnet, xMagnetIndex );
			}
			else
			{
				/* compute movement distance*/
				switch( fn_lMSMagnetGetStatus( h_Magnet ) )
				{
				case MAGNETOFF:
				case MAGNETRECOVERING:
					fn_vMSMagnetSetPositionModification( h_Magnet, FALSE );
					MGT_fn_vUpdateInfluence( h_Magnet , FALSE );
					MGT_fn_vSetMagnetModificationUse( h_Magnet , TRUE );
					break;
				case MAGNETON:
				case MAGNETGROWING:
					POS_fn_vGetTranslationVector( HIE_fn_hGetSuperObjectGlobalMatrix( (*p_h_SOMagnet) ), & stCurrentPosition );
					p_stPreviousPosition = fn_hMSMagnetGetPosition( h_Magnet );
					MTH3D_M_vSubVector( & stMove , & stCurrentPosition , p_stPreviousPosition );
					xDistance = MTH3D_M_xSqrVector( & stMove );
					if( MTH_M_bGreater( xDistance , MGT_C_NoMoveDistanceSqr ) )
					{
						fn_vMSMagnetSetPosition( h_Magnet, & stCurrentPosition );
						fn_vMSMagnetSetPositionModification( h_Magnet, TRUE );
						MGT_fn_vComputeInfluence( (*p_h_SOMagnet), h_Magnet, xMagnetIndex );
					}
					else
					{
					  fn_vMSMagnetSetPositionModification( h_Magnet, FALSE );
						MGT_fn_vSetMagnetModificationUse( h_Magnet , TRUE );
					}
					break;
				}
			}
		}
	}
	if( MGT_g_xMaxIndexOfModifiedObject )
	{
		MGT_fn_vEndTreatement();
	}
 
	/* compute influence*/
    for( xObjectIndex = 0 , p_h_ModifiedObject = MGT_g_aDEF_hModifiedObjects ;
         xObjectIndex < MGT_g_xMaxIndexOfModifiedObject ;
         xObjectIndex++, p_h_ModifiedObject++ )
	{
        if( *p_h_ModifiedObject )
		{
			bObjectChanged   = FALSE;
            for( xMagnetIndex = 0 , p_h_MagnetModif = (*p_h_ModifiedObject) -> aDEF_hMagnet ;
                 xMagnetIndex < MGT_MAX_NUMBEROF_MAGNETS ;
                 xMagnetIndex++, p_h_MagnetModif++ )
			{
                if( *p_h_MagnetModif )
				{
 
                    if( MGT_fn_bMorphMagnetModif( *p_h_MagnetModif ) )
						bObjectChanged = TRUE;
 
				}
			}
			if( bObjectChanged )
			{
                GEO_vEndModifyObject2( (*p_h_ModifiedObject) -> p_stMorphedObject );
			}
		}
	}
	if( MGT_g_xMaxIndexOfModifiedObject )
	{
		/* recompute bounding volume*/
		MGT_fn_bUpdateBoundingVolume();
		/* update ModifiedObjects List*/
		MGT_fn_vUpdateModifiedObjectsList();
	}
	/**/
	if( MGT_g_xMaxIndexOfActivatedMagnet )
	{
		/* update MSMagnet List*/
		MGT_fn_vUpdateActivatedMagnetsList();
	}
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vInitTreatement( void )
{
    ACP_tdxIndex                    xIndex , xIndexMagnet;
    MGT_tdxHandleToModifiedObject   *p_h_ModifiedObject;
    MGT_tdxHandleToMagnetModification   *p_h_MagnetModif;
 
    for( xIndex = 0 , p_h_ModifiedObject = MGT_g_aDEF_hModifiedObjects ;
         xIndex < MGT_g_xMaxIndexOfModifiedObject ;
         xIndex++, p_h_ModifiedObject++ )
    {
        if( *p_h_ModifiedObject )
		{
            MGT_fn_vClearAlreadyInfluencedPointsOfModifiedObject( *p_h_ModifiedObject );
            for ( xIndexMagnet = 0 , p_h_MagnetModif = (*p_h_ModifiedObject) -> aDEF_hMagnet ;
                  xIndexMagnet < MGT_MAX_NUMBEROF_MAGNETS ; xIndexMagnet++, p_h_MagnetModif++ )
            {
                if( (*p_h_MagnetModif) )
					(*p_h_MagnetModif) -> bUsed = FALSE;
            }
		}
    }
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vEndTreatement( void )
{
    ACP_tdxIndex						xIndex , xIndexMagnet;
    MGT_tdxHandleToModifiedObject		*p_h_ModifiedObject;
    MGT_tdxHandleToMagnetModification   *p_h_MagnetModif;
 
    for( xIndex = 0 , p_h_ModifiedObject = MGT_g_aDEF_hModifiedObjects ;
         xIndex < MGT_g_xMaxIndexOfModifiedObject ;
         xIndex++, p_h_ModifiedObject++ )
    {
        if( *p_h_ModifiedObject )
		{
            MGT_fn_vClearAlreadyInfluencedPointsOfModifiedObject( *p_h_ModifiedObject );
            for ( xIndexMagnet = 0 , p_h_MagnetModif = (*p_h_ModifiedObject) -> aDEF_hMagnet ;
                  xIndexMagnet < MGT_MAX_NUMBEROF_MAGNETS ; xIndexMagnet++, p_h_MagnetModif++ )
            {
				if( (*p_h_MagnetModif) )
				{
					if( (*p_h_MagnetModif) -> bUsed )
						break;
					else
						MGT_fn_vDeleteMagnetModification( *p_h_MagnetModif );
				}
            }
			if( xIndexMagnet == MGT_MAX_NUMBEROF_MAGNETS )
				MGT_fn_vDeleteModifiedObjectIfNeeded( xIndex );
		}
    }
 
}
 
/*=======================================================================================
 * Description      compute the influence of magnet in all static objects
 *
 * Creation date    01/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vComputeInfluence( HIE_tdxHandleToSuperObject h_SO , MS_tdxHandleToMSMagnet h_Magnet , ACP_tdxIndex x_Magnet )
{
    /* init influence*/
    ACP_tdxIndex									xIndex;
	MTH_tdxReal										xFar, xFarFar;
	MS_tdxHandleToSectInfo							hSectInfo;
	HIE_tdxHandleToSuperObject						h_SOSector;
	SECT_tdxHandleOfElementLstCollisionInteraction	hCollisionList;
 
    MGT_fn_vUpdateInfluence( h_Magnet , TRUE );
	MGT_fn_vSetMagnetModificationUse( h_Magnet , FALSE );
 
	xFar = fn_xMSMagnetGetFar( h_Magnet );
	xFarFar = MTH_M_xSqr( xFar );
 
	MGT_fn_vClearMagnetModificationFlagInHierarchy( SECT_hFatherSector );
 
	hSectInfo	= M_GetMSHandle( h_SO , SectInfo );
	h_SOSector	= fn_h_SectInfoGetCurrentSector( hSectInfo );
 
 
    /* call recurse influence on Current sector*/
    MGT_fn_bComputeInfluenceOnSuperObject( h_Magnet, x_Magnet, xFarFar, h_SOSector );
    /* call recurse influence on collisionable sectors*/
	SECT_M_ForEachCollisionNodeInCollisionInteractionList( h_SOSector, hCollisionList, xIndex )
	{
		h_SOSector = SECT_GetSectorInCollisionList( hCollisionList );
 
		MGT_fn_bComputeInfluenceOnSuperObject( h_Magnet, x_Magnet, xFarFar, h_SOSector );
	}
 
	/* update MSMagnet*/
	for( xIndex = 0 ; xIndex < MGT_MAX_NUMBEROF_MODIFIEDOBJECTS ; xIndex++ )
	{
		if( fn_hMSMagnetGetMagnetModification( h_Magnet, xIndex ) )
		{
			break;
		}
	}
	if( ( xIndex == MGT_MAX_NUMBEROF_MODIFIEDOBJECTS ) && (fn_lMSMagnetGetStatus( h_Magnet ) == MAGNETRECOVERING) )
	{
		fn_vMSMagnetSetStatus( h_Magnet, MAGNETOFF);
		/* delete the magnet from the active magnet list.*/
        MGT_fn_vDeleteMagnetFromMagnetList( x_Magnet );
	}
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
ACP_tdxIndex MGT_fn_bComputeInfluenceOnSuperObject( MS_tdxHandleToMSMagnet h_Magnet , ACP_tdxIndex x_Magnet , MTH_tdxReal xFarFar, HIE_tdxHandleToSuperObject  h_SuperObject )
{
    GEO_tdstGeometricObject						*p_stObject;
    HIE_tdxHandleToSuperObject					h_Child;
    ACP_tdxIndex								xIndex;
    POS_tdxHandleToPosition						hMatrix;
    POS_tdstCompletePosition					stMatrix;
    MTH3D_tdstVector stMagnetLocalPosition,		*p_stPosition;
    MTH_tdxReal                                 xRadius;
    ACP_tdxIndex                                x_ModifiedObject;
	ACP_tdxBool									bObjectModified , bIntersectBdV, bBoxVolume;
	GEO_tdxHandleToParallelBox					hBoxVolume;
	GEO_tdxHandleToBoundingSphere				hSphereVolume;
    MTH3D_tdstVector                            stMaxBoxPoint , stMinBoxPoint , stCenter;
 
    /* compute influence on the SO*/
	bIntersectBdV	= TRUE;
	bObjectModified = FALSE;
 
	p_stObject		= HIE_fn_p_stGetGeometricObjectFromSuperObject( h_SuperObject );
    if( p_stObject )
    {
		bBoxVolume		 = HIE_fn_SO_bHasABoxBoundingVolume( h_SuperObject );
        x_ModifiedObject = MGT_fn_xFindModifiedObject( p_stObject );
		bObjectModified  = FALSE;
        hMatrix          = HIE_fn_hGetSuperObjectGlobalMatrix( h_SuperObject );
        p_stPosition     = fn_hMSMagnetGetPosition( h_Magnet );
        /**/
		/* take account Bounding Box of SO*/
		if( bBoxVolume )
		{
			hBoxVolume = (GEO_tdxHandleToParallelBox)HIE_fn_hGetSuperObjectBoundingVolume( h_SuperObject );
			if( hBoxVolume )
			{
				MTH3D_M_vAddVector( & stMaxBoxPoint, & hMatrix -> stTranslationVector, GEO_fn_pGetMaxPointOfParallelBox( hBoxVolume ) );
				MTH3D_M_vAddVector( & stMinBoxPoint, & hMatrix -> stTranslationVector, GEO_fn_pGetMinPointOfParallelBox( hBoxVolume ) );
				bIntersectBdV = INT_fn_bIntersectSphereWithBox( p_stPosition, fn_xMSMagnetGetFar( h_Magnet ), & stMinBoxPoint, & stMaxBoxPoint );
			}
			if( bIntersectBdV )
			{
				POS_fn_vInvertMatrix( & stMatrix , hMatrix );
				POS_fn_vMulMatrixVertex( & stMagnetLocalPosition , & stMatrix , p_stPosition );
			}
		}
		else
		{
			hSphereVolume = (GEO_tdxHandleToBoundingSphere)HIE_fn_hGetSuperObjectBoundingVolume( h_SuperObject );
			POS_fn_vInvertMatrix( & stMatrix , hMatrix );
			POS_fn_vMulMatrixVertex( & stMagnetLocalPosition , & stMatrix , p_stPosition );
			if( hSphereVolume )
			{
				MTH3D_M_vCopyVector(&stCenter, GEO_fn_pGetCenterPointOfBoundingSphere(hSphereVolume));
				xRadius = GEO_fn_xGetRadiusOfBoundingSphere(hSphereVolume);
				bIntersectBdV = INT_fn_bIntersectSphereWithSphere( & stMagnetLocalPosition, fn_xMSMagnetGetFar( h_Magnet ), & stCenter , xRadius );
			}
		}
		if( bIntersectBdV )
		{
            bObjectModified = MGT_fn_bComputeInfluenceOnObject( x_Magnet, xFarFar, p_stObject , &x_ModifiedObject, & stMagnetLocalPosition , h_SuperObject );
			if( bObjectModified )
			{
				HIE_fn_vSetMagnetModification( h_SuperObject, TRUE );
			}
		}
        if( (x_ModifiedObject != MGT_C_xIndexError) && ! bObjectModified && ( fn_lMSMagnetGetStatus( h_Magnet ) == MAGNETRECOVERING ) )
		{
            MGT_fn_hDeleteIfExistsMagnetModification( x_ModifiedObject, x_Magnet );
		}
	}
	if( bIntersectBdV )
	{
		/* node examination*/
		HIE_M_ForEachChildOf(h_SuperObject, h_Child, xIndex)
		{
			/* recurence*/
			bObjectModified |= MGT_fn_bComputeInfluenceOnSuperObject( h_Magnet , x_Magnet , xFarFar, h_Child );
		}
	}
	HIE_fn_vSetMagnetModification( h_SuperObject, bObjectModified );
 
	return bObjectModified;
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    01/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vClearMagnetModificationFlagInHierarchy( HIE_tdxHandleToSuperObject  h_SuperObject )
{
    HIE_tdxHandleToSuperObject					h_Child;
    ACP_tdxIndex								xIndex;
 
	HIE_fn_vSetMagnetModification( h_SuperObject, FALSE );
 
	HIE_M_ForEachChildOf(h_SuperObject, h_Child, xIndex)
	{
		/* recurence*/
		MGT_fn_vClearMagnetModificationFlagInHierarchy( h_Child);
	}
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    01/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_bUpdateBoundingVolume( void )
{
    HIE_tdxHandleToSuperObject	h_Child;
    ACP_tdxIndex				xIndex;
 
	HIE_M_ForEachChildOf(SECT_hFatherSector, h_Child, xIndex)
	{
		if( HIE_fn_bGetMagnetModification( h_Child ) )
			MGT_fn_vRecurUpdateBoundingVolumeInHierarchy( h_Child );
	}
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    01/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vRecurUpdateBoundingVolumeInHierarchy( HIE_tdxHandleToSuperObject h_SuperObject )
{
    HIE_tdxHandleToSuperObject		h_Child;
    ACP_tdxIndex					xIndex;
	GEO_tdstGeometricObject		*	hGeometricObject;
	GEO_tdxHandleToParallelBox		hBdVBoxFather;
	GEO_tdxHandleToBoundingSphere	hBdVSphereFather;
	MTH3D_tdstVector			*	p_stGlobalMaxBoxPointFather, *p_stGlobalMinBoxPointFather , stSphereCenterFather;
	ACP_tdxBool						bBdVIsABox;
	MTH_tdxReal						xRadiusFather;
	GEO_tdxHandleToMatrix			hGlobalMatrix;
 
	if( ! HIE_fn_bGetMagnetModification( h_SuperObject ) )
		return;
 
	/* current*/
	/**/
	hGeometricObject = HIE_fn_p_stGetGeometricObjectFromSuperObject( h_SuperObject );
	hGlobalMatrix    = HIE_fn_hGetSuperObjectGlobalMatrix( h_SuperObject );
	bBdVIsABox		 = HIE_fn_SO_bHasABoxBoundingVolume( h_SuperObject );
 
	/* add local bounding volume*/
	/* compute local bounding volume*/
	if( bBdVIsABox )
	{
		hBdVBoxFather	 = (GEO_tdxHandleToParallelBox)HIE_fn_hGetSuperObjectBoundingVolume( h_SuperObject );
		hBdVSphereFather = NULL;
 
		if( hBdVBoxFather )
		{
			p_stGlobalMaxBoxPointFather = GEO_fn_pGetMaxPointOfParallelBox( hBdVBoxFather );
			p_stGlobalMinBoxPointFather = GEO_fn_pGetMinPointOfParallelBox( hBdVBoxFather );
 
			if( hGeometricObject )
			{
				MTH3D_tdstVector stLocalMaxBoxPoint, stLocalMinBoxPoint;
 
				MTH3D_M_vCopyVector(&stLocalMaxBoxPoint, hGeometricObject->d_stListOfPoints);
				MTH3D_M_vCopyVector(&stLocalMinBoxPoint, hGeometricObject->d_stListOfPoints);
 
                MTH3D_M_vMulMatrixVector( p_stGlobalMaxBoxPointFather, &hGlobalMatrix->stTransformMatrix, &stLocalMaxBoxPoint);
                MTH3D_M_vMulMatrixVector( p_stGlobalMinBoxPointFather, &hGlobalMatrix->stTransformMatrix, &stLocalMinBoxPoint);
 
				GEO_fn_vAddObjectToBox(hGeometricObject, hGlobalMatrix, p_stGlobalMaxBoxPointFather, p_stGlobalMinBoxPointFather);
			}
			else
			{
				/* init bdv*/
				MTH3D_M_vNullVector( p_stGlobalMaxBoxPointFather );
				MTH3D_M_vNullVector( p_stGlobalMinBoxPointFather );
			}
		}
	}
	else
	{
		hBdVSphereFather = (GEO_tdxHandleToBoundingSphere)HIE_fn_hGetSuperObjectBoundingVolume( h_SuperObject );
		hBdVBoxFather	 = NULL;
 
		if( hBdVSphereFather )
		{
			MTH3D_M_vCopyVector(&stSphereCenterFather, GEO_fn_pGetCenterPointOfBoundingSphere(hBdVSphereFather));
			xRadiusFather = GEO_fn_xGetRadiusOfBoundingSphere(hBdVSphereFather);
			if( hGeometricObject )
			{
				GEO_fn_vAddObjectToSphere(hGeometricObject, &stSphereCenterFather , & xRadiusFather );
			}
			else
			{
				/* init bdv*/
				MTH3D_M_vNullVector( & stSphereCenterFather );
				xRadiusFather = MTH_C_ZERO;
			}
		}
	}
 
    HIE_M_ForEachChildOf(h_SuperObject, h_Child, xIndex)
    {
        /* compute bounding volume of child chil*/
        MGT_fn_vRecurUpdateBoundingVolumeInHierarchy( h_Child );
/* 
			Now, the bounding volume of a SuperObject doesn't take account the bounding volume of children
 
        // recompute Bounding volume with children
        if( hBdVBoxFather || hBdVSphereFather )
        {
            // take account this bouding volume
			hLocalMatrix = HIE_fn_hGetSuperObjectMatrix( h_Child );
            POS_fn_vGetTranslationVector( hLocalMatrix, &stTranslation );
 
			if( HIE_fn_SO_bHasABoxBoundingVolume( h_Child ) )
			{
				// Child has a Box as Bounding Volume
				GEO_tdxHandleToParallelBox	hBdVBox;
				MTH3D_tdstVector			*p_stGlobalMaxBoxPoint, *p_stGlobalMinBoxPoint;
                MTH3D_tdstVector            stLocalMaxBoxPoint, stLocalMinBoxPoint;
 
				hBdVBox = (GEO_tdxHandleToParallelBox)HIE_fn_hGetSuperObjectBoxBoundingVolume( h_Child );
 
				if( hBdVBox )
				{
					p_stGlobalMaxBoxPoint = GEO_fn_pGetMaxPointOfParallelBox( hBdVBox );
					p_stGlobalMinBoxPoint = GEO_fn_pGetMinPointOfParallelBox( hBdVBox );
 
                    // translate points to father axis
                    MTH3D_M_vAddVector( &stLocalMaxBoxPoint, p_stGlobalMaxBoxPoint, &stTranslation );
                    MTH3D_M_vAddVector( &stLocalMinBoxPoint, p_stGlobalMinBoxPoint, &stTranslation );
 
					if( bBdVIsABox )
					{
						// Father has a Box as Bounding Volume
						// Box = Box + Box
						GEO_fn_vComputeParallelBoxOfTwoBoxes( p_stGlobalMaxBoxPointFather, p_stGlobalMinBoxPointFather,
															  & stLocalMaxBoxPoint, & stLocalMinBoxPoint,
															  p_stGlobalMaxBoxPointFather, p_stGlobalMinBoxPointFather );
					}
					else
					{
						// Father has a Sphere as Bounding Volume
						// Sphere = Sphere + Box
						MTH3D_tdstVector stSphereCenter;
						MTH_tdxReal		 xRadius;
 
						GEO_fn_vGetSphereFromParallelBox( & stSphereCenter , &xRadius, & stLocalMaxBoxPoint, & stLocalMinBoxPoint );
						GEO_fn_vComputeBoundingSphereOfTwoSpheres( & stSphereCenterFather , & xRadiusFather,
																   & stSphereCenterFather ,   xRadiusFather,
																   & stSphereCenter       ,   xRadius      );
					}
				}
			}
			else
			{
				// Child has a Sphere as Bounding Volume
				ACP_tdxHandleOfObject	hBdVSphere;
				MTH3D_tdstVector		stSphereCenter;
				MTH_tdxReal				xRadius;
 
				hBdVSphere = HIE_fn_hGetSuperObjectBoundingVolume( h_Child );
 
				if( hBdVSphere )
				{
					GEO_fn_vGetSphereFromBoundingVolume( & stSphereCenter , &xRadius , hBdVSphere );
                    // translate sphere to father axis
                    MTH3D_M_vAddVector( & stSphereCenter, & stSphereCenter, & stTranslation );
					if( bBdVIsABox )
					{
						// Father has a Box as Bounding Volume
						// Box = Box + Sphere
						COL_fn_vComputeBoundingBoxOfSphereAndBox ( p_stGlobalMinBoxPointFather, p_stGlobalMaxBoxPointFather,
																   & stSphereCenter , xRadius ,
																   p_stGlobalMinBoxPointFather, p_stGlobalMaxBoxPointFather );
					}
					else
					{
						// Father has a Sphere as Bounding Volume
						// Sphere = Sphere + Sphere
						GEO_fn_vComputeBoundingSphereOfTwoSpheres( & stSphereCenterFather , & xRadiusFather,
																   & stSphereCenterFather ,   xRadiusFather,
																   & stSphereCenter       ,   xRadius      );
					}
				}
			}
 
            if( ! bBdVIsABox )
            {
                GEO_fn_vSetSphereToBoundingVolume( & stSphereCenterFather, xRadiusFather, hBdVSphereFather);
            }
		}
*/
	}
}
 
 
/*=======================================================================================
 * Description
 *
 * Creation date    01/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
ACP_tdxBool MGT_fn_bComputeInfluenceOnObject( ACP_tdxIndex x_Magnet, MTH_tdxReal xFarFar, GEO_tdstGeometricObject *p_stObject ,
											  ACP_tdxIndex *p_x_ModifiedObject ,
											  MTH3D_tdstVector *p_stMagnetPosition , HIE_tdxHandleToSuperObject h_SuperObject )
{
    ACP_tdxIndex                        xIndexPoint;
    MTH3D_tdstVector                    *p_stCurrentPoint, stVect;
    MTH_tdxReal                         xDX , xTemp;
    MGT_tdxHandleToMagnetModification   h_MagnetModif;
	ACP_tdxBool							bObjectModified;
 
	bObjectModified	 = FALSE;
	h_MagnetModif	 = NULL;
 
    for ( xIndexPoint = 0 , p_stCurrentPoint = p_stObject -> d_stListOfPoints ; xIndexPoint < p_stObject -> xNbPoints ; xIndexPoint++, p_stCurrentPoint++ )
    {
        MTH3D_M_vSubVector( &stVect , p_stMagnetPosition, p_stCurrentPoint );
        xDX = MTH_M_xSqr( stVect . xX );
        if (MTH_M_bLess( xDX, xFarFar ))
        {
            xTemp = MTH_M_xSqr( stVect . xY );
            xDX   = MTH_M_xAdd( xDX, xTemp );
            if (MTH_M_bLess( xDX, xFarFar ))
            {
                xTemp = MTH_M_xSqr( stVect . xZ );
                xDX   = MTH_M_xAdd( xDX, xTemp );
                if (MTH_M_bLess( xDX, xFarFar ))
                {
                    /* the point is modified*/
                    if( h_MagnetModif == NULL )
                    {
                        /* new object modified*/
                        if( *p_x_ModifiedObject == MGT_C_xIndexError )
                            *p_x_ModifiedObject = MGT_fn_xCreateModifiedObject( p_stObject );
 
                        h_MagnetModif = MGT_fn_hFindOrAddMagnetModification( x_Magnet , *p_x_ModifiedObject , p_stObject );
						if( h_MagnetModif )
						{
							h_MagnetModif -> h_SuperObject = h_SuperObject;
							h_MagnetModif -> bUsed = TRUE;
							bObjectModified = TRUE;
						}
                    }
                    if( h_MagnetModif )
                    {
                        MGT_M_vSetBit( h_MagnetModif -> d_cFieldBitsModifiedPoints , xIndexPoint );
                        MGT_M_vSetBit( h_MagnetModif -> d_cFieldBitsInfluencedPoints , xIndexPoint );
                    }
                }
            }
        }
    }
	return bObjectModified;
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vUpdateInfluence( MS_tdxHandleToMSMagnet h_Magnet, ACP_tdxBool bRecompute )
{
    ACP_tdxIndex						xIndex;
    MGT_tdxHandleToMagnetModification	h_MagnetModif;
 
    for ( xIndex = 0 ; xIndex < MGT_MAX_NUMBEROF_MODIFIEDOBJECTS ; xIndex++ )
    {
        h_MagnetModif = fn_hMSMagnetGetMagnetModification( h_Magnet ,xIndex );
        if( h_MagnetModif )
        {
            MGT_fn_vClearInfluencedPointsOfMagnetModification( h_MagnetModif );
        }
    }
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vSetMagnetModificationUse( MS_tdxHandleToMSMagnet h_Magnet, ACP_tdxBool bUse )
{
    ACP_tdxIndex						xIndex;
    MGT_tdxHandleToMagnetModification	h_MagnetModif;
 
    for ( xIndex = 0 ; xIndex < MGT_MAX_NUMBEROF_MODIFIEDOBJECTS ; xIndex++ )
    {
        h_MagnetModif = fn_hMSMagnetGetMagnetModification( h_Magnet ,xIndex );
        if( h_MagnetModif )
        {
            h_MagnetModif -> bUsed = bUse;
        }
    }
}
 
/*=======================================================================================
 * Description      compute the influence of magnet in all static objects
 *
 * Creation date    01/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
ACP_tdxBool MGT_fn_bMorphMagnetModif( MGT_tdxHandleToMagnetModification h_MagnetModif )
{
    ACP_tdxIndex                xIndexPoint;
    GEO_tdstGeometricObject     *h_Object;
    POS_tdxHandleToPosition     hMatrix;
    POS_tdstCompletePosition    stMatrix;
    MTH3D_tdstVector            stMagnetLocalPosition, *p_stPosition;
	MS_tdxHandleToMSMagnet		h_Magnet;
	MTH_tdxReal					xNear , xFar , xStrength , xInvFarMinusNear , xInvFrames;
	ACP_tdxBool					bChanged , bUnsetPoint , bMagnetModified , bGrowing;
	unsigned long				ulFrameDuration , *p_ulCurrentDuration;
    MTH3D_tdstVector            *p_stOriginalPosition , *p_stCurrentPosition;
    MGT_tdxHandleToModifiedObject   h_ModifiedObject;
    char                            *p_cFieldBitsOfAlreadyInfluencedPoints;
	/**/
	if( ( h_MagnetModif == NULL ) || ! MGT_fn_bIsExistModifiedPointsOnMagnetModification( h_MagnetModif ) )
		return FALSE;
	
    /**/
    h_ModifiedObject					  = MGT_g_aDEF_hModifiedObjects[ h_MagnetModif -> xIndexOfModifiedObject ];
    p_cFieldBitsOfAlreadyInfluencedPoints = h_ModifiedObject -> d_cFieldBitsAlreadyInfluencedPoints;
	ulFrameDuration						  = g_stEngineStructure.stEngineTimer.ulUsefulDeltaTime;
	h_Object							  = h_ModifiedObject -> p_stMorphedObject;	
	if( MGT_g_aDEF_hActivatedMagnets[ h_MagnetModif -> xIndexOfActivatedMagnet ] == NULL )
	{
		for ( xIndexPoint = 0 , p_ulCurrentDuration = h_MagnetModif -> d_ulCurrentDuration , p_stOriginalPosition = h_ModifiedObject -> d_stOriginalPosition , p_stCurrentPosition = h_Object -> d_stListOfPoints ;
		xIndexPoint < h_Object -> xNbPoints ;
		xIndexPoint++, p_ulCurrentDuration++, p_stOriginalPosition++, p_stCurrentPosition++ )
		{
			if(      MGT_M_bIsSetBit( h_MagnetModif -> d_cFieldBitsModifiedPoints , xIndexPoint )		/* the point is modified, recompute influence*/
				&& ! MGT_M_bIsSetBit( h_MagnetModif -> d_cFieldBitsInfluencedPoints , xIndexPoint )		/* the point is currently not influenced by the magnet*/
				&&   ((*p_ulCurrentDuration) > 0)
				)
			{
				(*p_ulCurrentDuration) -= ( (*p_ulCurrentDuration) >= ulFrameDuration ) ? ulFrameDuration : (*p_ulCurrentDuration);
 
				MGT_fn_vComputePreviousPosition( h_MagnetModif, xIndexPoint, p_cFieldBitsOfAlreadyInfluencedPoints,
												 (*p_ulCurrentDuration) , ulFrameDuration ,
												 p_stOriginalPosition , p_stCurrentPosition );
				bChanged = TRUE;
				if( (*p_ulCurrentDuration) == 0 )
				{
					MGT_M_vUnSetBit( h_MagnetModif -> d_cFieldBitsModifiedPoints , xIndexPoint );
					bUnsetPoint = TRUE;
				}
			}
		}
	}
	else if( h_Magnet = M_GetMSHandle( MGT_g_aDEF_hActivatedMagnets[ h_MagnetModif -> xIndexOfActivatedMagnet ], MSMagnet))	/* volontary assignment*/
	{
		bGrowing			= FALSE;
		xFar				= fn_xMSMagnetGetFar(h_Magnet);
		xNear				= fn_xMSMagnetGetNear(h_Magnet);
		xStrength			= fn_xMSMagnetGetStrength(h_Magnet);
		xInvFarMinusNear	= MTH_M_xSub( xFar , xNear );
		bMagnetModified		= fn_bMSMagnetIsNearFarModified (h_Magnet) ||
							  fn_bMSMagnetIsStrengthModified(h_Magnet) ||
							  fn_bMSMagnetIsPositionModified(h_Magnet);
		
		
		if( MTH_M_bDifferentZero( xInvFarMinusNear ) )
			xInvFarMinusNear = MTH_M_xInv( xInvFarMinusNear );
		else
			xInvFarMinusNear = MTH_C_ONE;
		
		xInvFrames = MTH_M_xInv( (float)(h_Magnet -> ulDuration) );
		
		hMatrix = HIE_fn_hGetSuperObjectGlobalMatrix( h_MagnetModif -> h_SuperObject );
		POS_fn_vInvertMatrix( & stMatrix , hMatrix );
		p_stPosition = fn_hMSMagnetGetPosition( h_Magnet );
		POS_fn_vMulMatrixVertex( & stMagnetLocalPosition , & stMatrix , p_stPosition );
		
		h_Object    = h_ModifiedObject -> p_stMorphedObject;
		bChanged    = FALSE;
		bUnsetPoint = FALSE;
		
		for ( xIndexPoint = 0 , p_ulCurrentDuration = h_MagnetModif -> d_ulCurrentDuration , p_stOriginalPosition = h_ModifiedObject -> d_stOriginalPosition , p_stCurrentPosition = h_Object -> d_stListOfPoints ;
		xIndexPoint < h_Object -> xNbPoints ;
		xIndexPoint++, p_ulCurrentDuration++, p_stOriginalPosition++, p_stCurrentPosition++ )
		{
			if( MGT_M_bIsSetBit( h_MagnetModif -> d_cFieldBitsModifiedPoints , xIndexPoint ) )
			{
				/* the point is modified, recompute influence*/
				if( MGT_M_bIsSetBit( h_MagnetModif -> d_cFieldBitsInfluencedPoints , xIndexPoint ) )
				{
					/* the point is currently influenced by the magnet*/
					if( ((*p_ulCurrentDuration) < h_Magnet -> ulDuration) || bMagnetModified )
					{
						(*p_ulCurrentDuration) += ulFrameDuration;
						if( (*p_ulCurrentDuration) > h_Magnet -> ulDuration )
						{
							(*p_ulCurrentDuration) = h_Magnet -> ulDuration;
						}
						MGT_fn_vComputeNewPosition( h_MagnetModif, xIndexPoint, p_cFieldBitsOfAlreadyInfluencedPoints, (*p_ulCurrentDuration) ,
													p_stOriginalPosition , p_stCurrentPosition , p_stPosition ,
													xNear , xStrength , xInvFarMinusNear , xInvFrames);
						bChanged = TRUE;
					}
				}
				else
				{
					/* the point is currently not influenced by the magnet*/
					if( (*p_ulCurrentDuration) > 0 )
					{
						(*p_ulCurrentDuration) -= ( (*p_ulCurrentDuration) >= ulFrameDuration ) ? ulFrameDuration : (*p_ulCurrentDuration);
 
						MGT_fn_vComputePreviousPosition( h_MagnetModif, xIndexPoint, p_cFieldBitsOfAlreadyInfluencedPoints,
														 (*p_ulCurrentDuration) , ulFrameDuration ,
														 p_stOriginalPosition , p_stCurrentPosition );
						bChanged = TRUE;
						if( (*p_ulCurrentDuration) == 0 )
						{
							MGT_M_vUnSetBit( h_MagnetModif -> d_cFieldBitsModifiedPoints , xIndexPoint );
							bUnsetPoint = TRUE;
						}
					}
				}
			}
		}
	}
	else
		return FALSE;
 
	if( bUnsetPoint && ! MGT_fn_bIsExistModifiedPointsOnMagnetModification( h_MagnetModif ) )
	{
		MGT_fn_vDeleteMagnetModification( h_MagnetModif );
	}
	return bChanged;
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vComputeNewPosition( MGT_tdxHandleToMagnetModification h_MagnetModif , ACP_tdxIndex xIndexPoint, char *p_cFieldBitAlreadyInfluenced, unsigned long ulCurrentDuration ,
                                 MTH3D_tdstVector *p_stInitialPosition , MTH3D_tdstVector *p_stCurrentPosition , MTH3D_tdstVector *p_stMagnetPosition ,
								 MTH_tdxReal xNear , MTH_tdxReal xStrength , MTH_tdxReal xInvFarMinusNear , MTH_tdxReal xInvFrames)
{
    MTH_tdxReal                   xDistance , xFrameRatio, xRatio;
	MTH3D_tdstVector			  stVect , stVectA , stVectB ;
 
    xFrameRatio = MTH_M_xMul( (MTH_tdxReal)ulCurrentDuration , xInvFrames ) ;
 
    MTH3D_M_vSubVector( & stVect , p_stMagnetPosition, p_stInitialPosition );
    xDistance = MTH3D_M_xNormVector( & stVect );
 
    MTH3D_M_vNormalizeVector( & stVectB, & stVect );
 
    if( MTH_M_bLess( xDistance , xNear) )
	{
		if( MTH_M_bLess( xDistance , xStrength ) )
			xRatio = MTH_M_xMul( xFrameRatio , xDistance );
		else
			xRatio = MTH_M_xMul( xFrameRatio , xStrength );
	}
	else
	{
		xRatio = MTH_M_xSub( xDistance, xNear );
		xRatio = MTH_M_xMul( xRatio, xInvFarMinusNear );
		xRatio = MTH_M_xSub( MTH_C_ONE, xRatio );
		xRatio = MTH_M_xMul( xRatio, xStrength );
		xRatio = MTH_M_xMul( xRatio, xFrameRatio );
	}
 
	MTH3D_M_vMulScalarVector( & stVectA, xRatio,  & stVectB);
 
    if( MGT_M_bIsSetBit( p_cFieldBitAlreadyInfluenced , xIndexPoint ) )
    {
        /* the point isn't already influenced by another magnet, uses the initial value*/
        MTH3D_M_vAddVector   ( & stVectB , p_stInitialPosition , & stVectA );
        MTH3D_M_vMiddleVector( p_stCurrentPosition , p_stCurrentPosition, & stVectB );
    }
    else
    {
        /* the point is already influenced by another magnet, uses the modified value*/
        MTH3D_M_vAddVector( p_stCurrentPosition , p_stInitialPosition , & stVectA );
        MGT_M_vSetBit( p_cFieldBitAlreadyInfluenced , xIndexPoint );
    }
}
 
/*=======================================================================================
 * Description
 *
 * Creation date    02/03/98
 * Author           Marc Trabucato
 *=====================================================================================*/
void MGT_fn_vComputePreviousPosition( MGT_tdxHandleToMagnetModification h_MagnetModif , ACP_tdxIndex xIndexPoint, char *p_cFieldBitAlreadyInfluenced,
									  unsigned long ulCurrentDuration , unsigned long ulDecreaseDuration ,
									  MTH3D_tdstVector *p_stInitialPosition , MTH3D_tdstVector *p_stCurrentPosition)
{
    MTH_tdxReal                   xFrameRatio;
	MTH3D_tdstVector			  stVect , stVectA , stVectB ;
 
	/* compute previous deformation*/
	MTH3D_M_vSubVector( & stVect, p_stCurrentPosition, p_stInitialPosition );
 
	/* compute previous to current ratio*/
	xFrameRatio = MTH_M_xFloatToReal( ((float)ulCurrentDuration) / ((float)(ulCurrentDuration+ulDecreaseDuration)) );
 
	/* compute current deformation*/
	MTH3D_M_vMulScalarVector( & stVectA, xFrameRatio, & stVect );
 
    if( MGT_M_bIsSetBit( p_cFieldBitAlreadyInfluenced , xIndexPoint ) )
    {
        /* the point is already influenced by another magnet, uses the initial value*/
        MTH3D_M_vAddVector   ( & stVectB , p_stInitialPosition , & stVectA );
        MTH3D_M_vMiddleVector( p_stCurrentPosition , p_stCurrentPosition, & stVectB );
    }
    else
    {
        /* the point isn't already influenced by another magnet, uses the modified value*/
        MTH3D_M_vAddVector( p_stCurrentPosition , p_stInitialPosition , & stVectA );
        MGT_M_vSetBit( p_cFieldBitAlreadyInfluenced , xIndexPoint );
    }
 
}
 
