/**************************************************************************** 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 "3dsViewer.h" #include #include #include #include #include #include #include #include #include #include using namespace std; using namespace qglviewer; void Viewer::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_L : loadFile(); break; default: QGLViewer::keyPressEvent(e); } } QString Viewer::helpString() const { QString text("

3 d s V i e w e r

"); text += "This example uses the lib3ds library to load a 3ds object file.

"; text += "Press L(oad) to open a 3ds file.

"; text += "Note that certain 3ds files contain animated sequences that can "; text += "be played using the Return (animate) key."; return text; } void Viewer::loadFile() { #if QT_VERSION < 0x040000 QString name = QFileDialog::getOpenFileName(".", "3DS files (*.3ds *.3DS);;All files (*)", this, "Choose", "Select a 3ds model"); #else QString name = QFileDialog::getOpenFileName(this, "Select a 3ds model", ".", "3DS files (*.3ds *.3DS);;All files (*)"); #endif // In case of Cancel if (name.isEmpty()) return; #if QT_VERSION < 0x040000 file = lib3ds_file_load(name.latin1()); #else file = lib3ds_file_load(name.toLatin1().constData()); #endif if (!file) { qWarning("Error : Unable to open file "); exit(1); } if (file->cameras) camera_name = file->cameras->name; else camera_name = NULL; lib3ds_file_eval(file,0); initScene(); float min[3], max[3]; lib3ds_file_bounding_box(file, min, max); setSceneBoundingBox(Vec(min), Vec(max)); if (!file->cameras) camera()->showEntireScene(); else updateGL(); stopAnimation(); } void Viewer::init() { glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glDisable(GL_LIGHT1); glDepthFunc(GL_LEQUAL); glEnable(GL_DEPTH_TEST); glDisable(GL_COLOR_MATERIAL); glEnable(GL_CULL_FACE); glCullFace(GL_BACK); setKeyDescription(Qt::Key_L, "Loads a new 3ds file"); restoreStateFromFile(); help(); loadFile(); } void Viewer::initScene() { if (!file) return; // Lights GLfloat amb[] = {0.0, 0.0, 0.0, 1.0}; GLfloat dif[] = {1.0, 1.0, 1.0, 1.0}; GLfloat spe[] = {1.0, 1.0, 1.0, 1.0}; GLfloat pos[] = {0.0, 0.0, 0.0, 1.0}; int li=GL_LIGHT0; for (Lib3dsLight* l=file->lights; l; l=l->next) { glEnable(li); glLightfv(li, GL_AMBIENT, amb); glLightfv(li, GL_DIFFUSE, dif); glLightfv(li, GL_SPECULAR, spe); pos[0] = l->position[0]; pos[1] = l->position[1]; pos[2] = l->position[2]; glLightfv(li, GL_POSITION, pos); if (!l->spot_light) continue; pos[0] = l->spot[0] - l->position[0]; pos[1] = l->spot[1] - l->position[1]; pos[2] = l->spot[2] - l->position[2]; glLightfv(li, GL_SPOT_DIRECTION, pos); ++li; } // Camera Lib3dsNode* c = lib3ds_file_node_by_name(file, camera_name, LIB3DS_CAMERA_NODE); Lib3dsNode* t = lib3ds_file_node_by_name(file, camera_name, LIB3DS_TARGET_NODE); if (!c || !t) return; // Lib3dsMatrix M; // lib3ds_matrix_camera(M, c->data.camera.pos, t->data.target.pos, c->data.camera.roll); // cout << "Pos = " << Vec(c->data.camera.pos) << endl; // cout << "Tar = " << Vec(t->data.target.pos) << endl; // cout << "Rol = " << c->data.camera.roll << endl; camera()->setPosition(Vec(c->data.camera.pos)); camera()->lookAt(Vec(t->data.target.pos)); Vec up=camera()->frame()->transformOf(Vec(0.0, 0.0, 1.0)); float angle=atan2(up.x, up.y); Quaternion q(Vec(0.0, 0.0, 1.0), c->data.camera.roll-angle); camera()->frame()->rotate(q); camera()->setFieldOfView(M_PI/180.0*c->data.camera.fov); } void Viewer::renderNode(Lib3dsNode *node) { for (Lib3dsNode* p=node->childs; p!=0; p=p->next) renderNode(p); if (node->type == LIB3DS_OBJECT_NODE) { if (strcmp(node->name,"$$$DUMMY")==0) return; if (!node->user.d) { Lib3dsMesh *mesh=lib3ds_file_mesh_by_name(file, node->name); if (!mesh) return; node->user.d = glGenLists(1); glNewList(node->user.d, GL_COMPILE); Lib3dsVector *normalL = new Lib3dsVector[3*mesh->faces]; Lib3dsMatrix M; lib3ds_matrix_copy(M, mesh->matrix); lib3ds_matrix_inv(M); glMultMatrixf(&M[0][0]); lib3ds_mesh_calculate_normals(mesh, normalL); for (unsigned int p=0; pfaces; ++p) { Lib3dsFace *f=&mesh->faceL[p]; Lib3dsMaterial *mat=0; if (f->material[0]) mat=lib3ds_file_material_by_name(file, f->material); if (mat) { static GLfloat a[4]={0,0,0,1}; float s; glMaterialfv(GL_FRONT, GL_AMBIENT, a); glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse); glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular); s = pow(2, 10.0*mat->shininess); if (s>128.0) s=128.0; glMaterialf(GL_FRONT, GL_SHININESS, s); } else { Lib3dsRgba a={0.2, 0.2, 0.2, 1.0}; Lib3dsRgba d={0.8, 0.8, 0.8, 1.0}; Lib3dsRgba s={0.0, 0.0, 0.0, 1.0}; glMaterialfv(GL_FRONT, GL_AMBIENT, a); glMaterialfv(GL_FRONT, GL_DIFFUSE, d); glMaterialfv(GL_FRONT, GL_SPECULAR, s); } glBegin(GL_TRIANGLES); glNormal3fv(f->normal); for (int i=0; i<3; ++i) { glNormal3fv(normalL[3*p+i]); glVertex3fv(mesh->pointL[f->points[i]].pos); } glEnd(); } delete[] normalL; glEndList(); } if (node->user.d) { glPushMatrix(); Lib3dsObjectData* d = &node->data.object; glMultMatrixf(&node->matrix[0][0]); glTranslatef(-d->pivot[0], -d->pivot[1], -d->pivot[2]); glCallList(node->user.d); glPopMatrix(); } } } void Viewer::draw() { if (!file) return; for (Lib3dsNode* p=file->nodes; p!=0; p=p->next) renderNode(p); } void Viewer::animate() { current_frame++; if (current_frame > file->frames) current_frame=0; lib3ds_file_eval(file, current_frame); initScene(); }