 
#define PO_FRIEND
#define HieFriend
#define ENV_FRIEND
 
#define D_State_Define
 
#include "ToolsCPA.h"
 
#include "Mor.h" /* AR980213*/
 
#include "Options/Options.h"
#include "Macros.h"
 
#include "Actions/AllActs.h"
 
 
#include "Structur/MemGame.h"
#include "Structur/ErrGame.h"
#include "Structur/Objects.h"
#include "Structur/GameScpt.h"
#include "Structur/StdObjSt.h"
#include "Structur/EngMode.h"
#include "structur/anim_s.h"
#include "Structur/State.h"
 
#include "Basic.h"
#include "GameEng.h"
#include "ObjInit.h"
#include "ZeMem.h"
 
#include "ToolMatr.h"
 
/* anim interpolated*/
#include "ChanList.h"
#include "PlayAnim/Interpol/a3x_intn.h"
#include "playanim\playanim.h"
 
#include "prf.h"
 
#if defined (ACTIVE_EDITOR) || defined (RETAIL)
#define ENGassert(param)
#else
#define ENGassert(param) assert(param)
#endif
 
/*-----------------------------------------------------------------------------
*  Description : Return the channel which contains a SO
*-----------------------------------------------------------------------------
*  Input :         Handle to the list
Handle to the SO
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 25/03/97            Author : Michaël
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
 
#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC */
unsigned short fn_uwGetChannelOfSuperObject(CHN_tdxHandleToChannelArray hChannelArray, HIE_tdxHandleToSuperObject hSO, unsigned long ulNumberOfChannels)
{
	unsigned short i;
 
	for (i=0; i < ulNumberOfChannels; i++)
	{
		if (hChannelArray[i].hSupObject == hSO)
			return i;
	}
	/* The SO isn't found*/
	return C_ucUnknownChannel;
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC */
 
 
/*-----------------------------------------------------------------------------
*  Description : Init a CHN_tdxHandleToCSOList list.
*-----------------------------------------------------------------------------
*  Input :         Pointer on the handle to the list
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 25/03/97            Author : Michaël
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
void fn_vInitCSOList(CHN_tdxHandleToChannelArray *p_hChannelArray, unsigned long ulNumberOfChannels)
{
	unsigned long ulI;
    MMG_fn_vAddMemoryInfo( MMG_C_lTypeGAM , MMG_C_lSubTypeCSO , 0 );
	*p_hChannelArray = (CHN_tdxHandleToChannelArray)TMP_M_p_Malloc(sizeof(tdstAChannel) * ulNumberOfChannels);
/*	memset(*p_hChannelArray,0,sizeof(tdstAChannel) * ulNumberOfChannels); AR9904 Already done in the alloc function */
	for ( ulI = 0 ; ulI < ulNumberOfChannels ; ulI ++ )
		( * p_hChannelArray ) [ ulI ] . bActiveChannel = TRUE ;
 
#if defined(USE_PROFILER) && !defined(PRESS_DEMO)
	if (PRF_fn_lIncIndependantVariable(PRF_C_ulIdpNbAllocCHA,ulNumberOfChannels) > PRF_fn_lGetIndependantVariable(PRF_C_ulIdpNbMaxAllocCHA))
	{
		PRF_fn_vSetIndependantVariable(PRF_C_ulIdpNbMaxAllocCHA,PRF_fn_lGetIndependantVariable(PRF_C_ulIdpNbAllocCHA));
	}
#endif
}
 
/*-----------------------------------------------------------------------------
*  Description : Free a CHN_tdxHandleToCSOList list.
*-----------------------------------------------------------------------------
*  Input :         Pointer on the handle to the list
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 16/08/97            Author : Sebastien DAVID (Gizmo)
*---------------------------------------------------------------------------*/
void fn_vFreeCSOList(CHN_tdxHandleToChannelArray *p_hChannelArray/*, unsigned long ulNumberOfChannels*/)
{
/*	unsigned long i;*/
	CHN_tdxHandleToChannelArray hArray;
#ifndef RETAIL
	long	lSize;
#endif
 
	hArray = *p_hChannelArray;
	if (hArray == NULL)
		return;
	
#ifndef RETAIL
	lSize = *(((long*)hArray)-1);
 
	lSize *= 4;
	lSize /= sizeof(tdstAChannel);
#endif RETAIL
/*	if(hArray == NULL) return; AR9903 Already done ! */
 
 
/*	for (i=0; i<ulNumberOfChannels; i++)
	{
		// clean the channels control matrix
		if (hArray[i].hControlMatrix)
		{
			TMP_M_Free(hArray[i].hControlMatrix);
			hArray[i].hControlMatrix = NULL;
		}
	}
*/	/* and delete the array*/
    MMG_fn_vAddMemoryInfo( MMG_C_lTypeGAM , MMG_C_lSubTypeCSO , 0 );
	TMP_M_Free(hArray);
	hArray = NULL;
	PRF_fn_lIncIndependantVariable(PRF_C_ulIdpNbAllocCHA,-lSize);
}
 
 
/*-----------------------------------------------------------------------------
*  Description : Take the control of a channel. There are 2 types of controls:
*  The modifications could added to the local matrix, or they could overloaded it
*-----------------------------------------------------------------------------
*  Input :         The SO of the character
*					The channel number
*					The type of control
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 27/03/97            Author : Michaël
*-----------------------------------------------------------------------------
*  Modification date :	02 Apr 98        Modification Author : B. Bermain ANNECY BBB
*  Modifications : the UCCList no longer exists: a channel is controlled when the CSO element has a valid handle on an additional matrix
*---------------------------------------------------------------------------*/
void fn_vTakeControlOfChannel(struct tdstEngineObject_ *_hActor, unsigned short _uwChannel, ACP_tdxBool _bControlled)
{
	/* Recover the CSO list of the character*/
	unsigned long ulNbChannels ;
	MS_tdxHandleTo3dData hCurrent3dData = _hActor->h_3dData;
	CHN_tdxHandleToChannelArray hChannelArray = fn_h3dDataGetChannelSOList(hCurrent3dData);
 
	if (hChannelArray == NULL)
	{
		return;
	}

	ulNbChannels = fn_ul3dDataGetNumberOfChannels(hCurrent3dData) ;
 
	if (_uwChannel != 0xffff)
	{
		ENGassert(_uwChannel >= 0 && _uwChannel < ulNbChannels );
		/* loose control of one channel*/
		hChannelArray[_uwChannel].bControlledChannel = _bControlled;
	}
	else
	{
		/* loose control of all channels*/
		tdstAChannel *p_stChannel ;
		unsigned long ulI ;
		for ( ulI = 0 , p_stChannel = hChannelArray ; ulI < ulNbChannels ; ulI ++ , p_stChannel ++ )
		{
			p_stChannel->bControlledChannel = _bControlled;
		}
	}
}
 
/*-----------------------------------------------------------------------------
*  Description : activate a channel
*-----------------------------------------------------------------------------
*  Input :         The SO of the character
*					The channel number
*  Output :        None
*---------------------------------------------------------------------------*/

void fn_vUpdateSPOFlagsOfChannelForActivation(HIE_tdxHandleToSuperObject _hSOChannel, ACP_tdxBool _bActivate)
{
	unsigned long ulSpoFlags ;
	if ( _hSOChannel )
	{
		ulSpoFlags = HIE_M_xGetSuperObjectMember(_hSOChannel , ulFlags);
		if ( _bActivate )
		{
			/* it becomes pickable, visible and shadowable */
			HIE_M_vSetSuperObjectMember(_hSOChannel , ulFlags, ulSpoFlags & ~ ( HIE_C_Flag_ulNotPickable | HIE_C_Flag_ulHidden | HIE_C_Flag_ulNoShadowOnMe ) ) ;
		}
		else
		{
			/* it becomes not pickable, visible or shadowable */
			HIE_M_vSetSuperObjectMember(_hSOChannel , ulFlags, ulSpoFlags | HIE_C_Flag_ulNotPickable | HIE_C_Flag_ulHidden | HIE_C_Flag_ulNoShadowOnMe ) ;
		}
	}
}


void fn_vActivateChannel(HIE_tdxHandleToSuperObject _hPerso , unsigned short _uwChannel , ACP_tdxBool _bActivate )
{
	MS_tdxHandleTo3dData h_3dData = M_GetMSHandle(_hPerso,3dData);
	tdstAChannel *p_stChannel ;
	HIE_tdxHandleToSuperObject hModule ;
	/* Recover the CSO list of the character*/
	unsigned long ulNbChannels ;
	CHN_tdxHandleToChannelArray hChannelArray = fn_h3dDataGetChannelSOList(h_3dData);
 
	if (hChannelArray == NULL)
	{
		return;
	}

	ulNbChannels = fn_ul3dDataGetNumberOfChannels(h_3dData) ;
 
	if (_uwChannel != 0xffff)
	{
		ENGassert(_uwChannel >= 0 && _uwChannel < ulNbChannels );
		/* loose control of one channel*/
		p_stChannel = & hChannelArray [ _uwChannel ] ;
		p_stChannel -> bActiveChannel = _bActivate ;
		hModule = p_stChannel -> hZoomSupObject ? p_stChannel -> hZoomSupObject : p_stChannel -> hSupObject ;
		fn_vUpdateSPOFlagsOfChannelForActivation ( hModule , _bActivate ) ;
#ifndef U64
#ifndef RETAIL
        DEMO_fn_vSaveCanalActivationDesactivation ( _hPerso , ( unsigned char ) _uwChannel , _bActivate ) ;
#endif /* RETAIL */
#endif
	}
	else
	{
		/* loose control of all channels*/
		unsigned long ulI ;
		for ( ulI = 0 , p_stChannel = hChannelArray ; ulI < ulNbChannels ; ulI ++ , p_stChannel ++ )
		{
		p_stChannel = & hChannelArray [ ulI ] ;
		p_stChannel -> bActiveChannel = _bActivate ;
		hModule = p_stChannel -> hZoomSupObject ? p_stChannel -> hZoomSupObject : p_stChannel -> hSupObject ;
		fn_vUpdateSPOFlagsOfChannelForActivation ( hModule , _bActivate ) ;
#ifndef U64
#ifndef RETAIL
	        DEMO_fn_vSaveCanalActivationDesactivation ( _hPerso , ( unsigned char ) _uwChannel , _bActivate ) ;
#endif /* RETAIL */
#endif
		}
	}
}
 
/*-----------------------------------------------------------------------------
*  Description : deactivate a channel
*-----------------------------------------------------------------------------
*  Input :         The SO of the character
*					The channel number
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 27/03/97            Author : Michaël
*-----------------------------------------------------------------------------
*  Modification date :	02 Apr 98		        Modification Author : B. Germain ANNECY BBB
*  Modifications : - the UCC list no longer exists, it is replaced by a handle to the control matrix in the CSO element
- if uwChannel == 0xFFF, all controlled channels are released
*---------------------------------------------------------------------------*/

#ifndef _FIRE_DEADCODE_U64_ /* Added by RUC 04/06/99 */
void fn_vDeactivateChannel(struct tdstEngineObject_ *_hActor, unsigned short _uwChannel)
{
	/* Recover the CSO list of the character*/
	unsigned long ulNbChannels ;
	MS_tdxHandleTo3dData hCurrent3dData = _hActor->h_3dData;
	CHN_tdxHandleToChannelArray hChannelArray = fn_h3dDataGetChannelSOList(hCurrent3dData);
 
	if (hChannelArray == NULL)
	{
		return;
	}

	ulNbChannels = fn_ul3dDataGetNumberOfChannels(hCurrent3dData) ;
 
	if (_uwChannel != 0xffff)
	{
		ENGassert(_uwChannel >= 0 && _uwChannel < ulNbChannels );
		/* loose control of one channel*/
		hChannelArray[_uwChannel].bActiveChannel = FALSE;
	}
	else
	{
		/* loose control of all channels*/
		tdstAChannel *p_stChannel ;
		unsigned long ulI ;
		for ( ulI = 0 , p_stChannel = hChannelArray ; ulI < ulNbChannels ; ulI ++ , p_stChannel ++ )
		{
			p_stChannel->bActiveChannel = FALSE;
		}
	}
}
#endif /* _FIRE_DEADCODE_U64_ */ /* Added by RUC 04/06/99 */

 
/*
 
	if (_uwChannel != 0xffff && hChannelArray[_uwChannel].hControlMatrix)
	{
		// only one channel is requested
		// and it is controled, so loose control
		if (hChannelArray[_uwChannel].hSupObject)
		{
			// update the matrix if we release an active channel !!
			// if the channel is not active, its matrix is NULL anyway...
			// find and give back the animation element matrix to the superobject
			// (that would otherwise reference a nonexistent matrix, ARGH!!!
			tdstState  *p_stCurrentState  = fn_h3dDataGetCurrentState(hCurrent3dData);
			if ( p_stCurrentState )
			{
				struct tdstAnim3d_ *p_stCurrentAnim = p_stCurrentState->p_stAnim;
				if ( p_stCurrentAnim )
				{
					struct tdstFrame3d_ *p_stCurrentFrame3d = fn_p_GetFramesAddress(p_stCurrentAnim,fn_uw3dDataGetCurrentFrame(hCurrent3dData),g_stEngineStructure.stEngineTimer.ulTrameNumber,(void*)fn_h_StandardGameGetSuperObject(_hActor->h_StandardGame));
					if ( p_stCurrentFrame3d )
					{
						struct tdstElement3d_ *p_stCurrentElement3d, *p_stStopElt3d;
 
						p_stCurrentElement3d = p_stCurrentFrame3d->p_stArrayOfElts3d;
						p_stStopElt3d = p_stCurrentElement3d + p_stCurrentAnim->ucMaxNumberOfElements;
 
						// look for the 3d element that correspond to the channel that must be released
						while (p_stCurrentElement3d != p_stStopElt3d)
						{
							if (p_stCurrentElement3d->ucChannelNumber == _uwChannel)
							{
								HIE_fn_vSetSuperObjectMatrix(hChannelArray[_uwChannel].hSupObject, p_stCurrentElement3d->stMatrix);
								break;
							}
							p_stCurrentElement3d++;
						}
					}
				}
			}
		}
		//destroy the control matrix
		TMP_M_Free(hChannelArray[_uwChannel].hControlMatrix);
		//clear the handle in the CSO element
		hChannelArray[_uwChannel].hControlMatrix = NULL;
	}
	else if (_uwChannel == 0xffff)
	{
		// loose control of all channels
 
		tdstState  *p_stCurrentState  = fn_h3dDataGetCurrentState(hCurrent3dData);
		//and give back the animation element matrix to the superobject (that would otherwise reference a nonexistent matrix, ARGH!!!
		if ( p_stCurrentState )
		{
			struct tdstAnim3d_ *p_stCurrentAnim = p_stCurrentState->p_stAnim;
			if ( p_stCurrentAnim )
			{
				struct tdstFrame3d_ *p_stCurrentFrame3d = fn_p_GetFramesAddress(p_stCurrentAnim,fn_uw3dDataGetCurrentFrame(hCurrent3dData),g_stEngineStructure.stEngineTimer.ulTrameNumber,(void*)fn_h_StandardGameGetSuperObject(_hActor->h_StandardGame));
				if ( p_stCurrentFrame3d )
				{
					struct tdstElement3d_ *p_stCurrentElement3d, *p_stStopElt3d;
 
					p_stCurrentElement3d = p_stCurrentFrame3d->p_stArrayOfElts3d;
					p_stStopElt3d = p_stCurrentElement3d + p_stCurrentAnim->ucMaxNumberOfElements;
 
					// look for the 3d element that correspond to the channel that must be released
					while (p_stCurrentElement3d != p_stStopElt3d)
					{
						if (p_stCurrentElement3d->ucChannelNumber != C_ucUnknownChannel)
						{
							if (hChannelArray[p_stCurrentElement3d->ucChannelNumber].hControlMatrix)
							{
								if (hChannelArray[p_stCurrentElement3d->ucChannelNumber].hSupObject )
								{
									HIE_fn_vSetSuperObjectMatrix(hChannelArray[p_stCurrentElement3d->ucChannelNumber].hSupObject, p_stCurrentElement3d->stMatrix);
								}
								//destroy the control matrix
								TMP_M_Free(hChannelArray[p_stCurrentElement3d->ucChannelNumber].hControlMatrix);
								//clear the handle in the CSO element
								hChannelArray[p_stCurrentElement3d->ucChannelNumber].hControlMatrix = NULL;
							}
						}
						p_stCurrentElement3d++;
					}
				}
			}
		}
	}
}
*/
#include "ChanLis1.cxx"
 
/*-----------------------------------------------------------------------------
*  Description : Update the matrix of the controled channels of a character
*-----------------------------------------------------------------------------
*  Input :         The SO of the character
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 27/03/97            Author : Michaël
*-----------------------------------------------------------------------------
*  Modification date :	08/07/97		        Modification Author : CGHT
*  Modifications : Bug correction for absolute mode.
*---------------------------------------------------------------------------*/
/*void fn_vUpdateMatrixOfControledChannels(struct tdstEngineObject_ *_hActor)
{
//	tdstAChannel *p_stChannel;
 
 
// this function is not of any use now, because matrix, controlled or not, are automatically updated...
 
 
 
	// Recover the CSO list of the character
	MS_tdxHandleTo3dData hCurrent3dData;
	CHN_tdxHandleToChannelArray hChannelArray;
	// some variables to scan the CSO list
	unsigned long i;
	POS_tdstCompletePosition *hSource, *hDest;
	MS_tdxHandleToAnimEffect hAnimEffect;
 
	hCurrent3dData = _hActor->h_3dData;
	hChannelArray = fn_h3dDataGetChannelSOList(hCurrent3dData);
	if (!hChannelArray)
		return;
	hAnimEffect = _hActor->h_AnimEffect;
 
	p_stChannel = fn_h3dDataGetFirstActiveChannel(hCurrent3dData);
	i=0;
	while (p_stChannel)
	{
		if (p_stChannel->hControlMatrix)
		{
			hDest = p_stChannel->hControlMatrix;
			hSource = HIE_fn_hGetSuperObjectMatrix(p_stChannel->hSupObject);
			if ( hSource != hDest ) //if we did not already do it
			{
				//copy the current matrix in the control matrix
				POS_fn_vCopyMatrix(hDest, hSource);
				// and give the control matrix to the superobject
				HIE_fn_vSetSuperObjectMatrix(p_stChannel->hSupObject, hDest);
			}
			// if there is an animeffect structure
			if ( hAnimEffect )
			{
				//perform the effects on the controlled channel
				fn_vDoAnimEffect(hAnimEffect, M_GetSuperObject(_hActor), i, p_stChannel->hSupObject);
			}
		}
		i++;
		p_stChannel = p_stChannel->p_stNextActiveChannel;
	}
 
}*/
 
/*-----------------------------------------------------------------------------
*  Description : Create a Morph element
*-----------------------------------------------------------------------------
*  Input :         None
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 12/2/97             Author : alexander
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
tdstMorphChannelList* fn_p_stCreateMorphListElement()
{
    tdstMorphChannelList * p_stMorphList;
 
    MMG_fn_vAddMemoryInfo( MMG_C_lTypeGAM , MMG_C_lSubTypeMorphChannelList , 0 );
    p_stMorphList= (tdstMorphChannelList *) TMP_M_p_Malloc (sizeof (tdstMorphChannelList));
    LST2_M_DynamicInitElement (p_stMorphList);
 
    return p_stMorphList;
}
 
/*-----------------------------------------------------------------------------
*  Description : Free a Morph Channel element
*-----------------------------------------------------------------------------
*  Input :         None
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 12/1/97            Author : alexander
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
void fn_vFreeMorphListElement(tdstMorphChannelList * p_stMorphList)
{
    MMG_fn_vAddMemoryInfo( MMG_C_lTypeGAM , MMG_C_lSubTypeMorphChannelList , 0 );
	TMP_M_Free(p_stMorphList);
}
 
/*-----------------------------------------------------------------------------
*  Description : Init a CHN_tdxHandleToMorphList list.
*-----------------------------------------------------------------------------
*  Input :         Pointer on the handle to the list
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 12/2/97            Author : alexander
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
void fn_vInitMorphList(CHN_tdxHandleToMorphList *p_hMorphList)
{
	if( *p_hMorphList != NULL )
		return;
 
    MMG_fn_vAddMemoryInfo( MMG_C_lTypeGAM , MMG_C_lSubTypeMorphList , 0 );
	* p_hMorphList = (CHN_tdxHandleToMorphList) TMP_M_p_Malloc (sizeof (LST2_M_DynamicAnchorDeclaration(CHN_tdxHandleToMorphElement)));
	LST2_M_DynamicInitAnchor(*p_hMorphList);
}
 
/*-----------------------------------------------------------------------------
*  Description : Free a CHN_tdxHandleToMorphList list.
*-----------------------------------------------------------------------------
*  Input :         Pointer on the handle to the list
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 12/1/97            Author : alexander
*---------------------------------------------------------------------------*/
void fn_vFreeMorphList(CHN_tdxHandleToMorphList *p_hMorphList)
{
	if( *p_hMorphList == NULL ) return;
    while( LST2_M_DynamicGetNumberOfElements(*p_hMorphList) > 0 )
    {
        /* get head*/
        tdstMorphChannelList *p_hMorphElt = LST2_M_DynamicGetFirstElement(*p_hMorphList);
        /* isolate*/
        LST2_M_DynamicIsolate(p_hMorphElt);
        /* free*/
        fn_vFreeMorphListElement(p_hMorphElt);
    }
    MMG_fn_vAddMemoryInfo( MMG_C_lTypeGAM , MMG_C_lSubTypeMorphList , 0 );
	TMP_M_Free(*p_hMorphList);
	*p_hMorphList = NULL;
 
}
 
/*-----------------------------------------------------------------------------
*  Description : Add/change the Morphelement to/of a channel
*-----------------------------------------------------------------------------
*  Input :         Handle to the list
Channel number
Handle to the physical object
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 12/1/97            Author : Alexander
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
void fn_vPutMorphElementInChannel(CHN_tdxHandleToMorphList hMorphList,unsigned short uwChannel,ACP_tdxIndex IndexOfMorphList)
{
	tdstMorphChannelList *p_stMorph,*p_stMorph2;
    unsigned short uwIndex,uwNumOfElts;
 
/*FB190898	*/
	if (!hMorphList) return;
/*ENDFB*/
 
    uwNumOfElts=(unsigned short)LST2_M_DynamicGetNumberOfElements(hMorphList);
    LST2_M_DynamicForEachElementOf(hMorphList,p_stMorph2,uwIndex)
    {
		if (p_stMorph2->uwChannelNumber==uwChannel)
			/* If the channel is already active*/
		{	p_stMorph2->MorphListIndex=IndexOfMorphList;
		break;
		}
		if (p_stMorph2->uwChannelNumber>uwChannel)
			/* The channel will be included before the current channel*/
		{	break;
		}
    }
    if (!p_stMorph2)
		/* If the channel doesn't already active (and end of the list reached)*/
    {
		p_stMorph=fn_p_stCreateMorphListElement();
		p_stMorph->uwChannelNumber=uwChannel;
		p_stMorph->MorphListIndex=IndexOfMorphList;
		LST2_M_DynamicAddTail(hMorphList,p_stMorph);
    }
    else
	{
		if (p_stMorph2->uwChannelNumber!=uwChannel)
			/* If the channel doesn't already active*/
		{
			p_stMorph=fn_p_stCreateMorphListElement();
			p_stMorph->uwChannelNumber=uwChannel;
			p_stMorph->MorphListIndex=IndexOfMorphList;
			LST2_M_DynamicInsertBetween(p_stMorph,LST2_M_DynamicGetPrevElement(p_stMorph2),p_stMorph2);
		}
	}
}
 
/*-----------------------------------------------------------------------------
*  Description : Remove a channel from the list
*-----------------------------------------------------------------------------
*  Input :         Handle to the list
Channel number
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 12/2/97            Author : Alexander
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
void fn_vRemoveChannelFromMorphList(CHN_tdxHandleToMorphList hMorphList,unsigned short uwChannel)
{
    tdstMorphChannelList *p_stMorph,*p_stMorph_Next;
    unsigned short uwIndex;
 
/*FB190898	*/
	if (!hMorphList) return;
/*ENDFB*/
 
	LST2_M_DynamicForEachMovingElementOf(hMorphList,p_stMorph,p_stMorph_Next,uwIndex)
	{
		if (p_stMorph->uwChannelNumber==uwChannel)
		{
			if (!LST2_M_DynamicGetNumberOfElements(hMorphList))  break;
			LST2_M_DynamicIsolate(p_stMorph);
			fn_vFreeMorphListElement(p_stMorph);
			break;
		}
	}
}
 
/*-----------------------------------------------------------------------------
*  Description : Return the MorphListIndex corresponding to a channel
*-----------------------------------------------------------------------------
*  Input :         Handle to the list
Channel number
*  Output :        None
*-----------------------------------------------------------------------------
*  Creation date : 03/25/97            Author : Alexander
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
ACP_tdxIndex fn_hMorphListIndex(CHN_tdxHandleToMorphList hMorphList,unsigned short uwChannel)
{
    tdstMorphChannelList *p_stMorph;
    unsigned short uwIndex;
 
/*FB190898	*/
	if (!hMorphList) return -1;
/*ENDFB*/
 
	LST2_M_DynamicForEachElementOf(hMorphList,p_stMorph,uwIndex)
	{
		if (p_stMorph->uwChannelNumber==uwChannel)
			/* If the channel is found*/
		{	return p_stMorph->MorphListIndex;
		}
		if (p_stMorph->uwChannelNumber>uwChannel)
			/* The channel doesn't exist*/
		{	return -1;
		}
	}
	/* The channel doesn't exist*/
	return -1;
}
 
/*-----------------------------------------------------------------------------
*  Description : Return the PO currently morphed in a specific channel, NULL if none
*-----------------------------------------------------------------------------
*  Input :         Handle to the list
Channel number
*  Output :        PO
*-----------------------------------------------------------------------------
*  Creation date : 01/27/98            Author : Alexis Vaisse
*-----------------------------------------------------------------------------
*  Modification date :			        Modification Author :
*  Modifications :
*---------------------------------------------------------------------------*/
PO_tdxHandleToPhysicalObject fn_hGetMorphedObjectInChannel (CHN_tdxHandleToMorphList hMorphList,unsigned short uwChannel)
{
    ACP_tdxIndex xIndex = fn_hMorphListIndex(hMorphList, uwChannel);
    return xIndex != -1 ? MOR_fn_hGetMorphedObject (xIndex) : NULL;
}
