#include "stdafx.h"
#include "acp_base.h"
#include "ITF.h"
#include "caminter.hpp"
#include "camresrc.h"
#include "camera.hpp"
#include "propert.hpp"
#include "geo.h"
#include "compprop.hpp"

#define M_GetDLL() ((Camera_Interface*)GetEditor())
#define C_PI (float)3.14159265
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////  Camera  /////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

DeclareTemplateStatic(GLI_tdxHandleToCamera); 

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// FBFFBF the del function is temporary (waiting for a camera engine del function)
void del(GLI_tdxHandleToCamera h)
{
}
//fin FBFFBF


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::StaticInit()
{
	// FBFFBF the del function is temporary (waiting for a camera engine del function)
	CPA_EdMot<GLI_tdxHandleToCamera>::Init(NULL,GLI_vCopyCamera,del);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// construct an editor camera from a given camera engine structure 
Camera::Camera(tdeCameraType eType, CPA_ObjectDLLBase *p_oDLL, CPA_MainWorld* p_oMainWorld,GLI_tdxHandleToCamera hObj, CString csName, CString csFileName, CString csSectionName )
    :CPA_BaseObject (p_oDLL , C_szCameraObjectTypeName) ,
	 CPA_EdMot<GLI_tdxHandleToCamera>(hObj)
{

	m_eCameraType = eType;
	
	// name
	SetDefaultUniqueName();

	// axis systems
	m_eRotationAxisSystem = CameraCoordinates;
	m_eTranslationAxisSystem = CameraCoordinates;
	
	//types
	m_eTargetType = tNone;	
	m_eRotationCenterType = rTarget; //= Camera here
	
	// rotation center
	MTH3D_M_vNullVector(&m_stRotationCenterPoint);
	m_eRotationCenterPointCoordsType = Absolute;
	m_p_oRotationCenterSuperObject = NULL;
	
	//target point
	MTH3D_M_vNullVector(&m_stTargetPoint);
	m_p_oTargetSuperObject = NULL;
	
	//don't touch given engine camera

	// device, viewport
	m_bActive = FALSE;
	m_p_oViewPort = NULL;

	// others
	m_p_oActor = NULL;
	m_p_oActorSO = NULL;
	m_dTwistAngle = 0.0;
	m_lTwistRemoveCount = 0;
	m_bPrivilegeMode = TRUE;	

	m_oDialogBar.InitInertCameraDialogBar(this);

	POS_fn_vSetIdentityMatrix(&m_stCameraMatrix);

	UpdateFromEngine();
}
	
//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// construct an editor camera, create the corresponding engine camera
Camera::Camera(tdeCameraType eType, CPA_ObjectDLLBase *p_oDLL, CPA_MainWorld* p_oMainWorld, CString csName, CString csFileName, CString csSectionName )
    :CPA_BaseObject (p_oDLL , C_szCameraObjectTypeName) ,
	 CPA_EdMot<GLI_tdxHandleToCamera>( (GLI_tdxHandleToCamera) NULL )
{
	GLI_tdxHandleToCamera hCamera;

	m_eCameraType = eType;
	POS_fn_vSetIdentityMatrix(&m_stCameraMatrix);

	// name
	SetDefaultUniqueName();

	// axis systems
	m_eRotationAxisSystem = CameraCoordinates;
	m_eTranslationAxisSystem = CameraCoordinates;
	
	//types
	m_eTargetType = tNone;	
	m_eRotationCenterType = rTarget; //= Camera here
	
	// rotation center
	MTH3D_M_vNullVector(&m_stRotationCenterPoint);
	m_eRotationCenterPointCoordsType = Absolute;
	m_p_oRotationCenterSuperObject = NULL;
	
	//target point
	MTH3D_M_vNullVector(&m_stTargetPoint);
	m_p_oTargetSuperObject = NULL;
	
	//engine camera
	GLI_xCreateCamera(&hCamera, GLI_C_lPersCamWithoutDistorsion);
	SetStruct(hCamera);

	// camera_matrix:
	ResetCamera();

	// device, viewport
	m_bActive = FALSE;
	m_p_oViewPort = NULL;

	// others
	m_p_oActor = NULL;
	m_p_oActorSO = NULL;
	m_dTwistAngle = 0.0;
	m_lTwistRemoveCount = 0;
	m_bPrivilegeMode = TRUE;	

	m_oDialogBar.InitInertCameraDialogBar(this);
	
	Update();

	m_oDialogBar.SetCamera(this);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
Camera::Camera(Camera &src) :	CPA_BaseObject(src),
								CPA_EdMot<GLI_tdxHandleToCamera>( (GLI_tdxHandleToCamera) NULL ),
								m_oDialogBar(src.m_oDialogBar)
{
	GLI_tdxHandleToCamera hCamera;

	// name
	SetDefaultUniqueName();
	POS_fn_vSetIdentityMatrix(&m_stCameraMatrix);

	m_eCameraType = src.m_eCameraType;

	m_eRotationAxisSystem = m_eRotationAxisSystem;
	m_eTranslationAxisSystem = src.m_eTranslationAxisSystem;
	
//	m_eRotationCenterType = src.m_eRotationCenterType;
	m_eRotationCenterType = rTarget;
//	m_eTargetType = src.m_eTargetType;
	m_eTargetType = tNone;
	
	MTH3D_M_vCopyVector(&m_stRotationCenterPoint, &src.m_stRotationCenterPoint);
	m_eRotationCenterPointCoordsType = src.m_eRotationCenterPointCoordsType;
//	m_p_oRotationCenterSuperObject = src.m_p_oRotationCenterSuperObject;
	m_p_oRotationCenterSuperObject = NULL;
	
	MTH3D_M_vCopyVector(&m_stTargetPoint,&src.m_stTargetPoint); 
//	m_p_oTargetSuperObject = src.m_p_oTargetSuperObject;
	m_p_oTargetSuperObject = NULL;
	
	GEO_M_vCopyMatrix(&m_stCameraMatrix,&src.m_stCameraMatrix); 
	m_bActive = FALSE;

	GLI_xCreateCamera(&hCamera, GLI_C_lPersCamWithoutDistorsion);
	GLI_vCopyCamera(hCamera,src.GetStruct());
	SetStruct(hCamera);
	
	m_p_oViewPort = NULL;
	
	m_p_oActor = src.m_p_oActor;
	m_p_oActorSO = src.m_p_oActorSO;
	m_dTwistAngle = src.m_dTwistAngle;
	m_lTwistRemoveCount = 0;
	m_bPrivilegeMode = src.m_bPrivilegeMode;	

	m_oDialogBar.SetCamera(this);
	
}



//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
Camera::~Camera()
{
}



//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
/*void Camera::ReInit(GLI_tdxHandleToCamera hCamera)
{
	// axis systems
	m_eRotationAxisSystem = CameraCoordinates;
	m_eTranslationAxisSystem = CameraCoordinates;
	
	//types
	m_eTargetType = tNone;	
	m_eRotationCenterType = rTarget; //= Camera here
	
	// rotation center
	MTH3D_M_vNullVector(&m_stRotationCenterPoint);
	m_eRotationCenterPointCoordsType = Absolute;
	m_p_oRotationCenterSuperObject = NULL;
	
	//target point
	MTH3D_M_vNullVector(&m_stTargetPoint);
	m_p_oTargetSuperObject = NULL;
	
	//engine camera
	GLI_vCopyCamera(GetStruct(),hCamera);

	// device, viewport
	m_bActive = FALSE;
	m_p_oViewPort = NULL;

	// others
	m_p_oActor = NULL;
	m_p_oActorSO = NULL;
	m_p_oToolBarParentWnd = NULL;

	m_oDialogBar.ReInit;

	UpdateFromEngine();
}
*/



///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::CompletePreferences()
{
	HINSTANCE hOldInst;
	CompleteProperties *p_oProperties;
	
	// save dll resource handle
	hOldInst = AfxGetResourceHandle();
    AfxSetResourceHandle( ((CPA_DLLBase*)(GetEditor()))->GetDLLIdentity()->hModule );

	p_oProperties = new CompleteProperties(this);

	if (p_oProperties->DoModal() == IDOK)
	{
		GetMainWorld()->GetInterface()->fn_vUpdateAll(E_mc_JustDraw);
	}
	delete p_oProperties;

    AfxSetResourceHandle( hOldInst );

}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::Preferences()
{
	HINSTANCE hOldInst;
	Properties *p_oProperties;
	
	// save dll resource handle
	hOldInst = AfxGetResourceHandle();
    AfxSetResourceHandle( ((CPA_DLLBase*)(GetEditor()))->GetDLLIdentity()->hModule );

	p_oProperties = new Properties(this);

	if (p_oProperties->DoModal() == IDOK)
	{
		p_oProperties->DoUpdate();
		if (p_oProperties->WantToOpenCompleteProperties())
			CompletePreferences();
		else
			GetMainWorld()->GetInterface()->fn_vUpdateAll(E_mc_JustDraw);
	}
	delete p_oProperties;

    AfxSetResourceHandle( hOldInst );

}

void Camera::FrontView()
{
	SetRotation(0,0,0);
}
void Camera::BackView()
{
	SetRotation(0,0,C_PI);
}
void Camera::LeftView()
{
	SetRotation(0,0,-C_PI/2);
}
void Camera::RightView()
{
	SetRotation(0,0,C_PI/2);
}
void Camera::TopView()
{
	SetRotation(-C_PI/2,0,0);
}
void Camera::BottomView()
{
	SetRotation(C_PI/2,0,0);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::Activate(DEV_ViewPort3D *p_oViewPort, CPA_DialogBar *p_oPopUpParent, CPoint oPos)
{
	m_p_oViewPort = p_oViewPort;
	GLI_xSetViewportCamera(m_p_oViewPort->m_hDisplayDevice,m_p_oViewPort->m_hDisplayViewport,GetStruct());
	m_bActive = TRUE;
	Update();

	m_oDialogBar.Create(p_oPopUpParent,oPos);

	// if the viewport has the focus, then show the new toolbar
	if (m_p_oViewPort->GetFocus() == m_p_oViewPort)
		m_oDialogBar.Show();
	else
		m_oDialogBar.Hide();
}
	
//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::Disactivate()
{
	if (m_bActive)
	{
		m_oDialogBar.Destroy();
		m_p_oViewPort = NULL;
		m_bActive = FALSE;
		//	Update();
	}
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetRotationAxisSystem(tdeAxisSystem eSystem)
{
	if (m_bPrivilegeMode && eSystem != CameraCoordinates)
		return;
	m_eRotationAxisSystem = eSystem;
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetTranslationAxisSystem(tdeAxisSystem eSystem)
{
	if (m_bPrivilegeMode && eSystem != CameraCoordinates)
		return;
	m_eTranslationAxisSystem = eSystem;
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
tdeAxisSystem Camera::GetRotationAxisSystem()
{
	return m_eRotationAxisSystem;
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::GetMatrix(POS_tdstCompletePosition *p_stMatrix)
{
	GEO_M_vCopyMatrix(p_stMatrix,&m_stCameraMatrix); 
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetMatrix(POS_tdstCompletePosition *p_stMatrix)
{
	GEO_M_vCopyMatrix(&m_stCameraMatrix,p_stMatrix); 
	Update();
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
tdeAxisSystem Camera::GetTranslationAxisSystem()
{
	return m_eTranslationAxisSystem;
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
BOOL Camera::SetRotationCenterType(tdeRotationCenterType eRotCenterType)
{
	// if given type is superobject and superobject is null, bad!!!
	if ( (eRotCenterType == rSuperObject) && (m_p_oRotationCenterSuperObject == NULL) )
		return FALSE;
	
	// if rotcenter is the target
	if (eRotCenterType == rTarget)
	{
		// look what is the traget
		switch (m_eTargetType)
		{
		// a point, ok!
		case tPoint:
			m_eRotationCenterType = rTarget;
			return TRUE;
			break;

			// a superobject, ok if so is not NULL
		case tSuperObject:
			if (m_p_oTargetSuperObject == NULL)
				return FALSE;
			else
			{
				m_eRotationCenterType = rTarget;
				return TRUE;
			}
			break;

			// nothing, ok!
		case tNone:
			m_eRotationCenterType = rTarget;
			return TRUE;
		}
		return FALSE;
	}
	else
	{
		m_eRotationCenterType = eRotCenterType;
		return TRUE;
	}
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
tdeRotationCenterType Camera::GetRotationCenterType()
{
	return m_eRotationCenterType;
}
	
//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
BOOL Camera::SetTargetType(tdeTargetType eTargetType)
{
	CPA_PopUpToolBar *p_oToolBar;
	
	if ( (eTargetType == tSuperObject) && (m_p_oTargetSuperObject == NULL) )
		return FALSE;
	
	if ((p_oToolBar = m_oDialogBar.GetToolBar()) != NULL)
	{
		if (m_eTargetType != eTargetType)
		{
			switch(eTargetType)
			{
			case tNone:
				p_oToolBar->SetButton(ID_NOTTARGETED);
				break;
				
			case tSuperObject:
				p_oToolBar->SetButton(ID_SOTARGETED);
				break;
				
			case tPoint:
				p_oToolBar->SetButton(ID_POINTTARGETED);
				break;
			}
		}
		p_oToolBar->UpdateWindow();
	}
	m_eTargetType = eTargetType;
	

	return TRUE;
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
tdeTargetType Camera::GetTargetType()
{
	return m_eTargetType;
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetRotationCenterPoint(CPA_CameraCoords *p_oRotationCenter, tdeCoordsType eType)
{
	//copy coords in the class
	p_oRotationCenter->GetCoords(m_stRotationCenterPoint);

	switch (eType)
	{
	case Absolute:
		// the point is absolute, so in world coordinates
		if (p_oRotationCenter->GetAxisSystem() == CameraCoordinates)
			CameraToWorldCoordinates_Point(m_stRotationCenterPoint);
		break;

	case Relative:
		// the point is relative, so in camera coordinates
		if (p_oRotationCenter->GetAxisSystem() == WorldCoordinates)
			WorldToCameraCoordinates_Point(m_stRotationCenterPoint);
		break;
	}
	m_eRotationCenterPointCoordsType = eType;
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
BOOL Camera::SetRotationCenterSuperObject(CPA_SuperObject *p_oSuperObject)
{
	if (m_eRotationCenterType == rSuperObject && p_oSuperObject == NULL)
		return FALSE;

	m_p_oRotationCenterSuperObject = p_oSuperObject;
	return TRUE;
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetTargetPoint(CPA_CameraCoords *p_oTargetPoint)
{
	// copy coords in the class
	p_oTargetPoint->GetCoords(m_stTargetPoint);

	// the point is always in world coordinates
	if (p_oTargetPoint->GetAxisSystem() == CameraCoordinates)
		CameraToWorldCoordinates_Point(m_stTargetPoint);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::GetTargetPoint(MTH3D_tdstVector &r_stPoint)
{
	MTH3D_M_vCopyVector(&r_stPoint,&m_stTargetPoint);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// result is always in world coordinates
void Camera::GetRotationCenterPoint(MTH3D_tdstVector &r_stPoint, tdeCoordsType &r_eType)
{
	// copy values
	r_eType = m_eRotationCenterPointCoordsType;
	MTH3D_M_vCopyVector(&r_stPoint,&m_stRotationCenterPoint);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
BOOL Camera::SetTargetSuperObject(CPA_SuperObject *p_oSuperObject)
{
	CPA_PopUpToolBar *p_oToolBar;

	if (m_eTargetType == tSuperObject && p_oSuperObject == NULL)
		return FALSE;

	m_p_oTargetSuperObject = p_oSuperObject;

	if ((p_oToolBar = m_oDialogBar.GetToolBar()) != NULL)
	{
		if (m_p_oTargetSuperObject != NULL)
		{
			p_oToolBar->SetPermission(ID_SOTARGETED,TRUE);
		}
		else
		{
			p_oToolBar->SetPermission(ID_SOTARGETED,FALSE);
			p_oToolBar->UpdateWindow();
		}
	}
		
	return TRUE;
}



//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// returns the effective (valid) target type
tdeRotationCenterType Camera::GetEffectiveRotationCenterType()
{
	if (m_eRotationCenterType == rTarget)
	{
		switch (m_eTargetType)
		{
		case tPoint:
			return rTarget;
			break;

		case tSuperObject:
			ASSERT(m_p_oTargetSuperObject != NULL);
			return rTarget;
			break;
			
		case tNone:
			return rCamera;
		
		default:
			ASSERT(0); // rotation center type unknown...
			return rCamera;
		}
	}
	else
	{
		if (m_eRotationCenterType == rSuperObject)
			ASSERT(m_p_oRotationCenterSuperObject != NULL);
		return m_eRotationCenterType;
	}
}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// gets the current target
// if no target valid, return FALSE
// target is always in world coordinates
BOOL Camera::GetTarget(MTH3D_tdstVector &r_stTarget)
{
	ACP_tdxHandleOfObject	hBoundingVolume;
	CPA_BaseObject			*p_oObject;
	MTH_tdxReal				xRadius;
	
	switch (m_eTargetType)
	{
	case tNone:
		return FALSE;
		break;

	case tPoint:
		MTH3D_M_vCopyVector(&r_stTarget,&m_stTargetPoint);
		return TRUE;
		break;

	case tSuperObject:
		ASSERT(m_p_oTargetSuperObject != NULL);
	
		// get the object
		p_oObject = m_p_oTargetSuperObject->GetObject();
		if (p_oObject != NULL)
		{
			// get the bounding volume of the object
			hBoundingVolume = ((CPA_ObjectDLLBase*) (p_oObject->GetEditor()))->fn_hGetBoundingVolume(p_oObject);

			// get the center of the bounding volume
			if (hBoundingVolume != NULL)
			{
				POS_tdstCompletePosition *p_stSOGlobalMatrix;

				p_stSOGlobalMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(m_p_oTargetSuperObject->GetStruct());
//ANNECY TQ 22/06/98{
				GEO_fn_vGetInfoFromGeometricSphere(&r_stTarget,&xRadius,hBoundingVolume);
//ENDANNECY TQ}
				POS_fn_vMulMatrixVertex(&r_stTarget,p_stSOGlobalMatrix,&r_stTarget);
			}
			else
				POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(m_p_oTargetSuperObject->GetStruct()),
										  &r_stTarget);
		}
		else
		{
			POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(m_p_oTargetSuperObject->GetStruct()),&r_stTarget);
		}
		return TRUE;
		break;
	}
	return FALSE;
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// gets the current rotation center
// if center is camera, return FALSE
// center is always in world coordinates
BOOL Camera::GetRotationCenter(MTH3D_tdstVector &r_stCenter)
{
	switch (GetEffectiveRotationCenterType())
	{
	case rCamera:
		return FALSE;
		break;

	case rPoint:
		MTH3D_M_vCopyVector(&r_stCenter,&m_stRotationCenterPoint);
		// if the point is relative, then it's camera coordinates...
		// and we want world coorindates
		if (m_eRotationCenterPointCoordsType == Relative)
			CameraToWorldCoordinates_Point(r_stCenter);
		return TRUE;
		break;

	case rSuperObject:
		POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(m_p_oRotationCenterSuperObject->GetStruct()),
								  &r_stCenter);
		return TRUE;
		break;

	case rTarget:
		return GetTarget(r_stCenter);
	}
	return FALSE;
}




///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////



//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
//rotate the camera around the camera rotation center.
//If axis = custom, axis is considered camera axis, and we perform standard axis relations.
void Camera::Rotate(tdeAxis eAxis, double dAngle)
{
	MTH3D_tdstVector	stRotationCenter, stCameraPos, stTemp;
	POS_tdstCompletePosition stRotMatrix,stTwistRotMatrix,stTempM;
//	double				dTwistAngle;

	POS_fn_vSetIdentityMatrix(&stRotMatrix);
	POS_fn_vSetIdentityMatrix(&stTwistRotMatrix);

	if (!GetRotationCenter(stRotationCenter))
	{
		// rotation center = camera
		POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stRotationCenter);
	}
	else 
	{
		// if rotation center is not camera, the rotation angle
		// must be inversed in every case, but the X axe !
		if (eAxis != X_Custom && eAxis != X_World && eAxis != X_Camera)
			dAngle = -dAngle;
	}

	// if real twist shows that camera is inversed, inverse commands !
	if ( (fabs(GetRealTwistAngle()) > C_PI/2) &&
		 (m_bPrivilegeMode) &&
		 (eAxis == X_Custom || eAxis == Y_Custom) )

		dAngle = -dAngle;

	if (m_bPrivilegeMode)
	{
		m_dTwistAngle = GetRealTwistAngle();
		RemoveTwist();
//		m_dTwistAngle = dTwistAngle;
	}
		


	POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stCameraPos);
	// here, stRotationCenter is a valid point, in world coordinates
	// and stcamerapos contains the camera position

	MTH3D_M_vNullVector(&stTemp);

	if ( (eAxis == X_Custom) || (eAxis == Y_Custom) || (eAxis == Z_Custom) ) 
	{
		// if the given axis is custom, then it is considered camera axis
		// we have to look what is the camera rotation axis system
		// if this default is world, we have to make a camera - world axis relation
		// if we rotate around Y and there is no twist, then Y IS world coordinates
		if ((m_eRotationAxisSystem == WorldCoordinates) ||
			( (eAxis == Y_Custom) && m_bPrivilegeMode))
		{
			double dX,dY,dZ,dMax;
	 		// we build a temporary vector with X, Y or Z set to 1 according to axis
			// then we express this vector in world coordinates, and we look which
			// axis contains a 1 or a -1.
			switch(eAxis)
			{
			case X_Custom:
				MTH3D_M_vSetXofVector(&stTemp,1);
				CameraOriginalToWorldCoordinates(stTemp);
//				CameraToWorldCoordinates_Vector(stTemp);
				break;
				
			case Y_Custom:
				MTH3D_M_vSetYofVector(&stTemp,1);
				CameraOriginalToWorldCoordinates(stTemp);
//				CameraToWorldCoordinates_Vector(stTemp);
				break;
				
			case Z_Custom:
				MTH3D_M_vSetZofVector(&stTemp,1);
				CameraOriginalToWorldCoordinates(stTemp);
//				CameraToWorldCoordinates_Vector(stTemp);
				break;
			}
			
			MTH3D_M_vGetVectorElements(&dX,&dY,&dZ,&stTemp);
			dMax = (fabs(dX) > fabs(dY))? dX : dY;
			if (fabs(dMax) < fabs(dZ)) dMax = dZ;

			if (dMax == dX)
			{
				dAngle = (dX > 0)? dAngle : -dAngle;
				eAxis = X_World;
			}
			else if (dMax == dY)
			{
				dAngle = (dY > 0)? dAngle : -dAngle;
				eAxis = Y_World;
			}
			else if (dMax == dZ)
			{
				dAngle = (dZ > 0)? dAngle : -dAngle;
				eAxis = Z_World;
			}
		}
		else
		{
			//camera rotation axis system is camera coordinates --> ok
			if (eAxis == X_Custom) eAxis = X_Camera;
			if (eAxis == Y_Custom) eAxis = Y_Camera;
			if (eAxis == Z_Custom) eAxis = Z_Camera;
		}
	}
			 
	switch(eAxis)
	{
	case X_World:
	case Y_World:
	case Z_World:
		// substract the rotation center from the camera
		MTH3D_M_vSubVector(&stTemp,&stCameraPos,&stRotationCenter);
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stTemp);
		break;
	case X_Camera:
	case Y_Camera:
	case Z_Camera:
		MTH3D_M_vNullVector(&stTemp);
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stTemp);
		// build the camera->Rotationcenter vector
		MTH3D_M_vSubVector(&stTemp,&stRotationCenter,&stCameraPos);
	}
	
	// compute Rotation Matrix
	switch(eAxis)
	{
	case X_Camera:
	case X_World:
		BuildRotationMatrix_X(stRotMatrix,dAngle);
		break;

	case Y_Camera:
	case Y_World:
		BuildRotationMatrix_Y(stRotMatrix,dAngle);
		break;

	case Z_Camera:
	case Z_World:
		BuildRotationMatrix_Z(stRotMatrix,dAngle);
		break;
	}

	//rotate the camera
	switch(eAxis)
	{
	case X_World:
	case Y_World:
	case Z_World:

		// rotate : rotation matrix * camera
		POS_fn_vSetIdentityMatrix(&stTempM); 
		GEO_M_vCopyMatrix(&stTempM,&m_stCameraMatrix); 
		POS_fn_vMulMatrixMatrix(&m_stCameraMatrix,&stRotMatrix,&stTempM);

		// add back the rotation center to the camera
		POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stTemp);
		MTH3D_M_vAddVector(&stTemp,&stTemp,&stRotationCenter);
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stTemp);
		break;

	case X_Camera:
	case Y_Camera:
		// camera-center vector to camera coords
		WorldToCameraCoordinates_Vector(stTemp);

		//rotate
		POS_fn_vSetIdentityMatrix(&stTempM); 
		GEO_M_vCopyMatrix(&stTempM,&m_stCameraMatrix); 
		POS_fn_vMulMatrixMatrix(&m_stCameraMatrix,&stTempM,&stRotMatrix);

		// camera-center vector to world coords
		CameraToWorldCoordinates_Vector(stTemp);

		// add rotation center to 
		MTH3D_M_vSubVector(&stTemp,&stRotationCenter,&stTemp);

		// put new position
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stTemp);
		break;

	case Z_Camera:

		// camera-center vector to camera coords
		WorldToCameraCoordinates_Vector(stTemp);

		//rotate
		POS_fn_vSetIdentityMatrix(&stTempM); 
		GEO_M_vCopyMatrix(&stTempM,&m_stCameraMatrix); 
		POS_fn_vMulMatrixMatrix(&m_stCameraMatrix,&stTempM,&stRotMatrix);

		// camera-center vector to world coords
		CameraToWorldCoordinates_Vector(stTemp);

		// add rotation center to 
		MTH3D_M_vSubVector(&stTemp,&stRotationCenter,&stTemp);

		// put new position
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stTemp);

		if (m_bPrivilegeMode)
		{
			SetTwist();
			m_dTwistAngle += dAngle;
		}
		break;
	}

	// if rotation center is the camera, then the camera doesn't move!
	if (!GetRotationCenter(stRotationCenter))
	{
		// rotation center = camera
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stRotationCenter);
	}

	if (m_bPrivilegeMode)
		SetTwist();
	Update();
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetRotation(double dAngleX, double dAngleY, double dAngleZ)
{
	MTH3D_tdstVector stCameraPos,stTarget;
	double dDistToTarget;
	BOOL bCameraIsTargeted = FALSE;
	tdeRotationCenterType eRotSave;
	tdeTargetType eTargSave;

	if (m_bPrivilegeMode)
		RemoveTwist();
	//save the camera position
	POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stCameraPos);

	if (GetTarget(stTarget))
	{
		// there's a valid target
		//compute distance to target
		dDistToTarget = MTH3D_M_xVectorGap(&stCameraPos,&stTarget);
		bCameraIsTargeted = TRUE;
	}

	// reset camera to its original state
	ResetCamera();
	// set twist angle to NULL
	if (m_bPrivilegeMode)
		m_dTwistAngle = 0.0;
	// save actual target and rotation center parameters  
	eRotSave = m_eRotationCenterType;
	eTargSave = m_eTargetType;
	// set no target and no rotation center
	m_eRotationCenterType = rCamera;
	m_eTargetType = tNone;

	// rotate the camera
	if (dAngleX != 0)
		Rotate(X_World,dAngleX);
	if (dAngleY != 0)
		Rotate(Y_World,dAngleY);
	if (dAngleZ != 0)
		Rotate(Z_World,dAngleZ);

	// if camera is targeted, move the camera to the right place
	if (bCameraIsTargeted)
	{
		CPA_CameraCoords oCoords;
		// move camera to the target center
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stTarget);
		// translate the camera the right distance from the target
		oCoords.SetXYZ(0,0,(float)-dDistToTarget);
		oCoords.SetAxisSystem(CameraCoordinates);
		Translate(&oCoords);
	}
	else
	{
		//restore camera position
		POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stCameraPos);
	}
	//restore camera parameters
	m_eRotationCenterType = eRotSave;
	m_eTargetType = eTargSave;

	if (m_bPrivilegeMode)
		SetTwist();
	Update();
}





//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// translate the camera. Coords may be camera, world or camera default
// if camera default, cameradefault == world, and not targeted --> intuitive mode
void Camera::Translate(CPA_CameraCoords *p_oOffset, BOOL bUserDefinedAxis)
{
	MTH3D_tdstVector stOffset, stCameraPos;

	if (m_bPrivilegeMode)
		RemoveTwist();
	// we translate the camera...
	// the Offset must be in world coordinates
	p_oOffset->GetCoords(stOffset);
	
	if (bUserDefinedAxis)
	{
		// the translation is camera default...
		// so the coordinates are considered camera coordinates
		if (m_eTranslationAxisSystem == CameraCoordinates)
		{
			// ok, the given coordinates are right. we just have to 
			// express them in world axis system
			CameraToWorldCoordinates_Vector(stOffset);
		}
		else // camera default = world coordinates
		{
			// coordinates are considered camera coordinates
			// but we want a translation along world axis system
			// we will have to make the relation between axis
			if (m_eTargetType == tNone)
			{
				double dX,dY,dZ,dMax,dNorme;

				// no target, so no visual reference --> intuitive mode
				// first, express coordinates in world coordinates
				CameraToWorldCoordinates_Vector(stOffset);
				// compute Norme of the offset
				// this value will be used to build the good offset vector
				dNorme = MTH3D_M_xNormVector(&stOffset);
				//then, look which coord is the greater (absolute value)
				MTH3D_M_vGetVectorElements(&dX,&dY,&dZ,&stOffset);
				dMax = (fabs(dX) > fabs(dY))? dX : dY;
				if (fabs(dMax) < fabs(dZ)) dMax = dZ;
				//then, according to the greater coord, build the good offset vector
				if (dMax == dX)
				{
					dX = (dX > 0) ? dNorme : -dNorme;
					dY = 0;
					dZ = 0;
				}
				else if (dMax == dY)
				{
					dY = (dY > 0) ? dNorme : -dNorme;
					dX = 0;
					dZ = 0;
				}
				else if (dMax == dZ)
				{
					dZ = (dZ > 0) ? dNorme : -dNorme;
					dX = 0;
					dY = 0;
				}
				// here, dX, dY and dZ represent the real offset vector, in
				// world coorinates
				MTH3D_M_vSetVectorElements(&stOffset,(float)dX,(float)dY,(float)dZ);
			}
			else
			{
				// use the standard relation
				//(default : X --> -X; Y --> Z; Z-->Y)
				CameraOriginalToWorldCoordinates(stOffset);
			}
		}
	}
	
	else if (p_oOffset->GetAxisSystem() == CameraCoordinates)
		CameraToWorldCoordinates_Vector(stOffset);
	
	
	
	
	// get camera position
	POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stCameraPos);
	// adds offset
	MTH3D_M_vAddVector(&stCameraPos,&stCameraPos,&stOffset);
	// put back matrix in camera
	POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stCameraPos);
	if (m_bPrivilegeMode)
		SetTwist();
	Update();

//ROMTEAM Scale (Ionut Grozea 12/03/98)
	if ( GetMainWorld()->GetInterface()->fn_bIsScaleActive())
	{
		GetMainWorld()->GetInterface()->fn_vScale();
	}
//ENDROMTEAM Scale (Ionut Grozea)
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// set the camera at a certain position.
void Camera::SetPosition(CPA_CameraCoords *p_oPos)
{
	MTH3D_tdstVector stPos;
	
	// the Offset must be in world coordinates
	if (p_oPos)
	{
		p_oPos->GetCoords(stPos);

		if (p_oPos->GetAxisSystem() == CameraCoordinates)
			CameraToWorldCoordinates_Point(stPos);
	}
	else
	{
		MTH3D_M_vNullVector(&stPos);
	}

	// set the camera position
	POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stPos);

	Update();
}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// Update the camera matrix, according to the target mode.
// the camera may rotate to see the target if necessary.
// Update the engine camera matrix too
void Camera::Update()
{
	MTH3D_tdstVector stTarget;
	
	if (GetTarget(stTarget)) //world coordinates always
		RotateCameraToSeePoint(&stTarget);

	InternalUpdate();
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// Update the camera matrix according to the engine matrix
void Camera::UpdateFromEngine()
{
	InternalBackUpdate();
}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::ZoomOnTarget(CPA_SuperObject *p_oSuperObject)
{
	CPA_BaseObject			*p_oObject;
	ACP_tdxHandleOfObject	hBoundingVolume;
	MTH_tdxReal				xRadius;
	MTH3D_tdstVector		stCenter;
	CPA_CameraCoords		oCoords;
	POS_tdstCompletePosition *p_stSOGlobalMatrix;


	if (m_bPrivilegeMode)
		RemoveTwist();
	// get the object
	if (p_oSuperObject == NULL)
	{
		p_oObject = m_p_oTargetSuperObject->GetObject();
		p_oSuperObject = m_p_oTargetSuperObject;
	}
	else
	{
		p_oObject = p_oSuperObject->GetObject();
	}

	if (p_oObject != NULL)
	{
		// get the bounding volume of the object
		hBoundingVolume = ((CPA_ObjectDLLBase*) (p_oObject->GetEditor()))->fn_hGetBoundingVolume(p_oObject);
		if (hBoundingVolume != NULL)
		{
			MTH_tdxReal			xAlphaX,xRatio;
			float				fD1,fD2;
			
			// get center and radius of target 
//ANNECY TQ 22/06/98{
			GEO_fn_vGetInfoFromGeometricSphere(&stCenter,&xRadius,hBoundingVolume);
//ENDANNECY TQ}
			// compute the right distance to see the object in the window
			GLI_xGetCameraAspectAndRatio(GetStruct(),&xAlphaX,&xRatio);
			fD1 = MTH_M_xRealToFloat(MTH_M_xDiv(xRadius, MTH_M_xTan(MTH_M_xDiv(xAlphaX,2))));
			fD2 = MTH_M_xRealToFloat(MTH_M_xDiv(xRadius, MTH_M_xTan(MTH_M_xDiv(MTH_M_xMul(xAlphaX,xRatio),2))));
			xRadius = ((fD1 > fD2)? fD1 : fD2);

			p_stSOGlobalMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(p_oSuperObject->GetStruct());
			POS_fn_vMulMatrixVertex(&stCenter,p_stSOGlobalMatrix,&stCenter);
			
			//put camera at the same place that the object
			POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stCenter);
			//move back the camera a distance equal to the radius
			oCoords.SetAxisSystem(CameraCoordinates);
			oCoords.SetXYZ(0,0,-xRadius);
			Translate(&oCoords);
		}
		else
		{
			// get superobject position
			p_stSOGlobalMatrix = HIE_fn_hGetSuperObjectGlobalMatrix(p_oSuperObject->GetStruct());
			POS_fn_vGetTranslationVector(p_stSOGlobalMatrix, &stCenter);
			//put camera at the same place that the object
			POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stCenter);
			//move back the camera a distance equal to the radius
			oCoords.SetAxisSystem(CameraCoordinates);
			oCoords.SetXYZ(0,0,-5.0);
			Translate(&oCoords);
		}
	}
	if (m_bPrivilegeMode)
		SetTwist();
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetPrivilegeMode(BOOL bMode)
{
	if (bMode == m_bPrivilegeMode)
		return;
	m_bPrivilegeMode = bMode;
	if (bMode) // from non privilege to privilege...
	{
		m_bPrivilegeMode = TRUE;
		SetRotationAxisSystem(CameraCoordinates);
		SetTranslationAxisSystem(CameraCoordinates);
		ResetTwist();
		Update();
	}
}






///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
////////////// P R I V A T E //////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////


//reset camera, then rotate it to see the point
// the point is world coordinates
void Camera::RotateCameraToSeePoint(MTH3D_tdstVector *p_stTarget)
{
	MTH3D_tdstVector stCamPointVector,stCameraPos,stI,stJ,stK;
	double dAngle,dX,dY,dZ,dTwist;
	tdeRotationCenterType eRotSave;
	tdeTargetType eTargSave;

	// compute the twist angle:
	POS_fn_vGetRotationMatrix(&m_stCameraMatrix,&stI,&stJ,&stK);
	dX = MTH3D_M_xGetZofVector(&stI);
	dY = MTH3D_M_xGetZofVector(&stJ);
	dTwist = atan2(dX,dY);

	if (m_bPrivilegeMode)
		RemoveTwist();

	POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stCameraPos);

	// first, reset camera rotation matrix.
	ResetCameraRotationMatrix();

	// then, compute angles
	// compute camera - point vector
	MTH3D_M_vSubVector(&stCamPointVector,p_stTarget, &stCameraPos);
	// compute rotation around vertical axis
	MTH3D_M_vGetVectorElements(&dX,&dY,&dZ,&stCamPointVector);
	dAngle = atan2(-dX,dY);
	// rotate camera this angle
	eRotSave = m_eRotationCenterType;
	eTargSave = m_eTargetType;
	m_eRotationCenterType = rCamera;
	m_eTargetType = tNone;
	Rotate(Y_Camera,dAngle);

	// the camera just rotates, it doesn't move.
	// so the stCampointVector is still right.
	// but we must take the rotation into account
	WorldToCameraCoordinates_Vector(stCamPointVector);
	//now, stCamPointVector must have its X == 0, and Z >= 0
	MTH3D_M_vGetVectorElements(&dX,&dY,&dZ,&stCamPointVector);

	// compute rotation around camera X axis
	dAngle = -atan2(dY,dZ);
	// rotate camera this angle
	Rotate(X_Camera,dAngle);

	// put back twist angle
	if (m_bPrivilegeMode)
	{
		m_dTwistAngle = dTwist;
		SetTwist();
	}
	else
	{
		Rotate(Z_Camera,dTwist);
	}

	m_eRotationCenterType = eRotSave;
	m_eTargetType = eTargSave;

}




//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::ResetCamera()
{
	MTH3D_tdstVector stVect;

	MTH3D_M_vNullVector(&stVect);
	ResetCameraRotationMatrix();
	
	POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stVect);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::ResetCameraRotationMatrix()
{
	POS_tdstCompletePosition  *p_stWorldBaseMatrix;
	MTH3D_tdstVector stVector;

	// save camera position
	POS_fn_vGetTranslationVector(&m_stCameraMatrix,&stVector);

	// set rotation matrix
	p_stWorldBaseMatrix = &(M_GetMainApp()->m_stWorldBaseMatrix);
	GEO_M_vCopyMatrix(&m_stCameraMatrix,p_stWorldBaseMatrix);

	// restore camera position
	POS_fn_vSetTranslationVector(&m_stCameraMatrix,&stVector);
	POS_fn_vNormalizeMatrix(&m_stCameraMatrix);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// update the engine camera. do nothing else
void Camera::InternalUpdate()
{
	POS_tdstCompletePosition  stMatrix;

	// this function updates the GLI_tdstCamera* camera structure,
	// according to the information in the Camera object

	//invert the camera matrix
	POS_fn_vNormalizeMatrix(&m_stCameraMatrix);
	POS_fn_vInvertIsoMatrix(&stMatrix,&m_stCameraMatrix);
	POS_fn_vNormalizeMatrix(&stMatrix);
	// and set it in the engine camera structure

	GLI_xSetCameraMatrix(GetStruct(),&stMatrix);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
// update the editor camera from the engine camera
void Camera::InternalBackUpdate()
{
	GLI_tdxHandleToCamera	hEngineCamera;
	POS_tdstCompletePosition 			stTemp;

	// this function update the m_stMatrix structure,
	// according to the information in the Camera engine matrix

	// get the engine camera
	hEngineCamera = GetStruct();

	// get the engine camera matrix
	GLI_xGetCameraMatrix(hEngineCamera,&m_stCameraMatrix);

	//invert the camera matrix
	POS_fn_vNormalizeMatrix(&m_stCameraMatrix);
	GEO_M_vCopyMatrix(&stTemp,&m_stCameraMatrix);

	POS_fn_vInvertIsoMatrix(&m_stCameraMatrix,&stTemp);
	POS_fn_vNormalizeMatrix(&m_stCameraMatrix);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::CameraToWorldCoordinates_Point(MTH3D_tdstVector &r_stVector)
{
	MTH3D_tdstVector stVect;

	MTH3D_M_vCopyVector(&stVect,&r_stVector);

	// we receive a point in camera coordinates
	// we must put it in world coordinates
	// (cameramatrix * vector)
	
	POS_fn_vMulMatrixVertex(&r_stVector,&m_stCameraMatrix,&stVect);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::CameraToWorldCoordinates_Vector(MTH3D_tdstVector &r_stVector)
{
	MTH3D_tdstVector stVect;

	MTH3D_M_vCopyVector(&stVect,&r_stVector);

	// we receive a vector in camera coordinates
	// we must put it in world coordinates
	// (camerarotationmatrix  * vector)
	
	POS_fn_vMulMatrixVector(&r_stVector,&m_stCameraMatrix,&stVect);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::CameraOriginalToWorldCoordinates(MTH3D_tdstVector &r_stVector)
{
	MTH3D_tdstVector stVect;
	POS_tdstCompletePosition  stMatrix;

	POS_fn_vSetIdentityMatrix(&stMatrix);
	MTH3D_M_vNullVector(&stVect);

	// get a copy of world base matrix
	GEO_M_vCopyMatrix(&stMatrix,&(M_GetMainApp()->m_stWorldBaseMatrix));
	//set translation to NULL in the copy
	POS_fn_vSetTranslationVector(&stMatrix,&stVect);

	MTH3D_M_vCopyVector(&stVect,&r_stVector);

	// we receive a vector in camera coordinates
	// we must put it in world coordinates
	// (worldbasematrix  * vector)
	
	POS_fn_vMulMatrixVertex(&r_stVector,&stMatrix,&stVect);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::WorldToCameraCoordinates_Point(MTH3D_tdstVector &r_stVector)
{
	MTH3D_tdstVector stVect;
	POS_tdstCompletePosition  stMatrix;

	MTH3D_M_vCopyVector(&stVect,&r_stVector);

	// we receive a point in world coordinates
	// we must put it in camera coordinates
	// (invertcameramatrix * vector)
	POS_fn_vInvertIsoMatrix(&stMatrix,&m_stCameraMatrix);
	POS_fn_vMulMatrixVertex(&r_stVector,&stMatrix,&stVect);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::WorldToCameraCoordinates_Vector(MTH3D_tdstVector &r_stVector)
{
	MTH3D_tdstVector stVect;
	POS_tdstCompletePosition  stMatrix;

	MTH3D_M_vNullVector(&stVect);

	// get inverse of camera matrix
	POS_fn_vInvertIsoMatrix(&stMatrix,&m_stCameraMatrix);

	//set translation to NULL in the copy
	POS_fn_vSetTranslationVector(&stMatrix,&stVect);

	MTH3D_M_vCopyVector(&stVect,&r_stVector);

	// we receive a vector in world coordinates
	// we must put it in camera coordinates
	// (invertcamerarotationmatrix  * vector)
	POS_fn_vMulMatrixVertex(&r_stVector,&stMatrix,&stVect);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::WorldToCameraOriginalCoordinates(MTH3D_tdstVector &r_stVector)
{
	MTH3D_tdstVector stVect;
	POS_tdstCompletePosition  stMatrix;

	MTH3D_M_vNullVector(&stVect);

	// get inverse of world base matrix
	POS_fn_vInvertIsoMatrix(&stMatrix,&(M_GetMainApp()->m_stWorldBaseMatrix));

	//set translation to NULL in the copy
	POS_fn_vSetTranslationVector(&stMatrix,&stVect);

	MTH3D_M_vCopyVector(&stVect,&r_stVector);

	// we receive a vector in world coordinates
	// we must put it in camera coordinates
	// (invertworldbasematrix  * vector)
	POS_fn_vMulMatrixVertex(&r_stVector,&stMatrix,&stVect);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::BuildRotationMatrix_X( POS_tdstCompletePosition  &r_stMatrix, double xXAngle )
{
// build a rotation matrix
	MTH3D_tdstVector stVectI,stVectJ,stVectK;
	MTH_tdxReal	xReal;

	xReal = MTH_M_xDoubleToReal(xXAngle);

	POS_fn_vSetIdentityMatrix(&r_stMatrix);

	POS_fn_vGetRotationMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);
	MTH3D_M_vSetYofVector(&stVectJ,GLI_M_Cos(xReal));
	MTH3D_M_vSetZofVector(&stVectJ,GLI_M_Sin(xReal));
	MTH3D_M_vSetYofVector(&stVectK,GLI_M_Neg(GLI_M_Sin(xReal)));
	MTH3D_M_vSetZofVector(&stVectK,GLI_M_Cos(xReal));
	POS_fn_vSetRotationMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);

	// STM - camera's never have scale, so this shouldn't be needed
	POS_fn_vSetTransformMatrix (&r_stMatrix,&stVectI,&stVectJ,&stVectK);


}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::BuildRotationMatrix_Y( POS_tdstCompletePosition  &r_stMatrix, double xYAngle )
{
// build a rotation matrix
	MTH3D_tdstVector stVectI,stVectJ,stVectK;
	MTH_tdxReal	xReal;

	xReal = MTH_M_xDoubleToReal(xYAngle);

	POS_fn_vSetIdentityMatrix(&r_stMatrix);

	POS_fn_vGetRotationMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);
	MTH3D_M_vSetXofVector(&stVectI,GLI_M_Cos(xReal));
	MTH3D_M_vSetXofVector(&stVectK,GLI_M_Sin(xReal));
	MTH3D_M_vSetZofVector(&stVectI,GLI_M_Neg(GLI_M_Sin(xReal)));
	MTH3D_M_vSetZofVector(&stVectK,GLI_M_Cos(xReal));
	POS_fn_vSetRotationMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);

	// STM - camera's never have scale, so this shouldn't be needed
	POS_fn_vSetTransformMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);
}

//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::BuildRotationMatrix_Z( POS_tdstCompletePosition  &r_stMatrix, double xZAngle )
{
// build a rotation matrix
	MTH3D_tdstVector stVectI,stVectJ,stVectK;
	MTH_tdxReal	xReal;

	xReal = MTH_M_xDoubleToReal(xZAngle);

	POS_fn_vSetIdentityMatrix(&r_stMatrix);

	POS_fn_vGetRotationMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);
	MTH3D_M_vSetXofVector(&stVectI,GLI_M_Cos(xReal));
	MTH3D_M_vSetYofVector(&stVectI,GLI_M_Sin(xReal));
	MTH3D_M_vSetXofVector(&stVectJ,GLI_M_Neg(GLI_M_Sin(xReal)));
	MTH3D_M_vSetYofVector(&stVectJ,GLI_M_Cos(xReal));
	POS_fn_vSetRotationMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);

	// STM - camera's never have scale, so this shouldn't be needed
	POS_fn_vSetTransformMatrix(&r_stMatrix,&stVectI,&stVectJ,&stVectK);
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::RemoveTwist()
{
	POS_tdstCompletePosition 	stTwistRotMatrix,stTemp;

	if (m_lTwistRemoveCount == 0)
	{
		POS_fn_vSetIdentityMatrix(&stTemp); 
		GEO_M_vCopyMatrix(&stTemp,&m_stCameraMatrix); 
		// remove the camera twist :
		BuildRotationMatrix_Z(stTwistRotMatrix,-m_dTwistAngle);
		POS_fn_vMulMatrixMatrix(&m_stCameraMatrix,&stTemp,&stTwistRotMatrix);
	}
	m_lTwistRemoveCount++;
}


//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::SetTwist()
{
	POS_tdstCompletePosition 	stTwistRotMatrix,stTemp;

	if (m_lTwistRemoveCount == 0)
		return;

	if (m_lTwistRemoveCount == 1)
	{
		POS_fn_vSetIdentityMatrix(&stTemp); 
		GEO_M_vCopyMatrix(&stTemp,&m_stCameraMatrix); 
		// put back the camera twist :
		BuildRotationMatrix_Z(stTwistRotMatrix,m_dTwistAngle);
		POS_fn_vMulMatrixMatrix(&m_stCameraMatrix,&stTemp,&stTwistRotMatrix);
	}
	m_lTwistRemoveCount--;
}



//********************************************************************************************************
//********************************************************************************************************
//********************************************************************************************************
void Camera::ResetTwist()
{
	m_dTwistAngle = GetRealTwistAngle();
	RemoveTwist();
	m_dTwistAngle = 0.0;
	SetTwist();
}


double Camera::GetRealTwistAngle()
{
	MTH3D_tdstVector stI,stJ,stK;
	double dX,dY;

	POS_fn_vGetRotationMatrix(&m_stCameraMatrix,&stI,&stJ,&stK);
	dX = MTH3D_M_xGetZofVector(&stI);
	dY = MTH3D_M_xGetZofVector(&stJ);
	return atan2(dX,dY);
}

