1 /****************************************************************************
2 
3  Copyright (C) 2002-2014 Gilles Debunne. All rights reserved.
4 
5  This file is part of the QGLViewer library version 2.7.2.
6 
7  http://www.libqglviewer.com - contact@libqglviewer.com
8 
9  This file may be used under the terms of the GNU General Public License
10  versions 2.0 or 3.0 as published by the Free Software Foundation and
11  appearing in the LICENSE file included in the packaging of this file.
12  In addition, as a special exception, Gilles Debunne gives you certain
13  additional rights, described in the file GPL_EXCEPTION in this package.
14 
15  libQGLViewer uses dual licensing. Commercial/proprietary software must
16  purchase a libQGLViewer Commercial License.
17 
18  This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
19  WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
20 
21 *****************************************************************************/
22 
23 #include "luxo.h"
24 #include <math.h>
25 
26 #include <QGLViewer/manipulatedCameraFrame.h>
27 
28 using namespace qglviewer;
29 using namespace std;
30 
31 //////////////////////////////////  V i e w e r
32 ///////////////////////////////////////////
33 
helpString() const34 QString Viewer::helpString() const {
35   QString text("<h2>L u x o  ©</h2>");
36   text += "This example illustrates several functionnalities of QGLViewer, ";
37   text += "showing how easy it is to create a moderately complex "
38           "application.<br><br>";
39   text += "The famous luxo lamp (©Pixar) can interactively be manipulated ";
40   text += "with the mouse. <b>Shift</b> left click on an a part of the lamp to "
41           "select it, ";
42   text += "and then move it with the mouse. Press the <b>Alt</b> key or select "
43           "the background ";
44   text += "to move the camera instead.<br><br>";
45   text += "A simpler object selection example is given in the <i>select</i> "
46           "example. ";
47   text += "A simpler frame displacement example is available in "
48           "<i>manipulatedFrame</i> and ";
49   text += "a simpler constrained frame example is illustrated in "
50           "<i>constrainedFrame</i>. ";
51   text +=
52       "See <i>multiSelect</i> for a multi-object selection example.<br><br>";
53   text += "Feel free to use this code as the starting point of a multiple "
54           "frame manipulation application.";
55   return text;
56 }
57 
initSpotLight()58 void Viewer::initSpotLight() {
59   glMatrixMode(GL_MODELVIEW);
60   glEnable(GL_LIGHT1);
61   glLoadIdentity();
62 
63   // Light default parameters
64   GLfloat spot_dir[3] = {0.0, 0.0, 1.0};
65   GLfloat light_ambient[4] = {0.5, 0.5, 0.5, 1.0};
66   GLfloat light_specular[4] = {1.0, 1.0, 1.0, 1.0};
67   GLfloat light_diffuse[4] = {3.0, 3.0, 1.0, 1.0};
68 
69   glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir);
70   glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 3.0);
71   glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 50.0);
72   glLightf(GL_LIGHT1, GL_CONSTANT_ATTENUATION, 0.5);
73   glLightf(GL_LIGHT1, GL_LINEAR_ATTENUATION, 1.0);
74   glLightf(GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 1.5);
75   glLightfv(GL_LIGHT1, GL_AMBIENT, light_ambient);
76   glLightfv(GL_LIGHT1, GL_SPECULAR, light_specular);
77   glLightfv(GL_LIGHT1, GL_DIFFUSE, light_diffuse);
78 }
79 
init()80 void Viewer::init() {
81   restoreStateFromFile();
82 
83   // Make camera the default manipulated frame.
84   setManipulatedFrame(camera()->frame());
85 
86   setMouseBinding(Qt::AltModifier, Qt::LeftButton, QGLViewer::CAMERA,
87                   QGLViewer::ROTATE);
88   setMouseBinding(Qt::AltModifier, Qt::RightButton, QGLViewer::CAMERA,
89                   QGLViewer::TRANSLATE);
90   setMouseBinding(Qt::AltModifier, Qt::MidButton, QGLViewer::CAMERA,
91                   QGLViewer::ZOOM);
92   setWheelBinding(Qt::AltModifier, QGLViewer::CAMERA, QGLViewer::ZOOM);
93 
94   setMouseBinding(Qt::NoModifier, Qt::LeftButton, QGLViewer::FRAME,
95                   QGLViewer::ROTATE);
96   setMouseBinding(Qt::NoModifier, Qt::RightButton, QGLViewer::FRAME,
97                   QGLViewer::TRANSLATE);
98   setMouseBinding(Qt::NoModifier, Qt::MidButton, QGLViewer::FRAME,
99                   QGLViewer::ZOOM);
100   setWheelBinding(Qt::NoModifier, QGLViewer::FRAME, QGLViewer::ZOOM);
101 
102   initSpotLight();
103 
104   help();
105 }
106 
draw()107 void Viewer::draw() {
108   luxo.draw();
109 
110   // Draw the ground
111   glColor3f(0.4f, 0.4f, 0.4f);
112   const float nbPatches = 100;
113   glNormal3f(0.0, 0.0, 1.0);
114   for (int j = 0; j < nbPatches; ++j) {
115     glBegin(GL_QUAD_STRIP);
116     for (int i = 0; i <= nbPatches; ++i) {
117       glVertex2f((2 * i / nbPatches - 1.0), (2 * j / nbPatches - 1.0));
118       glVertex2f((2 * i / nbPatches - 1.0), (2 * (j + 1) / nbPatches - 1.0));
119     }
120     glEnd();
121   }
122 }
123 
drawWithNames()124 void Viewer::drawWithNames() {
125   // Render scene with objects ids
126   luxo.draw(true);
127 }
128 
postSelection(const QPoint &)129 void Viewer::postSelection(const QPoint &) {
130   if (selectedName() == -1) {
131     // Camera will be the default frame is no object is selected.
132     setManipulatedFrame(camera()->frame());
133     luxo.setSelectedFrameNumber(4); // dummy value meaning camera
134   } else {
135     setManipulatedFrame(luxo.frame(selectedName()));
136     luxo.setSelectedFrameNumber(selectedName());
137   }
138 }
139 
140 //////////////////////////////////  L u x o
141 ///////////////////////////////////////////
142 
Luxo()143 Luxo::Luxo() {
144   for (unsigned short i = 0; i < 4; ++i) {
145     frame_[i] = new ManipulatedFrame();
146 
147     // Creates a hierarchy of frames.
148     if (i > 0)
149       frame(i)->setReferenceFrame(frame(i - 1));
150   }
151 
152   // Initialize frames
153   frame(1)->setTranslation(Vec(0.0, 0.0, 0.08f)); // Base height
154   frame(2)->setTranslation(Vec(0.0, 0.0, 0.5f));  // Arm length
155   frame(3)->setTranslation(Vec(0.0, 0.0, 0.5f));  // Arm length
156 
157   frame(1)->setRotation(Quaternion(Vec(1.0, 0.0, 0.0), 0.6));
158   frame(2)->setRotation(Quaternion(Vec(1.0, 0.0, 0.0), -2.0));
159   frame(3)->setRotation(Quaternion(Vec(1.0, -0.3f, 0.0), -1.7));
160 
161   // Set frame constraints
162   WorldConstraint *baseConstraint = new WorldConstraint();
163   baseConstraint->setTranslationConstraint(AxisPlaneConstraint::PLANE,
164                                            Vec(0.0, 0.0, 1.0));
165   baseConstraint->setRotationConstraint(AxisPlaneConstraint::AXIS,
166                                         Vec(0.0, 0.0, 1.0));
167   frame(0)->setConstraint(baseConstraint);
168 
169   LocalConstraint *XAxis = new LocalConstraint();
170   XAxis->setTranslationConstraint(AxisPlaneConstraint::FORBIDDEN,
171                                   Vec(0.0, 0.0, 0.0));
172   XAxis->setRotationConstraint(AxisPlaneConstraint::AXIS, Vec(1.0, 0.0, 0.0));
173   frame(1)->setConstraint(XAxis);
174   frame(2)->setConstraint(XAxis);
175 
176   LocalConstraint *headConstraint = new LocalConstraint();
177   headConstraint->setTranslationConstraint(AxisPlaneConstraint::FORBIDDEN,
178                                            Vec(0.0, 0.0, 0.0));
179   frame(3)->setConstraint(headConstraint);
180 
181   // Means camera is selected.
182   selected = 4;
183 }
184 
draw(bool names)185 void Luxo::draw(bool names) {
186   // Luxo's local frame
187   glPushMatrix();
188   glMultMatrixd(frame(0)->matrix());
189 
190   if (names)
191     glPushName(0);
192   setColor(0);
193   drawBase();
194   if (names)
195     glPopName();
196 
197   if (names)
198     glPushName(1);
199   glMultMatrixd(frame(1)->matrix());
200   setColor(1);
201   drawCylinder();
202   drawArm();
203   if (names)
204     glPopName();
205 
206   if (names)
207     glPushName(2);
208   glMultMatrixd(frame(2)->matrix());
209   setColor(2);
210   drawCylinder();
211   drawArm();
212   if (names)
213     glPopName();
214 
215   if (names)
216     glPushName(3);
217   glMultMatrixd(frame(3)->matrix());
218   setColor(3);
219   drawHead();
220   if (names)
221     glPopName();
222 
223   // Add light
224   const GLfloat pos[4] = {0.0, 0.0, 0.0, 1.0};
225   glLightfv(GL_LIGHT1, GL_POSITION, pos);
226   const GLfloat spot_dir[3] = {0.0, 0.0, 1.0};
227   glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, spot_dir);
228   glPopMatrix();
229 }
230 
drawBase()231 void Luxo::drawBase() {
232   drawCone(0.0, 0.03f, 0.15f, 0.15f, 30);
233   drawCone(0.03f, 0.05f, 0.15f, 0.13f, 30);
234   drawCone(0.05f, 0.07f, 0.13f, 0.01f, 30);
235   drawCone(0.07f, 0.09f, 0.01f, 0.01f, 10);
236 }
237 
drawArm()238 void Luxo::drawArm() {
239   glTranslatef(0.02f, 0.0, 0.0);
240   drawCone(0.0, 0.5f, 0.01f, 0.01f, 10);
241   glTranslatef(-0.04f, 0.0, 0.0);
242   drawCone(0.0, 0.5f, 0.01f, 0.01f, 10);
243   glTranslatef(0.02f, 0.0, 0.0);
244 }
245 
drawHead()246 void Luxo::drawHead() {
247   drawCone(-0.02f, 0.06f, 0.04f, 0.04f, 30);
248   drawCone(0.06f, 0.15f, 0.04f, 0.17f, 30);
249   drawCone(0.15f, 0.17f, 0.17f, 0.17f, 30);
250 }
251 
drawCylinder()252 void Luxo::drawCylinder() {
253   glPushMatrix();
254   glRotatef(90, 0.0, 1.0, 0.0);
255   drawCone(-0.05f, 0.05f, 0.02f, 0.02f, 20);
256   glPopMatrix();
257 }
258 
setColor(unsigned short nb)259 void Luxo::setColor(unsigned short nb) {
260   if (nb == selected)
261     glColor3f(0.9f, 0.9f, 0.0);
262   else
263     glColor3f(0.9f, 0.9f, 0.9f);
264 }
265 
266 // Draws a truncated cone aligned with the Z axis.
drawCone(float zMin,float zMax,float r1,float r2,int nbSub)267 void Luxo::drawCone(float zMin, float zMax, float r1, float r2, int nbSub) {
268   static GLUquadric *quadric = gluNewQuadric();
269 
270   glTranslatef(0.0, 0.0, zMin);
271   gluCylinder(quadric, r1, r2, zMax - zMin, nbSub, 1);
272   glTranslatef(0.0, 0.0, -zMin);
273 }
274