Sophie

Sophie

distrib > Mandriva > 10.0 > i586 > media > contrib > by-pkgid > 9347541fe87a5ea3f3b8dbc50f660e8e > files > 139

libQGLViewer-devel-1.3.6-1mdk.i586.rpm

#include "luxo.h"
#include <math.h>

using namespace qglviewer;
using namespace std;

//////////////////////////////////  V i e w e r  ////////////////////////////////////////

QString Viewer::helpString() const
{
  QString text("<h2>L u x o  ©</h2>");
  text += "This example illustrates several functionnalities of QGLViewer, ";
  text += "showing how easy it is to create a moderately complex application.<br>";
  text += "The famous luxo® lamp (©Pixar) can interactively be manipulated ";
  text += "with the mouse. <b>Shift</b> left click on an a part of the lamp to select it, ";
  text += "and then move it with the mouse. Select the background to move the camera, or ";
  text += "press the <b>Control</b> key (the default shortcut modifier keys have been swapped).<br>";
  text += "A simpler object selection example is given in <i>select</i>. ";
  text += "A simpler frame displacement example is given in <i>manipulatedFrame</i>. ";
  text += "A simpler constrained frame example is given in <i>constrainedFrame</i>.<br>";
  text += "Feel free to use this code as the starting point of a multiple frame manipulation application.";
  return text;
}

void Viewer::initSpotLight()
{
  glMatrixMode(GL_MODELVIEW);
  glEnable(GL_LIGHT1);
  glLoadIdentity();

  // Light default parameters
  GLfloat spot_dir[3]       = {0.0, 0.0, 1.0};
  GLfloat light_ambient[4]  = {0.5, 0.5, 0.5, 1.0};
  GLfloat light_specular[4] = {1.0, 1.0, 1.0, 1.0};
  GLfloat light_diffuse[4]  = {3.0, 3.0, 1.0, 1.0};
  
  glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir);
  glLightf( GL_LIGHT1, GL_SPOT_EXPONENT,  3.0);
  glLightf( GL_LIGHT1, GL_SPOT_CUTOFF,    50.0);
  glLightf( GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.5);
  glLightf( GL_LIGHT1, GL_LINEAR_ATTENUATION, 1.0);
  glLightf( GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 1.5);
  glLightfv(GL_LIGHT1, GL_AMBIENT,  light_ambient);
  glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
  glLightfv(GL_LIGHT1, GL_DIFFUSE,  light_diffuse);
}

void Viewer::init()
{
  restoreFromFile();

  // Make camera the default manipulated frame.
  setManipulatedFrame( camera()->frame() );

  // Preserve CAMERA bindings, see setMouseStateKey documentation.
  setMouseStateKey(QGLViewer::CAMERA, Qt::AltButton);
  // The frames can be move without any key pressed
  setMouseStateKey(QGLViewer::FRAME, Qt::NoButton);
  // The camera can always be moved with the Control key.
  setMouseStateKey(QGLViewer::CAMERA, Qt::ControlButton);

  initSpotLight();

  help();
}

void Viewer::draw()
{
  // Draw the ground
  glColor3f(.4,.4,.4);
  const float nbPatches = 100;
  glNormal3f(0.0,0.0,1.0);
  for (int j=0; j<nbPatches; ++j)
    {
      glBegin(GL_QUAD_STRIP);
      for (int i=0; i<=nbPatches; ++i)
	{
	  glVertex2f((2*i/nbPatches-1.0), (2*j/nbPatches-1.0));
	  glVertex2f((2*i/nbPatches-1.0), (2*(j+1)/nbPatches-1.0));
	}
      glEnd();
    }

  luxo.draw();
}

void Viewer::select(const QMouseEvent* e)
{
  // Make openGL context current
  makeCurrent();
  
  const int SENSITIVITY = 4;
  const int NB_HITS_MAX = 1000;
  
  // Prepare the selection mode
  static GLuint hits[NB_HITS_MAX];
  static GLint nb_hits = 0;
  
  glSelectBuffer(NB_HITS_MAX, hits);
  glRenderMode(GL_SELECT);
  glInitNames();

  // Loads the matrices
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  GLint viewport[4];
  camera()->getViewport(viewport);
  gluPickMatrix(static_cast<GLdouble>(e->x()), static_cast<GLdouble>(e->y()), SENSITIVITY, SENSITIVITY, viewport);

  // loadProjectionMatrix() first resets the GL_PROJECTION matrix with a glLoadIdentity.
  // Give false as a parameter in order to prevent this and to combine the matrices.
  camera()->loadProjectionMatrix(false);

  camera()->loadModelViewMatrix();
  
  // Render scene with objects ids
  luxo.draw(true);
  glFlush();

  // Get the results
  nb_hits = glRenderMode(GL_RENDER);

  if (nb_hits <= 0)
    {
      // Camera will be the default frame is no selection occurs.
      setManipulatedFrame( camera()->frame() );
      luxo.setSelectedFrameNumber(4); // dummy value
    }
  else
    {
      // Interpret results
      unsigned int zMin = hits[1];
      short selected = hits[3];
      for (int i=1; i<nb_hits; ++i)
	if (hits[i*4+1] < zMin)
	  {
	    zMin = hits[i*4+1];
	    selected = hits[i*4+3];
	  }
      setManipulatedFrame(luxo.frame(selected));
      luxo.setSelectedFrameNumber(selected);
    }
}

//////////////////////////////////  L u x o ////////////////////////////////////////

Luxo::Luxo()
{
  for (unsigned short i=0; i<4; ++i)
    {
      frame_[i] = new ManipulatedFrame();
  
      // Creates a hierarchy of frames.
      if (i>0)
	frame(i)->setReferenceFrame(frame(i-1));
    }

  // Initialize frames
  frame(1)->setTranslation(Vec(0.0, 0.0, 0.08)); // Base height
  frame(2)->setTranslation(Vec(0.0, 0.0, 0.5));  // Arm length
  frame(3)->setTranslation(Vec(0.0, 0.0, 0.5));  // Arm length

  frame(1)->setRotation(Quaternion(Vec(1.0,0.0,0.0), 0.6));
  frame(2)->setRotation(Quaternion(Vec(1.0,0.0,0.0), -2.0));
  frame(3)->setRotation(Quaternion(Vec(1.0,-0.3,0.0), -1.7));

  // Set frame constraints
  WorldConstraint* baseConstraint = new WorldConstraint();
  baseConstraint->setTranslationConstraint(AxisPlaneConstraint::PLANE, Vec(0.0,0.0,1.0));
  baseConstraint->setRotationConstraint(AxisPlaneConstraint::AXIS, Vec(0.0,0.0,1.0));
  frame(0)->setConstraint(baseConstraint);

  LocalConstraint* XAxis = new LocalConstraint();
  XAxis->setTranslationConstraint(AxisPlaneConstraint::FORBIDDEN,  Vec(0.0,0.0,0.0));
  XAxis->setRotationConstraint   (AxisPlaneConstraint::AXIS, Vec(1.0,0.0,0.0));
  frame(1)->setConstraint(XAxis);
  frame(2)->setConstraint(XAxis);

  LocalConstraint* headConstraint = new LocalConstraint();
  headConstraint->setTranslationConstraint(AxisPlaneConstraint::FORBIDDEN, Vec(0.0,0.0,0.0));
  frame(3)->setConstraint(headConstraint);

  // Means camera is selected.
  selected = 4;
}

void Luxo::draw(const bool names)
{
  // Luxo's local frame
  glMultMatrixd(frame(0)->matrix());
    
  if (names) glPushName(0);
  setColor(0);
  drawBase();
  if (names) glPopName();
  
  if (names) glPushName(1);
  glMultMatrixd(frame(1)->matrix());
  setColor(1);
  drawCylinder();
  drawArm();
  if (names) glPopName();

  if (names) glPushName(2);
  glMultMatrixd(frame(2)->matrix());
  setColor(2);
  drawCylinder();
  drawArm();
  if (names) glPopName();

  if (names) glPushName(3);
  glMultMatrixd(frame(3)->matrix());
  setColor(3);
  drawHead();
  if (names) glPopName();

  // Add light
  const GLfloat pos[4] = {0.0,0.0,0.0,1.0};
  glLightfv(GL_LIGHT1, GL_POSITION, pos);
  GLfloat spot_dir[3]  = {0.0, 0.0, 1.0};
  glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir);
}

void Luxo::drawBase()
{
  drawCone(0.0,0.03, 0.15, 0.15, 30);
  drawCone(0.03,0.05, 0.15, 0.13, 30);
  drawCone(0.05,0.07, 0.13, 0.01, 30);
  drawCone(0.07,0.09, 0.01, 0.01, 10);
}

void Luxo::drawArm()
{
  glTranslatef(0.02, 0.0, 0.0);
  drawCone(0.0,0.5, 0.01, 0.01, 10);
  glTranslatef(-0.04, 0.0, 0.0);
  drawCone(0.0,0.5, 0.01, 0.01, 10);
  glTranslatef(0.02, 0.0, 0.0);
}

void Luxo::drawHead()
{
  drawCone(-0.02,0.06, 0.04, 0.04, 30);
  drawCone(0.06,0.15, 0.04, 0.17, 30);
  drawCone(0.15,0.17, 0.17, 0.17, 30);
}

void Luxo::drawCylinder()
{
  glPushMatrix();
  glRotatef(90, 0.0,1.0,0.0);
  drawCone(-0.05,0.05, 0.02, 0.02, 20);
  glPopMatrix();
}

void Luxo::setColor(const unsigned short nb)
{
  if (nb == selected)
    glColor3f(.9,.9,.0);
  else
    glColor3f(.9,.9,.9);
}

// Draws a truncated cone aligned with the Z axis.
void Luxo::drawCone(const float zMin,const float zMax, const float r1, const float r2, const float nbSub)
{
  float angle,c,s;
  Vec normal, p1, p2;
  glBegin(GL_QUAD_STRIP);
  for (unsigned short i=0; i<=nbSub; ++i)
    {
      angle = 2.0 * M_PI * i / nbSub;
      c = cos(angle);
      s = sin(angle);

      p1 = Vec(r1*c, r1*s, zMin);
      p2 = Vec(r2*c, r2*s, zMax);
      
      normal = cross(Vec(-s,c,0.0) , (p2-p1));
      normal.normalize();
      
      glNormal3fv(normal.address());
      glVertex3fv(p1.address());
      glVertex3fv(p2.address());
    }
  glEnd();
}