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

// Name:        3d_aux.cpp
/////////////////////////////////////////////////////////////////////////////


#ifdef __GNUG__
#pragma implementation
#pragma interface
#endif

#include "fctsys.h"

#if !wxUSE_GLCANVAS
#error Please set wxUSE_GLCANVAS to 1 in setup.h.
#endif

#include "common.h"
#include "trigo.h"

#include "bitmaps.h"

#include "3d_viewer.h"
#include "3d_struct.h"
#include "trackball.h"

/**************************************************************************/
void S3D_MASTER::Set_Object_Coords( S3D_Vertex* coord, int nbcoord )
/**************************************************************************/
{
    int ii;


    /* adjust object scale, rotation and offset position */
    for( ii = 0; ii < nbcoord; ii++ )
    {
        coord[ii].x *= m_MatScale.x;
        coord[ii].y *= m_MatScale.y;
        coord[ii].z *= m_MatScale.z;
        /* adjust rotation */
        if( m_MatRotation.x )
            RotatePoint( &coord[ii].y, &coord[ii].z,
                (int) (m_MatRotation.x * 10) );
        if( m_MatRotation.y )
            RotatePoint( &coord[ii].z, &coord[ii].x,
                (int) (m_MatRotation.y * 10) );
        if( m_MatRotation.z )
            RotatePoint( &coord[ii].x, &coord[ii].y,
                (int) (m_MatRotation.z * 10) );
        /* adjust offset position (offset is given in UNIT 3D (0.1 inch) */
#define SCALE_3D_CONV (PCB_INTERNAL_UNIT / UNITS3D_TO_UNITSPCB)
        coord[ii].x += m_MatPosition.x * SCALE_3D_CONV;
        coord[ii].y += m_MatPosition.y * SCALE_3D_CONV;
        coord[ii].z += m_MatPosition.z * SCALE_3D_CONV;
    }
}


/************************************************************/
void Set_Object_Data( const S3D_Vertex* coord, int nbcoord )
/************************************************************/
{
    int     ii;
    GLfloat ax, ay, az, bx, by, bz, nx, ny, nz, r;

    /* ignore faces with less than 3 points */
    if( nbcoord < 3 )
        return;

    /* calculate normal direction */
    ax = coord[1].x - coord[0].x;
    ay = coord[1].y - coord[0].y;
    az = coord[1].z - coord[0].z;

    bx = coord[nbcoord - 1].x - coord[0].x;
    by = coord[nbcoord - 1].y - coord[0].y;
    bz = coord[nbcoord - 1].z - coord[0].z;

    nx = ay * bz - az * by;
    ny = az * bx - ax * bz;
    nz = ax * by - ay * bx;

    r = sqrt( nx * nx + ny * ny + nz * nz );
    if( r >= 0.000001 ) /* avoid division by zero */
    {
        nx /= r; ny /= r; nz /= r;
        glNormal3f( nx, ny, nz );
    }

    /* glBegin/glEnd */
    switch( nbcoord )
    {
    case 3:
        glBegin( GL_TRIANGLES );
        break;

    case 4:
        glBegin( GL_QUADS );
        break;

    default:
        glBegin( GL_POLYGON );
        break;
    }

    /* draw polygon/triangle/quad */
    for( ii = 0; ii < nbcoord; ii++ )
    {
        glVertex3f( coord[ii].x * DataScale3D,
            coord[ii].y * DataScale3D,
            coord[ii].z * DataScale3D );
    }

    glEnd();
}


/**********************************************/
GLuint Pcb3D_GLCanvas::DisplayCubeforTest()
/**********************************************/
{
    GLuint gllist = glGenLists( 1 );

    glNewList( gllist, GL_COMPILE_AND_EXECUTE );
    /* draw six faces of a cube */
    glBegin( GL_QUADS );
    glNormal3f( 0.0F, 0.0F, 1.0F );
    glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( -0.5F, 0.5F, 0.5F );
    glVertex3f( -0.5F, -0.5F, 0.5F ); glVertex3f( 0.5F, -0.5F, 0.5F );

    glNormal3f( 0.0F, 0.0F, -1.0F );
    glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( -0.5F, 0.5F, -0.5F );
    glVertex3f( 0.5F, 0.5F, -0.5F ); glVertex3f( 0.5F, -0.5F, -0.5F );

    glNormal3f( 0.0F, 1.0F, 0.0F );
    glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( 0.5F, 0.5F, -0.5F );
    glVertex3f( -0.5F, 0.5F, -0.5F ); glVertex3f( -0.5F, 0.5F, 0.5F );

    glNormal3f( 0.0F, -1.0F, 0.0F );
    glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( 0.5F, -0.5F, -0.5F );
    glVertex3f( 0.5F, -0.5F, 0.5F ); glVertex3f( -0.5F, -0.5F, 0.5F );

    glNormal3f( 1.0F, 0.0F, 0.0F );
    glVertex3f( 0.5F, 0.5F, 0.5F ); glVertex3f( 0.5F, -0.5F, 0.5F );
    glVertex3f( 0.5F, -0.5F, -0.5F ); glVertex3f( 0.5F, 0.5F, -0.5F );

    glNormal3f( -1.0F, 0.0F, 0.0F );
    glVertex3f( -0.5F, -0.5F, -0.5F ); glVertex3f( -0.5F, -0.5F, 0.5F );
    glVertex3f( -0.5F, 0.5F, 0.5F ); glVertex3f( -0.5F, 0.5F, -0.5F );
    glEnd();

    glEndList();

    return gllist;
}


/**********************/
/* class Info_3D_Visu */
/**********************/

/* Constructor */
Info_3D_Visu::Info_3D_Visu()
{
    int ii;

    m_Beginx = m_Beginy = 0.0;  /* position of mouse */
    m_Zoom   = 1.0;             /* field of view in degrees */
    trackball( m_Quat, 0.0, 0.0, 0.0, 0.0 );
    for( ii = 0; ii < 4; ii++ )
        m_Rot[ii] = 0.0;

    m_Layers = 1;
    m_BoardSettings  = NULL;
    m_Draw3DAxis     = TRUE;
    m_Draw3DModule   = TRUE;
    m_Draw3DZone     = TRUE;
    m_Draw3DComments = TRUE;
    m_Draw3DDrawings = TRUE;
    m_Draw3DEco1 = TRUE;
    m_Draw3DEco2 = TRUE;
}


Info_3D_Visu::~Info_3D_Visu()
{
}


/*****************************************************************/
/* Classe pour afficher et editer un Vertex (triplet de valeurs),*/
/* en INCHES ou MM ou sans unites								 */
/*****************************************************************/

WinEDA_VertexCtrl::WinEDA_VertexCtrl( wxWindow* parent, const wxString& title,
                                      wxBoxSizer* BoxSizer,
                                      int units, int internal_unit )
{
    wxString      text;
    wxStaticText* msgtitle;

    m_Units = units;
    m_Internal_Unit = internal_unit;

    if( title.IsEmpty() )
        text = _( "Vertex " );
    else
        text = title;
    text += ReturnUnitSymbol( units );

    msgtitle = new                      wxStaticText( parent, -1, text, wxDefaultPosition, wxSize(
            -1,
            -1 ), 0 );

    BoxSizer->Add( msgtitle, wxGROW | wxLEFT | wxRIGHT | wxTOP | wxBOTTOM | wxADJUST_MINSIZE );

    wxFlexGridSizer* GridSizer = new    wxFlexGridSizer( 3, 2, 0, 0 );

    BoxSizer->Add( GridSizer, 0, wxGROW | wxALL, 5 );

    msgtitle = new                      wxStaticText( parent, -1, wxT( "X:" ) );

    GridSizer->Add( msgtitle,
        0,
        wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxADJUST_MINSIZE,
        5 );
    m_XValueCtrl = new                  wxTextCtrl( parent,
        -1,
        wxEmptyString,
        wxDefaultPosition,
        wxSize( -1, -1 ),
        0 );

    GridSizer->Add( m_XValueCtrl,
        0,
        wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT,
        5 );

    msgtitle = new                      wxStaticText( parent, -1, wxT(
            "Y:" ), wxDefaultPosition, wxSize( -1,
            -1 ), 0 );

    GridSizer->Add( msgtitle,
        0,
        wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxADJUST_MINSIZE,
        5 );
    m_YValueCtrl = new                  wxTextCtrl( parent,
        -1,
        wxEmptyString,
        wxDefaultPosition,
        wxSize( -1, -1 ),
        0 );

    GridSizer->Add( m_YValueCtrl,
        0,
        wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT,
        5 );

    msgtitle = new                      wxStaticText( parent, -1, wxT(
            "Z:" ), wxDefaultPosition, wxSize( -1,
            -1 ), 0 );

    GridSizer->Add( msgtitle,
        0,
        wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT | wxADJUST_MINSIZE,
        5 );
    m_ZValueCtrl = new                  wxTextCtrl( parent,
        -1,
        wxEmptyString,
        wxDefaultPosition,
        wxSize( -1, -1 ),
        0 );

    GridSizer->Add( m_ZValueCtrl,
        0,
        wxALIGN_CENTER_HORIZONTAL | wxALIGN_CENTER_VERTICAL | wxLEFT | wxRIGHT,
        5 );
}


WinEDA_VertexCtrl::~WinEDA_VertexCtrl()
{
}


/*******************************************/
S3D_Vertex WinEDA_VertexCtrl::GetValue()
/*******************************************/

/* Retourne (en unites internes) les coordonnes entrees (en unites utilisateur)
 */
{
    S3D_Vertex value;
    double     dtmp;

    m_XValueCtrl->GetValue().ToDouble( &dtmp );
    value.x = dtmp;
    m_YValueCtrl->GetValue().ToDouble( &dtmp );
    value.y = dtmp;
    m_ZValueCtrl->GetValue().ToDouble( &dtmp );
    value.z = dtmp;
    return value;
}


/**************************************************/
void WinEDA_VertexCtrl::SetValue( S3D_Vertex vertex )
/**************************************************/
{
    wxString text;

    text.Printf( wxT( "%f" ), vertex.x );
    m_XValueCtrl->Clear();
    m_XValueCtrl->AppendText( text );

    text.Printf( wxT( "%f" ), vertex.y );
    m_YValueCtrl->Clear();
    m_YValueCtrl->AppendText( text );

    text.Printf( wxT( "%f" ), vertex.z );
    m_ZValueCtrl->Clear();
    m_ZValueCtrl->AppendText( text );
}


/*****************************************/
void WinEDA_VertexCtrl::Enable( bool onoff )
/*****************************************/
{
    m_XValueCtrl->Enable( onoff );
    m_YValueCtrl->Enable( onoff );
    m_ZValueCtrl->Enable( onoff );
}