//-------------------------------------------------------------
//  Gestion des deplacements en 3d a l'aide de la souris.
// Olivier Didelot le 15 decembre 1995.
// modification : Marc Villemain le 04/07/96 : adaptation ACP
//-------------------------------------------------------------

#include "MTH.h"
#include "Acp_base.h"
#include "Cpa_std.h"
#include "HDL.h"
#include "POS.h"
#include "GMT.h"
#include "GEO.h"
#include "COL.h"
#include "GLI.h"
#include "PIC.h"

typedef enum 
{ 
  ECRAN = 0 , 
    MAP
} tdeTContrainte ;



#ifdef ACTIVE_EDITOR
static tdeTContrainte sTypeContrainte = ECRAN;
static GLI_tdst2DVertex stMouse2DPrec;
static MTH3D_tdstVector stPointMobil;
static GLI_tdstCamera *p_stCamPrec;
static BOOL gOkPourDeplacement = FALSE ;
static POS_tdstCompletePosition stMatrixPrec;
static GLD_tdhDevice g_hDev;
static GLD_tdhViewport g_hVp;
#endif
//***************************************************************************
// Definition of the plan as a non define plan.
//***************************************************************************
#ifdef ACTIVE_EDITOR
void PIC_vCreatePlan ( PIC_tdstEqPlan *p_stPlan )
{
  p_stPlan -> xA = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xB = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xC = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xD = GLI_M_FloatToValue ( 0.0 ) ;
}
#endif
//***************************************************************************
// Return true if the plan is undefine.
//***************************************************************************
#ifdef ACTIVE_EDITOR
BOOL PIC_cIsPlanNull ( PIC_tdstEqPlan *p_stPlan )
{
  return ( (p_stPlan -> xA == GLI_M_FloatToValue ( 0.0 ) ) 
    && (p_stPlan -> xB == GLI_M_FloatToValue ( 0.0 ) )
    && (p_stPlan -> xC == GLI_M_FloatToValue ( 0.0 ) )
    && (p_stPlan -> xD == GLI_M_FloatToValue ( 0.0 ) ) ) ;
}
#endif
//***************************************************************************
//  Definition of the plan thanks to his equation :
// a.x+b.y+c.z+d=0
//***************************************************************************
#ifdef ACTIVE_EDITOR
void PIC_vDefinePlanEquation ( PIC_tdstEqPlan *p_stPlan ,
                              GLI_tdxValue xA ,
                              GLI_tdxValue xB ,
                              GLI_tdxValue xC , 
                              GLI_tdxValue xD )
{
  p_stPlan -> xA = xA ;
  p_stPlan -> xB = xB ;
  p_stPlan -> xC = xC ;
  p_stPlan -> xD = xD ;
}
#endif
//***************************************************************************
//  Definition of the plan by a normal and a point.
//***************************************************************************
#ifdef ACTIVE_EDITOR
void PIC_vDefinePlanByNormale ( PIC_tdstEqPlan *p_stPlan ,
                               MTH3D_tdstVector *p_stNormal, 
                               MTH3D_tdstVector *p_stPoint )
{
  p_stPlan -> xA = p_stNormal -> xX ;
  p_stPlan -> xB = p_stNormal -> xY ;
  p_stPlan -> xC = p_stNormal -> xZ ;
  p_stPlan -> xD = GLI_M_Neg ( GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xA ,
                                                       p_stPoint -> xX ) ,
                                           GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xB ,
                                                                   p_stPoint -> xY ) ,
                                                       GLI_M_Mul ( p_stPlan -> xC ,
                                                                   p_stPoint -> xZ ) ) ) ) ;
}
#endif
//***************************************************************************
//  Definition of the plan by 3 points.
//***************************************************************************
#ifdef ACTIVE_EDITOR
void PIC_vDefinePlanBy3Points ( PIC_tdstEqPlan *p_stPlan ,
                               MTH3D_tdstVector *p_stA, 
                               MTH3D_tdstVector *p_stB, 
                               MTH3D_tdstVector *p_stC )
{
  MTH3D_tdstVector stNormal ;
  
  GEO_xComputeNormalWeightedBySurf ( &stNormal , p_stA , p_stB , p_stC ) ;
  PIC_vDefinePlanByNormale ( p_stPlan , &stNormal, p_stA ) ;
}
#endif
//***************************************************************************
//  Definition of the plan as a perpendicular to the Z axe (horizontal plan),
// and passing through the point (0, 0, Zo).
//***************************************************************************
#ifdef ACTIVE_EDITOR
void fn_vDefinePlanZConstant ( PIC_tdstEqPlan *p_stPlan ,
                              GLI_tdxValue stZConstant )
{
  p_stPlan -> xA = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xB = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xC = GLI_M_FloatToValue ( 1.0 ) ;
  p_stPlan -> xD = GLI_M_Neg ( stZConstant ) ;
}
#endif
//***************************************************************************
//  Definition of the plan as a perpendicular to the Y axe (vertical plan),
// and passing through the point (0, Yo, 0).
// Yo is a "long 1616".
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
void fn_vDefinePlanYConstant ( PIC_tdstEqPlan *p_stPlan ,
                              GLI_tdxValue stYConstant )
{
  p_stPlan -> xA = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xB = GLI_M_FloatToValue ( 1.0 ) ;
  p_stPlan -> xC = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xD = GLI_M_Neg ( stYConstant ) ;
}
#endif
//***************************************************************************
//  Definition of the plan as a perpendicular to the X axe (vertical plan),
// and passing through the point (Xo, 0, 0).
// Xo is a "long 1616".
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
void fn_vDefinePlanXConstant ( PIC_tdstEqPlan *p_stPlan ,
                              GLI_tdxValue stXConstant )
{
  p_stPlan -> xA = GLI_M_FloatToValue ( 1.0 ) ;
  p_stPlan -> xB = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xC = GLI_M_FloatToValue ( 0.0 ) ;
  p_stPlan -> xD = GLI_M_Neg ( stXConstant ) ;
}
#endif
//***************************************************************************
//  Modify equation of a plan : the plan become parallel to himself but he
// passes through a particular point.
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
void fn_vRecalePlanPoint ( PIC_tdstEqPlan *p_stPlan ,
                          MTH3D_tdstVector *p_stPoint )
{
  // On ne recalcul que le parametre xD.
  p_stPlan -> xD = GLI_M_Neg ( GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xA ,
    p_stPoint -> xX ) ,
    GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xB ,
    p_stPoint -> xY ) ,
    GLI_M_Mul ( p_stPlan -> xC ,
    p_stPoint -> xZ ) ) ) ) ;
}
#endif
//***************************************************************************
//  Intersection between a plan and a line.
// Input:
//         p_stA, p_stB --> The line.
// Output:
//         p_stInter    --> Intersection point.
//         Return TRUE if the Intersection exist, FALSE otherwise.
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
BOOL PIC_bIntersectionPlanDroite ( PIC_tdstEqPlan *p_stPlan ,
                                  MTH3D_tdstVector *p_stA ,
                                  MTH3D_tdstVector *p_stB ,
                                  MTH3D_tdstVector *p_stInter )
{
  GLI_tdxValue xReturnEqA , xReturnEqAB , xDivReturnEq ;
  MTH3D_tdstVector stAB ;
  
  MTH3D_M_vSubVector ( &stAB, p_stB, p_stA ) ;
  
  xReturnEqA = GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xA ,
                                       p_stA -> xX ) ,
                           GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xB ,
                                                   p_stA -> xY ) ,
                                       GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xC ,
                                                               p_stA -> xZ ) ,
                                                   p_stPlan -> xD ) ) ) ;
  
  xReturnEqAB = GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xA ,
                                        stAB . xX ) ,
                            GLI_M_Add ( GLI_M_Mul ( p_stPlan -> xB ,
                                                    stAB . xY ) ,
                                        GLI_M_Mul ( p_stPlan -> xC ,
                                                    stAB . xZ ) ) ) ;
  
  if ( xReturnEqAB == GLI_M_FloatToValue ( 0.0 ) ) /* le vecteur AB est dans le plan */
    return FALSE ;
  
  xDivReturnEq = GLI_M_Neg ( GLI_M_Div ( xReturnEqA , xReturnEqAB ) ) ;
  
  p_stInter->xX = GLI_M_Add ( p_stA -> xX ,
    GLI_M_Mul( xDivReturnEq , 
    GLI_M_Sub ( p_stB -> xX ,
    p_stA -> xX ) ) ) ;
  p_stInter->xY = GLI_M_Add ( p_stA -> xY ,
    GLI_M_Mul( xDivReturnEq , 
    GLI_M_Sub ( p_stB -> xY ,
    p_stA -> xY ) ) ) ;
  p_stInter->xZ = GLI_M_Add ( p_stA -> xZ ,
    GLI_M_Mul( xDivReturnEq , 
    GLI_M_Sub ( p_stB -> xZ ,
    p_stA -> xZ ) ) ) ;
  
  return TRUE ;
}
#endif

// Defini le plan de contrainte comme etant perpendiculaire a l'axe Z de la camera,
// et passant par le point P.
#ifdef ACTIVE_EDITOR
// active editor only
void fn_vDefScreenConstraint ( PIC_tdstEqPlan *p_stPlan ,
                              MTH3D_tdstVector *p_stPoint )
{
  MTH3D_tdstVector stAxeCameraZ, stTemp;
  POS_tdstCompletePosition stMatrix, stInvMatrix;
  
  POS_fn_vSetIdentityMatrix(&stMatrix);
  POS_fn_vSetIdentityMatrix(&stInvMatrix);
  GLI_xGetCameraMatrix ( p_stCamPrec , &stMatrix );
  POS_fn_vInvertIsoMatrix( &stInvMatrix , &stMatrix );  
  stTemp . xX = GLI_M_FloatToValue ( 0.0 );
  stTemp . xY = GLI_M_FloatToValue ( 0.0 );
  stTemp . xZ = GLI_M_FloatToValue ( 1.0 );
  POS_fn_vMulMatrixVertex( &stAxeCameraZ , &stInvMatrix , &stTemp );
  POS_fn_vGetTranslationVector( &stInvMatrix , &stTemp );
  MTH3D_M_vSubVector( &stAxeCameraZ, &stAxeCameraZ, &stTemp);
  
  PIC_vDefinePlanByNormale ( p_stPlan , &stAxeCameraZ , p_stPoint );
}
#endif
//***************************************************************************
//  Definition of the constraint plan, thanks to CONTRAINTE and point wich is
// defined by the editor (p_stPoint).
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
void fn_vDefPlanConstraint ( PIC_tdstEqPlan *p_stPlan ,
                            MTH3D_tdstVector *p_stPoint )
{
  switch (sTypeContrainte)
  {
  case MAP :
    break;
    
  case ECRAN :
    fn_vDefScreenConstraint ( p_stPlan , p_stPoint ) ;
    break ;
  }
  
}
#endif
//***************************************************************************
//  Calculate the mouse 3d position. The calculated point is the intersection
// between line [camera position; 3d Mouse (on screen)] and constraint plan.
// Return 1 if the intersection exist, 0 otherwise.
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
BOOL fn_bCalculateMouse3DConstraint
(
	PIC_tdstEqPlan *p_stPlan,
  GLI_tdst2DVertex *p_stPoint2D,
  MTH3D_tdstVector *p_stPoint3D
)
{
  MTH3D_tdstVector stPosMouse, stPosCam;
  POS_tdstCompletePosition stMatrix, stInvMatrix;
  
  PIC_vMouse3DScreen ( g_hDev, g_hVp, p_stPoint2D , &stPosMouse);
  
  if(  p_stCamPrec->lCameraMode == GLI_C_lPersCamWithDistorsion 
    || p_stCamPrec->lCameraMode == GLI_C_lPersCamWithoutDistorsion )
  {
    POS_fn_vSetIdentityMatrix(&stMatrix); //AR980624 A position MUST be initialised !
    POS_fn_vSetIdentityMatrix(&stInvMatrix);
    GLI_xGetCameraMatrix ( p_stCamPrec, &stMatrix ) ;
    POS_fn_vInvertIsoMatrix( &stInvMatrix , &stMatrix );  
    POS_fn_vGetTranslationVector( &stInvMatrix , &stPosCam ) ;
  }
  else if(  p_stCamPrec->lCameraMode == GLI_C_lIsoCamWithDistorsion 
    || p_stCamPrec->lCameraMode == GLI_C_lIsoCamWithoutDistorsion )
  {
    MTH3D_tdstVector stAxeCameraZ, stTemp;
  
    GLI_xGetCameraMatrix ( p_stCamPrec , &stMatrix );
    POS_fn_vInvertIsoMatrix( &stInvMatrix , &stMatrix );  
    stTemp . xX = GLI_M_FloatToValue ( 0.0 );
    stTemp . xY = GLI_M_FloatToValue ( 0.0 );
    stTemp . xZ = GLI_M_FloatToValue ( 1.0 );
    POS_fn_vMulMatrixVertex( &stAxeCameraZ , &stInvMatrix , &stTemp );

    MTH3D_M_vSubVector( &stPosCam, &stPosMouse, &stAxeCameraZ);
  }
  
  return PIC_bIntersectionPlanDroite ( p_stPlan , &stPosCam , &stPosMouse , p_stPoint3D ) ;
}
#endif
//***************************************************************************
//  Calculate the mouse 3d position. The calculated point is on the map.
// Return 1 if this position exist, 0 otherwise.
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
BOOL fn_bCalculateMouse3DMap( GLI_tdst2DVertex *p_stPoint2D ,
                             MTH3D_tdstVector *p_stPoint3D )
{
  return FALSE ;
}
#endif

//***************************************************************************
//  Calculate the mouse 3d position.
// Return 1 if this position exist, 0 otherwise.
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
BOOL fn_bCalculateMouse3D ( PIC_tdstEqPlan *p_stPlan ,
                           GLI_tdst2DVertex *p_stPoint2D ,
                           MTH3D_tdstVector *p_stPoint3D )
{
  switch (sTypeContrainte)
  {
  case MAP :
    return fn_bCalculateMouse3DMap ( p_stPoint2D , p_stPoint3D ) ;
    
  case ECRAN :
  default :
    return fn_bCalculateMouse3DConstraint ( p_stPlan , p_stPoint2D , p_stPoint3D ) ;
  }
}
#endif
//***************************************************************************
//  Calculate the moving vector of 3d Mouse. This moving is constraint by the 
// plan PlanC in the constraint mode else the moving is in the screen plan.
//***************************************************************************
#ifdef ACTIVE_EDITOR
// active editor only
BOOL fn_bCalculateVectorMouse3D ( PIC_tdstEqPlan *p_stPlan ,
                                 GLI_tdst2DVertex *p_stMouse2D ,
                                 MTH3D_tdstVector *p_stVect )
{
  MTH3D_tdstVector stMouse3D , stMouse3DPrec ;
  BOOL bTest1, bTest2 ;
  
  bTest1 = fn_bCalculateMouse3D ( p_stPlan , &stMouse2DPrec , &stMouse3DPrec) ;
  bTest2 = fn_bCalculateMouse3D ( p_stPlan , p_stMouse2D , &stMouse3D ) ;
  
  if (bTest1 && bTest2)
  {
    MTH3D_M_vSubVector ( p_stVect ,&stMouse3D,  &stMouse3DPrec ) ;
    
    return TRUE ;
  }
  else 
    return FALSE ;
}
#endif


//***************************************************************************
//  Calculate the moving vector of 3d Mouse, if this is possible.
// Input :
//          p_stMouse2D --> Mouse coordinates.
// Output :
//          p_stVect    --> Moving vector.
// Return : 
//          FALSE if no vecteur, else TRUE.
//***************************************************************************

#ifdef ACTIVE_EDITOR
// active editor only
BOOL PIC_bGetVecteurDeplacement ( GLI_tdst2DVertex *p_stMouse2D ,
                                 MTH3D_tdstVector *p_stVect )
{
  PIC_tdstEqPlan stPlan;
  MTH3D_tdstVector stVectCam;
  POS_tdstCompletePosition stMatrix, stChangeMatrix, stMatTemp;
  
  if( !gOkPourDeplacement )
    return FALSE ;
  
  GLI_xGetCameraMatrix ( p_stCamPrec , &stMatTemp );
  POS_fn_vInvertIsoMatrix( &stMatrix , &stMatTemp );  
  
  POS_fn_vMulMatrixMatrix( &stChangeMatrix, &stMatrix, &stMatrixPrec);
  POS_fn_vMulMatrixVertex( &stVectCam, &stChangeMatrix, &stPointMobil);
  
  MTH3D_M_vSubVector(&stVectCam, &stVectCam, &stPointMobil);
  
  // Calcul du deplacement de l'objet dû a la souris
  fn_vDefPlanConstraint( &stPlan , &stPointMobil ) ;
  if (! fn_bCalculateVectorMouse3D ( &stPlan , p_stMouse2D, p_stVect ) )
    return FALSE ;
  
  // On tient compte du deplacement de la camera
  MTH3D_M_vAddVector(p_stVect, p_stVect, &stVectCam);
  
  // Pour le deplacement suivant
  stMatrixPrec = stMatTemp;  
  stMouse2DPrec = *p_stMouse2D ;
  
  // mise a jour du point mobil
  MTH3D_M_vAddVector( &stPointMobil, &stPointMobil, p_stVect ) ;
  
  return TRUE ;
}
#endif

#ifdef ACTIVE_EDITOR
void PIC_vInitDeplacement ( GLD_tdhDevice hDev ,
                           GLD_tdhViewport hVp ,
                           GLI_tdst2DVertex *p_stMouse2D ,
                           MTH3D_tdstVector *p_stPointMobil)
{
  GLI_tdstSpecificAttributesFor3D *p_stSpecAttrib3D;
  GLD_tdstViewportAttributes    stViewAttrib;
  
  g_hDev = hDev;
  g_hVp = hVp;
  
  if ( !GLD_bGetViewportAttributes( hDev, hVp, &stViewAttrib ) )
    return;
  p_stSpecAttrib3D
    = (GLI_tdstSpecificAttributesFor3D *)stViewAttrib.p_vSpecificToXD;
  p_stCamPrec = p_stSpecAttrib3D->p_stCam;
  
  stMouse2DPrec = *p_stMouse2D ;
  gOkPourDeplacement = TRUE ;
  stPointMobil = *p_stPointMobil;
  
  GLI_xGetCameraMatrix( p_stCamPrec , &stMatrixPrec );
}
#endif
#ifdef ACTIVE_EDITOR
void PIC_vEndDeplacement ( void )
{
  gOkPourDeplacement = FALSE ;
}
#endif