Click here to Skip to main content
15,305,625 members
Articles / Multimedia / OpenGL
Posted 20 Jun 2012

Tagged as


23 bookmarked

Modified version of lib3ds reader of .3ds format

Rate me:
Please Sign up or sign in to vote.
4.78/5 (15 votes)
4 Oct 2012CPOL3 min read
In this article I present version of lib3ds reader for C++ language


Formats of keeping 3D models and stages in 3DStudio are very different. However, most of them are bound to the engine of 3DStudio. And only a few of them present data in form of simple rendering in OpenGL. For my project I chose 3DS format. I found a very powerfull code of reader of 3ds format - lib3ds on site Nonetheless, the code on this site is presented on C language. As a result, in the original code of lib3ds there are much static function which have difficult links and there are not possibilities to use abilities of object languages. For my project on C++ I rewrote the original lib3ds 2.0.0-rc1 from C into C++ structure with using of classes and interfaces. As a result, I wrote the code, which separates of reading 3ds data from using of data for rendering. This decision can be used in COM-like technologies and give simple managment with data.

For testing of code I make special program 3dsViewer whic is presented here Download

Image 1


For using of structure of interfaces I made 10 files which describ of structure of data which using in the interface. The interface is contented in seperated file ILib3ds_stage.h such as base class and contents all data and virtual functions. Other classes which inherit interface contents only functions. As a result, size of top inherit class is equal size of interface and enough to call delete for interface to free all memory, which selected for all data. Moreover, the date of different size such as vertexes and faces has very simple instrument of deleting. In the original code there is a difficult algorithm of managment data and deleting data. I changed them on simple classes: QString, QVector, QList, QMap - are analogy of Qt framework of std String, Vector, List, Map. As a result, data with non-fixed size is wrapped into stack object and is deleted automaticaly.

Using the code

All code is contented in 19 classes which have the inherited hierarchy. However, for using of code enough to call static function of makeILib3ds_stage of class Lib3ds_loader with path to 3ds file. This function returns interface ILib3ds_stage on data of 3D model.

class Lib3ds_loader // Class of loading
    static ILib3ds_stage *makeILib3ds_stage(QString filename); // Static
// function of making interface of 3ds data

This code is example of using interface ILib3ds_stage in form of pointer Istage. When there is not camera in data 3ds after examination Istage->cameras.isEmpty() in list Istage->cameras add structure of camera. The same doing with list of source of light.

bool OpenGLWidget::LoadModel(QString filename)
    if(Istage) delete Istage; // Deleting data
    Istage = Lib3ds_loader::makeILib3ds_stage(filename); // Getting interface on data

    if(Istage != NULL) 
    /*Checking of existence of inteface of 3ds data*/
        Istage->lib3ds_stage_eval(1.0f); // Setting first frame animation

        Istage->lib3ds_stage_bounding_box_of_nodes(1, 0, 0, bmin, bmax, NULL); //
        // finding of borders in node structure

        // Computing of size of box which surround of scene
        sx = bmax[0] - bmin[0];
        sy = bmax[1] - bmin[1];
        sz = bmax[2] - bmin[2];
        boxsize = MAX(sx, sy); boxsize = MAX(boxsize, sz);
        cx = (bmin[0] + bmax[0])/2; // Computing of centres of box
        cy = (bmin[1] + bmax[1])/2;
        cz = (bmin[2] + bmax[2])/2;
        if(Istage->cameras.isEmpty()) // Checking of list of cameras in 3ds data 
            // If thre is not any camera in 3ds data than created camera
            Lib3dsCamera camera; 
   = "Camera_Z"; // Naming new camera
            memset(&camera.setting, 0, sizeof(Lib3dsCamera_setting));
            // setting of angle of view
            camera.setting.fov = 45;

            // Setting point of target of camera in center of scene 
  [0] = cx;
  [1] = cy;
  [2] = cz;

            // Setting position camera out of scene
            camera.setting.position[0] = cx;
            camera.setting.position[1] = cy;
            camera.setting.position[2] = bmax[2] + 2 * MAX(sx,sy);

            // Setting near and far borders of camera
            camera.setting.near_range = ( camera.setting.position[2] - bmax[2] ) * .5;
            camera.setting.far_range = ( camera.setting.position[2] - bmin[2] ) * 2;
            // adding camera into list of cameras of 3ds data
            Istage->cameras[] = camera;  
        if (Istage->lights.isEmpty())// Checking of list of lights in 3ds data 
        // If thre is not any light source in 3ds data than created light source

          Lib3dsLight light;
          memset(&light.setting, 0, sizeof(Lib3dsLight_setting));
 = "light0"; // Named light source
          light.setting.spot_light = 0; // Setting of 3DStudio
          light.setting.see_cone = 0;// Setting of 3DStudio
          // Setting of color of light
          light.setting.color[0] = light.setting.color[1] = light.setting.color[2] = .6;
          // Setting position of light source out of scene

          light.setting.position[0] = cx + boxsize * .75;
          light.setting.position[1] = cy - boxsize * 1.;
          light.setting.position[2] = cz + boxsize * 1.5;
          light.setting.position[3] = 0.;

          light.setting.outer_range = 100;// Setting of 3DStudio
          light.setting.inner_range = 10;// Setting of 3DStudio
          light.setting.multiplier = 1;// Setting of 3DStudio
          Istage->lights[] = light; // adding light
        Istage->lib3ds_stage_eval(0.0f); // setting in start position

    // If there is 3ds data than return true;
    return (Istage != NULL);

The next code renders 3ds data by parsing of nodes of 3ds. Parsing is doing for root nodes and their children. Function of void OpenGLWidget::updateAnimation() executes animation of the positions of vertexes.

QList<lib3dsnode>::iterator p = Istage->nodes.begin();
// Enumiration of root nodes in 3ds data which do not have parents
  render_node(&(*p)); // Function of rendering of node

void OpenGLWidget::render_node(Lib3dsNode *node)
       QList<lib3dsnode>::iterator p = node->children.begin();
       // Enumiration of children nodes
         render_node(&(*p)); // Rendering of children nodes
     if (node->setting.type == LIB3DS_NODE_MESH_INSTANCE)
     /*Checking type of node. if it equals flag LIB3DS_NODE_MESH_INSTANCE then
     execute rendering of mesh's vertexes
       Lib3dsMesh *mesh = NULL; // Pointer on mesh
       if(node->name == "$$$DUMMY")
/*Checking name on valid*/
/*Checking of name node in list of meses in 3ds model
/*Getting addres on mesh*/
           mesh = &Istage->meshes[node->name];
       if(mesh != NULL)

/*Checking the binding of mesh with list rendering of OpenGL*/
           if (!mesh->setting.user_id)
               // Creating of binding with mesh
               glNewList(mesh->setting.user_id, GL_COMPILE);
// Iterator of trangles primitives in mesh
               QVector<lib3dsface>::iterator p = mesh->faces.begin();
// Setting movement mesh in initial position
               float M[4][4];
               Istage->lib3ds_matrix_copy(M, mesh->setting.matrix);
// Allocated memory for normals for smooth mesh
               Lib3dsVector *normalL = new Lib3dsVector[3*mesh->faces.size()];
// Calculation of smooth normals for vertexes
               Istage->lib3ds_mesh_calculate_vertex_normals(mesh, normalL);
               unsigned int f = 0;
 // Enumiration of trangles primitives in mesh
               while (p != mesh->faces.end())
                   Lib3dsMaterial *mat = NULL; // Material of triangle primitive
                   Lib3dsMaterial *oldmat = NULL;//Material of old triangle primitive

// Finding material in list of materials of 3ds data
                       mat = &Istage->materials[(*p).material];
                   if( mat)
// If material is founded than reading of data
                     if (mat != oldmat)
                         if( mat->setting.two_sided )

// Setting colors for lightning
                         glMaterialfv(GL_FRONT, GL_AMBIENT, mat->setting.ambient);
                         glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->setting.diffuse);
                         glMaterialfv(GL_FRONT, GL_SPECULAR, mat->setting.specular);
                         glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*
                       oldmat = mat;
// Setting default colors in cases of there is not material

                     static const GLfloat a[]={0.7, 0.7, 0.7, 1.0};
                     static const GLfloat d[]={0.7, 0.7, 0.7, 1.0};
                     static const GLfloat s[]={1.0, 1.0, 1.0, 1.0};
                     glMaterialfv(GL_FRONT, GL_AMBIENT, a);
                     glMaterialfv(GL_FRONT, GL_DIFFUSE, d);
                     glMaterialfv(GL_FRONT, GL_SPECULAR, s);
                     glMaterialf(GL_FRONT, GL_SHININESS, pow(2, 10.0*0.5));

                   glBegin(GL_TRIANGLES);// Start drawing primitive
                   for (int i=0; i<3; ++i)
// Setting normal for vertex

// Drawing of vertex
               delete []normalL;
//Rendering of list of calls of OpenGL
           if (mesh->setting.user_id)
//Multiplication of mesh position with current matrix
//Movement mesh in point rotation 
// Calling of list compiled commands
// There can be executed animation of other objects such as camera or light source
void OpenGLWidget::updateAnimation()

         // Current frame cannot be more maximum frames of 3ds model
         if (current_frame>Istage->frames)
         // Function of execution computing matrexes nodes in current frame

This code is written on Qt framework, but all specific classes such as QString, QList, or QVector3D can be rewritten in specific classes of almost all other platforms and languages.

Points of Interest

I spent much time on reading code of original lib3ds. For more clear understanding I commented almost all functions in classes. Alse I commented almost all application of flags for reading data. I hope my decision can help you to understand the structure of 3ds format.

Update for Qt5.3.2

I updated source code for lib3ds and Qt viewer for Qt5.3.2 - Download Source of viewer and lib3ds for Qt5.3.2 - 115 KB. 3ds model for testing - Download


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Evgeny Pereguda
Software Developer
Australia Australia
No Biography provided

Comments and Discussions

QuestionIs Visual C++ or .NET required? Pin
PotatoSoup2-Apr-20 13:21
MemberPotatoSoup2-Apr-20 13:21 
AnswerRe: Is Visual C++ or .NET required? Pin
Evgeny Pereguda4-Apr-20 5:38
MemberEvgeny Pereguda4-Apr-20 5:38 
Bugscenes because of coincidence of names aren't completely loaded Pin
Member 134387181-Oct-17 8:49
MemberMember 134387181-Oct-17 8:49 
Bugscenes because of coincidence of names aren't completely loaded Pin
Member 134387181-Oct-17 8:49
MemberMember 134387181-Oct-17 8:49 
GeneralMy vote of 4 Pin
macmaniak19-Aug-15 19:41
Membermacmaniak19-Aug-15 19:41 
QuestionПревед! Pin
macmaniak19-Aug-15 4:05
Membermacmaniak19-Aug-15 4:05 
AnswerRe: Превед! Pin
Evgeny Pereguda19-Aug-15 19:28
MemberEvgeny Pereguda19-Aug-15 19:28 
GeneralRe: Превед! Pin
macmaniak19-Aug-15 19:46
Membermacmaniak19-Aug-15 19:46 
GeneralRe: Превед! Pin
Evgeny Pereguda19-Aug-15 19:52
MemberEvgeny Pereguda19-Aug-15 19:52 
GeneralRe: Превед! Pin
macmaniak19-Aug-15 21:00
Membermacmaniak19-Aug-15 21:00 
Question3DS Viewer Pin
joanna0313-Apr-14 8:57
Memberjoanna0313-Apr-14 8:57 
GeneralMy vote of 5 Pin
EJ Smits9-Oct-12 20:56
MemberEJ Smits9-Oct-12 20:56 
QuestionSTL equivalent version? Pin
Shao Voon Wong4-Oct-12 22:35
mvaShao Voon Wong4-Oct-12 22:35 
AnswerRe: STL equivalent version? Pin
Evgeny Pereguda4-Oct-12 23:53
MemberEvgeny Pereguda4-Oct-12 23:53 
Questionmy vote is 5 Pin
Sergey Vystoropskiy4-Oct-12 3:20
MemberSergey Vystoropskiy4-Oct-12 3:20 
GeneralMy vote of 5 Pin
24532452433-Oct-12 14:36
Member24532452433-Oct-12 14:36 
BugBroken downloads Pin
Marius Bancila1-Oct-12 22:21
professionalMarius Bancila1-Oct-12 22:21 
QuestionNice Pin
xComaWhitex20-Jun-12 15:00
MemberxComaWhitex20-Jun-12 15:00 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.