#include "watrplan.h"
#include "linear.h"
#include "proj.h"
void GLI_vSinusEffetOn3DVertex ( MTH3D_tdstVector * p_stVertex3D ) ;
 
/*
 =======================================================================================
  Name        : Camera.cxx
  Description : Camera function -- PC specific version
 =======================================================================================
 */
 
static GLI_tdstCamera *p_stCamAntiBug;
 
void GLI_xAdjustCameraToViewport2 (GLD_tdstDeviceAttributes *p_stDev, GLD_tdstViewportAttributes *p_stVpt, GLI_tdstCamera *p_stCam ) ;
 
void GLI_xCreateCamera ( GLI_tdstCamera **h_stCam , long lCameraMode )
{
    MMG_fn_vAddMemoryInfo (MMG_C_lTypeGLI , MMG_C_lSubTypeCamera , NULL);
    GEO_M_CPAMalloc(*h_stCam,GLI_tdstCamera *,sizeof ( GLI_tdstCamera),E_uwGEONotEnoughtMemory );
    if ( (*h_stCam) == NULL) 
        return;    
    
    (*h_stCam)->lCameraMode = lCameraMode ;
    
    switch ( (*h_stCam) -> lCameraMode )
    {
        case GLI_C_lIsoCamWithDistorsion :
        case GLI_C_lIsoCamWithoutDistorsion :
            (*h_stCam)->xAlphaX = GLI_M_LongToValue ( 1 ) ;
            (*h_stCam)->xAlphaY = GLI_M_LongToValue ( 1 ) ;
            break ;
      
        case GLI_C_lPersCamWithDistorsion :
        case GLI_C_lPersCamWithoutDistorsion :
            (*h_stCam)-> xAlphaX = GLI_M_PIO4 ;
            (*h_stCam)-> xAlphaY = GLI_M_PIO4 ;
            break;
        
        default:
            break;
    }
    
    (*h_stCam)-> xNear = GLI_C_xZClippingNear ;
    (*h_stCam)-> xFar = GLI_M_FloatToValue( 10000.0 ) ;
	(*h_stCam)-> xRatio = GLI_M_Div ((*h_stCam)->xAlphaY , (*h_stCam)->xAlphaX );
   
    return;
}
 
 
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Adjust camera parameters to fit with viewport parameters
 ----------------------------------------------------------------------------------------
 */
void GLI_xAdjustCameraToViewport ( GLD_tdhDevice hDevice, GLD_tdhViewport hViewport, GLI_tdstCamera *p_stCam )
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    GLD_tdstDeviceAttributes        stDevAttrib;
    GLD_tdstViewportAttributes      stViewAttrib;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
    
	if ( !GLD_bGetDeviceAttributes( hDevice, &stDevAttrib ) )
		return ;
    if ( !GLD_bGetViewportAttributes( hDevice, hViewport, &stViewAttrib ) )
		return;
    
    /* ANTI BUG ------------------------------------------- */
    if (p_stCam == NULL)
		p_stCam = p_stCamAntiBug;
    else
		p_stCamAntiBug = p_stCam;/*  */
    /* ANTI BUG ------------------------------------------- */
    
    GLI_xAdjustCameraToViewport2 (&stDevAttrib, &stViewAttrib, p_stCam) ;
    return;
}                         
 
 
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : transform 2D position to 3D position
 ----------------------------------------------------------------------------------------
 */
void GLI_vGet3DVertexFromScreenPos 
		( 
			GLD_tdstViewportAttributes	*p_stVpt,
			MTH3D_tdstVector			*p_stPos3D,
			MTH_tdxReal					xRatioX, 
			MTH_tdxReal					xRatioY, 
			MTH_tdxReal					xSize 
		) 
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	GLI_tdst2DVertex					stPos2D, stTrans ;
	GLI_tdstSpecificAttributesFor3D		*p_stSpecAttrib3D;
	GLI_tdstCamera						*p_stCam;
	MTH_tdxReal							xScreen;
	MTH3D_tdstVector					stTemp ;
	POS_tdstCompletePosition			stMatrix, stInvMatrix ;
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
 
	stPos2D.xX = p_stVpt->dwWidth * xRatioX ;
	stPos2D.xY = p_stVpt->dwHeight * xRatioY;	
 
	p_stSpecAttrib3D = (GLI_tdstSpecificAttributesFor3D *)p_stVpt->p_vSpecificToXD;
	p_stCam = p_stSpecAttrib3D->p_stCam ;
  
	switch(p_stCam->lCameraMode)
	{
		case GLI_C_lIsoCamWithDistorsion :
		case GLI_C_lIsoCamWithoutDistorsion :
			xScreen = MTH_M_xFloatToReal(0.1f);
			break;
  
		case GLI_C_lPersCamWithDistorsion :
		case GLI_C_lPersCamWithoutDistorsion :
			xScreen = p_stCam->xScreen;
			break ;
	
		default:
			p_stPos3D->xX = p_stPos3D->xY = p_stPos3D->xZ = MTH_M_xFloatToReal(0.0f);
			return;
	}
    stTrans.xX = p_stCam->stTrans.xX;
    stTrans.xY = p_stCam->stTrans.xY;
	if ( xSize != 0.0 ) 
	{
		stTemp.xX = MTH_M_xDiv( MTH_M_xDiv( MTH_M_xSub( MTH_M_xLongToReal(stPos2D.xX), MTH_M_xLongToReal(stTrans.xX)), MTH_M_xFloatToReal(p_stCam->stScale.xX)), MTH_M_xFloatToReal(xSize) );
		stTemp.xY = MTH_M_xDiv( MTH_M_xDiv( MTH_M_xSub( MTH_M_xLongToReal(stPos2D.xY), MTH_M_xLongToReal(stTrans.xY)),MTH_M_xFloatToReal(p_stCam->stScale.xY) ), MTH_M_xFloatToReal(xSize) );
		stTemp.xZ = MTH_M_xMul( xScreen, MTH_M_xDiv( MTH_M_xAdd( MTH_M_xFloatToReal(1.0f), xSize ), xSize) );
	}
	else 
	{
		stTemp.xX = MTH_M_xDiv( MTH_M_xSub( MTH_M_xLongToReal(stPos2D.xX), MTH_M_xLongToReal(stTrans.xX)),MTH_M_xFloatToReal(p_stCam->stScale.xX) ) ;
		stTemp.xY = MTH_M_xDiv( MTH_M_xSub( MTH_M_xLongToReal(stPos2D.xY), MTH_M_xLongToReal(stTrans.xY)),MTH_M_xFloatToReal(p_stCam->stScale.xY) ) ;
		stTemp.xZ = MTH_M_xFloatToReal(0.0f);
	}
  
	/* 
	 * Convertion dans le repere du monde 
	 */
	GLI_xGetCameraMatrix ( p_stCam , &stMatrix );
	POS_fn_vInvertMatrix ( &stInvMatrix , &stMatrix );  
	POS_fn_vMulMatrixVertex ( p_stPos3D , &stInvMatrix , &stTemp );
}
 
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Adjust camera parameters to fit with viewport parameters
 ----------------------------------------------------------------------------------------
 */
void GLI_xAdjustCameraToViewport2 (GLD_tdstDeviceAttributes *p_stDev, GLD_tdstViewportAttributes *p_stVpt, GLI_tdstCamera *p_stCam ) {
  /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  GLI_tdxValue					xHeightForAlphaY ;
  GLI_tdxValue					xVptWidthInPix , xVptHeightInPix ;
  GLI_tdxValue					xVptWidthInMeters , xVptHeightInMeters ;
  GLI_tdxValue					xVptRatio , xOOScale;
  GLI_tdstSpecificAttributesFor3D *p_stSpecAttrib3D;
  float							fZ, fOoL, fH;
  /*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
  
  p_stSpecAttrib3D = (GLI_tdstSpecificAttributesFor3D *) p_stVpt->p_vSpecificToXD;
  
  xVptWidthInPix		= GLI_M_LongToValue ( p_stVpt->dwWidth ) ;
  xVptWidthInMeters	= GLI_M_Mul ( xVptWidthInPix , p_stDev->xPixelDimensionX ) ;
  xVptHeightInPix		= GLI_M_LongToValue ( p_stVpt->dwHeight ) ;
  xVptHeightInMeters	= GLI_M_Mul ( xVptHeightInPix , p_stDev->xPixelDimensionY ) ;
  xVptRatio			= GLI_M_Div ( xVptHeightInMeters , xVptWidthInMeters ) ;
 
  p_stCam->stTrans.xX = (int) p_stVpt->iOffsetPosX + MTH_M_xRealToFloat( GLI_M_Mul ( xVptWidthInPix , GLI_M_FloatToValue ( 0.5f ) ) ) ;
  p_stCam->stTrans.xY = (int) p_stVpt->iOffsetPosY + MTH_M_xRealToFloat( GLI_M_Mul ( xVptHeightInPix, GLI_M_FloatToValue ( 0.5f ) ) ) ;
  
  switch ( p_stCam -> lCameraMode )
  {
		case GLI_C_lIsoCamWithoutDistorsion :
      p_stCam->xScreen = GLI_M_LongToValue ( 0 ) ;
      p_stCam->xAlphaY = p_stCam -> xAlphaX ;
      p_stCam->stScale.xX = MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Inv ( GLI_M_Mul ( p_stCam -> xAlphaX , p_stDev->xPixelDimensionX ) ) ) ) ;
      p_stCam->stScale.xY = MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Inv ( GLI_M_Mul ( p_stCam -> xAlphaY , p_stDev->xPixelDimensionY ) ) ) ) ;
      
      p_stCam->stNormPlaneUp    .xX = p_stCam->stNormPlaneDown.xX =
        p_stCam->stNormPlaneRight .xY = p_stCam->stNormPlaneLeft.xY =
        p_stCam->stNormPlaneRight .xZ = p_stCam->stNormPlaneLeft.xZ =
        p_stCam->stNormPlaneDown  .xZ = p_stCam->stNormPlaneUp  .xZ = 0.0f;
      p_stCam->stNormPlaneLeft  .xX = -1.0f;
      p_stCam->stNormPlaneRight .xX = +1.0f;
      p_stCam->stNormPlaneUp    .xY = -1.0f;
      p_stCam->stNormPlaneDown  .xY = +1.0f;
      
      xOOScale = -GLI_M_Div ( xVptWidthInPix  , p_stCam -> stScale . xX);
      xOOScale = GLI_M_Mul ( xOOScale , GLI_M_FloatToValue ( 0.5f ) );
      p_stCam -> xDistPlaneRight = xOOScale ;
      p_stCam -> xDistPlaneLeft  = xOOScale ;
      xOOScale = -GLI_M_Div ( xVptHeightInPix , p_stCam -> stScale . xY);
      xOOScale = GLI_M_Mul ( xOOScale , GLI_M_FloatToValue ( 0.5f ) );
      p_stCam -> xDistPlaneUp    = xOOScale ;
      p_stCam -> xDistPlaneDown  = xOOScale ;
			break;
      
    case GLI_C_lIsoCamWithDistorsion :
      p_stCam->xScreen = GLI_M_LongToValue ( 0 ) ;
      p_stCam->stScale.xX = MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Div ( xVptWidthInPix , GLI_M_Mul ( GLI_M_Mul ( p_stCam -> xAlphaX , GLI_M_LongToValue ( p_stVpt->dwWidth ) ) , p_stDev->xPixelDimensionX ) ) ) );
      p_stCam->stScale.xY = MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Div ( xVptHeightInPix ,GLI_M_Mul ( GLI_M_Mul ( p_stCam -> xAlphaY , GLI_M_LongToValue ( p_stVpt->dwHeight ) ) , p_stDev->xPixelDimensionY ) ) ) ) ;
      
      p_stCam -> stNormPlaneUp    .xX =  p_stCam -> stNormPlaneDown .xX =
        p_stCam -> stNormPlaneRight .xY =  p_stCam -> stNormPlaneLeft .xY =
        p_stCam -> stNormPlaneRight .xZ =  p_stCam -> stNormPlaneLeft .xZ =
        p_stCam -> stNormPlaneDown  .xZ =  p_stCam -> stNormPlaneUp   .xZ = 0.0f;
      p_stCam -> stNormPlaneLeft  .xX = -1.0f;
      p_stCam -> stNormPlaneRight .xX = +1.0f;
      p_stCam -> stNormPlaneUp    .xY = -1.0f;
      p_stCam -> stNormPlaneDown  .xY = +1.0f;
      
      xOOScale = -GLI_M_Div ( xVptWidthInPix  , p_stCam -> stScale . xX);
      xOOScale = GLI_M_Mul ( xOOScale , GLI_M_FloatToValue ( 0.5f ) );
      p_stCam -> xDistPlaneRight = xOOScale ;
      p_stCam -> xDistPlaneLeft  = xOOScale ;
      xOOScale = -GLI_M_Div ( xVptHeightInPix , p_stCam -> stScale . xY);
      xOOScale = GLI_M_Mul ( xOOScale , GLI_M_FloatToValue ( 0.5f ) );
      p_stCam -> xDistPlaneUp    = xOOScale ;
      p_stCam -> xDistPlaneDown  = xOOScale ;
      break ;
 
		case GLI_C_lPersCamWithoutDistorsion :
			p_stCam -> xScreen = GLI_M_Mul 
							( 
								GLI_M_Mul 
								( 
                                    GLI_M_Mul ( GLI_M_LongToValue ( p_stVpt->dwWidth ) ,p_stDev->xPixelDimensionX ) ,
									GLI_M_FloatToValue ( 0.5f ) 
								) ,
								GLI_M_Cotan ( GLI_M_Mul ( p_stCam -> xAlphaX , GLI_M_FloatToValue ( 0.5f ) ) )
							) ;
			p_stCam -> stScale . xX = MTH_M_xRealToFloat
								( 
									GLI_M_Mul 
										(
											GLI_M_Neg ( GLI_M_Inv ( p_stDev->xPixelDimensionX ) ) , 
											GLI_M_Div ( GLI_M_LongToValue(xVptWidthInPix) , GLI_M_LongToValue(p_stVpt->dwWidth) ) 
										) 
								);
      
			xHeightForAlphaY = MTH_M_xRealToFloat
							( 
								GLI_M_Mul 
								(
									GLI_M_Mul ( GLI_M_LongToValue ( 2 ) , p_stCam -> xScreen ) ,
									GLI_M_Tan ( GLI_M_Mul ( GLI_M_FloatToValue ( 0.5f ) , p_stCam -> xAlphaY ) ) 
								) 
							);
			p_stCam->stScale.xY = MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Div ( xVptHeightInPix , xHeightForAlphaY ) ) ) ;
 
 
            {
			    fH = (float)((long)(p_stVpt->dwClipRightInPix - p_stVpt->iOffsetPosX) - (long)(p_stVpt->dwWidth / 2));
				fZ = (p_stVpt->dwWidth / 2) / MTH_M_xTan( MTH_M_xMul( p_stCam->xAlphaX , 0.5f));
			    
				fOoL = fZ * fZ + fH * fH;
			    fOoL = MTH_M_xInvSqrt( fOoL );
 
				p_stCam->stNormPlaneLeft.xX = -fZ * fOoL;
				p_stCam->stNormPlaneLeft.xY = 0.0f;
			    p_stCam->stNormPlaneLeft.xZ = -fH * fOoL;
 
				fH = (float)((long)(p_stVpt->dwWidth / 2) - (long)(p_stVpt->dwClipLeftInPix - p_stVpt->iOffsetPosY) );
			    
 				fOoL = fZ * fZ + fH * fH;
			    fOoL = MTH_M_xInvSqrt( fOoL );
 
			    p_stCam->stNormPlaneRight.xX = fZ * fOoL;
				p_stCam->stNormPlaneRight.xY = 0.0f;
			    p_stCam->stNormPlaneRight.xZ = -fH * fOoL;
            }
 
            {
			    fH = (float)((long)(p_stVpt->dwClipBottomInPix - p_stVpt->iOffsetPosY) - (long)(p_stVpt->dwHeight / 2)) ;
				fZ = (p_stVpt->dwHeight / 2) / MTH_M_xTan( MTH_M_xMul( p_stCam->xAlphaY , 0.5f));
			    fOoL = fZ * fZ + fH * fH;
			    fOoL = MTH_M_xInvSqrt( fOoL );
 
				p_stCam->stNormPlaneDown.xX = 0.0f;
			    p_stCam->stNormPlaneDown.xY = -fZ * fOoL;
			    p_stCam->stNormPlaneDown.xZ = -fH * fOoL;
 
			    fH = (float)((long)(p_stVpt->dwHeight / 2) - ((long)p_stVpt->dwClipTopInPix - p_stVpt->iOffsetPosY) ) ;
			    fOoL = fZ * fZ + fH * fH;
			    fOoL = MTH_M_xInvSqrt( fOoL );
 
				p_stCam->stNormPlaneUp.xX = 0.0f;
			    p_stCam->stNormPlaneUp.xY = fZ * fOoL;
			    p_stCam->stNormPlaneUp.xZ = -fH * fOoL;
            }
 
      
			p_stCam -> xDistPlaneUp = 0.0f;
			p_stCam -> xDistPlaneDown = 0.0f;
			p_stCam -> xDistPlaneRight = 0.0f;
			p_stCam -> xDistPlaneLeft = 0.0f;
			break;
      
    
		case GLI_C_lPersCamWithDistorsion :
			p_stCam -> xScreen = GLI_M_Mul ( GLI_M_Mul ( xVptWidthInMeters , GLI_M_FloatToValue ( 0.5f ) ) , GLI_M_Cotan ( GLI_M_Mul ( p_stCam -> xAlphaX , GLI_M_FloatToValue ( 0.5f ) ) ) ) ;
			p_stCam -> xAlphaY = GLI_M_Mul ( GLI_M_LongToValue ( 2 ) , GLI_M_Atan ( GLI_M_Div ( xVptHeightInMeters , GLI_M_Mul ( GLI_M_LongToValue ( 2 ) , p_stCam -> xScreen ) ) ) ) ;
      
			p_stCam -> stScale . xX =  MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Inv ( p_stDev->xPixelDimensionX ) ) );
			p_stCam -> stScale . xY =  MTH_M_xRealToFloat( GLI_M_Neg ( GLI_M_Inv ( p_stDev->xPixelDimensionY ) ) ) ;
      
			/* compute norme & disytances of 4 planes of camera*/
			p_stCam -> stNormPlaneLeft  .xZ =  -MTH_M_xSin( MTH_M_xMul( p_stCam -> xAlphaX , 0.5f));
			p_stCam -> stNormPlaneRight .xZ =  p_stCam -> stNormPlaneLeft .xZ;
			p_stCam -> stNormPlaneLeft  .xX = -MTH_M_xCos( MTH_M_xMul( p_stCam -> xAlphaX , 0.5f));
			p_stCam -> stNormPlaneRight .xX = -p_stCam -> stNormPlaneLeft .xX;
			p_stCam -> stNormPlaneRight .xY =  p_stCam -> stNormPlaneLeft .xY = 0.0f;
      
			p_stCam -> stNormPlaneUp    .xZ =  -MTH_M_xSin( MTH_M_xMul( p_stCam -> xAlphaY , 0.65f));
			p_stCam -> stNormPlaneDown  .xZ =  p_stCam -> stNormPlaneUp   .xZ ;
			p_stCam -> stNormPlaneUp    .xY = MTH_M_xCos( MTH_M_xMul( p_stCam -> xAlphaY , 0.65f));
			p_stCam -> stNormPlaneDown  .xY = -p_stCam -> stNormPlaneUp   .xY;
			p_stCam -> stNormPlaneUp    .xX =  p_stCam -> stNormPlaneDown .xX = 0.0f;
			MTH3D_M_vNormalizeVector(&p_stCam -> stNormPlaneDown  , &p_stCam -> stNormPlaneDown  );
      
			p_stCam -> xDistPlaneUp = 0.0f;
			p_stCam -> xDistPlaneDown = 0.0f;
			p_stCam -> xDistPlaneRight = 0.0f;
			p_stCam -> xDistPlaneLeft = 0.0f;
			break ;
    }
    return;
}                         
 
 
/*
 ----------------------------------------------------------------------------------------
  Description   : Adjust the camera to the mirror for an optimized clipping 
 ----------------------------------------------------------------------------------------
 */
ACP_tdxBool GLI_vAdjustCameraToMirror( ACP_tdxHandleOfObject hHandleOfGometricMirror, GEO_tdxHandleToMatrix	hGlobalMatrixOfMirror, GEO_tdxHandleToMatrix	hMatrixOfCamera, struct GLI_tdstCamera_ *pstCamera, GLD_tdstViewportAttributes *p_stVpt,long lDrawModeMask)
{
  MTH3D_tdstVector						  pstPointOfRectangleMirror[4];
  GLI_tdstAligned3DVector		pstAligned3DPointOfRectangleMirror[4];
  GLI_tdstAligned3DVector		pstAligned3DCorrectedPointOfRectangleMirror[5];
  GLI_tdstAligned2DVector		pstAligned2DProjectedPointOfRectangleMirror[5];
  short i,j;
  ACP_tdxIndex	xTempIndexForRectangle;
  float						fXMin,fXMax,fYMin,fYMax;
  float						fXMin1,fXMax1,fYMin1,fYMax1;
  float						xConstantMinForZ;
  float						xConstantDivForZ;
  POS_tdstCompletePosition		stMatrixFromSuperObjectToCamera;
  ACP_tdxBool			bIDrawTheMirrorNormally=TRUE;
  ACP_tdxBool			p_bPointOfMirrorIsBehindCamera[4];
  float					fNear;
 
 
  fXMin1=(float)p_stVpt->dwClipLeftInPix;
  fXMax1=(float)p_stVpt->dwClipRightInPix;
  fYMin1=(float)p_stVpt->dwClipTopInPix;
  fYMax1=(float)p_stVpt->dwClipBottomInPix;
  
 
  xTempIndexForRectangle=hHandleOfGometricMirror->xNbPoints;
  for (j=0;j<4;j++)
  {
    xTempIndexForRectangle--;
    GEO_vGetPointOfObject(hHandleOfGometricMirror,&pstPointOfRectangleMirror[j],xTempIndexForRectangle);
  }
  
  POS_fn_vSetIdentityMatrix(&stMatrixFromSuperObjectToCamera);
  POS_fn_vMulMatrixMatrix(&stMatrixFromSuperObjectToCamera,hMatrixOfCamera,hGlobalMatrixOfMirror);
  
  GLI_xSerialLinearOp (4 ,pstPointOfRectangleMirror,
    pstAligned3DPointOfRectangleMirror ,
    &stMatrixFromSuperObjectToCamera);
 
  fNear = pstCamera->xFar;
  for (j=0;j<4;j++) {
	/* check if There is a Sinus Effect*/
    if ( ( (g_cSinusEffectState == 1) && ((lDrawModeMask & GLI_C_lHasNotSinusEffect) == 0) ) || 
         ( (g_cSinusEffectState == 2) && (lDrawModeMask & GLI_C_lHasNotSinusEffect) ) ||  
         (g_cSinusEffectState == 3) ) 
		GLI_vSinusEffetOn3DVertex((MTH3D_tdstVector *)&pstAligned3DPointOfRectangleMirror[j]) ;
 
	fNear = MTH_M_xMin(fNear,pstAligned3DPointOfRectangleMirror[j].xZ);
 
    if  (MTH_M_bLess(pstAligned3DPointOfRectangleMirror[j].xZ,pstCamera->xNear))
      p_bPointOfMirrorIsBehindCamera[j]=TRUE;	
    else   p_bPointOfMirrorIsBehindCamera[j]=FALSE;
  }
 
  xConstantMinForZ = pstCamera->xNear = MTH_M_xMax(fNear,pstCamera->xNear);
 
  if ((p_bPointOfMirrorIsBehindCamera[0])||
    (p_bPointOfMirrorIsBehindCamera[1])||
    (p_bPointOfMirrorIsBehindCamera[2])||
    (p_bPointOfMirrorIsBehindCamera[3])) bIDrawTheMirrorNormally=FALSE;
  
 
  if (bIDrawTheMirrorNormally)
  {
 
    GLI_xSerialProjection (pstCamera ,4 ,
      pstAligned3DPointOfRectangleMirror ,
      pstAligned2DProjectedPointOfRectangleMirror ) ;
    
    fXMin=fXMax1;
    fXMax=fXMin1;
    fYMin=fYMax1;
    fYMax=fXMin1;
    
    for (j=0;j<4;j++)
    {
      if (MTH_M_bLess(pstAligned2DProjectedPointOfRectangleMirror[j].xX,fXMin)) 	fXMin=pstAligned2DProjectedPointOfRectangleMirror[j].xX;
      if (MTH_M_bGreater(pstAligned2DProjectedPointOfRectangleMirror[j].xX,fXMax)) 	fXMax=pstAligned2DProjectedPointOfRectangleMirror[j].xX;
      if (MTH_M_bLess(pstAligned2DProjectedPointOfRectangleMirror[j].xY,fYMin)) 	fYMin=pstAligned2DProjectedPointOfRectangleMirror[j].xY;
      if (MTH_M_bGreater(pstAligned2DProjectedPointOfRectangleMirror[j].xY,fYMax)) 	fYMax=pstAligned2DProjectedPointOfRectangleMirror[j].xY;
    }
    
    if (MTH_M_bGreater(fXMin,fXMax)) return FALSE;
    if (MTH_M_bGreater(fYMin,fYMax)) return FALSE;
    
    fXMin=MTH_M_xSub(fXMin,MTH_C_ONE);
    fXMax=MTH_M_xAdd(fXMax,MTH_C_ONE);
    fYMin=MTH_M_xSub(fYMin,MTH_C_ONE);
    fYMax=MTH_M_xAdd(fYMax,MTH_C_ONE);
    
    if (MTH_M_bLess(fXMin,fXMin1)) fXMin=fXMin1;
    
    if (MTH_M_bGreater(fXMax,fXMax1)) fXMax=fXMax1;
    
    if (MTH_M_bLess(fYMin,fYMin1)) fYMin=fYMin1;
    
    if (MTH_M_bGreater(fYMax,fYMax1)) fYMax=fYMax1;
    
    
    p_stVpt->dwClipLeftInPix=((long)fXMin);
    p_stVpt->dwClipRightInPix=((long)fXMax);
    p_stVpt->dwClipTopInPix=((long)fYMin);
    p_stVpt->dwClipBottomInPix=((long)fYMax);
 
    
    return TRUE;
  }
  else
  {
    if ((p_bPointOfMirrorIsBehindCamera[0])&&
      (p_bPointOfMirrorIsBehindCamera[1])&&
      (p_bPointOfMirrorIsBehindCamera[2])&&
      (p_bPointOfMirrorIsBehindCamera[3])) return FALSE;
    
    else
    {
      short xNewNbPoints=0;
      
      for (i=0;i<4;i++)
      {
        if (!p_bPointOfMirrorIsBehindCamera[i])
        {
          pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xX=pstAligned3DPointOfRectangleMirror[i].xX;
          pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xY=pstAligned3DPointOfRectangleMirror[i].xY;
          pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xZ=pstAligned3DPointOfRectangleMirror[i].xZ;
          xNewNbPoints++;
        }	
        else
        {
          short xIPlusTemp=(i+1)%4;
          if (!p_bPointOfMirrorIsBehindCamera[xIPlusTemp])
          {
            xConstantDivForZ=
              MTH_M_xDiv(MTH_M_xSub(xConstantMinForZ,pstAligned3DPointOfRectangleMirror[i].xZ),
              pstAligned3DPointOfRectangleMirror[xIPlusTemp].xZ);
            
            pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xX=
              MTH_M_xAdd(pstAligned3DPointOfRectangleMirror[i].xX,MTH_M_xMul(xConstantDivForZ,
              pstAligned3DPointOfRectangleMirror[xIPlusTemp].xX));
            
            pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xY=
              MTH_M_xAdd(pstAligned3DPointOfRectangleMirror[i].xY,MTH_M_xMul(xConstantDivForZ,
              pstAligned3DPointOfRectangleMirror[xIPlusTemp].xY));
            
            pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xZ=xConstantMinForZ;
            xNewNbPoints++;
          }	
          
          xIPlusTemp=(i+3)%4;
          if (!p_bPointOfMirrorIsBehindCamera[xIPlusTemp])
          {
            xConstantDivForZ=
              MTH_M_xDiv(MTH_M_xSub(xConstantMinForZ,pstAligned3DPointOfRectangleMirror[i].xZ),
              pstAligned3DPointOfRectangleMirror[xIPlusTemp].xZ);
            
            pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xX=
              MTH_M_xAdd(pstAligned3DPointOfRectangleMirror[i].xX,MTH_M_xMul(xConstantDivForZ,
              pstAligned3DPointOfRectangleMirror[xIPlusTemp].xX));
            
            pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xY=
              MTH_M_xAdd(pstAligned3DPointOfRectangleMirror[i].xY,MTH_M_xMul(xConstantDivForZ,
              pstAligned3DPointOfRectangleMirror[xIPlusTemp].xY));
            
            pstAligned3DCorrectedPointOfRectangleMirror[xNewNbPoints].xZ=xConstantMinForZ;
            xNewNbPoints++;
          }	
        }/* End of if point is behind	*/
        
      }/*End of for i*/
      
      GLI_xSerialProjection (pstCamera ,xNewNbPoints ,
        pstAligned3DCorrectedPointOfRectangleMirror ,
        pstAligned2DProjectedPointOfRectangleMirror ) ;
      
      /*			  g_stCurLLInterface.p_fnSerialSnap2DVertices (pstAligned2DProjectedPointOfRectangleMirror,xNewNbPoints);*/
      
      fXMin=fXMax1;
      fXMax=fXMin1;
      fYMin=fYMax1;
      fYMax=fXMin1;
      
      for (j=0;j<xNewNbPoints;j++)
      {
        if (MTH_M_bLess(pstAligned2DProjectedPointOfRectangleMirror[j].xX,fXMin)) 	fXMin=pstAligned2DProjectedPointOfRectangleMirror[j].xX;
        if (MTH_M_bGreater(pstAligned2DProjectedPointOfRectangleMirror[j].xX,fXMax)) 	fXMax=pstAligned2DProjectedPointOfRectangleMirror[j].xX;
        if (MTH_M_bLess(pstAligned2DProjectedPointOfRectangleMirror[j].xY,fYMin)) 	fYMin=pstAligned2DProjectedPointOfRectangleMirror[j].xY;
        if (MTH_M_bGreater(pstAligned2DProjectedPointOfRectangleMirror[j].xY,fYMax)) 	fYMax=pstAligned2DProjectedPointOfRectangleMirror[j].xY;
      }
      
      if (MTH_M_bGreater(fXMin,fXMax)) return FALSE;
      if (MTH_M_bGreater(fYMin,fYMax)) return FALSE;
      
      fXMin=MTH_M_xSub(fXMin,MTH_C_ONE);
      fXMax=MTH_M_xAdd(fXMax,MTH_C_ONE);
      fYMin=MTH_M_xSub(fYMin,MTH_C_ONE);
      fYMax=MTH_M_xAdd(fYMax,MTH_C_ONE);
      
      if (MTH_M_bLess(fXMin,fXMin1)) fXMin=fXMin1;
      
      if (MTH_M_bGreater(fXMax,fXMax1)) fXMax=fXMax1;
      
      if (MTH_M_bLess(fYMin,fYMin1)) fYMin=fYMin1;
      
      if (MTH_M_bGreater(fYMax,fYMax1)) fYMax=fYMax1;
      
      p_stVpt->dwClipLeftInPix=((long)fXMin);
      p_stVpt->dwClipRightInPix=((long)fXMax);
      p_stVpt->dwClipTopInPix=((long)fYMin);
      p_stVpt->dwClipBottomInPix=((long)fYMax);
 
 
      return TRUE;
      
    }/*End of not all points behind*/
    
      }/*End of not draw normally */
      
      return FALSE; 	  
}
 
 
