/**************************************************************************** Copyright (C) 2002-2006 Gilles Debunne (Gilles.Debunne@imag.fr) This file is part of the QGLViewer library. Version 2.2.4-1, released on December 12, 2006. http://artis.imag.fr/Members/Gilles.Debunne/QGLViewer libQGLViewer is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. libQGLViewer is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with libQGLViewer; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA *****************************************************************************/ #include "luxo.h" #include using namespace qglviewer; using namespace std; ////////////////////////////////// V i e w e r //////////////////////////////////////// QString Viewer::helpString() const { QString text("

L u x o ©

"); text += "This example illustrates several functionnalities of QGLViewer, "; text += "showing how easy it is to create a moderately complex application.

"; text += "The famous luxo lamp (©Pixar) can interactively be manipulated "; text += "with the mouse. Shift left click on an a part of the lamp to select it, "; text += "and then move it with the mouse. Press the Control key or select the background "; text += "to move the camera instead.

"; text += "A simpler object selection example is given in the select example. "; text += "A simpler frame displacement example is available in manipulatedFrame and "; text += "a simpler constrained frame example is illustrated in constrainedFrame. "; text += "See multiSelect for a multi-object selection example.

"; 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() { restoreStateFromFile(); // Make camera the default manipulated frame. setManipulatedFrame( camera()->frame() ); #if QT_VERSION < 0x040000 // Preserve CAMERA bindings, see setHandlerKeyboardModifiers documentation. setHandlerKeyboardModifiers(QGLViewer::CAMERA, Qt::AltButton); // The frames can be move without any key pressed setHandlerKeyboardModifiers(QGLViewer::FRAME, Qt::NoButton); // The camera can always be moved with the Control key. setHandlerKeyboardModifiers(QGLViewer::CAMERA, Qt::ControlButton); #else setHandlerKeyboardModifiers(QGLViewer::CAMERA, Qt::AltModifier); setHandlerKeyboardModifiers(QGLViewer::FRAME, Qt::NoModifier); setHandlerKeyboardModifiers(QGLViewer::CAMERA, Qt::ControlModifier); #endif initSpotLight(); help(); } void Viewer::draw() { luxo.draw(); // Draw the ground glColor3f(.4,.4,.4); const float nbPatches = 100; glNormal3f(0.0,0.0,1.0); for (int j=0; jframe() ); luxo.setSelectedFrameNumber(4); // dummy value meaning camera } else { setManipulatedFrame(luxo.frame(selectedName())); luxo.setSelectedFrameNumber(selectedName()); } } ////////////////////////////////// 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(bool names) { // Luxo's local frame glPushMatrix(); 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); const GLfloat spot_dir[3] = {0.0, 0.0, 1.0}; glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir); glPopMatrix(); } 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(unsigned short nb) { if (nb == selected) glColor3f(0.9, 0.9, 0.0); else glColor3f(0.9, 0.9, 0.9); } // Draws a truncated cone aligned with the Z axis. void Luxo::drawCone(float zMin, float zMax, float r1, float r2, int nbSub) { static GLUquadric* quadric = gluNewQuadric(); glTranslatef(0.0, 0.0, zMin); gluCylinder(quadric, r1, r2, zMax-zMin, nbSub, 1); glTranslatef(0.0, 0.0, -zMin); }