/*=========================================================================
*
* CPA_Grid.cpp : Implementation file.
*
*
* Version           1.0
* Creation date
* Revision date
*
* MT
*=======================================================================*/

#ifdef ACTIVE_EDITOR

#include "stdafx.h"
#define HieFriend
#include "ACP_Base.h"

#include "incvig.h"
#include "incGam.h"

#include "Itf.h"


#include "CPA_Grid.hpp"

/*****************************************************************************
 MACROS
 *****************************************************************************/
#define     M_GetLSTWorld()         (((DEV_MultiDevice3D*)GetDevice())->GetWorld())
#define     M_GetLSTViewPort()      ((DEV_ViewPort3D*)((DEV_MultiDevice3D*)GetDevice())->GetFocusDevice()->GetViewPort())
// ALX
#define     M_GetLSTCameraInterface() (M_GetLSTViewPort()->GetCameraInterface())
#define     M_GetLSTCamera()          (M_GetLSTViewPort()->GetCamera())
// End ALX
#define     M_GetLSTEvtEditor()     (m_p_oDevice->GetInterface())
#define     M_GetFocusDevice()      (GetDevice()->GetFocusDevice())
#define     M_RedrawAll()           (M_GetLSTEvtEditor()->fn_vUpdateAll(E_mc_JustDraw))
#define     MAKE_RGB(r,g,b)         (((r&0xff)<<16)+((g&0xff)<<8)+(b&0xff))

/*****************************************************************************
 CONSTANTS
 *****************************************************************************/
static long C_lGridColor = MAKE_RGB(255,255,255);     // Color of grid
static long C_lSelColor  = MAKE_RGB(0,128,0);         // Color of box selection

#define     C_xNbLines      5
#define     C_xLineWidth    MTH_M_xFloatToReal(1000)

#define C_xDefaultSphereRadius  MTH_M_xFloatToReal(0.1)

//--------------------------------------------------------------------------------------
// Constructor
//--------------------------------------------------------------------------------------
CPA_Grid::CPA_Grid(CPA_KeyActionConfiguration *p_oKeyboard, DEV_MultiDevice3D *p_oDevice /*=NULL*/) : CPA_Contact(p_oDevice)
{
    m_p_oMultiDevice        = NULL;
    m_wNbOfColumns          = 0;
    m_wNbOfRows             = 0;
    m_xMaxSphereBoxRadius   = 0;
    m_xGridSquareSize       = 0;
    m_xFirstCenterX         = 0;
    m_xFirstCenterZ         = 0;
    m_xLastCenterX          = 0;
    m_xLastCenterZ          = 0;
    m_bShowSelection        = TRUE;
    m_bShowGrid             = TRUE;

	// Keys
	m_p_oKeyboard = p_oKeyboard;
	m_bNavigationMode = FALSE;
}

// ----------------------------------------------------------------------------
// Create grid for receiving current World
// ----------------------------------------------------------------------------
void CPA_Grid::m_fn_vPositionWorldOnGrid(void)
{
    if(M_GetLSTWorld() == NULL)
        return;

    m_fn_vComputeRowColumn();
    if(!m_wNbOfRows || !m_wNbOfColumns)
        return;

    m_fn_vComputeMaxSphereBoxRadius();
    m_fn_vComputeFirstAndLastCenters();
    m_fn_vComputeObjectsPosition();
    m_fn_vCenterOnGrid();
}

//--------------------------------------------------------------------------------------
//  Compute the position of each objects, and move them.
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vComputeObjectsPosition(void)
{
    CPA_SuperObject     *p_oEdList  = M_GetLSTWorld() -> GetRoot();
    POSITION            stPos       = p_oEdList -> GetHeadPosition();
    CPA_SuperObject     *p_oEdChild = p_oEdList -> GetSuperObjectFirstChild();
    short               wRow        = 0;
    short               wColumn     = 0;

    while(p_oEdChild)
	{
        POS_tdxHandleToPosition _hMatrix;
        GLI_tdstSphere          *p_stSphere = NULL;
        MTH3D_tdstVector        st3DCenter,st3DPosition;
        MTH3D_tdstVector        stTranslation;

        m_fn_vConvertRowColumnTo3D(wRow, wColumn, &st3DPosition);
        _hMatrix = HIE_fn_hGetSuperObjectMatrix(p_oEdChild->GetStruct());
        POS_fn_vSetIdentityMatrix(_hMatrix);

        POS_fn_vGetTranslationVector(_hMatrix, &stTranslation);
        // First, centred with sphere box center
        //p_stSphere = HIE_fn_hGetSuperObjectSphere(p_oEdChild->GetStruct());
        if( m_fn_bGetSphereBoxCenter( p_oEdChild, &st3DCenter ) )
        {
            MTH3D_M_vSubVector(&stTranslation, &stTranslation, &st3DCenter);
        }
        // Second, place the object
        MTH3D_M_vAddVector(&stTranslation, &stTranslation, &st3DPosition);

        POS_fn_vSetTranslationVector(_hMatrix, &stTranslation);

        // Force the absolute matrix to be recalculated
        POS_fn_vNormalizeMatrix(_hMatrix);

        wColumn = (wColumn + 1) % m_wNbOfColumns;
        if(wColumn == 0)
            wRow++;

        p_oEdChild = p_oEdList->GetSuperObjectNextChild( p_oEdChild );
	}
}

//======================================================================================
//
//  SPECIAL METHODS
//
//======================================================================================

//--------------------------------------------------------------------------------------
//  Reset content
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vResetContent(void)
{
    // No grid
    m_wNbOfRows = 0;                // No rows
    m_wNbOfColumns = 0;             // No columns
    m_bShowSelection = FALSE;       // No current selection
    m_xMaxSphereBoxRadius = 0;      // No object, so no max sphere box radius
}

//======================================================================================
//
//  GRID
//
//======================================================================================

//======================================================================================
// COMPUTING
//======================================================================================

//--------------------------------------------------------------------------------------
//  Convert a row and column to a 3D position.  (square center)
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vConvertRowColumnTo3D(short _wRow, short _wColumn, MTH3D_tdstVector *_p_stVxCenter)
{
    MTH3D_M_vSetVectorElements(_p_stVxCenter, - m_xFirstCenterX + MTH_M_xMul(m_xGridSquareSize,_wColumn)
                                            , 0
                                            ,   m_xFirstCenterZ - MTH_M_xMul(m_xGridSquareSize,_wRow));
}

// ----------------------------------------------------------------------------
// compute center of square of given SuperObject
// ----------------------------------------------------------------------------
/*
void CPA_Grid::m_fn_vComputeCenterOfSuperObject(CPA_SuperObject *_p_SprObj, MTH3D_tdstVector *_p_stVxCenter)
{
    short wRow, wColumn;

    // Compute row and column of selection
    m_fn_vComputeGridPosOfSuperObject(_p_SprObj, &wRow, &wColumn);
    m_fn_vConvertRowColumnTo3D(wRow, wColumn, _p_stVxCenter);
}
*/
//--------------------------------------------------------------------------------------
//  Compute the m_xMaxSphereBoxRadius that is the maximum sphere box radius of all
//  the displayed objects. It is used to compute the size of a rectangle of the grid.
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vComputeMaxSphereBoxRadius(void)
{
    CPA_SuperObject *p_oEdList = M_GetLSTWorld()->GetRoot();

    m_xMaxSphereBoxRadius = 0;
    CPA_SuperObject *p_oEdChild = p_oEdList->GetSuperObjectFirstChild();
    while(p_oEdChild)
	{
        MTH_tdxReal xRadius = m_fn_xGetSphereBoxRadius(p_oEdChild);
        m_xMaxSphereBoxRadius = MTH_M_xMax( m_xMaxSphereBoxRadius, xRadius);
        p_oEdChild = p_oEdList->GetSuperObjectNextChild( p_oEdChild );
	}
    m_xGridSquareSize = MTH_M_xAdd(m_xMaxSphereBoxRadius,m_xMaxSphereBoxRadius);
}

//--------------------------------------------------------------------------------------
//  Compute the sphere box radius of an object
//--------------------------------------------------------------------------------------
MTH_tdxReal CPA_Grid::m_fn_xGetSphereBoxRadius(CPA_SuperObject *_p_oSprObj)
{
    MTH_tdxReal xResult = 0;
    CPA_BaseObject *p_oObject = _p_oSprObj -> GetObject();

    if( p_oObject )
    {
        MTH3D_tdstVector  stCenter;

        ACP_tdxHandleOfObject hObj = ((CPA_ObjectDLLBase*)p_oObject -> GetEditor()) -> fn_hGetBoundingVolume( p_oObject );
        if( hObj )
//ANNECY TQ 22/06/98{
            GEO_fn_vGetInfoFromGeometricSphere( &stCenter, &xResult, hObj );
//ENDANNECY TQ}

    }
    return xResult;
}

//--------------------------------------------------------------------------------------
//  Compute the sphere box center of an object
//--------------------------------------------------------------------------------------
BOOL CPA_Grid::m_fn_bGetSphereBoxCenter(CPA_SuperObject *_p_oSprObj, MTH3D_tdstVector *_p_stCenter)
{
    CPA_BaseObject *p_oObject = _p_oSprObj -> GetObject();

    if( p_oObject )
    {
        MTH_tdxReal xResult;

        ACP_tdxHandleOfObject hObj = ((CPA_ObjectDLLBase*)p_oObject -> GetEditor()) -> fn_hGetBoundingVolume( p_oObject );
        if( hObj )
        {
//ANNECY TQ 22/06/98{
            GEO_fn_vGetInfoFromGeometricSphere( _p_stCenter, &xResult, hObj );
//ENDANNECY TQ}

            return TRUE;
        }
    }
    return FALSE;
}
//--------------------------------------------------------------------------------------
//  Compute distances between center of grid and first and last object in grid.
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vComputeFirstAndLastCenters(void)
{
    // First center
    m_xFirstCenterX = MTH_M_xSub(MTH_M_xDiv(MTH_M_xMul(m_wNbOfColumns, m_xGridSquareSize), 2), m_xMaxSphereBoxRadius);
    m_xFirstCenterZ = MTH_M_xSub(MTH_M_xDiv(MTH_M_xMul(m_wNbOfRows, m_xGridSquareSize), 2), m_xMaxSphereBoxRadius);

    // Last center
    m_xLastCenterX = - m_xFirstCenterX + (MTH_M_xMul(m_xGridSquareSize, (m_wNbOfColumns - 1)));
    m_xLastCenterZ = m_xFirstCenterZ - (MTH_M_xMul(m_xGridSquareSize, (m_wNbOfRows - 1)));
}

//--------------------------------------------------------------------------------------
//  Compute number of row and columns
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vComputeRowColumn(void)
{
    int iCount = M_GetLSTWorld() -> GetRoot() -> GetCount();
    /*
    m_wNbOfRows = m_wNbOfColumns = 0;
    if(iCount)
    {
        m_wNbOfRows = ((short) sqrt((double) iCount)) + 1;
        m_wNbOfColumns = m_wNbOfRows;
    }
    */
    if( iCount > 0 )
    {
        m_wNbOfRows = (short)floor(sqrt((double)iCount));
        m_wNbOfColumns = iCount / m_wNbOfRows ;

        while( m_wNbOfColumns * m_wNbOfRows < iCount )
        {
            if( m_wNbOfRows < m_wNbOfColumns )
                m_wNbOfRows++;
            else
                m_wNbOfColumns++;
        }
    }
    else
    {
        m_wNbOfRows = m_wNbOfColumns = 1;
    }
}

//--------------------------------------------------------------------------------------
//  Reset the selection
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vCompute3DPosOfSuperObject(CPA_SuperObject *_p_SprObj,MTH_tdxReal *_p_xLeftX, MTH_tdxReal *_p_xTopZ,
                                               MTH_tdxReal *_p_xRightX, MTH_tdxReal *_p_xBottomZ,
                                               MTH_tdxReal *_p_xXL, MTH_tdxReal *_p_xZL)
{
    MTH_tdxReal    xLeftX      = - m_xFirstCenterX - m_xMaxSphereBoxRadius;
    MTH_tdxReal    xTopZ       =   m_xFirstCenterZ + m_xMaxSphereBoxRadius;
    MTH_tdxReal    xRightX     =   m_xLastCenterX  + m_xMaxSphereBoxRadius;
    MTH_tdxReal    xBottomZ    =   m_xLastCenterZ  - m_xMaxSphereBoxRadius;
    short          wSelRow, wSelColumn;

    // Compute row and column of selection
    m_fn_vComputeGridPosOfSuperObject(_p_SprObj, &wSelRow, &wSelColumn);
    // Compute coordinates of selection box
    *_p_xLeftX   = MTH_M_xAdd(xLeftX, MTH_M_xMul(wSelColumn, m_xGridSquareSize));
    *_p_xTopZ    = MTH_M_xSub(xTopZ, MTH_M_xMul(wSelRow, m_xGridSquareSize));
    *_p_xRightX  = MTH_M_xAdd(*_p_xLeftX, m_xGridSquareSize);
    *_p_xBottomZ = MTH_M_xSub(*_p_xTopZ, m_xGridSquareSize);

    *_p_xZL = MTH_M_xDiv(m_xGridSquareSize,C_xLineWidth);
    *_p_xXL = MTH_M_xDiv(m_xGridSquareSize,C_xLineWidth);

    *_p_xLeftX   += MTH_M_xMul(*_p_xXL,C_xNbLines);
    *_p_xTopZ    -= MTH_M_xMul(*_p_xZL,C_xNbLines);
    *_p_xRightX  -= MTH_M_xMul(*_p_xXL,C_xNbLines);
    *_p_xBottomZ += MTH_M_xMul(*_p_xZL,C_xNbLines);
}


// ----------------------------------------------------------------------------
// search column and row of given SuperObject
// ----------------------------------------------------------------------------
void CPA_Grid::m_fn_vComputeGridPosOfSuperObject(CPA_SuperObject *_p_SprObj,short *_p_wRow,short *_p_wColumn)
{
    CPA_SuperObject     *p_oEdList = M_GetLSTWorld()->GetRoot();
    CPA_SuperObject     *p_oChild  = p_oEdList->GetSuperObjectFirstChild();
    BOOL                bFound     = FALSE;

    *_p_wRow    = 0;
    *_p_wColumn = 0;
    while(p_oChild && !bFound)
	{
		if(p_oChild == _p_SprObj)
            bFound = TRUE;
        else
        {
            *_p_wColumn = (*_p_wColumn + 1) % m_wNbOfColumns;
            if(*_p_wColumn == 0)
                (*_p_wRow)++;
        }
        p_oChild = p_oEdList->GetSuperObjectNextChild(p_oChild);
	}
}

//--------------------------------------------------------------------------------------
// To see all the grid in the window.
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vCenterOnGrid(void)
{
    CPA_CameraDLLBase  *p_oCameraInterface = M_GetLSTCameraInterface();
    CPA_BaseObject     *p_oCamera          = M_GetLSTCamera();
    MTH_tdxReal         xRadius    = MTH_M_xMul(m_wNbOfColumns, m_xMaxSphereBoxRadius);
    MTH_tdxReal         xAlphaX,xRatio;
    CPA_CameraCoords    CameraCoords;

    GLI_xGetCameraAspectAndRatio((GLI_tdxHandleToCamera)p_oCamera->GetData(),&xAlphaX,&xRatio);

/*
    float          fD1        = MTH_M_xRealToFloat(MTH_M_xDiv(xRadius, MTH_M_xTan(MTH_M_xDiv(xAlphaX,2))));
    float          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);
*/
    // target camera
    CameraCoords . SetXYZ( 0, 0, 0 );
    CameraCoords . SetAxisSystem( WorldCoordinates );
    p_oCameraInterface -> SetTargetPoint( p_oCamera , &CameraCoords );
    p_oCameraInterface -> SetTargetType (p_oCamera , tPoint );
    // position camera
    CameraCoords . SetXYZ( 0, -xRadius, 0 );
    CameraCoords . SetAxisSystem( WorldCoordinates );
    p_oCameraInterface -> SetPosition( p_oCamera , &CameraCoords );

    // Free camera
    p_oCameraInterface -> SetTargetType( p_oCamera , tNone );
}

//--------------------------------------------------------------------------------------
// Center on current selected object.
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vCenterOnSuperObject(CPA_SuperObject *_p_SprObj)
{
    /*
    MTH3D_tdstVector  stVertex;

    CPA_Camera      *p_oCamera = M_GetLSTCamera();
    MTH_tdxReal    xAlphaX,xRatio;

    GLI_xGetCameraAspectAndRatio(p_oCamera->GetEngineCamera(),&xAlphaX,&xRatio);
    GLI_tdstSphere  *p_stSphere = HIE_fn_hGetSuperObjectSphere(_p_SprObj->GetStruct());
    MTH_tdxReal     xRadius = (p_stSphere ? p_stSphere->xRadius : C_xDefaultSphereRadius );
    float           fD1     = MTH_M_xRealToFloat(MTH_M_xDiv(xRadius, MTH_M_xTan(MTH_M_xDiv(xAlphaX,2))));
    float           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);

    POS_fn_vGetTranslationVector(HIE_fn_hGetSuperObjectGlobalMatrix(_p_SprObj->GetStruct()), &stVertex);
    MTH3D_M_vGetVectorElements(&p_oCamera->m_fPosX, &p_oCamera->m_fPosY, &p_oCamera->m_fPosZ, &stVertex);
    p_oCamera->m_fPosY = -xRadius;
    p_oCamera->SetMode(p_oCamera->Free);
    p_oCamera->UpdateAbsolute();
    */
}

// ----------------------------------------------------------------------------
// search square picked
// ----------------------------------------------------------------------------
void CPA_Grid::m_fn_vComputePickedSquare(GLI_tdst2DVertex *_p_st2DMousePos, short *_p_wRow, short *_p_wColumn)
{
    MTH3D_tdstVector st3DMouse ;
    MTH_tdxReal      xLeftX      = - m_xFirstCenterX - m_xMaxSphereBoxRadius;
    MTH_tdxReal      xTopZ       =   m_xFirstCenterZ + m_xMaxSphereBoxRadius;

    // compute clipping point on grid plane
    m_fn_vGetPosOnGridPlane(M_GetLSTViewPort()->m_hDisplayDevice,M_GetLSTViewPort()->m_hDisplayViewport,_p_st2DMousePos,&st3DMouse);

    *_p_wRow = 0;
    *_p_wColumn = 0;

    // compute column
    while( st3DMouse.xX > xLeftX )
    {
        (*_p_wColumn)++;
        xLeftX += m_xGridSquareSize;
    }

    (*_p_wColumn)--;

    // compute row
    while( st3DMouse.xZ < xTopZ )
    {
        (*_p_wRow)++;
        xTopZ -= m_xGridSquareSize;
    }

    (*_p_wRow)--;

    if( (*_p_wRow <0) || (*_p_wRow>=m_wNbOfRows) || (*_p_wColumn<0) || (*_p_wColumn>=m_wNbOfColumns))
        // out of grid
        *_p_wRow  = *_p_wColumn = -1;

}

// ----------------------------------------------------------------------------
// search point picked on grid plane
// ----------------------------------------------------------------------------
void CPA_Grid::m_fn_vGetPosOnGridPlane(GLD_tdhDevice hDev, GLD_tdhViewport hVp,
                                        GLI_tdst2DVertex *_p_st2DMousePos,
                                        MTH3D_tdstVector *p_stDstVertex)
{
    GLD_tdstViewportAttributes  stViewAttrib;

    if(GLD_bGetViewportAttributes( hDev, hVp, &stViewAttrib ))
    {
        GLI_tdstSpecificAttributesFor3D *p_stSpecAttrib3D = (GLI_tdstSpecificAttributesFor3D *)stViewAttrib.p_vSpecificToXD;
        POS_tdstCompletePosition		stMatrix, stInvMatrix ;
        MTH3D_tdstVector                 stPosCam,stPosClip;
        GLI_tdstEqPlan                   stPlan;

		POS_fn_vSetIdentityMatrix(&stInvMatrix);
    	POS_fn_vSetIdentityMatrix(&stMatrix);
	    // get picked position
        PIC_vMouse3DScreen(hDev, hVp, _p_st2DMousePos, &stPosClip);

        // get camera position
        GLI_xGetCameraMatrix ( p_stSpecAttrib3D->p_stCam , &stMatrix );
        POS_fn_vInvertMatrix( &stInvMatrix , &stMatrix );
        POS_fn_vGetTranslationVector( &stInvMatrix, &stPosCam );
        // get grid plane equation
        GLI_vDefinePlanEquation( &stPlan , MTH_M_xFloatToReal(0.0) ,
                                           MTH_M_xFloatToReal(1.0) ,
                                           MTH_M_xFloatToReal(0.0) ,
                                           MTH_M_xFloatToReal(0.0) );
        // compute intersection
        GLI_bIntersectionPlanDroite( &stPlan , &stPosCam, &stPosClip, p_stDstVertex) ;
    }
}


//======================================================================================
// DISPLAY
//======================================================================================
//--------------------------------------------------------------------------------------
//  Display grid and selection
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vDisplay(GLD_tdstViewportAttributes *_p_stViewAttrib)
{
    // There's not gris yet
    if (!m_wNbOfRows || !m_wNbOfColumns || (!m_bShowGrid && !m_bShowSelection))
        return;

    // Load camera matrix
    POS_tdstCompletePosition stMatrix;
	POS_fn_vSetIdentityMatrix(&stMatrix);

    GLI_xGetCameraMatrix(((GLI_tdstSpecificAttributesFor3D*)(_p_stViewAttrib->p_vSpecificToXD))->p_stCam,&stMatrix);
    GLI_xLoadMatrix(&stMatrix);

    if(m_bShowGrid)
        m_fn_vDisplayGrid(_p_stViewAttrib);
    if(m_bShowSelection)
        m_fn_vDisplaySelection(_p_stViewAttrib);
    GLI_xPopMatrix();
}

//--------------------------------------------------------------------------------------
// Display grid
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vDisplayGrid(GLD_tdstViewportAttributes *_p_stViewAttrib)
{
    MTH_tdxReal         xLeftX      = - m_xFirstCenterX - m_xMaxSphereBoxRadius;
    MTH_tdxReal         xTopZ       =   m_xFirstCenterZ + m_xMaxSphereBoxRadius;
    MTH_tdxReal         xRightX     =   m_xLastCenterX  + m_xMaxSphereBoxRadius;
    MTH_tdxReal         xBottomZ    =   m_xLastCenterZ  - m_xMaxSphereBoxRadius;
    MTH_tdxReal         xXL         = MTH_M_xDiv(m_xGridSquareSize,C_xLineWidth);
    MTH_tdxReal         xZL         = MTH_M_xDiv(m_xGridSquareSize,C_xLineWidth);
    MTH_tdxReal         xTopZE      = MTH_M_xSub(xTopZ,MTH_M_xMul(xXL,C_xNbLines));
    MTH_tdxReal         xBottomZE   = MTH_M_xAdd(xBottomZ,MTH_M_xMul(xXL,C_xNbLines));
    MTH_tdxReal         xLeftXE     = MTH_M_xSub(xLeftX,MTH_M_xMul(xZL,C_xNbLines));
    MTH_tdxReal         xRightXE    = MTH_M_xAdd(xRightX,MTH_M_xMul(xZL,C_xNbLines));
    MTH_tdxReal         xX, xZ;
    MTH3D_tdstVector    stVxA, stVxB;
    MTH3D_tdstVector    stDepl;
    WORD                wLine;

    // Vertical lines
    xX = xLeftXE;
    MTH3D_M_vNullVector(&stDepl);
    MTH3D_M_vSetXofVector(&stDepl,xXL);
    for (wLine = 0; wLine < (m_wNbOfColumns + 1); wLine++)
    {
        MTH3D_M_vSetVectorElements(&stVxA, xX, 0.0, xTopZE);
        MTH3D_M_vSetVectorElements(&stVxB, xX, 0.0, xBottomZE);
        m_fn_vDrawOneLine(_p_stViewAttrib,C_lGridColor,&stVxA,&stVxB,&stDepl,C_xNbLines<<1);
        xX += m_xGridSquareSize;
    }

    // Horizontal lines
    xZ = xTopZE;
    MTH3D_M_vNullVector(&stDepl);
    MTH3D_M_vSetZofVector(&stDepl,xZL);
    for (wLine = 0; wLine < (m_wNbOfRows + 1); wLine++)
    {
        MTH3D_M_vSetVectorElements(&stVxA, xLeftXE, 0.0, xZ);
        MTH3D_M_vSetVectorElements(&stVxB, xRightXE, 0.0, xZ);
        m_fn_vDrawOneLine(_p_stViewAttrib,C_lGridColor,&stVxA,&stVxB,&stDepl,C_xNbLines<<1);
        xZ -= m_xGridSquareSize;
    }
}

//--------------------------------------------------------------------------------------
// Display selection
//--------------------------------------------------------------------------------------
void CPA_Grid::m_fn_vDisplaySelection(GLD_tdstViewportAttributes *_p_stViewAttrib)
{
    if(M_GetLSTEvtEditor())
    {
        CPA_List<CPA_SuperObject> *p_List = M_GetLSTWorld()->GetListSelected();
        POSITION                   pos    = p_List->GetHeadPosition();
        while(pos)
        {
            CPA_SuperObject     *p_Obj = p_List->GetNext(pos);

            MTH3D_tdstVector    stVxA, stVxB, stDepl;
            MTH_tdxReal         xLeftX,xTopZ,xRightX,xBottomZ;
            MTH_tdxReal         xXL,xZL;
            MTH_tdxReal         xFront;

            m_fn_vCompute3DPosOfSuperObject(p_Obj,&xLeftX,&xTopZ,&xRightX,&xBottomZ,&xXL,&xZL);
            xFront = -MTH_M_xMul(xXL,50);
            //  horizontal lines
            MTH3D_M_vNullVector(&stDepl);
            MTH3D_M_vSetZofVector(&stDepl,-xZL);
            MTH3D_M_vSetVectorElements(&stVxA, xLeftX, xFront, xTopZ);
            MTH3D_M_vSetVectorElements(&stVxB, xRightX, xFront, xTopZ);
            m_fn_vDrawOneLine(_p_stViewAttrib,C_lSelColor,&stVxA,&stVxB,&stDepl,C_xNbLines);
            MTH3D_M_vSetZofVector(&stDepl,xZL);
            MTH3D_M_vSetVectorElements(&stVxA, xLeftX, xFront, xBottomZ);
            MTH3D_M_vSetVectorElements(&stVxB, xRightX, xFront, xBottomZ);
            m_fn_vDrawOneLine(_p_stViewAttrib,C_lSelColor,&stVxA,&stVxB,&stDepl,C_xNbLines);

            // vertical lines
            MTH3D_M_vNullVector(&stDepl);
            MTH3D_M_vSetXofVector(&stDepl,xXL);
            MTH3D_M_vSetVectorElements(&stVxA, xLeftX, xFront, xTopZ);
            MTH3D_M_vSetVectorElements(&stVxB, xLeftX, xFront, xBottomZ);
            m_fn_vDrawOneLine(_p_stViewAttrib,C_lSelColor,&stVxA,&stVxB,&stDepl,C_xNbLines);
            MTH3D_M_vSetXofVector(&stDepl,-xXL);
            MTH3D_M_vSetVectorElements(&stVxA, xRightX, xFront, xBottomZ);
            MTH3D_M_vSetVectorElements(&stVxB, xRightX, xFront, xTopZ);
            m_fn_vDrawOneLine(_p_stViewAttrib,C_lSelColor,&stVxA,&stVxB,&stDepl,C_xNbLines);
        }
    }
}

// ----------------------------------------------------------------------------
// draw one line
// ----------------------------------------------------------------------------
void CPA_Grid::m_fn_vDrawOneLine(GLD_tdstViewportAttributes *_p_stViewAttrib, long lColor,
                                 MTH3D_tdstVector *_p_stVxA, MTH3D_tdstVector *_p_stVxB,
                                 MTH3D_tdstVector *_p_stDepl, ACP_tdxIndex _xNbLines)
{
    for ( ACP_tdxIndex xLarg=0 ; xLarg<_xNbLines ; xLarg++ )
    {
        GLI_xDraw3DLine16((GLD_tdstViewportAttributes_*)_p_stViewAttrib, _p_stVxA, _p_stVxB, lColor);
        MTH3D_M_vAddVector(_p_stVxA, _p_stVxA, _p_stDepl);
        MTH3D_M_vAddVector(_p_stVxB, _p_stVxB, _p_stDepl);
    }
}

//======================================================================================
//
//  MESSAGES FROM THE DEVICE
//
//======================================================================================

/*===========================================================================
		KeyDown
=========================================================================*/
BOOL CPA_Grid::_OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
	unsigned short uwAction = m_p_oKeyboard->mfn_uwKeyToAction(nChar);

	// change mode
	if (uwAction == KA_ID_NAVMODE)
	{
		m_bNavigationMode = !m_bNavigationMode;
		return TRUE;
	}

	// navigation mode
	if (m_bNavigationMode && (M_GetLSTWorld()->GetCountSelected() == 1))
	{
		CPA_SuperObject *pEdList = M_GetLSTWorld()->GetRoot();
		CPA_SuperObject *pSelected = M_GetLSTWorld()->GetSingleSelection();
		CPA_SuperObject *pNewSelection;
		int				iColumn;

		switch (uwAction)
		{
			case KA_ID_LEFT:
				pNewSelection = pEdList->GetSuperObjectPrevChild(pSelected);
				if (pNewSelection)
					m_p_oDevice->GetInterface()->fn_bSelectObject(pNewSelection, FALSE, FALSE);
				return TRUE;

			case KA_ID_RIGHT:
				pNewSelection = pEdList->GetSuperObjectNextChild(pSelected);
				if (pNewSelection)
					m_p_oDevice->GetInterface()->fn_bSelectObject(pNewSelection, FALSE, FALSE);
				return TRUE;

			case KA_ID_UP:
				iColumn = 0; 
				pNewSelection = pSelected;
				while (iColumn < m_wNbOfColumns && pNewSelection)
				{
					pNewSelection = pEdList->GetSuperObjectPrevChild(pNewSelection);
					iColumn++;
				}
				if (pNewSelection && (pNewSelection != pSelected))
					m_p_oDevice->GetInterface()->fn_bSelectObject(pNewSelection, FALSE, FALSE);
				return TRUE;

			case KA_ID_DOWN:
				iColumn = 0; 
				pNewSelection = pSelected;
				while (iColumn < m_wNbOfColumns && pNewSelection)
				{
					pNewSelection = pEdList->GetSuperObjectNextChild(pNewSelection);
					iColumn++;
				}
				if (pNewSelection && (pNewSelection != pSelected))
					m_p_oDevice->GetInterface()->fn_bSelectObject(pNewSelection, FALSE, FALSE);
				return TRUE;

			default :
				return CPA_Contact::_OnKeyDown(nChar, nRepCnt, nFlags);
		}
	}

	//key not processed
	return CPA_Contact::_OnKeyDown(nChar, nRepCnt, nFlags);
}

//--------------------------------------------------------------------------------------
// if no object is picked, search if a square is picked
//--------------------------------------------------------------------------------------
BOOL CPA_Grid::_OnLButtonDown(UINT nFlags, tdstMousePos *p_stPos, ACP_tdxIndex xIndex, HIE_tdstPickInfo *p_stObject)
{
    BOOL bResult = CPA_Contact::_OnLButtonDown(nFlags, p_stPos, xIndex, p_stObject);

    // if no picking
    if(!xIndex && m_bShowGrid)
    {
        // search object on grid
        CPA_SuperObject *p_oEdChild = m_fn_p_oGetSuperObjectFromPos( p_stPos );
        // select object
        if(p_oEdChild)
            m_p_oDevice->GetInterface()->fn_vAddSelectedObject(p_oEdChild);
    }
    return bResult;
}

// ----------------------------------------------------------------------------
// Description : return SO on square under pos
// ----------------------------------------------------------------------------
CPA_SuperObject *CPA_Grid::m_fn_p_oGetSuperObjectFromPos(tdstMousePos *p_stPos)
{
    CPA_SuperObject *p_oEdChild = NULL;
    short           wRow = 0;
    short           wColumn = 0;
    short           wRowPicked,wColumnPicked;

    m_fn_vComputePickedSquare(&(p_stPos->stPos2D),&wRowPicked,&wColumnPicked);
    // if picking on a square
    if( (wRowPicked != -1) && (wColumnPicked != -1) )
    {
        CPA_SuperObject *p_oEdList = M_GetLSTWorld()->GetRoot();
        p_oEdChild = p_oEdList->GetSuperObjectFirstChild();
        // search object piched
        while( (p_oEdChild) && !((wColumn == wColumnPicked) && (wRow == wRowPicked)) )
        {
            wColumn = (wColumn + 1) % m_wNbOfColumns;
            if(wColumn == 0)
                wRow = wRow + 1;
            p_oEdChild = p_oEdList->GetSuperObjectNextChild(p_oEdChild);
        }
    }
    return p_oEdChild;
}
//--------------------------------------------------------------------------------------
//  Call to draw something in the viewport.
//--------------------------------------------------------------------------------------
void CPA_Grid::fn_vAddObjectsToDraw( GLD_tdstViewportAttributes *_p_stViewAttrib, GLI_tdxHandleToLight _p_stLight,DEV_ViewPort *p3)
{
    /*
    MTH_tdxReal xMaxSphereBoxRadiusBackup = m_xMaxSphereBoxRadius;

    // if object size has changed, must compute new size of grid
    m_fn_vComputeMaxSphereBoxRadius();
    if(xMaxSphereBoxRadiusBackup != m_xMaxSphereBoxRadius)
    {
        m_fn_vComputeFirstAndLastCenters();
        m_fn_vComputeObjectsPosition();
        m_fn_vCenterOnGrid();
    }
    */
    if(_p_stViewAttrib)
        m_fn_vDisplay(_p_stViewAttrib);
    CPA_Contact::fn_vAddObjectsToDraw(_p_stViewAttrib,_p_stLight,p3);
}

#endif //ACTIVE_EDITOR