/*@@@**************************************************************************
* \file  glViewer
* \author Hernan Badino
* \date  Tue Sep  8 13:34:41 EDT 2009
* \notes 
*******************************************************************************
*****          (C) COPYRIGHT Hernan Badino - All Rights Reserved          *****
******************************************************************************/

/* INCLUDES */
#include "glViewer.h"

using namespace VIC;

CGLViewer::CGLViewer()
        : QGLViewer (),
          CIOObj (),
          m_bgColor ( 96, 96, 96 ),
          m_pointSize_f ( 0.f ),
          m_lineWidth_f ( 0.f )
{}


// Draws a spiral
void CGLViewer::draw()
{
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();

    camera()->setSceneRadius( 30. );

    // Reset modelview matrix
    QGLViewer::setBackgroundColor( QColor( m_bgColor.r, m_bgColor.g, m_bgColor.b ));
    printf ("Setting background color to %i %i %i (%f %f)\n", m_bgColor.r, m_bgColor.g, m_bgColor.b,
            m_pointSize_f,
            m_lineWidth_f ) ;

    glPointSize ( m_pointSize_f );
    glLineWidth( m_lineWidth_f );

    glDisable( GL_TEXTURE_GEN_Q );
    glDisable( GL_TEXTURE_GEN_S );
    glDisable( GL_TEXTURE_GEN_R );
    glDisable( GL_TEXTURE_GEN_T );

    glDisable( GL_TEXTURE_1D );
    glDisable( GL_TEXTURE_2D );

    glDisable( GL_COLOR_MATERIAL );

    glDisable( GL_LIGHTING );

    glBegin(GL_POINTS);
    
    for (unsigned int i = 0; i < m_points.size(); ++i)
    {
        glColor3f(m_colors[i].r/255., 
                  m_colors[i].g/255., 
                  m_colors[i].b/255.);
        
        glNormal3f( m_normals[i].x(), 
                    m_normals[i].y(), 
                    m_normals[i].z() );

        glVertex3f( m_points[i].x(), 
                    m_points[i].y(), 
                    m_points[i].z() );
    }
   
    glEnd();

    glPointSize ( m_pointSize_f );
    glLineWidth( m_lineWidth_f );
    glBegin(GL_LINES);

    for (unsigned int i = 0; i < m_points.size(); ++i)
    {
        if ( m_normals[i].x() != 0 || 
             m_normals[i].y() != 0 || 
             m_normals[i].z() != 0 )
        {
            glColor3f(m_colors[i].r/255., 
                      m_colors[i].g/255., 
                      m_colors[i].b/255.);
            
            //glNormal3f( f_normal.x(), f_normal.y(), f_normal.z() );
            C3DVector p2 = m_points[i] + m_normals[i];
            
            glVertex3f( m_points[i].x(), 
                        m_points[i].y(), 
                        m_points[i].z() );
            
            glVertex3f( p2.x(), 
                        p2.y(), 
                        p2.z() );
        }
    }
   
    glEnd();

    drawMeshes();

    glPointSize ( m_pointSize_f );
    glLineWidth( m_lineWidth_f );

    glColor3f( 150.f/256.f, 
               150.f/256.f,
               150.f/256.f);

    glPopMatrix();  
}

void
CGLViewer::preDraw()
{
    QGLViewer::preDraw();
}

void
CGLViewer::postDraw()
{
    glPushMatrix();
    camera()->loadModelViewMatrix();
    glPushAttrib( GL_ALL_ATTRIB_BITS );

    glDisable( GL_TEXTURE_GEN_Q );
    glDisable( GL_TEXTURE_GEN_S );
    glDisable( GL_TEXTURE_GEN_R );
    glDisable( GL_TEXTURE_GEN_T );

    glDisable( GL_TEXTURE_1D );
    glDisable( GL_TEXTURE_2D );

    glDisable( GL_COLOR_MATERIAL );

    // Draw all visual hints (revolve around point, zoom and so on).
    drawVisualHints();

    if ( gridIsDrawn() )
        drawGrid( 100, 100 );

    glDisable( GL_LIGHTING );

    if ( axisIsDrawn() )
    {
        glLineWidth( 3 );
        drawAxis( 1. );
    }

    // Restore GL state
    glPopAttrib();
    glPopMatrix();
}


void CGLViewer::init()
{
    /// From f1 to f3 different camera poses.
    camera()->setPosition( qglviewer::Vec( 0.0, 0.0, 0.0 ) );
    camera()->lookAt(      qglviewer::Vec( 0.0, 0.0, 1.0 ) );
    camera()->setUpVector( qglviewer::Vec( 0.0, 1.0, 0.0 ) );
    camera()->setRevolveAroundPoint( qglviewer::Vec( 0.0,  0.0, 1.0 ) ); // not saved :(
    camera()->addKeyFrameToPath( 1 );
    
    camera()->setPosition( qglviewer::Vec( 0.0, 75.0, 25.0 ) );
    camera()->lookAt(      qglviewer::Vec( 0.0,  0.0, 25.0 ) );
    camera()->setUpVector( qglviewer::Vec( 0.0,  0.0,  1.0 ) );
    camera()->setRevolveAroundPoint( qglviewer::Vec( 0.0,  0.0, 25.0 ) );
    camera()->addKeyFrameToPath( 2 );
    
    camera()->setPosition( qglviewer::Vec( -50.0, 1.0, 25.0 ) );
    camera()->lookAt(      qglviewer::Vec( 0.0,   1.0, 25.0 ) );
    camera()->setUpVector( qglviewer::Vec( 0.0,  1.0,  0.0 ) );
    camera()->setRevolveAroundPoint( qglviewer::Vec( 0.0,  1.0, 25.0 ) );
    camera()->addKeyFrameToPath( 3 );

    if ( displayMessage_ ) drawText( 10, height() - 10,  message_ );

    // Restore previous viewer state.
    //restoreStateFromFile();
    
    // Opens help window
    //help();
}

QString CGLViewer::helpString() const
{
    QString text("<h2>S i m p l e V i e w e r</h2>");
    text += "Use the mouse to move the camera around the object. ";
    text += "You can respectively revolve around, zoom and translate with the three mouse buttons. ";
    text += "Left and middle buttons pressed together rotate around the camera view direction axis<br><br>";
    text += "Pressing <b>Alt</b> and one of the function keys (<b>F1</b>..<b>F12</b>) defines a camera keyFrame. ";
    text += "Simply press the function key again to restore it. Several keyFrames define a ";
    text += "camera path. Paths are saved when you quit the application and restored at next start.<br><br>";
    text += "Press <b>F</b> to display the frame rate, <b>A</b> for the world axis, ";
    text += "<b>Alt+Return</b> for full screen mode and <b>Control+S</b> to save a snapshot. ";
    text += "See the <b>Keyboard</b> tab in this window for a complete shortcut list.<br><br>";
    text += "Double clicks automates single click actions: A left button double click aligns the closer axis with the camera (if close enough). ";
    text += "A middle button double click fits the zoom of the camera and the right button re-centers the scene.<br><br>";
    text += "A left button double click while holding right button pressed defines the camera <i>Revolve Around Point</i>. ";
    text += "See the <b>Mouse</b> tab and the documentation web pages for details.<br><br>";
    text += "Press <b>Escape</b> to exit the viewer.";
    return text;
}

void CGLViewer::addPoint ( const C3DVector & f_point,
                           const SRgb      & f_color,
                           const C3DVector & f_normal /*= C3DVector (0,0,0) */ )
{
    m_points.push_back ( f_point );
    m_colors.push_back ( f_color );
    m_normals.push_back ( f_normal );
}

void CGLViewer::clear ()
{
    m_meshes.clear();
    m_points.clear();
    m_colors.clear();
    m_normals.clear();
}


void
CGLViewer::add3DVectorImg4Mesh ( const C3DVectorImage * f_3dvImg_p,
                                 const CUShortImage *   f_dispTexture_p,
                                 const float            f_maxDist_f,
                                 const float            f_maxInvDist_f )
{
    SMeshData newMesh;
    newMesh.vectorImg_p   = f_3dvImg_p;
    newMesh.dispTexture_p = f_dispTexture_p;
    newMesh.maxDist_f     = f_maxDist_f;
    newMesh.maxInvDist_f  = f_maxInvDist_f;
    newMesh.created_b     = false;

    m_meshes.push_back( newMesh );
}


void
CGLViewer::drawMeshes()
{    
    for ( unsigned int m = 0 ; m < m_meshes.size(); ++m )
    {
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();

        if ( m_meshes[m].created_b == true && 
             m_meshes[m].displayList_ui != 0 )
            glCallList( m_meshes[m].displayList_ui );
        else
        {
            m_meshes[m].displayList_ui  = glGenLists(1);
            printf("m_meshes[m].displayList_ui = %i\n", m_meshes[m].displayList_ui);
            m_meshes[m].created_b = true;

            const C3DVectorImage *  vimg_p = m_meshes[m].vectorImg_p;
            const int rows_i = (int) vimg_p->getHeight();
            const int cols_i = (int) vimg_p->getWidth();
        
            const CUShortImage *  timg_p = m_meshes[m].dispTexture_p;
           
            glNewList( m_meshes[m].displayList_ui, GL_COMPILE );

            glBegin(GL_TRIANGLES);
        
            for (int i = 0 ; i < rows_i-1; ++i)
            {
                for (int j = 0 ; j < cols_i-1; ++j)
                {
                    int idx[4] = { (i  ) * cols_i + j,
                                   (i+1) * cols_i + j,
                                   (i  ) * cols_i + j+1,
                                   (i+1) * cols_i + j+1 };

                    C3DVector vecs[4] = { vimg_p->getData()[idx[0]],
                                          vimg_p->getData()[idx[1]],
                                          vimg_p->getData()[idx[2]],
                                          vimg_p->getData()[idx[3]] };

                    SRgb colors[4];
                
                    int t;
                    for (t = 0; t < 4; ++t)
                    {
                        if ( !vecs[t] ) break;

                        if (t < 3)
                            if ( fabs(vecs[t].z()   - vecs[t+1].z())   > m_meshes[m].maxDist_f &&
                                 fabs(1/vecs[t].z() - 1/vecs[t+1].z()) > m_meshes[m].maxInvDist_f )
                                break;

                        unsigned short int val = timg_p->getData()[idx[t]];
                        colors[t].set(val/256, val/256, val/256 );
                    }

                    if (t<4) continue;
                
                    for (t = 0; t < 2; ++t)
                    {
                        SRgb color;
                    
                        for (int k = 0; k < 3; ++k)
                        {
                            glColor4f( colors[t+k].r/255., 
                                       colors[t+k].g/255., 
                                       colors[t+k].b/255.,
                                       1.0 );
                        
                            glVertex3f( vecs[t+k].x(), 
                                        vecs[t+k].y(), 
                                        vecs[t+k].z() );
                        }
                    }
                }
            }

            glEnd();
            /*
            glBegin(GL_LINES);
        
            for (int i = 0 ; i < rows_i-1; ++i)
            {
                for (int j = 0 ; j < cols_i-1; ++j)
                {
                    int idx[4] = { (i  ) * cols_i + j,
                                   (i+1) * cols_i + j,
                                   (i  ) * cols_i + j+1,
                                   (i+1) * cols_i + j+1 };

                    C3DVector vecs[4] = { vimg_p->getData()[idx[0]],
                                          vimg_p->getData()[idx[1]],
                                          vimg_p->getData()[idx[2]],
                                          vimg_p->getData()[idx[3]] };

                    SRgb colors[4];
                
                    int t;
                    for (t = 0; t < 4; ++t)
                    {
                        if ( !vecs[t] ) break;

                        if (t < 3)
                            if ( fabs(vecs[t].z()   - vecs[t+1].z())   > m_meshes[m].maxDist_f &&
                                 fabs(1/vecs[t].z() - 1/vecs[t+1].z()) > m_meshes[m].maxInvDist_f )
                                break;

                        unsigned short int val = timg_p->getData()[idx[t]];
                        colors[t].set(val/256, val/256, val/256 );
                    }

                    if (t<4) continue;
                
                    for (t = 0; t < 2; ++t)
                    {
                        SRgb color;
                    
                        for (int k = 0; k < 3; ++k)
                        {
                            glColor4f( colors[t+k].r/255., 
                                       colors[t+k].g/255., 
                                       colors[t+k].b/255.,
                                       1.0 );
                        
                            glVertex3f( vecs[t+k].x(), 
                                        vecs[t+k].y(), 
                                        vecs[t+k].z() );
                        }
                    }
                }
            }

            glEnd();
            */
            /*
            glBegin(GL_LINES);
            for (int i = 0 ; i < rows_i-1; ++i)
            {
                for (int j = 0 ; j < cols_i-1; ++j)
                {
                    int idx[4] = { (i  ) * cols_i + j,
                                   (i+1) * cols_i + j,
                                   (i  ) * cols_i + j+1,
                                   (i+1) * cols_i + j+1 };
                    SRgb colors[4];

                    for (int t = 0; t < 4; ++t)
                        colorEnc.colorFromValue ( m_data_v[idx[t]].upperBound_f,
                                                  colors[t]);
            
                    for (int t = 0; t < 2; ++t)
                    {
                        SRgb color;
        
                        for (int k = 0; k < 3; ++k)
                        {
                            //glColor3f( colors[t+k].r/255., colors[t+k].g/255., colors[t+k].b/255. );
                            //glColor4f( 1.f, 1.f, 1.f, 0.2f );//colors[t+k].r/255., colors[t+k].g/255., colors[t+k].b/255. );
                            glColor4f( 0.f, 0.f, 0.f, 0.2f );//colors[t+k].r/255., colors[t+k].g/255., colors[t+k].b/255. );

                            glVertex3f(m_data_v[idx[t+k]].point.x,
                                       m_data_v[idx[t+k]].point.z,
                                       m_data_v[idx[t+k]].point.y);
                        }                
                    }
                }
            } 
            */  
            glEndList();

            glCallList( m_meshes[m].displayList_ui );
        }
        glPopMatrix();
    }
}


/* ////////////  Version History ///////////////
 *  $Log: glViewer.cpp,v $
 *  Revision 1.3  2010/01/18 17:12:29  badino
 *  General updates and added new classes.
 *
 *  Revision 1.2  2009/11/18 15:50:15  badino
 *  badino: global changes.
 *
 *//////////////////////////////////////////////
