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