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