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 "3dsViewer.h"
24 
25 #include <QKeyEvent>
26 #include <lib3ds/camera.h>
27 #include <lib3ds/light.h>
28 #include <lib3ds/material.h>
29 #include <lib3ds/matrix.h>
30 #include <lib3ds/mesh.h>
31 #include <lib3ds/vector.h>
32 #include <math.h>
33 #include <qfiledialog.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 using namespace std;
38 using namespace qglviewer;
39 
keyPressEvent(QKeyEvent * e)40 void Viewer::keyPressEvent(QKeyEvent *e) {
41   switch (e->key()) {
42   case Qt::Key_L:
43     loadFile();
44     break;
45   default:
46     QGLViewer::keyPressEvent(e);
47   }
48 }
49 
helpString() const50 QString Viewer::helpString() const {
51   QString text("<h2>3 d s V i e w e r</h2>");
52   text +=
53       "This example uses the lib3ds library to load a 3ds object file.<br><br>";
54   text += "Press <b>L</b>(oad) to open a 3ds file.<br><br>";
55   text += "Note that certain 3ds files contain animated sequences that can ";
56   text += "be played using the <b>Return</b> (animate) key.";
57   return text;
58 }
59 
loadFile()60 void Viewer::loadFile() {
61 #if QT_VERSION < 0x040000
62   QString name = QFileDialog::getOpenFileName(
63       ".", "3DS files (*.3ds *.3DS);;All files (*)", this, "Choose",
64       "Select a 3ds model");
65 #else
66   QString name =
67       QFileDialog::getOpenFileName(this, "Select a 3ds model", ".",
68                                    "3DS files (*.3ds *.3DS);;All files (*)");
69 #endif
70 
71   // In case of Cancel
72   if (name.isEmpty())
73     return;
74 
75 #if QT_VERSION < 0x040000
76   file = lib3ds_file_load(name.latin1());
77 #else
78   file = lib3ds_file_load(name.toLatin1().constData());
79 #endif
80   if (!file) {
81     qWarning("Error : Unable to open file ");
82     exit(1);
83   }
84 
85   if (file->cameras)
86     camera_name = file->cameras->name;
87   else
88     camera_name = NULL;
89 
90   lib3ds_file_eval(file, 0);
91 
92   initScene();
93 
94   float min[3], max[3];
95   lib3ds_file_bounding_box_of_objects(file, true, true, true, min, max);
96   // lib3ds_file_bounding_box(file, min, max);
97   setSceneBoundingBox(Vec(min), Vec(max));
98 
99   if (!file->cameras)
100     camera()->showEntireScene();
101   else
102     updateGL();
103   stopAnimation();
104 }
105 
init()106 void Viewer::init() {
107   glShadeModel(GL_SMOOTH);
108   glEnable(GL_LIGHTING);
109   glEnable(GL_LIGHT0);
110   glDisable(GL_LIGHT1);
111   glDepthFunc(GL_LEQUAL);
112   glEnable(GL_DEPTH_TEST);
113   glDisable(GL_COLOR_MATERIAL);
114   glEnable(GL_CULL_FACE);
115   glCullFace(GL_BACK);
116 
117   setKeyDescription(Qt::Key_L, "Loads a new 3ds file");
118 
119   restoreStateFromFile();
120   help();
121   loadFile();
122 }
123 
initScene()124 void Viewer::initScene() {
125   if (!file)
126     return;
127 
128   // Lights
129   GLfloat amb[] = {0.0, 0.0, 0.0, 1.0};
130   GLfloat dif[] = {1.0, 1.0, 1.0, 1.0};
131   GLfloat spe[] = {1.0, 1.0, 1.0, 1.0};
132   GLfloat pos[] = {0.0, 0.0, 0.0, 1.0};
133   int li = GL_LIGHT0;
134   for (Lib3dsLight *l = file->lights; l; l = l->next) {
135     glEnable(li);
136 
137     glLightfv(li, GL_AMBIENT, amb);
138     glLightfv(li, GL_DIFFUSE, dif);
139     glLightfv(li, GL_SPECULAR, spe);
140 
141     pos[0] = l->position[0];
142     pos[1] = l->position[1];
143     pos[2] = l->position[2];
144     glLightfv(li, GL_POSITION, pos);
145 
146     if (!l->spot_light)
147       continue;
148 
149     pos[0] = l->spot[0] - l->position[0];
150     pos[1] = l->spot[1] - l->position[1];
151     pos[2] = l->spot[2] - l->position[2];
152     glLightfv(li, GL_SPOT_DIRECTION, pos);
153     ++li;
154   }
155 
156   // Camera
157   Lib3dsNode *c =
158       lib3ds_file_node_by_name(file, camera_name, LIB3DS_CAMERA_NODE);
159   Lib3dsNode *t =
160       lib3ds_file_node_by_name(file, camera_name, LIB3DS_TARGET_NODE);
161   if (!c || !t)
162     return;
163 
164   // Lib3dsMatrix M;
165   // lib3ds_matrix_camera(M, c->data.camera.pos, t->data.target.pos,
166   // c->data.camera.roll);
167 
168   // cout << "Pos = " << Vec(c->data.camera.pos) << endl;
169   // cout << "Tar = " << Vec(t->data.target.pos) << endl;
170   // cout << "Rol = " << c->data.camera.roll << endl;
171 
172   camera()->setPosition(Vec(c->data.camera.pos));
173   camera()->lookAt(Vec(t->data.target.pos));
174   Vec up = camera()->frame()->transformOf(Vec(0.0, 0.0, 1.0));
175   float angle = atan2(up.x, up.y);
176   Quaternion q(Vec(0.0, 0.0, 1.0), c->data.camera.roll - angle);
177   camera()->frame()->rotate(q);
178   camera()->setFieldOfView(M_PI / 180.0 * c->data.camera.fov);
179 }
180 
renderNode(Lib3dsNode * node)181 void Viewer::renderNode(Lib3dsNode *node) {
182   for (Lib3dsNode *p = node->childs; p != 0; p = p->next)
183     renderNode(p);
184 
185   if (node->type == LIB3DS_OBJECT_NODE) {
186     if (strcmp(node->name, "$$$DUMMY") == 0)
187       return;
188 
189     if (!node->user.d) {
190       Lib3dsMesh *mesh = lib3ds_file_mesh_by_name(file, node->name);
191       if (!mesh)
192         return;
193 
194       node->user.d = glGenLists(1);
195       glNewList(node->user.d, GL_COMPILE);
196 
197       Lib3dsVector *normalL = new Lib3dsVector[3 * mesh->faces];
198 
199       Lib3dsMatrix M;
200       lib3ds_matrix_copy(M, mesh->matrix);
201       lib3ds_matrix_inv(M);
202       glMultMatrixf(&M[0][0]);
203 
204       lib3ds_mesh_calculate_normals(mesh, normalL);
205 
206       for (unsigned int p = 0; p < mesh->faces; ++p) {
207         Lib3dsFace *f = &mesh->faceL[p];
208         Lib3dsMaterial *mat = 0;
209         if (f->material[0])
210           mat = lib3ds_file_material_by_name(file, f->material);
211 
212         if (mat) {
213           static GLfloat a[4] = {0, 0, 0, 1};
214           float s;
215           glMaterialfv(GL_FRONT, GL_AMBIENT, a);
216           glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse);
217           glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular);
218           s = pow(2, 10.0 * mat->shininess);
219           if (s > 128.0)
220             s = 128.0;
221           glMaterialf(GL_FRONT, GL_SHININESS, s);
222         } else {
223           Lib3dsRgba a = {0.2, 0.2, 0.2, 1.0};
224           Lib3dsRgba d = {0.8, 0.8, 0.8, 1.0};
225           Lib3dsRgba s = {0.0, 0.0, 0.0, 1.0};
226           glMaterialfv(GL_FRONT, GL_AMBIENT, a);
227           glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
228           glMaterialfv(GL_FRONT, GL_SPECULAR, s);
229         }
230 
231         glBegin(GL_TRIANGLES);
232         glNormal3fv(f->normal);
233         for (int i = 0; i < 3; ++i) {
234           glNormal3fv(normalL[3 * p + i]);
235           glVertex3fv(mesh->pointL[f->points[i]].pos);
236         }
237         glEnd();
238       }
239 
240       delete[] normalL;
241 
242       glEndList();
243     }
244 
245     if (node->user.d) {
246       glPushMatrix();
247       Lib3dsObjectData *d = &node->data.object;
248       glMultMatrixf(&node->matrix[0][0]);
249       glTranslatef(-d->pivot[0], -d->pivot[1], -d->pivot[2]);
250       glCallList(node->user.d);
251       glPopMatrix();
252     }
253   }
254 }
255 
draw()256 void Viewer::draw() {
257   if (!file)
258     return;
259 
260   for (Lib3dsNode *p = file->nodes; p != 0; p = p->next)
261     renderNode(p);
262 }
263 
animate()264 void Viewer::animate() {
265   current_frame++;
266   if (current_frame > file->frames)
267     current_frame = 0;
268   lib3ds_file_eval(file, current_frame);
269   initScene();
270 }
271