Home | Documentation | Download | Screenshots | Developper |
The LGPL lib3ds library is used to load and display a 3ds scene
You need to install the lib3ds library in order to compile this file. See http://lib3ds.sourceforge.net/.
The current version (Dec 2002) is flawed and a patched version is available on the libQGLViewer rpm page.
Once this is done, edit 3dsViewer.pro and set INCLUDEPATH and LIBS to the path where you installed lib3ds.
Simply press 'L' (load) to load a new 3DS scene.
#include "qglviewer.h" #include <lib3ds/file.h> #include <lib3ds/node.h> class Viewer : public QGLViewer { public : Viewer() : file(NULL), current_frame(0.0), camera_name(NULL) { help(); }; protected : void draw(); void animate(); void renderNode(Lib3dsNode *node); void loadFile(); void initScene(); void init(); void help(); void keyPressEvent(QKeyEvent *e); private : Lib3dsFile *file; float current_frame; char* camera_name; };
#include "3dsViewer.h" #include <lib3ds/camera.h> #include <lib3ds/mesh.h> #include <lib3ds/material.h> #include <lib3ds/matrix.h> #include <lib3ds/vector.h> #include <lib3ds/light.h> #include <string.h> #include <config.h> #include <stdlib.h> #include <math.h> #include <qfiledialog.h> using namespace std; using namespace qglviewer; void Viewer::keyPressEvent(QKeyEvent *e) { switch (e->key()) { case Qt::Key_L : loadFile(); break; default: QGLViewer::keyPressEvent(e); } } void Viewer::help() { cout << endl << "\t\t- - 3 d s V ie w e r - -" << endl << endl; cout << "This example uses the lib3ds library to load a 3ds object file." << endl; cout << "Press 'L'(oad) to open a 3ds file." << endl; cout << "Note that certain 3ds files contain animated sequences that can" << endl; cout << "be played using the Return (animate) key." << endl << endl; } void Viewer::loadFile() { QString name = QFileDialog::getOpenFileName("", "3DS files (*.3ds *.3DS);;All files (*)", this); // In case of Cancel if (name.isEmpty()) return; file = lib3ds_file_load(name.latin1()); if (!file) { cout << "Error : Unable to open file " << name << endl; 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); setSceneRadius((Vec(max)-Vec(min)).norm()); setSceneCenter(0.5*(Vec(max)+Vec(min))); if (!file->cameras) camera.fitBBox(Vec(min), Vec(max)); 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); 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.referenceFrame()->rotate(q); camera.setFieldOfView(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; p<mesh->faces; ++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(); }
#include "3dsViewer.h" #include <qapplication.h> int main(int argc, char** argv) { // Read command lines arguments. QApplication application(argc,argv); // Instantiate the viewer, show it on screen. Viewer viewer; viewer.show(); // Set the viewer as the application main widget. application.setMainWidget(&viewer); // Run main loop. return application.exec(); }
Back to the main page