Logo Search packages:      
Sourcecode: ball version File versions

glRenderer.C

// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: glRenderer.C,v 1.72.12.2 2007/03/25 23:30:45 amoll Exp $
//

#include <BALL/VIEW/RENDERING/glRenderer.h>
#include <BALL/VIEW/KERNEL/common.h>
#include <BALL/VIEW/KERNEL/clippingPlane.h>
#include <BALL/VIEW/DATATYPE/colorMap.h>
#include <BALL/VIEW/KERNEL/mainControl.h>

#include <BALL/VIEW/WIDGETS/scene.h>
#include <BALL/VIEW/PRIMITIVES/label.h>
#include <BALL/VIEW/PRIMITIVES/line.h>
#include <BALL/VIEW/PRIMITIVES/mesh.h>
#include <BALL/VIEW/PRIMITIVES/quadMesh.h>
#include <BALL/VIEW/PRIMITIVES/point.h>
#include <BALL/VIEW/PRIMITIVES/box.h>
#include <BALL/VIEW/PRIMITIVES/simpleBox.h>
#include <BALL/VIEW/PRIMITIVES/sphere.h>
#include <BALL/VIEW/PRIMITIVES/disc.h>
#include <BALL/VIEW/PRIMITIVES/tube.h>
#include <BALL/VIEW/PRIMITIVES/twoColoredLine.h>
#include <BALL/VIEW/PRIMITIVES/twoColoredTube.h>
#include <BALL/VIEW/PRIMITIVES/multiLine.h>
#include <BALL/VIEW/PRIMITIVES/gridVisualisation.h>

#include <BALL/SYSTEM/timer.h>
#include <BALL/KERNEL/atom.h>

#include <QtGui/qpixmap.h>
#include <QtGui/qpainter.h>
#include <QtGui/qimage.h>

#include <BALL/MATHS/vector2.h>
#include <BALL/MATHS/plane3.h>
#include <BALL/MATHS/analyticalGeometry.h>

#ifndef BALL_USE_GLEW
 #define GLX_GLXEXT_PROTOTYPES // required for Mesa-like implementations
 #include <GL/gl.h>
 #include <GL/glx.h>
 #include <GL/glext.h>
#endif

#ifdef BALL_USE_GLEW
# include <BALL/VIEW/RENDERING/vertexBuffer.h>
#endif

using namespace std;

//   #define BALL_VIEW_DEBUG
//   #define BALL_BENCHMARKING

#define BYTES_PER_TEXEL 4

namespace BALL
{
      namespace VIEW
      {

#ifdef BALL_VIEW_DEBUG
#define CHECK_GL_ERROR \
            {\
                  GLenum e = glGetError(); \
                  if (e != GL_NO_ERROR)\
                  {\
                        Log.error() << "GL Error occurred in " << __FILE__ << " " << __LINE__ << std::endl;\
                        switch (e)\
                        {\
                              case GL_INVALID_VALUE: Log.error() << " GL_INVALID_VALUE" << std::endl;break;\
                              case GL_INVALID_ENUM: Log.error() << " GL_INVALID_ENUM" << std::endl;break;\
                              case GL_INVALID_OPERATION: Log.error() << " GL_INVALID_OPERATION" << std::endl;break;\
                              case GL_STACK_OVERFLOW: Log.error() << " GL_STACK_OVERFLOW" << std::endl;break;\
                              case GL_STACK_UNDERFLOW: Log.error() << " GL_STACK_UNDERFLOW" << std::endl;break;\
                              case GL_TABLE_TOO_LARGE: Log.error() << " GL_TABLE_TOO_LARGE" << std::endl;break;\
                              default: Log.error() << " UNKNOWN ERROR" << std::endl;\
                        }\
                  }\
            }
#else
#define CHECK_GL_ERROR
#endif

00086             GLRenderer::GLRenderer()
                  : Renderer(),
                        drawing_mode_(DRAWING_MODE_SOLID),
                        drawing_precision_(DRAWING_PRECISION_HIGH),
                        near_(1.5),
                        far_(600.),
                        left_(-1),
                        right_(1),
                        top_(1),
                        bottom_(-1),
                        GL_spheres_list_(0),
                        GL_tubes_list_(0),
                        GL_boxes_list_(0),
                        name_to_object_(),
                        object_to_name_(),
                        all_names_(1),
                        stereo_(NO_STEREO),
                        render_mode_(RENDER_MODE_UNDEFINED),
                        use_vertex_buffer_(false),
                        smooth_lines_(false),
                        picking_mode_(false),
                        model_type_(MODEL_LINES),
                        drawed_other_object_(false),
                        drawed_mesh_(false),
                        GLU_quadric_obj_(0)
            {
            }

00114             GLRenderer::~GLRenderer()
            {
                  clear();
            }

00119             void GLRenderer::clear()
            {
                  name_to_object_.clear();
                  object_to_name_.clear();
                  all_names_ = 1;

                  if (GL_spheres_list_ != 0) delete[] GL_spheres_list_;
                  if (GL_boxes_list_   != 0) delete[] GL_boxes_list_;
                  if (GL_tubes_list_   != 0) delete[] GL_tubes_list_;

                  DisplayListHashMap::Iterator it = display_lists_.begin();
                  for (; it != display_lists_.end(); it++)
                  {
                        delete it->second;
                  }
                  display_lists_.clear();
            }

00137             void GLRenderer::setAntialiasing(bool state)
            {
#ifndef GL_MULTISAMPLE
#define GL_MULTISAMPLE  0x809D
#endif
                  if (state)
                  {
                        glEnable(GL_MULTISAMPLE);

                        if(smooth_lines_) {
                              // smooth line drawing
                              glEnable(GL_LINE_SMOOTH);
                        }
                        // slower, but better results:
                        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);
                        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

                  }
                  else
                  {
                        glDisable(GL_MULTISAMPLE);
                        glDisable(GL_LINE_SMOOTH);
                        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
                        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
                  }
            }

00164             void GLRenderer::setSmoothLines(bool smooth_lines)
            {
                  smooth_lines_ = smooth_lines;
            }

            bool GLRenderer::getSmoothLines()
            {
                  return smooth_lines_;
            }

00174             bool GLRenderer::init(Scene& scene)
            {
                  return Renderer::init(scene);
            }

00179             bool GLRenderer::init(const Stage& stage, float width, float height)
            {
                  Renderer::init(stage, width, height);
                  
                  // Force OpenGL to normalize transformed normals to be of unit
                  // length before using the normals in OpenGL's lighting equations
                  // While this corrects potential lighting problems introduced by scaling,
                  // it also slows OpenGL's vertex processing speed since normalization requires extra operations.
                  glEnable(GL_NORMALIZE);

#ifdef BALL_USE_GLEW
                  glewInit();
                  // accelerate lighting calculations, if possible:
                  if (isExtensionSupported("GL_EXT_rescale_normal"))
                  {
                        // workaround for some Radeon cards and Mesa:
                        String renderer = getRenderer();
                        if (!renderer.hasSubstring("Mesa") ||
                                    !renderer.hasSubstring("Radeon"))
                        {
                              glEnable(GL_RESCALE_NORMAL);
                        }
                  }
#endif

                  glFrontFace(GL_CCW);     // selects counterclockwise polygons as front-facing
                  glCullFace(GL_BACK);           // specify whether front- or back-facing facets can be culled

                  glDisable(GL_FOG);
                  
                  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, false);

                  // Specifies the depth comparison function:
                  // Passes if the incoming z value is greater than  or equal to the stored z value
                  glDepthFunc(GL_LEQUAL);

                  // specify the clear value for the depth buffer 
                  glClearDepth(200.0);

                  setAntialiasing(true);

                  glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
                  // select smooth shading 
                  glShadeModel(GL_SMOOTH);

                  // is problematic on some machines and should not be used:
                  glDisable(GL_POLYGON_SMOOTH);
                  // glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);

                  glBlendFunc(GL_SRC_ALPHA,  GL_ONE_MINUS_SRC_ALPHA);

                  // setup all in the stage given lightsources
                  setSize(width, height);
                  setLights();
                  glEnable(GL_LIGHTING);

                  // set the background color according to the stage
                  updateBackgroundColor();

                  glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE);
                  glEnable(GL_COLOR_MATERIAL);
                  
                  GLfloat diff[] = {0.4, 0.4, 0.4, 1.0};
                  GLfloat shin[] = {76.8};
                  GLfloat spec[] = {0.774597, 0.774597, 0.774597, 1.0};
                  GLfloat ambient[] = {0.25, 0.25, 0.25, 1.0};

                  glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,  spec);
                  glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shin );
                  glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,  diff);
                  glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT,  ambient);

                  // if displaylists were already calculated, return
                  if (GL_spheres_list_ != 0) return true;

                  initSolid();

                  GL_spheres_list_ = new GLDisplayList[BALL_VIEW_MAXIMAL_DISPLAY_LIST_OBJECT_SIZE]();
                  GL_tubes_list_   = new GLDisplayList[BALL_VIEW_MAXIMAL_DISPLAY_LIST_OBJECT_SIZE]();
                  GL_boxes_list_   = new GLDisplayList[BALL_VIEW_MAXIMAL_DISPLAY_LIST_OBJECT_SIZE]();

                  GLU_quadric_obj_ = gluNewQuadric();
                  gluQuadricOrientation(GLU_quadric_obj_, GLU_OUTSIDE);
                  gluQuadricNormals(GLU_quadric_obj_, GLU_SMOOTH); //GLU_FLAT GLU_SMOOTH
                  gluQuadricTexture(GLU_quadric_obj_, GL_FALSE);
                  gluQuadricDrawStyle(GLU_quadric_obj_, GLU_FILL);

                  createSpheres_();
                  createTubes_();
                  createBoxes_();

                  //////////////////////////////////////////////////////
                  // toon shader:
                  // first entries: greatest angle between normal and light vector
                  float shader[32] = { 0.2, 0.21, 0.23, 0.25, 0.27, 0.29, 0.31, 0.33, 0.36, 0.39, 0.41, 0.4, 0.44, 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0 };

                  float cel_shader_data[32][3];

                  for (Position p = 0; p < 32; p++)
                  {
                        cel_shader_data[p][0] = 
                        cel_shader_data[p][1] = 
                        cel_shader_data[p][2] = shader[p];
                  }

                  glEnable(GL_TEXTURE_1D);
                  glGenTextures(1, &cel_texture_);          
                  glBindTexture(GL_TEXTURE_1D, cel_texture_);     
                  glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGB , GL_FLOAT, cel_shader_data);
                  glBindTexture(GL_TEXTURE_1D, 0);    

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

                  // display list for illuminated lines
                  generateIlluminationTexture_(0.1, 0.3, 0.599, 0.5);
                  line_list_.clear();
                  glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
                  glGenTextures(1, &line_texture_bind_);
                  glBindTexture(GL_TEXTURE_2D, line_texture_bind_); 
                  glTexImage2D(GL_TEXTURE_2D, 0, 4, 128, 128, 0, GL_RGBA, GL_UNSIGNED_BYTE, line_tex_);

                  line_list_.useCompileMode();
                  line_list_.startDefinition();

                  glBindTexture(GL_TEXTURE_2D, line_texture_bind_);
                  
                  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP );
                  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP );
                  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
                  glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
                  glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
                  glEnable( GL_TEXTURE_2D );

                  // glEnable( GL_LINE_SMOOTH );
                  glEnable( GL_BLEND );
            //         glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );    
                  // glHint( GL_LINE_SMOOTH_HINT, GL_DONT_CARE );

                  line_list_.endDefinition();

                  initSolid();
                  updateCamera();

                  return true;
            }


00326             void GLRenderer::updateBackgroundColor() 
            {
                  glClearColor((float) stage_->getBackgroundColor().getRed(),
                                                       (float) stage_->getBackgroundColor().getGreen(),
                                                       (float) stage_->getBackgroundColor().getBlue(),
                                                       (float) stage_->getBackgroundColor().getAlpha());
            }
                  
00334             void GLRenderer::setLights(bool reset_all)
            {
                  GLenum light_nr = GL_LIGHT0;

                  if (reset_all)
                  {
                        GLint lights_max;
                        glGetIntegerv(GL_MAX_LIGHTS, &lights_max);
                        for (; (GLint)light_nr < GL_LIGHT0 + lights_max; light_nr++)
                        {
                              glDisable(light_nr);
                        }
                        
                        light_nr = GL_LIGHT0;
                  }

                  List<LightSource>::ConstIterator it = stage_->getLightSources().begin();
                  for (; it != stage_->getLightSources().end(); it++)
                  {
                        if (reset_all && !it->isRelativeToCamera())
                        {
                              continue;
                        }
                        
                        // setup the light intensity
                        GLfloat intensity[] = {((float) it->getColor().getRed())          * it->getIntensity(),
                                                                                          ( (float) it->getColor().getGreen())      * it->getIntensity(),
                                                                                          ( (float) it->getColor().getBlue())       * it->getIntensity(),
                                                                                          ( (float) it->getColor().getAlpha())};

                        GLfloat zero[] = {0, 0, 0, 0};

                        if (it->getType() == LightSource::AMBIENT)
                        {
                              glLightfv(light_nr, GL_AMBIENT, intensity);
                              glLightfv(light_nr, GL_DIFFUSE, zero);
                              glLightfv(light_nr, GL_SPECULAR, zero);
                              glEnable(light_nr);
                              light_nr++;
                              continue;
                        }
                        
                        glLightfv(light_nr, GL_AMBIENT, zero);
                        glLightfv(light_nr, GL_DIFFUSE, intensity);
                        glLightfv(light_nr, GL_SPECULAR, intensity);

                        Vector3 light_dir;

                        if (it->getType() == LightSource::DIRECTIONAL)
                        {
                              // directional light sources dont have a position!
                              // but they get their direction with GL_POSITION!
                              light_dir = -it->getDirection();
                              if (it->isRelativeToCamera())
                              {
                                    light_dir = stage_->calculateAbsoluteCoordinates(light_dir);
                              }

                              GLfloat pos[]  = { light_dir.x,
                                                                                     light_dir.y,
                                                                                     light_dir.z,
                                                                                     0.0};  // the 1 is for positional lights

                              glLightfv(light_nr, GL_POSITION, pos);    
                              glEnable(light_nr);
                              light_nr++;
                              continue;
                        }

                        Vector3 light_pos;

                        if (it->isRelativeToCamera())
                        {
                              light_pos = stage_->calculateAbsoluteCoordinates(it->getPosition()) + stage_->getCamera().getViewPoint();
                              light_dir = stage_->calculateAbsoluteCoordinates(it->getDirection());
                        }
                        else
                        {
                              light_pos = it->getPosition();
                              light_dir = it->getDirection() - light_pos;
                        }
                  
                        // setup the direction of the light
                        GLfloat dir[] = { light_dir.x,
                                                                              light_dir.y,
                                                                              light_dir.z};
                        glLightfv(light_nr, GL_SPOT_DIRECTION, dir);

                        // setup the angle of the light cone
                        GLfloat angle = 180;
                        if (it->getAngle().toDegree() <= 90)
                        {
                              angle = it->getAngle().toDegree();
                        }
                        
                        glLightfv(light_nr, GL_SPOT_CUTOFF, &angle);
                        glLightf(light_nr, GL_SPOT_EXPONENT, (GLfloat) 100);

                        // setup the position of the lightsource
                        GLfloat pos[]  = { light_pos.x,
                                                                               light_pos.y,
                                                                               light_pos.z,
                                                                               1.0};  // the 1 is for positional lights

                        glLightfv(light_nr, GL_POSITION, pos);
                  
                        Vector3 att =  it->getAttenuation();
                        glLightf(light_nr, GL_CONSTANT_ATTENUATION, att.x);
                        glLightf(light_nr, GL_LINEAR_ATTENUATION, att.y);
                        glLightf(light_nr, GL_QUADRATIC_ATTENUATION, att.z);

                        glEnable(light_nr);
                        light_nr++;
                  }
            }

00450             void GLRenderer::removeRepresentation(const Representation& rep)
            {
                  if (!getMainControl()->getRepresentationManager().has(rep)) return;

                  if (rep.getGeometricObjects().size() == 0) return;

                  if (vertexBuffersEnabled())
                  {
                        clearVertexBuffersFor(*(Representation*)&rep);
                  }

                  DisplayListHashMap::Iterator hit = display_lists_.find(&rep);
                  if (hit == display_lists_.end()) return;

                  delete hit->second;
                  display_lists_.erase(hit);
            }

00468             void GLRenderer::bufferRepresentation(const Representation& rep)
            {
#ifdef BALL_BENCHMARKING
                  Timer t;
                  t.start();
#endif
                  GLDisplayList* display_list;
                  if (display_lists_.has(&rep))
                  {
                        display_list = display_lists_[&rep];
                        display_list->clear();
                  }
                  else
                  {
                        display_list = new GLDisplayList;
                        display_lists_[&rep] = display_list;
                  }

                  display_list->useCompileMode();
                  display_list->startDefinition();
                  
                  render(rep, true);
                  
                  display_list->endDefinition();

#ifdef BALL_USE_GLEW
                  clearVertexBuffersFor(*(Representation*)&rep);
                  
                  if (use_vertex_buffer_ && drawing_mode_ != DRAWING_MODE_WIREFRAME)
                  {
                        // prevent copying the pointers of the buffers later...
                        rep_to_buffers_[&rep] = vector<MeshBuffer*>();
                        
                        vector<MeshBuffer*>& buffers = rep_to_buffers_.find(&rep)->second;

                        const List<GeometricObject*>& geometric_objects = rep.getGeometricObjects();
                        List<GeometricObject*>::ConstIterator git = geometric_objects.begin();
                        for (; git != geometric_objects.end(); git++)
                        {
                              const Mesh* const mesh = dynamic_cast<Mesh*>(*git);
                              if (mesh != 0) 
                              {
                                    MeshBuffer* buffer = new MeshBuffer;
                                    buffer->setMesh(*mesh);
                                    buffer->initialize();
                                    buffers.push_back(buffer);
                              }
                        }
                  }
#endif

#ifdef BALL_BENCHMARKING
            t.stop();
            logString("OpenGL rendering time: " + String(t.getCPUTime()));
#endif
            }

            // TODO: do we need the mode???
00526             void GLRenderer::renderToBuffer(RenderTarget* renderTarget, BufferMode mode)
            {
                  if (show_preview_)
                        setAntialiasing(false);

                  glDepthMask(GL_TRUE);

                  glDrawBuffer(GL_BACK);
                  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

                  if (!getMainControl())
                        return;

                  RepresentationManager& pm = getMainControl()->getRepresentationManager();

                  // ============== enable active Clipping planes ==============================
                  GLint current_clipping_plane = GL_CLIP_PLANE0;

                  vector<ClippingPlane*> active_planes;
                  vector<ClippingPlane*> inactive_planes;

                  bool move_mode = scene_->inMoveMode();
                  
                  const vector<ClippingPlane*>& vc = pm.getClippingPlanes();
                  vector<ClippingPlane*>::const_iterator plane_it = vc.begin();
                  for (;plane_it != vc.end(); plane_it++)
                  {
                        ClippingPlane& plane = **plane_it;

                        if (plane.isHidden()) continue;

                        if (!plane.isActive()) 
                        {
                              inactive_planes.push_back(*plane_it);
                              if (!move_mode) continue;
                        }

                        active_planes.push_back(*plane_it);

                        const Vector3& n(plane.getNormal());
                        const GLdouble planef[] ={n.x, n.y, n.z, plane.getDistance()};
                        glClipPlane(current_clipping_plane, planef);
                        current_clipping_plane++;
                  }

                  // -------------------------------------------------------------------
                  // show light sources
                  if (show_light_sources_)
                  {
                        List<LightSource>::ConstIterator lit = stage_->getLightSources().begin();
                        for (; lit != stage_->getLightSources().end(); lit++)
                        {
                              Vector3 pos = (*lit).getPosition();
                              Vector3 dir = (*lit).getDirection();

                              if ((*lit).isRelativeToCamera())
                              {
                                    pos = stage_->getCamera().getViewPoint() + stage_->calculateAbsoluteCoordinates(pos);
                                    dir = pos + stage_->calculateAbsoluteCoordinates(dir);
                              }

                              Vector3 diff = dir - pos;
                              if (!Maths::isZero(diff.getSquareLength())) diff.normalize();
                              diff *= 100.0;

                              Sphere s;
                              s.setPosition(pos);
                              s.setRadius(5);
                              s.setColor(ColorRGBA(255,255,255));
                              renderSphere_(s);

                              Tube t;
                              t.setVertex1(pos);
                              t.setVertex2(pos + diff);
                              t.setColor(ColorRGBA(255,255,255));
                              renderTube_(t);
                        }
                  }
                  // -------------------------------------------------------------------
                  
                  
                  // we draw all the representations in different runs, 
                  // 1. normal reps
                  // 2. transparent reps
                  // 3. allways front
                  for (Position run = 0; run < 3; run++)
                  {
                        if (run == 1)
                        {
                              // render inactive clipping planes
                              for (plane_it = inactive_planes.begin(); plane_it != inactive_planes.end(); plane_it++)
                              {
                                    renderClippingPlane_(**plane_it);
                              }
                        }

                        RepresentationList::ConstIterator it = pm.getRepresentations().begin();
                        for(; it != pm.getRepresentations().end(); it++)
                        {
                              Representation& rep = **it;
                              if (rep.isHidden()) continue;

                              if (run == 0)
                              {
                                    // render all "normal" (non always front and non transparent models)
                                    if (!rep.hasProperty("DONT_CLIP") && (
                                                rep.getTransparency() != 0 ||
                                                rep.hasProperty(Representation::PROPERTY__ALWAYS_FRONT)))
                                    {
                                          continue;
                                    }
                              }
                              else if (run == 1)
                              {
                                    // render all transparent models
                                    if (rep.hasProperty("DONT_CLIP") ||
                                                rep.getTransparency() == 0 ||
                                                rep.hasProperty(Representation::PROPERTY__ALWAYS_FRONT))
                                    {
                                          continue;
                                    }
                              }
                              else
                              {
                                    // render all always front models
                                    if (!rep.hasProperty(Representation::PROPERTY__ALWAYS_FRONT)) continue;
                              }
                              
                              vector<Position> rep_active_planes; // clipping planes

                              Index cap_nr = -1;
                              for (Position plane_nr = 0; plane_nr < active_planes.size(); plane_nr++)
                              {
                                    if (!active_planes[plane_nr]->getRepresentations().has(*it)) continue;
                                    
                                    const ClippingPlane& plane = *active_planes[plane_nr];
                                    rep_active_planes.push_back(plane_nr);
                                    if (!plane.cappingEnabled())
                                    {
                                          glEnable(plane_nr + GL_CLIP_PLANE0);
                                          continue;
                                    }

                                    cap_nr = plane_nr;
                              }

                              // no capping? then we are done: disable again all clipping planes
                              if (cap_nr == -1)
                              {
                                    bufferingDependentRender_(rep, mode);

                                    for (Position p = 0; p < rep_active_planes.size(); p++)
                                    {
                                          glDisable(rep_active_planes[p] + GL_CLIP_PLANE0);
                                    }
                                    continue;
                              }

                              // draw a capping plane
                              const ClippingPlane& plane = *active_planes[cap_nr];
                              Vector3 p, x, y, n;
                              p = plane.getPoint();
                              x = getNormal(plane.getNormal()) * 400;
                              y = x % plane.getNormal() * 400;
                              n = plane.getNormal();
                              n.normalize();
                              
                              // disable all clipping planes
                              for (Position p = 0; p < rep_active_planes.size(); p++)
                              {
                                    glDisable(rep_active_planes[p] + GL_CLIP_PLANE0);
                              }

                              // fill the stencil buffer
                              glEnable(cap_nr + GL_CLIP_PLANE0);
                              glEnable(GL_STENCIL_TEST);
                              glClearStencil(0);
                              glClear(GL_STENCIL_BUFFER_BIT);
                              glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
                              glStencilFunc(GL_ALWAYS, 0x0, 0xff);
                              glStencilOp(GL_KEEP, GL_INVERT, GL_INVERT);
                              bufferingDependentRender_(rep, mode);
                              
                              // disable all clipping planes
                              for (Position p = 0; p < rep_active_planes.size(); p++)
                              {
                                    glEnable(rep_active_planes[p] + GL_CLIP_PLANE0);
                              }

                              // render the Representation once again, this time with colors
                              setColorRGBA_(ColorRGBA(0,1.0,0));
                              glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
                              glDisable(GL_STENCIL_TEST);
                              bufferingDependentRender_(rep, mode);

                              // render the capping plane
                              glEnable(GL_STENCIL_TEST);
                              glStencilFunc(GL_NOTEQUAL, 0x0, 0xff);

                              ColorRGBA color = ClippingPlane::getCappingColor();
                              bool transparent = (int)color.getAlpha() != 255;
                              if (transparent) initTransparent();
                              else                                 initSolid();

                              glDisable(cap_nr + GL_CLIP_PLANE0);
                              Disc d(Circle3(p, n, 400));
                              d.setColor(color);
                              render_(&d);
                              
                              glDisable(GL_STENCIL_TEST);
                        }
                  }

                  if (show_preview_) 
                        setAntialiasing(true);

                  return;
            }

            void GLRenderer::bufferingDependentRender_(const Representation& repr, BufferMode mode)
            {
                  RepresentationManager& pm = getMainControl()->getRepresentationManager();
                  Representation* rep = (Representation*)& repr;

                  // preview mode:
                  // if we have a model with only sticks and cylinders, decrease the rendering detail
                  // and draw it directly instead of using display lists.
                  // BUT: if the representation is currently rebuild, we can only draw buffered!
                  DrawingPrecision pbak = repr.getDrawingPrecision();

                  if (show_preview_)
                  {
                        if (repr.getModelType() >= MODEL_STICK &&
                                    repr.getModelType() <= MODEL_VDW &&
                                    pm.startRendering(rep))
                        {
                              rep->setDrawingPrecision(DRAWING_PRECISION_LOW);
                              mode = DIRECT_RENDERING;
                        }
                  }

                  if (mode == DISPLAY_LISTS_RENDERING &&
                              !repr.hasProperty("RENDER_DIRECT") && 
                              repr.getDrawingMode() != DRAWING_MODE_TOON)
                  {
                        drawBuffered(repr);
                        return;
                  }

                  if (!show_preview_) 
                  {
                        // if we use previewing mode, the RepresentationManager was already notified above
                        if (!pm.startRendering(rep))
                        {
                              // if Representation is to be rebuilded, but it is currently recalculated,
                              // we can only draw it from the DisplayList
                              drawBuffered(repr);
                              return;
                        }
                  }

                  if (mode == REBUILD_DISPLAY_LISTS)
                  {
                        bufferRepresentation(repr);
                  }
                  else //     DIRECT_RENDERING:
                  {
                        render(repr);
                  }

                  if (show_preview_)
                  {
                        if (repr.getDrawingPrecision() != pbak)
                        {
                              // if previewing mode was used: reset the drawing precision
                              (*(Representation*)&repr).setDrawingPrecision(pbak);
                        }
                  }

                  pm.finishedRendering(rep);
            }

            bool GLRenderer::render(const Representation& representation, bool for_display_list)
            {
                  if (representation.isHidden()) return true;

                  if (!representation.isValid())
                  {
                        BALLVIEW_DEBUG;
                        representation.dump(std::cout, 0);
                        return false;
                  }

                  drawing_precision_  = representation.getDrawingPrecision();
                  drawing_mode_             = representation.getDrawingMode();

                  drawed_mesh_ = false;
                  drawed_other_object_ = false;

                  display_lists_index_ = drawing_mode_ * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + drawing_precision_;

                  if (representation.getDrawingMode() == DRAWING_MODE_DOTS)
                  {
                        glDisable(GL_LIGHTING);
                  }
                  else
                  {
                        glEnable(GL_LIGHTING);
                  }

                  if (representation.hasProperty(Representation::PROPERTY__ALWAYS_FRONT))
                  {
                        initAlwaysFront();
                  }
                  else if (representation.getTransparency() == 0)
                  {
                        initSolid();
                  }
                  else
                  {
                        if (!representation.hasProperty("DONT_CLIP"))
                        {
                              // prevent artifacts:
                              // first run to fill depth buffer
                              initTransparent();
                              glDepthMask(GL_TRUE);
                              glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
                              renderRepresentation_(representation, for_display_list);

                              // options for second run 
                              glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
                        }
                        initTransparent();
                  }

                  renderRepresentation_(representation, for_display_list);
                  glFlush();

                  return true;
            }

            void GLRenderer::renderRepresentation_(const Representation& representation, bool for_display_list)
            {
                  model_type_ = representation.getModelType();

                  // accelerate things a little by calling getGeometricObjects() only once
                  const List<GeometricObject*>& geometric_objects = representation.getGeometricObjects();
                  if (geometric_objects.size() == 0) return;
                  List<GeometricObject*>::ConstIterator it = geometric_objects.begin();
                  if (for_display_list)
                  {
                        if (use_vertex_buffer_ && drawing_mode_ != DRAWING_MODE_WIREFRAME)
                        {
                              // draw everything except of meshes, these are put into vertex buffer objects in bufferRepresentation()
                              for (; it != geometric_objects.end(); it++)
                              {
                                    if (dynamic_cast<Mesh*>(*it) == 0) render_(*it);
                              }
                        }
                        else
                        {
                              // render everything
                              for (; it != geometric_objects.end(); it++)
                              {
                                    render_(*it);
                              }
                        }
                  }
                  else // drawing for picking directly
                  {
                        for (; it != geometric_objects.end(); it++)
                        {
                              // render everything with names from glLoadName
                              glLoadName(getName(**it));
                              render_(*it);
                        }
                  }

                  glFlush();
            }

            void GLRenderer::dump(std::ostream& s, Size depth) const
            {
                  BALL_DUMP_STREAM_PREFIX(s);

                  BALL_DUMP_DEPTH(s, depth);
                  BALL_DUMP_HEADER(s, this, this);

                  BALL_DUMP_DEPTH(s, depth);
                  s << "Drawing Precision: "    << drawing_precision_   << std::endl;

                  BALL_DUMP_DEPTH(s, depth);
                  s << "Drawing Mode: "               << drawing_mode_  << std::endl;

                  BALL_DUMP_DEPTH(s, depth);
                  s << "Width: " << width_ << endl;

                  BALL_DUMP_DEPTH(s, depth);
                  s << "Height: " << height_ << endl;

                  BALL_DUMP_DEPTH(s, depth);
                  s << "XScale: " << x_scale_ << endl;

                  BALL_DUMP_DEPTH(s, depth);
                  s << "YScale: " << y_scale_ << endl;

                  BALL_DUMP_STREAM_SUFFIX(s);
            }

            // Convert 2D screen coordinate to 3D coordinate on the view plane
00936             Vector3 GLRenderer::mapViewportTo3D(Position x, Position y)
            {
                  // the mapping works as follows:
                  //   - all points are mapped to the view plane, defined by the view 
                  //     vector and the right/up vectors of the camera
                  //   - the width of the view plane in world coordinates can be computed
                  //     using elementary geometry from the intercept theorem as
                  //     (right - left) * distance_camera_view_plane / distance_camera_near_plane
                  //   - the look_at_vector of the camera points at the center of the view plane
                  //       this center should be mapped to (width()/2, height()/2)
                  const Camera&  camera  = stage_->getCamera();

                  const Vector3& view      = camera.getViewVector();
                  const Vector3& right = camera.getRightVector();
                  const Vector3& up    = camera.getLookUpVector();

                  float distance_camera_view_plane = view.getLength();

                  float scale_right_vector = (distance_camera_view_plane / near_) * (right_ - left_  )/2.;
                  float scale_up_vector    = (distance_camera_view_plane / near_) * (top_   - bottom_)/2.;

                  Vector3 result =        camera.getLookAtPosition()
                                                                        + right   * (2.*(float)x/width_  - 1.) * scale_right_vector
                                                                        - up      * (2.*(float)y/height_ - 1.) * scale_up_vector;

                  return result;
            }     

00964             Vector2 GLRenderer::map3DToViewport(const Vector3& vec)
            {
                  const Camera&  camera  = stage_->getCamera();

                  const Vector3& right   = camera.getRightVector();
                  const Vector3& up      = camera.getLookUpVector();
                  
                  Vector3 point = vec - camera.getViewPoint();

                  Vector3 normalized_view = camera.getViewVector();
                  if (normalized_view.getLength() > 0)
                        normalized_view.normalize();
                  else
                        normalized_view = Vector3(0.,0.,-1.);

                  Vector2 result(FLT_MAX, FLT_MAX); 

                  float projection_on_view = normalized_view * point;
                  if (projection_on_view <= 0)
                        return result;

                  Vector3 point_on_near = near_ / projection_on_view * point;

                  // project point on plane
                  point_on_near -= near_ * normalized_view;

                  float near_width = right_-left_;
                  result.x = width_ / near_width * ((point_on_near * right) + near_width/2.);

                  float near_height = top_-bottom_;
                  result.y = height_ / near_height * ((point_on_near * (-up)) + near_height/2.);

                  return result;
            }


// =================================================================================
// --------------------------render methods-----------------------------------------
// =================================================================================

01004             void GLRenderer::renderRuler()
            {
                  const Camera& s = stage_->getCamera();
                  Vector3 v = s.getViewVector();
                  v.normalize();
                  const Vector3 x = s.getRightVector();
                  const Vector3 y = s.getLookUpVector();
                  float delta = 0.001;
                  float size = 50;

                  initTransparent();

                  Vector3 p = mapViewportTo3D((Index)(width_ / 2.0), (Index)(height_ / 2.0)) - x * size / 2.0 - y * size / 2.0;

                  Box xp(p, x * size, y * size, delta);
                  xp.setColor(ColorRGBA(0,255,190,90));
                  render_(&xp);

                  ColorRGBA color1(255,255,255,255);
                  ColorRGBA color2(0,0,0,230);
                  Line line;
                  p -= v * delta;

                  for (Position i = 0; i <= size; i+=1)
                  {
                        if (i % 10 == 0) line.setColor(color2);
                        else                                 line.setColor(color1);

                        line.setVertex1(p + x * i);
                        line.setVertex2(p + x * i + y * size);
                        render_(&line);

                        line.setVertex1(p + y * i);
                        line.setVertex2(p + y * i + x * size);
                        render_(&line);
                  }

                  initSolid();
            }

01044             void GLRenderer::renderSphere_(const Sphere& sphere)
            {
                  initDrawingOthers_();

                  glPushMatrix();
                  setColor4ub_(sphere);
                  translateVector3_(sphere.getPosition());
                  scale_(sphere.getRadius());

                  // render spheres of stick models with less precision for atoms with
                  // more than 2 bonds:
                  if (model_type_ == MODEL_STICK &&
                              drawing_precision_ > DRAWING_PRECISION_LOW)
                  {
                        Index precision = drawing_precision_;
                        const Atom* const atom = dynamic_cast<const Atom*>(sphere.getComposite());

                        if (atom != 0 && atom->countBonds() > 2)
                        {
                              precision--;
                        }

                        GL_spheres_list_[drawing_mode_ * BALL_VIEW_MAXIMAL_DRAWING_PRECISION +
                                                                         precision].draw();
                  }
                  else
                  {
                        GL_spheres_list_[display_lists_index_].draw();
                  }

                  glPopMatrix();
            }

01077             void GLRenderer::renderDisc_(const Disc& disc)
            {
                  initDrawingOthers_();

                  glPushMatrix();
                  setColor4ub_(disc);
                  translateVector3_(disc.getCircle().p);
                  const Vector3 rotation_axis(-disc.getCircle().n.y, disc.getCircle().n.x, 0.0);
                  // angle between z-axis-vector and result
                  const float angle = BALL_ANGLE_RADIAN_TO_DEGREE(acos(disc.getCircle().n.z / disc.getCircle().n.getLength()));
                  rotateVector3Angle_(rotation_axis, angle);

                  static Position slices[4] = {6, 14, 24, 40};
                  static Position rings[4]  = {4, 8, 16, 32};

                  initGLU_(drawing_mode_);

                  gluDisk(GLU_quadric_obj_, 0, disc.getCircle().radius, slices[drawing_precision_], rings[drawing_precision_]);

                  glPopMatrix();
            }


01100             void GLRenderer::renderLine_(const Line& line)
            {
                  initDrawingOthers_();

                  glDisable(GL_LIGHTING);
                  setColor4ub_(line);

                  glBegin(GL_LINES);
                        vertexVector3_(line.getVertex1());
                        vertexVector3_(line.getVertex2());
                  glEnd();

                  glEnable(GL_LIGHTING);
            }

01115             void GLRenderer::renderMultiLine_(const MultiLine& line)
            {
                  initDrawingOthers_();

                  glDisable(GL_LIGHTING);
                  /*

                  // TEST!!! this should use a light source. currently we use a headlight
                  Vector3 view_vector = stage_->getCamera().getViewVector();
                  view_vector.normalize();
                  Vector3 light_source = view_vector - stage_->getCamera().getLookUpVector();;
                  light_source.normalize();
            //                      Vector3 light_source = stage_->getCamera().getRightVector();

                  // This should be definitely done somewhere else...
                  GLint current_matrix_mode;
                  glGetIntegerv(GL_MATRIX_MODE, &current_matrix_mode);

                  glMatrixMode(GL_TEXTURE);
                  GLfloat matrix[16];

                  for (Size i=0; i<16; i++)
                        matrix[i] = 0.;

            //                matrix[0] = 0.5 * light_source.x; matrix[1] = 0.5 * light_source.y; matrix[2] = 0.5 * light_source.z; matrix[3] = 1.;
            //                matrix[4] = 0.5 * view_vector.x;  matrix[5] = 0.5 * view_vector.y;  matrix[6] = 0.5 * view_vector.z;  matrix[7] = 1.;
                  matrix[0] = 0.5 * light_source.x; matrix[4] = 0.5 * light_source.y; matrix[8] = 0.5 * light_source.z; matrix[12] = 1.;
                  matrix[1] = 0.5 * view_vector.x;  matrix[5] = 0.5 * view_vector.y;  matrix[9] = 0.5 * view_vector.z;  matrix[13] = 1.;

                  matrix[15] = 2.;

                  glLoadMatrixf(matrix);
                  glMatrixMode(current_matrix_mode);

                  line_list_.draw();
                  */

                  const std::vector<Vector3>& vertices = line.vertices;
            //                const std::vector<Vector3>& tangents = line.tangents;
                  const std::vector<ColorRGBA>& colors = line.colors;

                  glBegin(GL_LINE_STRIP);

                  if (colors.size() > 0) setColorRGBA_(colors[0]);

                  for (Position i = 0; i < vertices.size(); i++)
                  {
                        if (colors.size() > 1) setColorRGBA_(colors[i]);
            //                            glTexCoord3f(tangents[i].x, tangents[i].y, tangents[i].z);
                        vertexVector3_(vertices[i]);
                  }

                  glEnd();

            //                glDisable(GL_TEXTURE_2D);
            }

            void GLRenderer::renderLabel_(const Label& label)
            {
                  initDrawingOthers_();

                  glPushMatrix();
                  glDisable(GL_LIGHTING);

                  glRasterPos3f((GLfloat)label.getVertex().x,
                                                            (GLfloat)label.getVertex().y,
                                                            (GLfloat)label.getVertex().z);

                  QFontMetrics fm(label.getFont());
                  QString text = label.getExpandedText().c_str();
                  QRect r = fm.boundingRect(text);

                  int border = 2;
                  QPixmap pm(r.size() + QSize(border * 2, border * 2));

                  QPainter p;
                  p.begin(&pm);
                        p.setFont(label.getFont());
                        pm.fill(scene_->getStage()->getBackgroundColor().getQColor());
                        p.setPen(label.getColor().getQColor());
                        p.drawText(-r.x() + border, -r.y() + border, text);
                  p.end();

                  QImage data = pm.toImage();
                  QImage gldata = QGLWidget::convertToGLFormat(data);

                  glDrawPixels(data.width(), data.height(), GL_RGBA, GL_UNSIGNED_BYTE, gldata.bits());

                  glPopMatrix();
                  glEnable(GL_LIGHTING);
            }


01208             void GLRenderer::renderPoint_(const Point& point)
            {
                  initDrawingOthers_();

                  glDisable(GL_LIGHTING);
                  setColor4ub_(point);
                  glBegin(GL_POINTS);
                  normalVector3_(normal_vector_);
                  vertexVector3_(point.getVertex());
                  glEnd();
                  glEnable(GL_LIGHTING);
            }


01222             void GLRenderer::renderSimpleBox_(const SimpleBox& box)
            {
                  initDrawingOthers_();

                  glPushMatrix();
                  setColor4ub_(box);
                  translateVector3_(box.a);
                  scaleVector3_(box.b - box.a);
                  GL_boxes_list_[display_lists_index_].draw();
                  glPopMatrix();
            }


01235             void GLRenderer::renderBox_(const Box& box)
            {
                  initDrawingOthers_();

                  glPushMatrix();
                  setColor4ub_(box);

                  translateVector3_(box.getPoint());

                  Vector3 v1(box.getRightVector());
                  if (v1.getSquareLength() != 0) v1.normalize();

                  Vector3 v2(box.getHeightVector());
                  if (v2.getSquareLength() != 0) v2.normalize();

                  Vector3 v3(box.getRightVector() % box.getHeightVector());
                  if (v3.getSquareLength() != 0) v3.normalize();

                  float m[16] = { v1.x, v1.y, v1.z, 0,
                                                                  v2.x, v2.y, v2.z, 0,
                                                                  v3.x, v3.y, v3.z, 0,
                                                                  0,0,0,1};
                  glMultMatrixf(m);

                  glScalef(box.getRightVector().getLength(),
                                           box.getHeightVector().getLength(),
                                           box.getDepth());

                  GL_boxes_list_[display_lists_index_].draw();

                  glPopMatrix();
            }

01268             void GLRenderer::renderTube_(const Tube& tube)
            {
                  initDrawingOthers_();

                  glPushMatrix();
                  setColor4ub_(tube);

                  const Vector3 result = tube.getVertex2() - tube.getVertex1();
                  const float length = result.getLength();

                  if (Maths::isZero(length)) return;

                  // cross product with z-axis-vector and result
                  const Vector3 rotation_axis(-result.y, result.x, 0.0);
                  // angle between z-axis-vector and result
                  const float angle = BALL_ANGLE_RADIAN_TO_DEGREE(acos(result.z / length));

                  translateVector3_(tube.getVertex1());

                  rotateVector3Angle_(rotation_axis, angle);

                  glScalef((GLfloat)tube.getRadius(),
                                           (GLfloat)tube.getRadius(),
                                           (GLfloat)tube.getLength());

                  GL_tubes_list_[display_lists_index_].draw();

                  glPopMatrix();
            }


01299             void GLRenderer::renderTwoColoredTube_(const TwoColoredTube& tube)
            {
                  initDrawingOthers_();

                  const Vector3 result(tube.getVertex2() - tube.getVertex1());
                  const float length = result.getLength();

                  if (Maths::isZero(length)) return;

                  // cross product with z-axis-vector and result
                  const Vector3 rotation_axis(-result.y, result.x, 0.0);
                  // angle between z-axis-vector and result
                  const float angle = BALL_ANGLE_RADIAN_TO_DEGREE(acos(result.z / length));

                  glPushMatrix();
                  setColor4ub_(tube);

                  translateVector3_(tube.getVertex1());

                  rotateVector3Angle_(rotation_axis, angle);

                  glScalef((GLfloat)tube.getRadius(),
                                           (GLfloat)tube.getRadius(),
                                           (GLfloat)tube.getLength() / (float)2);

                  GL_tubes_list_[display_lists_index_].draw();

                  glPopMatrix();
                  glPushMatrix();
                  translateVector3_(tube.getMiddleVertex());

                  rotateVector3Angle_(rotation_axis, angle);

                  glScalef((GLfloat)tube.getRadius(),
                                           (GLfloat)tube.getRadius(),
                                           (GLfloat)tube.getLength() / (float)2);

                  setColorRGBA_(tube.getColor2());

                  GL_tubes_list_[display_lists_index_].draw();

                  glPopMatrix();
            }

01343             void GLRenderer::renderTwoColoredLine_(const TwoColoredLine& line)
            {
                  initDrawingOthers_();

                  setColor4ub_(line);
                  glDisable(GL_LIGHTING);

                  glBegin(GL_LINES);
                  vertexVector3_(line.getVertex1());
                  vertexVector3_(line.getMiddleVertex());
                  glEnd();

                  glBegin(GL_LINES);
                  setColorRGBA_(line.getColor2());
                  vertexVector3_(line.getMiddleVertex());
                  vertexVector3_(line.getVertex2());
                  glEnd();

                  glEnable(GL_LIGHTING);
            }


            void GLRenderer::initDrawingMeshes_()
            {
                  if (drawed_mesh_) return;

                  if (drawing_mode_ == DRAWING_MODE_DOTS)
                  {
                        glDisable(GL_LIGHTING);
                        normalVector3_(normal_vector_);
                  }
                  else if (drawing_mode_ == DRAWING_MODE_WIREFRAME)
                  {
                        glDisable(GL_LIGHTING);
                  }
                  else // draw the triangles solid
                  {
                        if (model_type_  == MODEL_CARTOON)
                        {
                              glEnable(GL_CULL_FACE);
                        }
                        else
                        {
                              glDisable(GL_CULL_FACE);
                              glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true);
                        }
                  }

                  drawed_mesh_ = true;
                  drawed_other_object_ = false;
            }


            void GLRenderer::initDrawingOthers_()
            {
                  if (drawed_other_object_) return;

                  if (drawing_mode_ == DRAWING_MODE_DOTS ||
                              drawing_mode_ == DRAWING_MODE_WIREFRAME)
                  {
                        glEnable(GL_LIGHTING);
                  }
                  else // solid
                  {
                        glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, false);
                  }

                  glEnable(GL_CULL_FACE);

                  drawed_other_object_ = true;
                  drawed_mesh_ = false;
            }


01417             void GLRenderer::renderMesh_(const Mesh& mesh)
            {
                  if (mesh.normal.size() != mesh.vertex.size())
                  {
                        BALLVIEW_DEBUG;
                        return;
                  }

                  /*
                  // debugging for normals:
                  initDrawingOthers_();
                  glDisable(GL_LIGHTING);
                  glBegin(GL_LINES);

                  for (Size index = 0; index < mesh.vertex.size(); ++index)
                  {
                        vertexVector3_(mesh.vertex[index]);
                        vertexVector3_(mesh.vertex[index] + mesh.normal[index]);
                  }
                  glEnd();
                  glEnable(GL_LIGHTING);
                  */

                  ///////////////////////////////////////////////
                  // here starts the normal mesh rendering code:
                  initDrawingMeshes_();

                  // If we have only one color for the whole mesh, this can
                  // be assigned efficiently
                  bool multiple_colors = true;
                  if (mesh.colors.size() < mesh.vertex.size())
                  {
                        if (mesh.colors.size() > 0)
                        {
                              setColorRGBA_(mesh.colors[0]);
                        }
                        multiple_colors = false;
                  }

                  Size nr_triangles = mesh.triangle.size();

                  ///////////////////////////////////////////////////////////////////
                  if (drawing_mode_ == DRAWING_MODE_DOTS)
                  {
                        glBegin(GL_POINTS);
                        for (Size index = 0; index < mesh.vertex.size(); ++index)
                        {
                              if (multiple_colors) setColorRGBA_(mesh.colors[index]);
                              vertexVector3_(mesh.vertex[index]);
                        }
                        glEnd();
                  }
                  ///////////////////////////////////////////////////////////////////
                  else if (drawing_mode_ == DRAWING_MODE_WIREFRAME)
                  {
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              glBegin(GL_LINE_STRIP);

                              normalVector3_(normal_vector_);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.triangle[index].v1]);
                              vertexVector3_(mesh.vertex[mesh.triangle[index].v1]);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.triangle[index].v2]);
                              vertexVector3_(mesh.vertex[mesh.triangle[index].v2]);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.triangle[index].v3]);
                              vertexVector3_(mesh.vertex[mesh.triangle[index].v3]);

                              glEnd();
                        }
                  }
                  ///////////////////////////////////////////////////////////////////
                  else if (drawing_mode_ == DRAWING_MODE_SOLID)                     // draw the triangles solid
                  {
                        glBegin(GL_TRIANGLES);
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              Position p = mesh.triangle[index].v1;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.triangle[index].v2;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.triangle[index].v3;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);
                        }
                        glEnd();
                  }
                  else        // draw the triangles per cel shading
                  {
                        // a part of this code stems from http://nehe.gamedev.net lesson 37
                        glDisable(GL_LIGHTING);
                        glPolygonMode(GL_BACK, GL_LINE);                                                          // Draw Backfacing Polygons As Wireframes
                        glLineWidth(3);                                                                                                               // Set The Line Width
                        glEnable(GL_CULL_FACE);
                        glCullFace(GL_FRONT);                                                                                             // Don't Draw Any Front-Facing Polygons
                        glDepthFunc(GL_LEQUAL);                                                                                     // Change The Depth Mode
                        setColorRGBA_(ColorRGBA(0.,0.,0.,1.));
                        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);                                       // Use The Good Calculations
                        glEnable(GL_LINE_SMOOTH);                                                                                   // Enable Anti-Aliasing

                        glBegin(GL_TRIANGLES);                                                                                      // Tell OpenGL What We Want To Draw
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              vertexVector3_(mesh.vertex[mesh.triangle[index].v1]);
                              vertexVector3_(mesh.vertex[mesh.triangle[index].v2]);
                              vertexVector3_(mesh.vertex[mesh.triangle[index].v3]);
                        }
                        glEnd ();                                                                           // Tell OpenGL We've Finished

                        // reset to normal:
                        glCullFace(GL_BACK);                                        // Reset The Face To Be Culled
                        glPolygonMode (GL_BACK, GL_FILL);   // Reset Back-Facing Polygon Drawing Mode
                        glLineWidth(1);                                                         // Set The Line Width

                        // map the texture so it simulates shadows:
                        glEnable(GL_TEXTURE_1D);
                        glBindTexture(GL_TEXTURE_1D, cel_texture_);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);

                        // some artefacts when using GL_LINEAR:
            //                      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            //                      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

                        vector<float> tex_values;
                        tex_values.reserve(mesh.normal.size());
                        Vector3 vv = -scene_->getStage()->getCamera().getViewVector() ;
                        vv.normalize();
                        // other light positions possible:
            //                            vv += scene_->getStage()->getCamera().getLookUpVector() / 2.0;
            //                            vv += scene_->getStage()->getCamera().getRightVector() / 2.0;
            //                            vv.normalize();

                        float v;
                        for (Position p = 0; p < mesh.normal.size(); p++)
                        {
                              v = mesh.normal[p] * vv;
                              if (v < 0.) v = 0.;
                              tex_values.push_back(BALL_MIN(1., v));
                        }

                        // prevent problems with single colored meshes:
                        if (mesh.colors.size() > 0) setColorRGBA_(mesh.colors[0]);

                        glBegin(GL_TRIANGLES);
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              Position p = mesh.triangle[index].v1;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              glTexCoord1f (tex_values[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.triangle[index].v2;
                              glTexCoord1f (tex_values[p]);
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.triangle[index].v3;
                              glTexCoord1f (tex_values[p]);
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              vertexVector3_(mesh.vertex[p]);
                        }

                        glEnd();
                        glEnable(GL_LIGHTING);
                        glDisable(GL_TEXTURE_1D);
                  }
            }


            void GLRenderer::initGLU_(DrawingMode mode)
            {
                  if (mode == DRAWING_MODE_WIREFRAME)
                  {
                        gluQuadricDrawStyle(GLU_quadric_obj_, GLU_LINE);
                  }
                  else if (mode >= DRAWING_MODE_SOLID)
                  {
                        gluQuadricDrawStyle(GLU_quadric_obj_, GLU_FILL);
                  }
                  else if (mode == DRAWING_MODE_DOTS)
                  {
                        gluQuadricDrawStyle(GLU_quadric_obj_, GLU_POINT);
                  }
                  else
                  {
                        BALLVIEW_DEBUG;
                  }
            }

            void GLRenderer::createSpheres_()
            {
                  glPushMatrix();

                  Position slices[4] = {14, 24, 64, 100};
                  Position stacks[4] = {8, 16, 44, 80};

                  for (Position mode = DRAWING_MODE_DOTS; mode < BALL_VIEW_MAXIMAL_DRAWING_MODE; mode++)
                  {
                        initGLU_((DrawingMode)mode);

                        for (Position dp = DRAWING_PRECISION_LOW; dp <= DRAWING_PRECISION_ULTRA; dp++)
                        {
                              GL_spheres_list_[mode * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + dp].startDefinition();
                              gluSphere(GLU_quadric_obj_, 1, slices[dp], stacks[dp]);
                              GL_spheres_list_[mode * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + dp].endDefinition();
                        }
                  }

                  glPopMatrix();
            }


            void GLRenderer::createDottedSphere_(int precision)
            {
                  glBegin(GL_POINTS);

                  vector<Vector3> results = createSphere((Size)precision);
                  for (Position p = 0; p < results.size(); p++)
                  {
                        vertexVector3_(results[p]);
                  }

                  glEnd();
            }


            void GLRenderer::createTubes_()
            {
                  glPushMatrix();

                  Position slices[4] = {6, 10, 20, 64};

                  for (Position mode = DRAWING_MODE_DOTS; mode < BALL_VIEW_MAXIMAL_DRAWING_MODE; mode++)
                  {
                        initGLU_((DrawingMode)mode);

                        for (Position dp = DRAWING_PRECISION_LOW; dp <= DRAWING_PRECISION_ULTRA; dp++)
                        {
                              GL_tubes_list_[mode * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + dp].startDefinition();
                              gluCylinder(GLU_quadric_obj_, 1, 1, 1, slices[dp], 1);
                              GL_tubes_list_[mode * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + dp].endDefinition();
                        }
                  }

                  glPopMatrix();
            }


            void GLRenderer::createBoxes_()
            {
                  // building point display list
                  for (Position pos = 0; pos < BALL_VIEW_MAXIMAL_DRAWING_PRECISION; pos++)
                  {
                        GL_boxes_list_[0 * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + pos].startDefinition();
                        createDotBox_();
                        GL_boxes_list_[0 * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + pos].endDefinition();
                  }

                  // building wireframe display list
                  for (Position pos = 0; pos < BALL_VIEW_MAXIMAL_DRAWING_PRECISION; pos++)
                  {
                        GL_boxes_list_[1 * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + pos].startDefinition();
                        createLineBox_();
                        GL_boxes_list_[1 * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + pos].endDefinition();
                  }

                  // building solid display list
                  for (Position pos = 0; pos < BALL_VIEW_MAXIMAL_DRAWING_PRECISION; pos++)
                  {
                        GL_boxes_list_[2 * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + pos].startDefinition();
                        createSolidBox_();
                        GL_boxes_list_[2 * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + pos].endDefinition();
                  }
            }


            void GLRenderer::createLineBox_()
            {
                  glBegin(GL_LINES);

                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);

                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);

                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);

                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);

                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);

                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);

                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);

                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);

                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);

                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);

                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);

                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);

                  glEnd();
            }


            void GLRenderer::createDotBox_()
            {
                  glBegin(GL_POINTS);

                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);

                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);

                  glEnd();
            }


            void GLRenderer::createSolidBox_()
            {
                  glBegin(GL_QUADS);

                  // back
                  glNormal3f((GLfloat)0, (GLfloat)0, (GLfloat)-1);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);

                  // above
                  glNormal3f((GLfloat)0, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);

                  // front
                  glNormal3f((GLfloat)0, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);

                  // under
                  glNormal3f((GLfloat)0, (GLfloat)-1, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);

                  // left
                  glNormal3f((GLfloat)-1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)0, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)0, (GLfloat)1, (GLfloat)1);

                  // right
                  glNormal3f((GLfloat)1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)1);
                  glVertex3f((GLfloat)1, (GLfloat)0, (GLfloat)0);
                  glVertex3f((GLfloat)1, (GLfloat)1, (GLfloat)0);

                  glEnd();
            }


            // ############################ PICKING ###################################
01818             void GLRenderer::pickObjects1(Position x1, Position y1, Position x2, Position y2)
            {
                  glFlush();
                  GLint viewport[4];
                  // init name stack for 32000 objects
                  glGetIntegerv(GL_VIEWPORT, viewport);
                  glSelectBuffer(BALL_GLRENDERER_PICKING_NUMBER_OF_MAX_OBJECTS, object_buffer_);
                  // uncoment this for debuging:
                  glRenderMode(GL_SELECT);
                  glInitNames();
                  glPushName(0);
                  glMatrixMode(GL_PROJECTION);

                  glPushMatrix();
                  glLoadIdentity();

                  // calculate picking rectangle
                  Size width  = BALL_ABS((Index)x2 - (Index)x1);
                  Size height = BALL_ABS((Index)y2 - (Index)y1);

                  Position center_x = BALL_MIN(x2, x1) + width / 2;
                  Position center_y = BALL_MIN(y2, y1) + height / 2;

                  if (width == 0)   width = 1;
                  if (height == 0) height = 1;

                  single_pick_ = (width <= 3 && height <= 3);
                  clearNames_();

                  // calculate picking matrix
                  gluPickMatrix(center_x, viewport[3] - center_y, width, height, viewport);

                  // prepare camera
                  initPerspective();

                  glMatrixMode(GL_MODELVIEW);
                  updateCamera();
            }


01858             void GLRenderer::pickObjects2(List<GeometricObject*>& objects)
            {
                  glFlush();

                  glMatrixMode(GL_PROJECTION);
                  // get number of hits
                  int number_of_hits = glRenderMode(GL_RENDER);
                  glPopMatrix();
                  glMatrixMode(GL_MODELVIEW);
                  // return if no objects are picked
                  if (number_of_hits == 0)
                  {
                        updateCamera();
                        return;
                  }

                  Position minimum_z_coord = UINT_MAX;
                  Position names;
                  Name nearest_name = 0;
                  Position* object_buffer_ptr = (Position*) object_buffer_;
                  GeometricObject* go = 0;

                  // collect only the nearest Object
                  if (single_pick_)
                  {
                        Position z_coord;

                        // find minimum z-coord
                        for (Index index = 0; index < number_of_hits; ++index)
                        {
                              names = *object_buffer_ptr;
                              ++object_buffer_ptr;
                              z_coord = *object_buffer_ptr;

                              object_buffer_ptr += 2;

                              if (z_coord <= minimum_z_coord)
                              {
                                    minimum_z_coord = z_coord;
                                    nearest_name = *object_buffer_ptr;
                              }

                              object_buffer_ptr += names;
                        }

                        go = getObject(nearest_name);
                        if (go != 0) objects.push_back(go);
                  }
                  else // collect all objects that are in the picking area
                  {
                        for (Index index = 0; index < number_of_hits; ++index)
                        {
                              names = *object_buffer_ptr;
                              object_buffer_ptr += 3;
                              nearest_name = *object_buffer_ptr;
                              object_buffer_ptr += names;

                              go = getObject(nearest_name);
                              if (go != 0) objects.push_back(go);
                        }
                  }

                  updateCamera();
            }


            // ############################ MOVEMENT/SIZE ###################################
            // TODO: shouldn't we use a camera aperture angle?
01926             void GLRenderer::setSize(float width, float height)
            {
                  width_      = width;
                  height_ = height;

                  if (width > height)
                  {
                        x_scale_ = width / (height * 2);
                        y_scale_ = 0.5;
                  }
                  else
                  {
                        x_scale_ = 0.5;
                        y_scale_ = height / (width * 2);
                  }

                  glViewport(0, 0, (int)width_, (int)height_);

                  glMatrixMode(GL_PROJECTION);
                  glLoadIdentity();
                  initPerspective();
                  glMatrixMode(GL_MODELVIEW);
            }


01951             void GLRenderer::updateCamera(const Camera* camera)
            {
                  if (camera == 0) camera = &(stage_->getCamera());

                  if (Maths::isZero(camera->getViewVector().getSquareLength()))
                  {
                        Log.error() << "Unvalid camera settings: View point = LookAt point" << std::endl;
                        return;
                  }

                  glLoadIdentity();

                  gluLookAt(camera->getViewPoint().x,
                                                camera->getViewPoint().y,
                                                camera->getViewPoint().z,
                                                camera->getLookAtPosition().x,
                                                camera->getLookAtPosition().y,
                                                camera->getLookAtPosition().z,
                                                camera->getLookUpVector().x,
                                                camera->getLookUpVector().y,
                                                camera->getLookUpVector().z);

                  normal_vector_ = (-camera->getViewVector().normalize());

                  setLights(false);
            }

01978             void GLRenderer::setupStereo(float eye_separation, float focal_length)
            {
                  // TODO: - make near and far clip configurable!!!
                  //       - keep the same frustrum until either the size or the stereo settings change

                  float ndfl    = near_ / focal_length;

                  float new_left   = left_  - eye_separation * ndfl;
                  float new_right  = right_ - eye_separation * ndfl;

                  glMatrixMode(GL_PROJECTION);

                  glLoadIdentity();
                  glFrustum(new_left, new_right, bottom_, top_, near_, far_);
                  glViewport(0, 0, width_, height_);

                  glMatrixMode(GL_MODELVIEW);
            }

01997             bool GLRenderer::hasDisplayListFor(const Representation& rep) const
            {
                  return display_lists_.has(&rep);
            }

02002             bool GLRenderer::isExtensionSupported(const String& extension) const
            {
                  // Extension names should not have spaces
                  if (extension == "" || extension.hasSubstring(" ")) return false;

                  // Get Extensions String
                  if (glGetString(GL_EXTENSIONS) == 0)
                  {
                        return false;
                  }

                  String supported_extensions = (const char*) glGetString(GL_EXTENSIONS);
                  if (supported_extensions.hasSubstring(extension)) return true;

                  return false;
            }

            String GLRenderer::getVendor()
            {
                  if (glGetString(GL_VENDOR) == 0) return "";
                  return (char*)glGetString(GL_VENDOR);
            }

            String GLRenderer::getRenderer()
            {
                  if (glGetString(GL_RENDERER) == 0) return "";
                  return (char*)glGetString(GL_RENDERER);
            }

            String GLRenderer::getOpenGLVersion()
            {
                  if (glGetString(GL_VERSION) == 0) return "";
                  return (char*)glGetString(GL_VERSION);
            }

            vector<String> GLRenderer::getExtensions()
            {
                  vector<String> string_vector;
                  char* extensions = (char*)glGetString(GL_EXTENSIONS);

                  if (!extensions) 
                        return string_vector;

                  String exts(extensions);

                  exts.split(string_vector);
                  return string_vector;
            }

            bool GLRenderer::enableVertexBuffers(bool state)
            {
#ifndef BALL_USE_GLEW
                  return false;
#else
                  if (!isExtensionSupported("GL_ARB_vertex_buffer_object"))
                  {
                        use_vertex_buffer_ = false;
                        return false;
                  }

                  if (state != use_vertex_buffer_)
                  {
                        if (state) Log.info() << "Enabling Vertex Buffer" << std::endl;
                        else       Log.info() << "Disabling Vertex Buffer" << std::endl;
                  }
                  use_vertex_buffer_ = state;

                  if (use_vertex_buffer_) MeshBuffer::initGL();

                  return true;
#endif
            }

            void GLRenderer::clearVertexBuffersFor(Representation& rep)
            {
#ifdef BALL_USE_GLEW
                  MeshBufferHashMap::Iterator vit = rep_to_buffers_.find(&rep);
                  if (vit == rep_to_buffers_.end()) return;

                  vector<MeshBuffer*>& meshes = vit->second;
                  vector<MeshBuffer*>::iterator bit = meshes.begin();
                  for (; bit != meshes.end(); bit++)
                  {
                        delete *bit;
                  }

                  meshes.clear();
                  rep_to_buffers_.erase(vit);
#endif
            }

02093             void GLRenderer::drawBuffered(const Representation& rep)
            {
                  if (rep.isHidden()) return;

#ifdef BALL_USE_GLEW
                  // if we have vertex buffers for this Representation, draw them
                  if (use_vertex_buffer_ && drawing_mode_ != DRAWING_MODE_WIREFRAME)
                  {
                        MeshBufferHashMap::Iterator vit = rep_to_buffers_.find(&rep);
                        if (vit != rep_to_buffers_.end())
                        {
                              initDrawingMeshes_();
                              MeshBuffer::setGLRenderer(this);
                              vector<MeshBuffer*>& buffers = vit->second;

                              vector<MeshBuffer*>::iterator bit = buffers.begin();
                              for (; bit != buffers.end(); bit++)
                              {
                                    (*bit)->draw();
                              }
                        }
                  }
#endif

                  // if we have a displaylist for this Representation, draw it
                  DisplayListHashMap::Iterator dit = display_lists_.find(&rep);
                  if (dit != display_lists_.end())
                  {
                        dit->second->draw();
                  }
            }

            void GLRenderer::enterPickingMode()
            {
                  picking_mode_ = true;
            }

            void GLRenderer::exitPickingMode()
            {
                  picking_mode_ = false;
                  object_to_name_.clear();
                  name_to_object_.clear();
                  all_names_ = 1;
            }


            bool GLRenderer::vertexBuffersSupported() const
            {
#ifdef BALL_USE_GLEW
                  return isExtensionSupported("GL_ARB_vertex_buffer_object");
#else
                  return false;
#endif
            }

            void GLRenderer::renderClippingPlane_(const ClippingPlane& plane)
            {
                  display_lists_index_ = DRAWING_MODE_SOLID * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + DRAWING_PRECISION_HIGH;

                  glPushAttrib(GL_LIGHTING_BIT | GL_BLEND);
                  const Vector3& point(plane.getPoint());
                  const Vector3& n(plane.getNormal());

                  Tube tube;
                  tube.setVertex1(point);
                  tube.setVertex2(point - (plane.getNormal() * 10.0));
                  tube.setColor(ColorRGBA(0,255,255));
                  tube.setRadius(1);

                  initDrawingOthers_();
                  initTransparent();
                  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true);
                  glDisable(GL_CULL_FACE);
                  renderTube_(tube);

                  initDrawingOthers_();
                  glEnable(GL_DEPTH_TEST);
                  glEnable(GL_BLEND);
                  glDepthMask(GL_FALSE);

                  glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, true);
                  glDisable(GL_CULL_FACE);

                  glPushMatrix();
                  setColorRGBA_(ColorRGBA(0,0,255, 190));;
                  translateVector3_(point);
                  const Vector3 rotation_axis(-n.y, n.x, 0.0);
                  // angle between z-axis-vector and result
                  const float angle = BALL_ANGLE_RADIAN_TO_DEGREE(acos(n.z / n.getLength()));
                  rotateVector3Angle_(rotation_axis, angle);

                  initGLU_(DRAWING_MODE_SOLID);
                  gluDisk(GLU_quadric_obj_, 0, 20 , 140, 80);

                  glPopMatrix();
                  glEnable(GL_CULL_FACE);

                  glPopAttrib();
            }

            void GLRenderer::initPerspective()
            {
                  if (getStereoMode() == GLRenderer::ACTIVE_STEREO)
                  {
                        //  "Dont call GLRenderer::initPerspective() in Stereo mode! "
                        return;
                  }

                  left_   = -2.0 * x_scale_;
                  right_  =  2.0 * x_scale_;
                  bottom_ = -2.0 * y_scale_;
                  top_    =  2.0 * y_scale_;

                  glFrustum(left_, right_, bottom_, top_, near_, far_);
            }

            void GLRenderer::generateIlluminationTexture_(float ka, float kd, float kr, float shininess)
            {
                  const int TEXTURE_SIZE = 128;  // including border
                  enum { R = 0, G = 1, B = 2, A = 3 };

            //                assert( 0. <= ka && ka <= 1. );
            //                assert( 0. <= kd && kd <= 1. );
            //                assert( 0. <= kr && kr <= 1. );
            //                float k = ka + kd + kr;
            //                assert( 0. <= k  &&  k <= 1. );

                  Index i = 0;
                  Index j = 0;
                  for( i = 0; i < TEXTURE_SIZE; ++i )
                  {
                        for( j = 0; j < TEXTURE_SIZE; ++j )
                        {
                              float x = ( (float) j + 1. ) / (TEXTURE_SIZE + 1.);
                              float y = ( (float) i + 1. ) / (TEXTURE_SIZE + 1.);

                              float LT = 2. * x - 1.;
                              float VT = 2. * y - 1.;

                              float intensity = 0.;
                              intensity += ka;
                              intensity += kd * sqrt( 1. - LT*LT );
                              intensity += kr * pow( fabs( LT*VT - sqrt( 1. - LT*LT ) * sqrt( 1. - VT*VT ) ), shininess * 255. );

                              if( intensity < 0. || 1. < intensity )
                              {
                                    if( intensity < 0. ) intensity = 0.;
                                    if( 1. < intensity ) intensity = 1.;
                              }
            //                            assert( 0. <= intensity && intensity <= 1. );

                              Index c = (Index)(intensity * 255);
            //                            assert( 0 <= c && c <= 255 );

                              line_tex_[i][j][R] = (GLubyte) c;
                              line_tex_[i][j][G] = (GLubyte) c;
                              line_tex_[i][j][B] = (GLubyte) c;
                              line_tex_[i][j][A] = 127;
                        }
                  }
            }

            Position GLRenderer::getTextureIndex_(Position x, Position y, Position z, Size width, Size height)
            {
                  return BYTES_PER_TEXEL * (x * width + y) +
                                     BYTES_PER_TEXEL * width * height * z;
            }

            Position GLRenderer::createTextureFromGrid(const RegularData3D& grid, const ColorMap& map)
            {
                  if (!isExtensionSupported("GL_EXT_texture3D")) return 0;

                  // prevent warning and error if not using GLEW:
                  Position texname = 0;
#ifdef BALL_USE_GLEW
                  removeTextureFor_(grid);
                  RegularData3D::IndexType tex_size = grid.getSize();

                  // Generate The Texture
                  Position i = 0;
                  GLubyte* texels = new GLubyte[tex_size.x * tex_size.y * tex_size.z * BYTES_PER_TEXEL];
                  for (Position z = 0; z < tex_size.z; z++)
                  {
                        for (Position y = 0; y < tex_size.y; y++)
                        {
                              for (Position x = 0; x < tex_size.x; x++)
                              {
                                    const ColorRGBA& c = map.map(grid.getData(RegularData3D::IndexType(x,y,z)));
                                    texels[i + 0] = (unsigned char)c.getRed();
                                    texels[i + 1] = (unsigned char)c.getGreen();
                                    texels[i + 2] = (unsigned char)c.getBlue();
                                    texels[i + 3] = (unsigned char)c.getAlpha();
                                    i += 4;
                              }
                        }
                  }

                  glGenTextures(1, &texname);
                  glBindTexture(GL_TEXTURE_3D, texname);
                  glTexImage3D(GL_TEXTURE_3D, 0, GL_RGBA, tex_size.x, tex_size.y, tex_size.z, 0, GL_RGBA, GL_UNSIGNED_BYTE, texels);
                  glBindTexture(GL_TEXTURE_3D, 0);
                  grid_to_texture_[&grid] = texname;
                  delete[] texels;
#endif
                  return texname;
            }

            void GLRenderer::removeTextureFor_(const RegularData3D& grid)
            {
                  if (!grid_to_texture_.has(&grid)) return;
                  glDeleteTextures(1, (GLuint*)&grid_to_texture_[&grid]);
                  grid_to_texture_.erase(&grid);
            }

            void GLRenderer::setupGridClipPlanes_(const GridVisualisation& slice)
            {
                  double planes[6][4];

                  Vector3 x,y,z;
                  x = slice.x;
                  x.normalize();
                  y = slice.y;
                  y.normalize();
                  z = slice.z;
                  z.normalize();


                  Vector3 origin = slice.origin;
                  Vector3 dv = slice.x + slice.y + slice.z;
                  dv *= 0.001;
                  Vector3 e = origin + slice.x + slice.y + slice.z + dv ;
                  origin -= dv;

                  float d = x * (-origin);
                  planes[0][0] = x.x; planes[0][1] = x.y; planes[0][2] = x.z; planes[0][3] = d;
                  d = y * (-origin);
                  planes[1][0] = y.x; planes[1][1] = y.y; planes[1][2] = y.z; planes[1][3] = d;
                  d = z * (-origin);
                  planes[2][0] = z.x; planes[2][1] = z.y; planes[2][2] = z.z; planes[2][3] = d;

                  d = -x * (-e);
                  planes[3][0] = -x.x; planes[3][1] = -x.y; planes[3][2] = -x.z; planes[3][3] = d;
                  d = -y * (-e);
                  planes[4][0] = -y.x; planes[4][1] = -y.y; planes[4][2] = -y.z; planes[4][3] = d;
                  d = -z * (-e);
                  planes[5][0] = -z.x; planes[5][1] = -z.y; planes[5][2] = -z.z; planes[5][3] = d;

                  for (Position plane = GL_CLIP_PLANE0 + 0; plane < GL_CLIP_PLANE0 + 6; plane++)
                  {
                        glClipPlane(plane, &planes[plane - GL_CLIP_PLANE0][0]);
                        glEnable(plane);
                  }
            }


02348             void GLRenderer::renderGridVisualisation_(const GridVisualisation& vol)
            {
                  if (!grid_to_texture_.has(vol.getGrid()))
                        return;

                  Position texname = grid_to_texture_[vol.getGrid()];
                  if (texname == 0)
                  {
                        scene_->setStatusbarText("Graphics card does not support 3D textures", true);
                        return;
                  }

                  const Vector3 origin = vol.origin;

                  if (vol.draw_box)
                  {
                        Box box(origin, vol.x, vol.y, vol.z.getLength());
                        box.setColor(stage_->getBackgroundColor().getInverseColor());
                        Position dli = display_lists_index_;
                        display_lists_index_ = DRAWING_MODE_WIREFRAME * BALL_VIEW_MAXIMAL_DRAWING_PRECISION + drawing_precision_;
                        renderBox_(box);
                        display_lists_index_ = dli;
                  }

                  initDrawingOthers_();
                  glDisable(GL_LIGHTING);
                  glDisable(GL_CULL_FACE);

                  ////////////////////////////////////////////////////////////////////////////////
                  glBindTexture(GL_TEXTURE_3D, texname);
                  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
                  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_CLAMP);
                  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_CLAMP);
                  glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_CLAMP);
                  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

                  ///// init the texture: automated texture coordinate generation
                  // normalized vectors in grids directions:
                  Vector3 xd = vol.x;
                  xd.normalize();
                  Vector3 yd = vol.y;
                  yd.normalize();
                  Vector3 zd = vol.z;
                  zd.normalize();

                  // plane vectors and distance for texture coordinates:
                  float xp[4], yp[4], zp[4], d;
                  Vector3 n;

                  n = zd;
                  d = n * (-origin);
                  xp[0] = n.x; xp[1] = n.y; xp[2] = n.z; xp[3] = d;

                  n = xd;
                  d = n * (-origin);
                  yp[0] = n.x; yp[1] = n.y; yp[2] = n.z; yp[3] = d;

                  n = yd;
                  d = n * (-origin);
                  zp[0] = n.x; zp[1] = n.y; zp[2] = n.z; zp[3] = d;

                  glEnable(GL_TEXTURE_3D);
                  glTexGenf(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
                  glTexGenf(GL_T,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
                  glTexGenf(GL_R,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR);
                  glTexGenfv(GL_S,GL_OBJECT_PLANE, yp);
                  glTexGenfv(GL_T,GL_OBJECT_PLANE, zp);
                  glTexGenfv(GL_R,GL_OBJECT_PLANE, xp);
                  glEnable(GL_TEXTURE_GEN_S);
                  glEnable(GL_TEXTURE_GEN_T);
                  glEnable(GL_TEXTURE_GEN_R);

                  // stretch the texture accordingly
                  glMatrixMode(GL_TEXTURE);
                  glLoadIdentity();
                  const Vector3 dim = vol.x + vol.y + vol.z;
                  glScaled((double)1.0 / (double) dim.x,
                                           (double)1.0 / (double) dim.y,
                                           (double)1.0 / (double) dim.z);
                  glMatrixMode(GL_MODELVIEW);

                  // render this as one slice
                  if (vol.type == GridVisualisation::PLANE)
                  {
                        setupGridClipPlanes_(vol);
                        Vector3 n = vol.getNormal();
                        Vector3 v1 = getNormal(n);
                        Vector3 v2 = v1 % n;

                        v1.normalize();
                        v2.normalize();
                        v1 *= vol.max_dim * 2.0;
                        v2 *= vol.max_dim * 2.0;

                        Vector3 o = vol.getPoint() - v1 - v2;

                        v1 *= 2.0;
                        v2 *= 2.0;

                        glBegin(GL_QUADS);
                        normalVector3_(-vol.getNormal());
                        vertexVector3_(o);
                        vertexVector3_(o + v1);
                        vertexVector3_(o + v1 + v2);
                        vertexVector3_(o + v2);
                        glEnd();

                        for (Position plane = GL_CLIP_PLANE0; plane < GL_CLIP_PLANE0 + 6; plane++)
                        {
                              glDisable(plane);
                        }
                  }
                  else if (vol.type == GridVisualisation::SLICES)
                  {
                        // volume rendering
                        const Vector3& vv = scene_->getStage()->getCamera().getViewVector();

                        Vector3 normals[3];
                        normals[0] = vol.x;
                        normals[1] = vol.y;
                        normals[2] = vol.z;

                        // calculate the angles between vv and the axes of the grid
                        Angle angles[3], aangles[3];

                        for (Position i = 0; i < 3; i++)
                        {
                              angles[i] = normals[i].getAngle(vv);
                              aangles[i] = (-normals[i]).getAngle(vv);
                        }

                        Angle min_angle(angles[0]);
                        Position min = 0;
                        bool anti = false;
                        for (Position i = 0; i < 3; i++)
                        {
                              if (angles[i] < min_angle)
                              {
                                    min = i;
                                    anti = false;
                                    min_angle = angles[i];
                              }

                              if (aangles[i] < min_angle)
                              {
                                    min = i;
                                    anti = true;
                                    min_angle = aangles[i];
                              }
                        }

                        // order the axes: 3. vector is the axis nearest to view vector direction
                        Vector3 vectors[2];
                        Position v = 0;
                        Vector3 normal;
                        for (Position i = 0; i < 3; i++)
                        {
                              if (i == min)
                              {
                                    normal = normals[i];
                                    continue;
                              }

                              vectors[v] = normals[i];
                              v++;
                        }

                        // order of layers: depends on direction of normal to view vector direction
                        Vector3 offset;
                        Vector3 diff = normal;
                        if (!anti)
                        {
                              offset = normal;
                              diff *= -1;
                        }

                        // normal and start points
                        diff /= ((float)vol.slices - 1.);
                        Vector3 o  = origin + offset;
                        Vector3 x  = o + vectors[0];
                        Vector3 xy = x + vectors[1];
                        Vector3 y  = o + vectors[1];

                        glBegin(GL_QUADS);
                        for (Position i = 0; i < vol.slices; ++i)
                        {
                              vertexVector3_(y);
                              vertexVector3_(xy);
                              vertexVector3_(x);
                              vertexVector3_(o);

                              o  += diff;
                              x  += diff;
                              xy += diff;
                              y  += diff;
                        }
                        glEnd();
                  }
                  else
                  {
                        glPointSize(vol.getDotSize());
                        glBegin(GL_POINTS);
                        for (Position p = 0; p < vol.points.size(); p++)
                        {
                              vertexVector3_(vol.points[p]);
                        }
                        glEnd();
                        glEnable(GL_LIGHTING);
                        glPointSize(1);
                  }

                  glEnable(GL_LIGHTING);
                  glEnable(GL_CULL_FACE);

                  glDisable(GL_TEXTURE_GEN_S);
                  glDisable(GL_TEXTURE_GEN_T);
                  glDisable(GL_TEXTURE_GEN_R);
                  glBindTexture(GL_TEXTURE_3D, 0);
            }

02569             void GLRenderer::renderQuadMesh_(const QuadMesh& mesh)
            {
                  if (mesh.normal.size() != mesh.vertex.size())
                  {
                        BALLVIEW_DEBUG;
                        return;
                  }

                  /*
                  // debugging for normals:
                  initDrawingOthers_();
                  glDisable(GL_LIGHTING);
                  glBegin(GL_LINES);

                  for (Size index = 0; index < mesh.vertex.size(); ++index)
                  {
                        vertexVector3_(mesh.vertex[index]);
                        vertexVector3_(mesh.vertex[index] + mesh.normal[index]);
                  }
                  glEnd();
                  glEnable(GL_LIGHTING);
                  */

                  ///////////////////////////////////////////////
                  // here starts the normal mesh rendering code:
                  initDrawingMeshes_();

                  // If we have only one color for the whole mesh, this can
                  // be assigned efficiently
                  bool multiple_colors = true;
                  if (mesh.colors.size() < mesh.vertex.size())
                  {
                        if (mesh.colors.size() > 0)
                        {
                              setColorRGBA_(mesh.colors[0]);
                        }
                        multiple_colors = false;
                  }

                  Size nr_triangles = mesh.quad.size();

                  ///////////////////////////////////////////////////////////////////
                  if (drawing_mode_ == DRAWING_MODE_DOTS)
                  {
                        glBegin(GL_POINTS);
                        for (Size index = 0; index < mesh.vertex.size(); ++index)
                        {
                              if (multiple_colors) setColorRGBA_(mesh.colors[index]);
                              vertexVector3_(mesh.vertex[index]);
                        }
                        glEnd();
                  }
                  ///////////////////////////////////////////////////////////////////
                  else if (drawing_mode_ == DRAWING_MODE_WIREFRAME)
                  {
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              glBegin(GL_LINE_STRIP);

                              normalVector3_(normal_vector_);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.quad[index].q1]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q1]);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.quad[index].q2]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q2]);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.quad[index].q3]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q3]);

                              if (multiple_colors) setColorRGBA_(mesh.colors[mesh.quad[index].q4]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q4]);

                              glEnd();
                        }
                  }
                  ///////////////////////////////////////////////////////////////////
                  else if (drawing_mode_ == DRAWING_MODE_SOLID)                     // draw the triangles solid
                  {
                        glBegin(GL_QUADS);
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              Position p = mesh.quad[index].q1;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.quad[index].q2;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.quad[index].q3;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.quad[index].q4;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              normalVector3_(mesh.normal[p]);
                              vertexVector3_(mesh.vertex[p]);
                        }
                        glEnd();
                  }
                  else        // draw the triangles per cel shading
                  {
                        // a part of this code stems from http://nehe.gamedev.net lesson 37
                        glDisable(GL_LIGHTING);
                        glPolygonMode(GL_BACK, GL_LINE);                                                          // Draw Backfacing Polygons As Wireframes
                        glLineWidth(3);                                                                                                               // Set The Line Width
                        glEnable(GL_CULL_FACE);
                        glCullFace(GL_FRONT);                                                                                             // Don't Draw Any Front-Facing Polygons
                        glDepthFunc(GL_LEQUAL);                                                                                     // Change The Depth Mode
                        setColorRGBA_(ColorRGBA(0.,0.,0.,1.));
                        glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);                                       // Use The Good Calculations
                        glEnable(GL_LINE_SMOOTH);                                                                                   // Enable Anti-Aliasing

                        glBegin(GL_TRIANGLES);                                                                                      // Tell OpenGL What We Want To Draw
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              vertexVector3_(mesh.vertex[mesh.quad[index].q1]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q2]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q3]);
                              vertexVector3_(mesh.vertex[mesh.quad[index].q3]);
                        }
                        glEnd ();                                                                           // Tell OpenGL We've Finished

                        // reset to normal:
                        glCullFace(GL_BACK);                                        // Reset The Face To Be Culled
                        glPolygonMode (GL_BACK, GL_FILL);   // Reset Back-Facing Polygon Drawing Mode
                        glLineWidth(1);                                                         // Set The Line Width

                        // map the texture so it simulates shadows:
                        glEnable(GL_TEXTURE_1D);
                        glBindTexture(GL_TEXTURE_1D, cel_texture_);
                        glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
                        glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);

                        // some artefacts when using GL_LINEAR:
            //                      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            //                      glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
                        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
                        glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

                        vector<float> tex_values;
                        tex_values.reserve(mesh.normal.size());
                        Vector3 vv = -scene_->getStage()->getCamera().getViewVector() ;
                        vv.normalize();
                        // other light positions possible:
            //                            vv += scene_->getStage()->getCamera().getLookUpVector() / 2.0;
            //                            vv += scene_->getStage()->getCamera().getRightVector() / 2.0;
            //                            vv.normalize();

                        float v;
                        for (Position p = 0; p < mesh.normal.size(); p++)
                        {
                              v = mesh.normal[p] * vv;
                              if (v < 0.) v = 0.;
                              tex_values.push_back(BALL_MIN(1., v));
                        }

                        // prevent problems with single colored meshes:
                        if (mesh.colors.size() > 0) setColorRGBA_(mesh.colors[0]);

                        glBegin(GL_QUADS);
                        for (Size index = 0; index < nr_triangles; ++index)
                        {
                              Position p = mesh.quad[index].q1;
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              glTexCoord1f (tex_values[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.quad[index].q2;
                              glTexCoord1f (tex_values[p]);
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.quad[index].q3;
                              glTexCoord1f (tex_values[p]);
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              vertexVector3_(mesh.vertex[p]);

                              p = mesh.quad[index].q4;
                              glTexCoord1f (tex_values[p]);
                              if (multiple_colors) setColorRGBA_(mesh.colors[p]);
                              vertexVector3_(mesh.vertex[p]);
                        }

                        glEnd();
                        glEnable(GL_LIGHTING);
                        glDisable(GL_TEXTURE_1D);
                  }
            }

#ifdef BALL_COMPILER_MSVC
// don't ask... just *don't* ask... *sigh*
#undef near
#undef far
#endif

            void GLRenderer::getFrustum(float& near, float& far, float& left, float& right, float& top, float& bottom)
            {
                  near = near_;
                  far  = far_;

                  left  = left_;
                  right = right_;

                  top    = top_;
                  bottom = bottom_;
            }


#     ifdef BALL_NO_INLINE_FUNCTIONS
#           include <BALL/VIEW/RENDERING/glRenderer.iC>
#     endif

      } // namespace VIEW
} // namespace BALL

Generated by  Doxygen 1.6.0   Back to index