#include <QMouseEvent>
#include <QEvent>
#include <QPaintEvent>
#include <QCloseEvent>
#include <QApplication>
#include <QMessageBox>
#include <QGLFormat>

#include "OpenRMWidget.h"
#include "Program_title.h"

#include "Defs.h"
#include "OpenRMcpp.h"

#include "MinMax.h"

OpenRMWidget::
OpenRMWidget (QWidget *parent)
:   
    QGLWidget (QGLFormat(QGL::SampleBuffers), parent),
    pipe_       (0),
    root_node_  (0),
    camera_node_(0),
    scene_node_ (0),
    object_node_(0)
{
    setFocusPolicy (Qt::ClickFocus);
    setMouseTracking (true);
}

OpenRMWidget::
~OpenRMWidget()
{
    pipe_       = 0;
    root_node_  = 0;
    camera_node_= 0;
    scene_node_ = 0;
    object_node_= 0;
}

void OpenRMWidget::
paintEvent (QPaintEvent *event)
{
    RMtime *time_1 = rmTimeNew ();
    RMtime *time_2 = rmTimeNew ();
    rmTimeCurrent (time_1);

    QGLWidget::paintEvent(event);

    rmTimeCurrent (time_2);
    rmTimeDelete (time_1);
    rmTimeDelete (time_2);
}

void OpenRMWidget::
initializeGL ()
{
    RMenum result = RM_WHACKED;

    // Pipe
    #if defined(Q_WS_WIN)
        pipe_ = rmPipeNew (RM_PIPE_WGL);
    #else
        pipe_ = rmPipeNew (RM_PIPE_GLX);
    #endif

    if (pipe_ == 0)
        throw QString ("Can not create RMpipe.");

    result = rmPipeSetProcessingMode  (pipe_, RM_PIPE_MULTISTAGE);
    if (result != RM_CHILL)
        throw QString ("rmPipeSetProcessingMode");

    rmPipeSetSwapBuffersFunc (pipe_, NULL);

#if 0
    // wes 9/26/04 - don't set the window handle, just tell OpenRM how
    // big the display window is in terms of width, height.
    result = rmPipeSetWindow          (pipe_, winId(), width(), height());
#else
    result = rmPipeSetWindowSize(pipe_, width(), height());
#endif
    if (result != RM_CHILL)
        throw QString ("rmPipeSetWindow");

    //rmxPipeSetDisplay (pipe_, NULL);
    rmPipeSetContext  (pipe_, 0);

    result = rmPipeMakeCurrent (pipe_);  //fix move to render ?
    if (result != RM_CHILL)
        throw QString ("rmPipeMakeCurrent");//*/

    //rmPipeSetProcessingMode (pipe_, RM_PIPE_MULTISTAGE_VIEW_PARALLEL);
    //rmPipeSetInitMatrixStackMode (pipe_, RM_FALSE);
    rmPipeSetDisplayListEnable (pipe_, RM_TRUE);

    // Scene graph
    
    // initObjectTree /////////////////////////////////////////////////////////////////
    //root_node_   = rmNodeNew ("Root",   RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    float      vp[4];
    RMvertex3D bmin, bmax;
    
    root_node_ = rmNodeNew("Root", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    //root_node_ = rmNodeNew("Root", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);

    vp[0] = RM_DEFAULT_VIEWPORT_XMIN;
    vp[1] = RM_DEFAULT_VIEWPORT_YMIN;
    vp[2] = RM_DEFAULT_VIEWPORT_XMAX;
    vp[3] = RM_DEFAULT_VIEWPORT_YMAX;

    rmNodeSetSceneViewport (root_node_, vp);

    bmin.x = bmin.y = bmin.z = RM_MAXFLOAT;
    bmax.x = bmax.y = bmax.z = RM_MINFLOAT;
    rmNodeSetBoundingBox (root_node_, &bmin, &bmax);

    rmNodeSetAmbientColor       (root_node_, &RM_DEFAULT_AMBIENT_COLOR);
    rmNodeSetDiffuseColor       (root_node_, &RM_DEFAULT_DIFFUSE_COLOR);
    rmNodeSetSpecularColor      (root_node_, &RM_DEFAULT_SPECULAR_COLOR);
    rmNodeSetSpecularExponent   (root_node_, RM_DEFAULT_SPECULAR_EXPONENT);
    rmNodeSetUnlitColor         (root_node_, &RM_DEFAULT_UNLIT_COLOR);
    rmNodeSetNormalizeNormals   (root_node_, RM_FALSE);

    /* set the default rendering parms */
    //rmNodeSetShader(root_node_, RM_DEFAULT_RENDERMODE); 
    rmNodeSetShader(root_node_, RM_SHADER_SMOOTH);

    //rmNodeSetPolygonDrawMode(root_node_, RM_FRONT_AND_BACK, RM_FILL);
    rmNodeSetPolygonDrawMode(root_node_, RM_FRONT, RM_FILL);

    //rmNodeSetPolygonCullMode(root_node_, RM_CULL_NONE);
    rmNodeSetPolygonCullMode(root_node_, RM_CULL_BACK);
    rmNodeSetFrontFace(root_node_, RM_CCW);

    rmNodeSetLineStyle(root_node_, RM_LINES_SOLID);
    rmNodeSetLineWidth(root_node_, RM_LINEWIDTH_NARROW);

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

    camera_node_ = rmNodeNew ("Camera", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    scene_node_  = rmNodeNew ("Scene",  RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);

    //camera_node_ = rmNodeNew ("Camera", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);
    //scene_node_  = rmNodeNew ("Scene",  RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);

    rmNodeAddChild (root_node_,   camera_node_);
    rmNodeAddChild (camera_node_, scene_node_);

    RMmatrix initial_transform;
    rmMatrixIdentity (&initial_transform);
    rmNodeSetRotateMatrix (root_node_,   &initial_transform);
    rmNodeSetRotateMatrix (camera_node_, &initial_transform);
    rmNodeSetRotateMatrix (scene_node_,  &initial_transform);

    float viewport[4] = {0.F, 0.F, 1.F, 1.F};
    rmNodeSetSceneViewport (root_node_, viewport);

    create_camera ();
    create_lighting ();
    create_light_model ();

    //RMcolor4D specular = {0.4F, 0.4F, 0.4F, 1.0F};
    
    object_node_ = rmNodeNew ("Object", RM_RENDERPASS_3D, RM_RENDERPASS_OPAQUE);
    //object_node_ = rmNodeNew ("Object", RM_RENDERPASS_ALL, RM_RENDERPASS_ALL);

    rmNodeSetRotateMatrix (object_node_,  &initial_transform);
    //rmNodeSetSpecularColor    (object_node_, &specular);
    //rmNodeSetSpecularExponent (object_node_, 20);//*/  
    rmNodeAddChild (scene_node_, object_node_);    //fix remove

    fog_ = rmFogNew ();
    rmFogSetStartEnd (fog_, 300, 400);
    rmNodeSetSceneFog  (scene_node_, fog_);

    time_1_ = rmTimeNew ();
    time_2_ = rmTimeNew ();

    set_eye_distance (50);
}

void OpenRMWidget::
fit (double & x_center,
     double & y_center,
     double & z_center,
     double & scale)
{
    if (scale == 0)
        return;

    RMcamera3D *camera;
    rmNodeGetSceneCamera3D (camera_node_, &camera);

    RMvertex3D  center;

    //rmNodeUnionAllBoxes (root_node_);
    //rmNodeComputeCenterFromBoundingBox(root_node_);
    //rmNodeComputeBoundingBox(root_node_);

    double new_eye_distance = (scale/2)
                        / tan (rmCamera3DGetFOV (camera) * 3.14 / 180 / 2);

    set_eye_distance (new_eye_distance);
    
    center.x = -x_center;
    center.y = -y_center;
    center.z = -z_center;
    rmNodeSetTranslateVector (camera_node_, &center);

    center.x = x_center;
    center.y = y_center;
    center.z = z_center;
    rmNodeSetCenter          (camera_node_, &center);

    rmCamera3DDelete (camera);
    updateGL ();
}

void OpenRMWidget::
flush_camera ()
{
    RMmatrix transform;
    rmMatrixIdentity      (&transform);
    rmNodeSetRotateMatrix (camera_node_, &transform);
    updateGL ();
}

//void OpenRMWidget::
//demo_rotation (int steps)
//{
//    for (int i=0;  i<steps;  ++i)
//    {
//         double x = 400. + 300. * cos(.02 * i + 3.14);
//         double y = 300. + 200. * sin(.02 * i);
//
//         QMouseEvent event
//            (QEvent::MouseMove, QPoint(int(x), int(y)), 
//	     Qt::NoButton, Qt::LeftButton);
//         QApplication::sendEvent (this, &event);
//    }
//}

double OpenRMWidget::
eye_distance () const
{
    RMcamera3D *camera;
    rmNodeGetSceneCamera3D (camera_node_, &camera);
    
    double result = eye_distance (camera);
    
    rmCamera3DDelete (camera);
    return result;
}

double OpenRMWidget::
eye_distance (RMcamera3D *camera) const
{
    RMvertex3D  at_point, eye_point, eye_vector;

    rmCamera3DGetEye (camera, &eye_point);
    rmCamera3DGetAt  (camera, &at_point);
    rmVertex3DDiff   (&eye_point, &at_point, &eye_vector);

    return rmVertex3DMag (&eye_vector);
}

void OpenRMWidget::
set_eye_distance (double distance)
{
    RMcamera3D *camera;
    rmNodeGetSceneCamera3D (camera_node_, &camera);
    set_eye_distance (camera, distance);

    rmCamera3DSetYon (camera, 10000.F);//fix

    rmNodeSetSceneCamera3D (camera_node_, camera);
    rmCamera3DDelete (camera);
}

void OpenRMWidget::
set_eye_distance (RMcamera3D *camera, double distance)
{
    RMvertex3D  at_point, old_eye_point, new_eye_point, eye_vector;

    rmCamera3DGetEye    (camera, &old_eye_point);
    rmCamera3DGetAt     (camera, &at_point);
    rmVertex3DDiff      (&old_eye_point, &at_point, &eye_vector); 
    rmVertex3DNormalize (&eye_vector);
    eye_vector.x *= distance;
    eye_vector.y *= distance;
    eye_vector.z *= distance;
    rmVertex3DSum (&at_point, &eye_vector, &new_eye_point);
    rmCamera3DSetEye (camera, &new_eye_point);

    //int lod = int(10/sqrt(distance));
    //int lod = int(50/sqrt(distance));
    int lod = int(80/sqrt(distance));
    //model_view_->set_level_of_details (lod);
    set_level_of_details (lod);
    //model_view_->set_level_of_details (3);

    QString name (MM::program_title ());

#ifdef ASCALAPH
    //if (name.contains ("Ascalaph",  Qt::CaseInsensitive))
    {
        //RMcolor4D         fog_color = {0.2f, 0.2f, 0.3f, 1.f};
        double k = 0.8;
        //RMcolor4D         fog_color = {k*100.F/256.F, k*95.F/256.F, k*85.F/256.F, 1.0F};
        //RMcolor4D         fog_color = {k*118.F/256.F, k*112.F/256.F, k*100.F/256.F, 1.0F};
        RMcolor4D         fog_color = {k*140.F/256.F, k*130.F/256.F, k*120.F/256.F, 1.0F};

        rmFogSetColor    (fog_, &fog_color);
    }
#else
    //else if (name.contains ("Abalone",  Qt::CaseInsensitive))
    {
        double k = 0.80;
        //RMcolor4D fog_color = {k*227.F/256.F, k*222.F/256.F, k*200.F/256.F, 1.0F};
        RMcolor4D fog_color = {k*241.F/256.F, k*232.F/256.F, k*218.F/256.F, 1.0F};
        rmFogSetColor (fog_, &fog_color);
    }
#endif

    rmFogSetMode     (fog_, GL_LINEAR);
    //rmFogSetDensity  (fog_, .5);
    //rmFogSetStartEnd (fog_, 0.95*distance, 1.15*distance);
    rmFogSetDensity  (fog_, 1.0);
    rmFogSetStartEnd (fog_, 0.95*distance, 1.2*distance);

    //rmFogSetMode     (fog_, GL_EXP);
    //rmFogSetDensity  (fog_, .5);
    //rmFogSetStartEnd (fog_, 100*distance, 200*distance);

    rmNodeSetSceneFog  (scene_node_, fog_);
}

void OpenRMWidget::
paintGL ()
{
    rmTimeCurrent (time_1_);

    rmFrame (pipe_, root_node_);

    rmTimeCurrent (time_2_);
    
    //rmPipeSetDisplayListEnable (pipe_, RM_TRUE);
}

void OpenRMWidget::
create_lighting ()
{
    //rmDefaultLighting (root_); return;

    //RMcolor4D background_color = {.30f, .22f, .15f, 1.0f};
    //RMcolor4D background_color = {.30f, .26f, .20f, 1.0f};
    //RMcolor4D background_color = {.30F, .28F, .25F, 1.0F};

    //RMcolor4D background_color = {.35F, .33F, .30F, 1.0F};
    //RMcolor4D background_color = {.35F, .33F, .28F, 1.0F};
    //RMcolor4D background_color = {60.F/256.F, 90.F/256.F, 80.F/256.F, 1.0F};
    //RMcolor4D background_color = {80.F/256.F, 70.F/256.F, 60.F/256.F, 1.0F};

    QString name (MM::program_title ());

#ifdef ASCALAPH
    //if (name.contains ("Ascalaph",  Qt::CaseInsensitive))
    {
        //double k = 1.5;
        //double k = 1.6;
        double k = 1.7;
        //RMcolor4D background_color = {k*95.F/256.F, k*85.F/256.F, k*70.F/256.F, 1.0F};
        //RMcolor4D background_color = {k*95.F/256.F, k*88.F/256.F, k*75.F/256.F, 1.0F};
        RMcolor4D background_color = {k*100.F/256.F, k*95.F/256.F, k*85.F/256.F, 1.0F};

        //RMcolor4D background_color = {242.F/256.F, 242.F/256.F, 232.F/256.F, 1.0F};
        //RMcolor4D background_color = {223.F/256.F, 223.F/256.F, 211.F/256.F, 1.0F};
    //    RMcolor4D background_color = {199.F/256.F, 199.F/256.F, 183.F/256.F, 1.0F};
        //RMcolor4D background_color = {190.F/256.F, 190.F/256.F, 175.F/256.F, 1.0F};
 
        rmNodeSetSceneBackgroundColor (root_node_, &background_color);

        //RMcolor4D unlit_color = {0.9f, 0.9f, 0.9f, 1.0f}; 
        RMcolor4D unlit_color = {0.5f, 0.5f, 0.5f, 1.f};
        rmNodeSetUnlitColor (root_node_, &unlit_color);


        //RMcolor4D  ambient_0 = {0.1f, 0.1f, 0.1f, 1.0f};
        RMcolor4D  ambient_0 = {0.15f, 0.15f, 0.15f, 1.0f};
        //RMcolor4D  ambient_0 = {0.2f, 0.2f, 0.2f, 1.0f};
        //RMcolor4D  ambient_0 = {0.25f, 0.25f, 0.25f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.7f, 0.7f, 0.7f, 1.0f};
        RMcolor4D  ambient_1 = {0.0f, 0.0f, 0.0f, 1.0f};

        //RMcolor4D  diffuse_0 = {0.80f, 0.80f, 0.80f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.70f, 0.70f, 0.70f, 1.0f};
        RMcolor4D  diffuse_0 = {0.60f, 0.60f, 0.60f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.50f, 0.50f, 0.50f, 1.0f};
        //RMcolor4D  diffuse_1 = {0.0f, 0.0f, 0.0f, 1.0f};
        RMcolor4D  diffuse_1 = {0.25f, 0.25f, 0.25f, 1.0f};

        RMcolor4D  specular_0 = {0.1f, 0.1f, 0.1f, 1.0f};
        //RMcolor4D  specular_0 = {0.15f, 0.15f, 0.15f, 1.0f};
        //RMcolor4D  specular_0 = {0.2f, 0.2f, 0.2f, 1.0f};
        //RMcolor4D  specular_0 = {0.3f, 0.3f, 0.3f, 1.0f};
        //RMcolor4D  specular_0 = {0.4f, 0.4f, 0.4f, 1.0f};
        //RMcolor4D  specular_0 = {0.7f, 0.7f, 0.7f, 1.0f};
        //RMcolor4D  specular_0 = {1.f, 1.f, 1.f, 1.0f};    
        RMcolor4D  specular_1 = {0.4f, 0.4f, 0.4f, 1.0f};
        //RMcolor4D  specular_1 = {0.5f, 0.5f, 0.5f, 1.0f};

        RMvertex3D position_0 = {0.0,  0.0,  1.0}; 
        RMvertex3D position_1 = {-5.0, 5.0,  -2.0};

        RMlight *light_0 = rmLightNew();
        if (light_0 == 0)
            throw QString ("Can not create first light source");;

        //rmLightSetType  (light_0, RM_LIGHT_DIRECTIONAL); 
        //rmLightSetColor (light_0, NULL, NULL, NULL); 
        rmLightSetColor (light_0, &ambient_0, &diffuse_0, &specular_0); 
        rmLightSetXYZ   (light_0, &position_0);

        RMlight *light_1 = rmLightNew();
        if (light_1 == 0)
            throw QString ("Can not create second light source");
        
        //rmLightSetType  (light_1, RM_LIGHT_DIRECTIONAL); 
        //rmLightSetColor (light_1, NULL, NULL, NULL);
        rmLightSetColor (light_1, &ambient_1, &diffuse_1, &specular_1);
        rmLightSetXYZ   (light_1, &position_1);

        rmNodeSetSceneLight (root_node_, RM_LIGHT0, light_0);
        rmNodeSetSceneLight (root_node_, RM_LIGHT1, light_1);   

        rmNodeSetSpecularExponent (root_node_, 20);

        rmLightDelete (light_1);
        rmLightDelete (light_0); 
    }
#else
    //else if (name.contains ("Abalone",  Qt::CaseInsensitive))
    {
        //double k = 1.7;
        //RMcolor4D background_color = {k*100.F/256.F, k*95.F/256.F, k*85.F/256.F, 1.0F};

        //float k = 1.15;
        //float k = 1.10;
        //float k = 1.1;
        //float k = 1.F;
        //float k = 1.05;
        float k = 0.98f;
        //float k = 0.90;
        //RMcolor4D background_color = {k*225.F/256.F, k*222.F/256.F, k*200.F/256.F, 1.0F};
        //RMcolor4D background_color = {k*230.F/256.F, k*230.F/256.F, k*210.F/256.F, 1.0F};
        //RMcolor4D background_color = {k*216.F/256.F, k*202.F/256.F, k*179.F/256.F, 1.0F};
        //RMcolor4D background_color = {k*238.F/256.F, k*233.F/256.F, k*218.F/256.F, 1.0F};

		RMcolor4D background_color = {k*244.F/256.F, k*245.F/256.F, k*239.F/256.F, 1.0F};
		//RMcolor4D background_color = {k*210.F/256.F, k*210.F/256.F, k*200.F/256.F, 1.0F};
		//RMcolor4D background_color = {k*226.F/256.F, k*224.F/256.F, k*215.F/256.F, 1.0F};
        rmNodeSetSceneBackgroundColor (root_node_, &background_color);

        //RMcolor4D unlit_color = {0.9f, 0.9f, 0.9f, 1.0f}; 
        RMcolor4D unlit_color = {0.5f, 0.5f, 0.5f, 1.f};
        rmNodeSetUnlitColor (root_node_, &unlit_color);

        //RMcolor4D  ambient_0 = {0.1f, 0.1f, 0.1f, 1.0f};
        //RMcolor4D  ambient_0 = {0.15f, 0.15f, 0.15f, 1.0f};
        //RMcolor4D  ambient_0 = {0.2f, 0.2f, 0.2f, 1.0f};
        RMcolor4D  ambient_0 = {0.25f, 0.25f, 0.25f, 1.0f};
        //RMcolor4D  ambient_0 = {0.40f, 0.40f, 0.40f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.7f, 0.7f, 0.7f, 1.0f};
        RMcolor4D  ambient_1 = {0.0f, 0.0f, 0.0f, 1.0f};

        //RMcolor4D  diffuse_0 = {0.80f, 0.80f, 0.80f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.75f, 0.75f, 0.75f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.70f, 0.70f, 0.70f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.63f, 0.63f, 0.63f, 1.0f};
        RMcolor4D  diffuse_0 = {0.60f, 0.60f, 0.60f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.50f, 0.50f, 0.50f, 1.0f};
        //RMcolor4D  diffuse_0 = {0.40f, 0.40f, 0.40f, 1.0f};
        RMcolor4D  diffuse_1 = {0.0f, 0.0f, 0.0f, 1.0f};
        //RMcolor4D  diffuse_1 = {0.25f, 0.25f, 0.25f, 1.0f};

        RMcolor4D  specular_0 = {0.2f, 0.2f, 0.2f, 1.0f};
        //RMcolor4D  specular_0 = {0.15f, 0.15f, 0.15f, 1.0f};
        //RMcolor4D  specular_0 = {0.2f, 0.2f, 0.2f, 1.0f};
        //RMcolor4D  specular_0 = {0.3f, 0.3f, 0.3f, 1.0f};
        //RMcolor4D  specular_0 = {0.4f, 0.4f, 0.4f, 1.0f};
        //RMcolor4D  specular_0 = {0.7f, 0.7f, 0.7f, 1.0f};
        //RMcolor4D  specular_0 = {1.f, 1.f, 1.f, 1.0f};    
        RMcolor4D  specular_1 = {0.4f, 0.4f, 0.4f, 1.0f};
        //RMcolor4D  specular_1 = {0.5f, 0.5f, 0.5f, 1.0f};

        RMvertex3D position_0 = {0.0,  0.0,  1.0}; 
        RMvertex3D position_1 = {-5.0, 5.0,  -2.0};

        RMlight *light_0 = rmLightNew();
        if (light_0 == 0)
            throw QString ("Can not create first light source");;

        //rmLightSetType  (light_0, RM_LIGHT_DIRECTIONAL); 
        //rmLightSetColor (light_0, NULL, NULL, NULL); 
        rmLightSetColor (light_0, &ambient_0, &diffuse_0, &specular_0); 
        rmLightSetXYZ   (light_0, &position_0);

        RMlight *light_1 = rmLightNew();
        if (light_1 == 0)
            throw QString ("Can not create second light source");
        
        //rmLightSetType  (light_1, RM_LIGHT_DIRECTIONAL); 
        //rmLightSetColor (light_1, NULL, NULL, NULL);
        rmLightSetColor (light_1, &ambient_1, &diffuse_1, &specular_1);
        rmLightSetXYZ   (light_1, &position_1);

        rmNodeSetSceneLight (root_node_, RM_LIGHT0, light_0);
        rmNodeSetSceneLight (root_node_, RM_LIGHT1, light_1);   

        rmNodeSetSpecularExponent (root_node_, 20);

        rmLightDelete (light_1);
        rmLightDelete (light_0); 
    }
#endif
}

void OpenRMWidget::
create_light_model ()
{
    RMlightModel * light_model  = rmLightModelNew ();

    RMcolor4D  ambient = {0.15f, 0.15f, 0.15f, 1.0f};

    rmLightModelSetAmbient (light_model, &ambient);


    //rmLightModelSetTwoSided     (light_model, RM_TRUE);
    //rmLightModelSetLocalViewer  (light_model, RM_TRUE);

    
    rmNodeSetSceneLightModel (root_node_, light_model);
    //rmLightModelDelete (light_model);
}

void OpenRMWidget::
create_camera ()
{
    RMcamera3D *camera;
    RMvertex3D eye = {0.0, 0.0, 1000.0};
    RMvertex3D up  = {0.0, 1.0, 0.0};
    RMvertex3D at  = {0.0, 0.0, 0.0} ;
    float hither   = 0.1F, yon = 500.F;

    camera = rmCamera3DNew();
    
    rmCamera3DSetEye        (camera, &eye);
    rmCamera3DSetAt         (camera, &at);
    rmCamera3DSetUpVector   (camera, &up);
    rmCamera3DSetHither     (camera, hither);
    rmCamera3DSetYon        (camera, yon);
    rmCamera3DSetAspectRatio(camera, 1.0F);
    rmCamera3DSetProjection (camera, RM_PROJECTION_PERSPECTIVE); 
    //rmCamera3DSetFOV(camera, 40.0F);
    //rmCamera3DSetFOV(camera, 90.0F);
    //rmCamera3DSetFOV (camera, 10.0F);
    rmCamera3DSetFOV (camera, 20.0F);

    //rmDefaultCamera3D(camera);
    //rmCamera3DComputeViewFromGeometry (camera, root_node_, width(), height());
    /*//if (stereo_format != RM_MONO_CHANNEL)
    {
        rmCamera3DSetStereo(camera,RM_TRUE);
        rmCamera3DSetEyeSeparation(camera,2.5F);
        rmCamera3DSetFocalDistance (camera,0.707F);
    }//*/

    {
       float vp[4] = {0.0, 0.0, 1.0, 1.0};
       rmCamera3DResetAspectRatio (camera, vp, width(), height());
    }//*/

    //rmCamera3DComputeViewFromGeometry(camera,root_,width(),height());

    rmNodeSetSceneCamera3D (camera_node_, camera);
    //rmNodeSetSceneCamera3D (scene_, camera);
    rmCamera3DDelete (camera);
}

void OpenRMWidget::
resizeGL (int width, int height)
{
    RMcamera3D *camera = 0;

    if (rmNodeGetSceneCamera3D (camera_node_, &camera) != RM_WHACKED)
    {
        rmCamera3DSetAspectRatio (camera, (float(width) / float(height)));
        rmNodeSetSceneCamera3D   (camera_node_, camera);
    }

    if (camera == 0)
    {
        QMessageBox::warning (0 , "", "the cameraNode does not contain "
                             "either a 2D or 3D camera scene parameter!");
    }

    rmPipeSetWindowSize (pipe_, width, height);

    QGLWidget::resizeGL (width, height);
}

void OpenRMWidget::
mousePressEvent (QMouseEvent * event)
{
    last_press_position_ = last_position_ = event->pos();
    QGLWidget::mousePressEvent (event);
}

void OpenRMWidget::
mouseMoveEvent (QMouseEvent * event)
{
    //float hypotenuse = sqrt (2);
    int scale = min (width(), height());
    
    float last_x    =  pixel_to_float (last_position_.x(), width (), scale);
    float last_y    = -pixel_to_float (last_position_.y(), height(), scale);
    float current_x =  pixel_to_float (event->x(),         width (), scale);
    float current_y = -pixel_to_float (event->y(),         height(), scale);//*/

    //double dx = current_x - last_x;
    double dy = current_y - last_y;

    if (event->buttons () & Qt::LeftButton)  //fix
    {
        if (event->modifiers () & Qt::ShiftModifier ) // Zoom
        {
            double increment = 1. + mouse_scaling_increment * dy;
            double distance = eye_distance ();
            set_eye_distance (distance * increment);
        }

        else if (event->modifiers () & Qt::ControlModifier ) //Move
        {
            RMcamera3D *camera;
            rmNodeGetSceneCamera3D (camera_node_, &camera);
            //rmauxTranslate (camera, &last_x_, &last_y_, &current_x, &current_y);
            //rmNodeSetSceneCamera3D (root_, camera);

            RMvertex3D  at_point, eye_point, up_point, 
                        eye_vector, up_vector, rigth_vector, movement;

            rmCamera3DGetEye      (camera, &eye_point);
            rmCamera3DGetAt       (camera, &at_point);
            rmCamera3DGetUpVector (camera, &up_point);

            rmVertex3DDiff  (&eye_point, &at_point, &eye_vector);
            rmVertex3DDiff  (&up_point,  &at_point, &up_vector);
//            rmVertex3DCross (&up_vector, &eye_vector, &rigth_vector);
            rmVertex3DCross (&eye_vector, &up_vector, &rigth_vector);

            rmVertex3DNormalize (&up_vector);
            rmVertex3DNormalize (&rigth_vector);

            double eye_distance = rmVertex3DMag (&eye_vector);
            rmVertex3DNormalize (&eye_vector);


            double tg_FOV2      = tan ((rmCamera3DGetFOV (camera)*3.14159265/180) / 2);
            double x_movement   = (event->x() - last_position_.x()) 
                                    * eye_distance * 2 * tg_FOV2 / height ();

            double y_movement   = (event->y() - last_position_.y()) 
                                    * eye_distance * 2 * tg_FOV2 / height();

            RMvertex3D v;
            rmVertex3DCross (&rigth_vector, &eye_vector, &v);
            rmVertex3DNormalize (&v);

            v.x *= y_movement;
            v.y *= y_movement;
            v.z *= y_movement;

            rigth_vector.x *= x_movement;
            rigth_vector.y *= x_movement;
            rigth_vector.z *= x_movement;

            rmVertex3DSum (&v, &rigth_vector, &movement);

            ///rmVertex3DSum (&eye_point, &movement, &eye_point);
            ///rmVertex3DSum (&at_point,  &movement, &at_point);
            //rmVertex3DSum (&up_point,  &movement, &up_point);

            ///rmCamera3DSetEye      (camera, &eye_point);
            ///rmCamera3DSetAt       (camera, &at_point);
            //rmCamera3DSetUpVector (camera, &up_point);

            //rmNodeSetSceneCamera3D (root_, camera);//*/
            
            RMvertex3D  last_movement; 
            rmNodeGetTranslateVector (camera_node_, &last_movement);
            rmVertex3DDiff  (&last_movement, &movement, &movement);
            rmNodeSetTranslateVector (camera_node_, &movement);//*/

            rmCamera3DDelete (camera);
        }

        else // Rotate
        {
            RMmatrix last_transform;
            RMmatrix result_transform;

            float k = .6f;             //fix magic
            last_x    *= k;
            last_y    *= k;
            current_x *= k;
            current_y *= k;//*/

            rmauxArcBall          (&last_x, &last_y, &current_x, &current_y,
                                   &result_transform);
            rmNodeGetRotateMatrix (camera_node_, &last_transform);
            rmMatrixMultiply      (&last_transform, &result_transform, 
                                   &result_transform);
            rmNodeSetRotateMatrix (camera_node_, &result_transform);
        }
        updateGL ();
    }
    
    last_position_ = event->pos();
    //QGLWidget::mouseMoveEvent (event);
}

void OpenRMWidget::
closeEvent (QCloseEvent * e)
{
    //doneCurrent ();
    makeCurrent ();

    if (!isValid ())
        throw QString ("has not a valid GL rendering context");

    RMenum result = RM_WHACKED;
    
#ifdef MM_WIN32
    result = rmSubTreeDelete (root_node_, RM_TRUE);//fix RM_TRUE
#else
    result = rmSubTreeDelete (root_node_);
#endif

    if (result != RM_CHILL)
        throw QString ("rmSubTreeDelete");//*/

    // wes 9/26/04 - it is correct to first close the pipe with rmPipeClose
    // followed by deleting it with rmPipeDelete. Alternatively, you could
    // just call rmPipeDelete with no rmPipeClose, since rmPipeDelete will
    // itself call rmPipeClose. Having both here was a good exercise for
    // OpenRM for it revealed a bug. (Thanks!)

    result = rmPipeClose  (pipe_);
    if (result != RM_CHILL)
        throw QString ("rmPipeClose");
    
    result = rmPipeDelete (pipe_);
    if (result != RM_CHILL)
        throw QString ("rmPipeDelete");

    rmTimeDelete (time_2_);
    rmTimeDelete (time_1_);

    QGLWidget::closeEvent (e);
}
