/*
 * RenderState.cpp
 *
 * Copyright (C) 2000 Stephen F. White
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program (see the file "COPYING" for details); if 
 * not, write to the Free Software Foundation, Inc., 675 Mass Ave, 
 * Cambridge, MA 02139, USA.
 */

#include "stdafx.h"

#include "DuneApp.h"
#include "RenderState.h"
#include "Scene.h"
#include "Util.h"

#define ROTATION_HANDLE_SEGMENTS    40

RenderState::RenderState()
{
    _axesStart = 0.0f;
    _vectorStart = 0.0f;
}

Vec3f
RenderState::project(const Vec3f &point)
{
    Vec3d w(point.x, point.y, point.z);
    Vec3d d = project(w);
    Vec3f r(d.x, d.y, d.z);   
    return r;
}

Vec3d
RenderState::project(const Vec3d &point)
{
    Vec3d w = _projectionMatrix * (_modelviewMatrix * point);
    Vec3d r;

    r.x = _viewport[0] + (w.x + 1.0f) * _viewport[2] * 0.5;
    r.y = _viewport[1] + (w.y + 1.0f) * _viewport[3] * 0.5;
    r.z = (w.z + 1.0) * 0.5;
    
    return r;
}

void
RenderState::startDrawHandles()
{
    glGetDoublev(GL_MODELVIEW_MATRIX, (GLdouble *) _modelviewMatrix);
    glGetDoublev(GL_PROJECTION_MATRIX, (GLdouble *) _projectionMatrix);
    glGetDoublev(GL_VIEWPORT, (GLdouble *) _viewport);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(_viewport[0], _viewport[0] + _viewport[2],
            _viewport[1], _viewport[1] + _viewport[3],
            -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    glDisable(GL_CULL_FACE);
    glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}

void
RenderState::drawHandle(const Vec3f &pos)
{
    Vec3f w = project(pos);

    float handleSize = TheApp->GetHandleSize();

    glBegin(GL_POLYGON);
    glVertex3f(w.x - handleSize, w.y - handleSize, w.z);
    glVertex3f(w.x - handleSize, w.y + handleSize, w.z);
    glVertex3f(w.x + handleSize, w.y + handleSize, w.z);
    glVertex3f(w.x + handleSize, w.y - handleSize, w.z);
    glEnd();
}

void
RenderState::drawHandle(const Vec3d &pos)
{
    Vec3d w = project(pos);

    float handleSize = TheApp->GetHandleSize();

    glBegin(GL_POLYGON);
    glVertex3d(w.x - handleSize, w.y - handleSize, w.z);
    glVertex3d(w.x - handleSize, w.y + handleSize, w.z);
    glVertex3d(w.x + handleSize, w.y + handleSize, w.z);
    glVertex3d(w.x + handleSize, w.y - handleSize, w.z);
    glEnd();
}

void
RenderState::setHandleColor(Scene *scene, int handle)
{
    if (scene->isInSelectedHandles(handle))
        Util::myGlColor3f(0.0f, 1.0f, 0.0f);
    else
        Util::myGlColor3f(1.0f, 1.0f, 1.0f);
}

void
RenderState::endDrawHandles()
{
    glPopMatrix();
    glMatrixMode(GL_PROJECTION);
    glLoadMatrixd((GLdouble *) _projectionMatrix);
    glMatrixMode(GL_MODELVIEW);
}

void
RenderState::drawTranslationHandles(Node* node, float scale)
{
    float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(TRANSLATION);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(TRANSLATION);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_X);
        drawCone(obj, 1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Y);
        drawCone(obj, 0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Z);
        drawCone(obj, 0.0f, 0.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::draw6DHandles(Node* node, float scale)
{
    float    black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(TRANSLATION);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(TRANSLATION);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_X);
        drawSphere(obj, 1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Y);
        drawSphere(obj, 0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Z);
        drawSphere(obj, 0.0f, 0.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::draw6DlocalHandles(Node* node, float scale)
{
    float    black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(TRANSLATION);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(TRANSLATION);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_X);
        drawSphere(obj, 1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Y);
        drawSphere(obj, 0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Z);
        drawCone(obj, 0.0f, 0.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawRocketHandles(Node* node, float scale)
{
    float    black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(TRANSLATION);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(TRANSLATION);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_X);
        drawCylinder(obj, 1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Y);
        drawCylinder(obj, 0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Z);
        drawCone(obj, 0.0f, 0.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawHoverHandles(Node* node, float scale)
{
    float    black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(TRANSLATION);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(TRANSLATION);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_X);
        drawAntiCone(obj, 1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Y);
        drawAntiCone(obj, 0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(TRANSLATION_Z);
        drawCone(obj, 0.0f, 0.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawCenterHandles(Node* node, float scale)
{
    float    black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(CENTER);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(CENTER);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(CENTER_X);
        drawCone(obj, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(CENTER_Y);
        drawCone(obj, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(CENTER_Z);
        drawCone(obj, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawScaleHandles(Node* node, float scale, const float *fscale)
{
    float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(SCALE_X);

    glScalef(fscale[0], fscale[1], fscale[2]);

    glScalef(scale, scale, scale);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glPushName(SCALE);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(SCALE_X);
        drawScaleHandle(1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(SCALE_Y);
        drawScaleHandle(0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(SCALE_Z);
        drawScaleHandle(0.0f, 0.0f, 1.0f);
    }

    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawProximityCenterHandles(Node* node, float scale)
{
    float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(PROXIMITY_CENTER);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glScalef(scale, scale, scale);

    glPushName(PROXIMITY_CENTER);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    GLUquadricObj   *obj = gluNewQuadric();

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(PROXIMITY_CENTER_X);
        drawCone(obj, 1.0f, 0.0f, 0.0f);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(PROXIMITY_CENTER_Y);
        drawCone(obj, 0.0f, 1.0f, 0.0f);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(PROXIMITY_CENTER_Z);
        drawCone(obj, 0.0f, 0.0f, 1.0f);
    }

    gluDeleteQuadric(obj);
    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawUniformScaleHandles(Node* node, float scale, 
                                     const float *fscale)
{
    float black[4] = { 0.0f, 0.0f, 0.0f, 1.0f };

    Scene *scene = node->getScene();

    glPushMatrix();
    node->transformForHandle(SCALE);
    glScalef(fscale[0], fscale[1], fscale[2]);

    glScalef(scale, scale, scale);

    glScalef(HANDLE_SIZE, HANDLE_SIZE, HANDLE_SIZE);

    glPushName(SCALE);
    drawAxisLines();

    glEnable(GL_CULL_FACE);

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, black);
    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);

    if (scene->getXonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(UNIFORM_SCALE_X);
        drawScaleHandle(1.0f, 0.0f, 0.0f, true);
    }

    if (scene->getYonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(UNIFORM_SCALE_Y);
        drawScaleHandle(0.0f, 1.0f, 0.0f, true);
    }

    if (scene->getZonly() || (scene->getConstrain() == CONSTRAIN_NONE)) {
        glLoadName(UNIFORM_SCALE_Z);
        drawScaleHandle(0.0f, 0.0f, 1.0f, true);
    }

    glPopName();

    glDisable(GL_CULL_FACE);

    glPopMatrix();
}

void
RenderState::drawScaleHandle(float x, float y, float z, bool uniform)
{
    float color[4] = {x, y, z, 1.0f};

    if (uniform)
        color[0] = color[1] = color[2] = 1.0f;

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);

    glPushMatrix();
    glRotatef(90.0f * x - 90.0f * y, y, x, z);
    glTranslatef(0.0f, 0.0f, 1.1f);
    Util::DrawBox(0.1f, 0.1f, 0.1f);
    glPopMatrix();
}

void
RenderState::drawCone(GLUquadricObj *obj, float x, float y, float z)
{
    drawCone(obj,x,y,z, x,y,z);
}

void
RenderState::drawCone(GLUquadricObj *obj, float x, float y, float z,
                                            float r, float b, float g)
{
    float color[4] = {r, b, g, 1.0f};

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);

    glPushMatrix();

    glRotatef(90.0f * x - 90.0f * y, y, x, z);
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluCylinder(obj, 0.07, 0.0, 0.2, 10, 10);
    gluQuadricOrientation(obj, (GLenum) GLU_INSIDE);
    gluDisk(obj, 0.0, 0.07, 10, 1);
    gluQuadricOrientation(obj, (GLenum) GLU_OUTSIDE);
    glPopMatrix();
}

void
RenderState::drawSphere(GLUquadricObj *obj, float x, float y, float z)
{
    drawSphere(obj,x,y,z, x,y,z);
}

void
RenderState::drawSphere(GLUquadricObj *obj, float x, float y, float z,
                                              float r, float b, float g)
{
    float color[4] = {r, b, g, 1.0f};

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);

    glPushMatrix();
    glRotatef(90.0f * x - 90.0f * y, y, x, z);
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluSphere(obj, 0.07, 10, 10);
    glPopMatrix();
}

void
RenderState::drawAntiCone(GLUquadricObj *obj, float x, float y, float z)
{
    drawAntiCone(obj,x,y,z, x,y,z);
}

void
RenderState::drawAntiCone(GLUquadricObj *obj, float x, float y, float z,
                                                float r, float b, float g)
{
    float color[4] = {r, b, g, 1.0f};

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);

    glPushMatrix();
    glRotatef(90.0f * x - 90.0f * y, y, x, z);
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluCylinder(obj, 0.0, 0.07, 0.2, 10, 10);
    glTranslatef(0.0f, 0.0f, 0.2f);
    gluDisk(obj, 0.0, 0.07, 10, 1);
    glPopMatrix();
}

void
RenderState::drawCylinder(GLUquadricObj *obj, float x, float y, float z)
{
    drawCylinder(obj,x,y,z, x,y,z);
}

void
RenderState::drawCylinder(GLUquadricObj *obj, float x, float y, float z,
                                                float r, float b, float g)
{
    float color[4] = {r, b, g, 1.0f};

    Util::myGlMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, color);

    glPushMatrix();
    glRotatef(90.0f * x - 90.0f * y, y, x, z);
    glTranslatef(0.0f, 0.0f, 1.0f);
    gluCylinder(obj, 0.07, 0.07, 0.2, 10, 10);
    gluQuadricOrientation(obj, (GLenum) GLU_INSIDE);
    gluDisk(obj, 0.0, 0.07, 10, 1);
    gluQuadricOrientation(obj, (GLenum) GLU_OUTSIDE);
    glTranslatef(0.0f, 0.0f, 0.2f);
    gluDisk(obj, 0.0, 0.07, 10, 1);
    glPopMatrix();
}

void
RenderState::drawRotationHandles(Node* node, int handle, float scale)
{
    float inc = 2 * M_PI / ROTATION_HANDLE_SEGMENTS;
    float i;
    GLint mode;

    glGetIntegerv(GL_RENDER_MODE, &mode);
    bool picking = mode == GL_SELECT;

    glPushMatrix();
    glPushAttrib(GL_LIGHTING | GL_LINE_SMOOTH);
    glDisable(GL_LIGHTING);
    glEnable(GL_LINE_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    glPushName(handle);
    node->transformForHandle(handle);

    if (picking) {
        float mat[4][4];
        glGetFloatv(GL_MODELVIEW_MATRIX, (GLfloat *) mat);
        glPushMatrix();
        glLoadIdentity();
        glTranslatef(mat[3][0], mat[3][1], mat[3][2]);
        glScalef(HANDLE_SIZE * scale, HANDLE_SIZE * scale, HANDLE_SIZE * scale);
        Util::myGlColor4f(1.0f, 1.0f, 1.0f, 0.5f);
        glBegin(GL_POLYGON);

        for (i = 0.0f; i < 2 * M_PI; i += inc) {
            float s = (float) sin(i);
            float c = (float) cos(i);
            glVertex3f(c, s, 0.0f);
        }
        glEnd();
        glPopMatrix();
    }

    glScalef(HANDLE_SIZE * scale, HANDLE_SIZE * scale, HANDLE_SIZE * scale);

    glScalef(scale, scale, scale);

//    glLoadName(ROTATION_X);
    glLoadName(handle);
    Util::myGlColor3f(1.0f, 0.0f, 0.0f);
    glBegin(GL_LINE_LOOP);

    for (i = 0.0f; i < 2 * M_PI; i += inc) {
        float s = (float) sin(i);
        float c = (float) cos(i);
        glVertex3f(0.0f, c, s);
    }
    glEnd();

//    glLoadName(ROTATION_Y);
    glLoadName(handle);
    Util::myGlColor3f(0.0f, 1.0f, 0.0f);
    glBegin(GL_LINE_LOOP);

    for (i = 0.0f; i < 2 * M_PI; i += inc) {
        float s = (float) sin(i);
        float c = (float) cos(i);
        glVertex3f(s, 0.0f, c);
    }
    glEnd();

//    glLoadName(ROTATION_Z);
    glLoadName(handle);
    Util::myGlColor3f(0.0f, 0.0f, 1.0f);
    glBegin(GL_LINE_LOOP);

    for (i = 0.0f; i < 2 * M_PI; i += inc) {
        float s = (float) sin(i);
        float c = (float) cos(i);
        glVertex3f(c, s, 0.0f);
    }
    glEnd();

    glPopMatrix();
    glPopName();
    glPopAttrib();
}

void
RenderState::drawAxisLines()
{
    float white[4] = { 1.0f, 1.0f, 1.0f, 1.0f };

    glPushAttrib(GL_LIGHTING | GL_LINE_SMOOTH);
    glDisable(GL_LIGHTING);
    glEnable(GL_LINE_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    Util::myGlColor3fv(white);
    glBegin(GL_LINES);
    glVertex3f(_axesStart,          0,          0);
    glVertex3f(         1,          0,          0);
    glVertex3f(         0, _axesStart,          0);
    glVertex3f(         0,           1,         0);
    glVertex3f(         0,           0, _axesStart);
    glVertex3f(         0,           0,         1);
    glEnd();

    glDisable(GL_CULL_FACE);
    glPopAttrib();
}

void
RenderState::drawAxisLine()
{
    glPushAttrib(GL_LIGHTING | GL_LINE_SMOOTH);
    glDisable(GL_LIGHTING);
    glEnable(GL_LINE_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    glBegin(GL_LINES);
    glVertex3f(0, 0, 0);
    glVertex3f(0, 0, 1);
    glEnd();

    glDisable(GL_CULL_FACE);
    glPopAttrib();
}

void         
RenderState::drawVectorHandle(int handleName, float x, float y, float z, 
                              float r, float b, float g)
{
    glPushName(NO_HANDLE);
    glPushAttrib(GL_LIGHTING | GL_LINE_SMOOTH);
    glDisable(GL_LIGHTING);
    glEnable(GL_LINE_SMOOTH);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);

    Util::myGlColor3f(r, g, b);
    glBegin(GL_LINES);
    glVertex3f(x * _vectorStart, y * _vectorStart, z * _vectorStart);
    glVertex3f(x, y, z);
    glEnd();

    RenderState state;
    state.startDrawHandles();
    glLoadName(handleName);
    state.drawHandle(Vec3f(x, y, z));
    state.endDrawHandles();

    glDisable(GL_CULL_FACE);
    glPopAttrib();
    glPopName();
}

