PDA

View Full Version : how to use lib3ds



deepha
11-06-2005, 09:47 PM
hi,
I would like to know how to import a 3D model into my application (rendering) using lib3ds import library.please give ur views.
regards,
deepha.

jide
11-07-2005, 03:14 AM
but the fact that this is not directly opengl related, this topic has been treated several up to many times here. Make a search then:

http://www.opengl.org/discussion_boards/cgi_directory/ultimatebb.cgi?ubb=search;search_forum=2

And have a look at the lib3ds website too.

http://lib3ds.sourceforge.net/

Also check google for what you're looking for.

Hylke Donker
11-07-2005, 06:01 AM
my 3ds class:
3DS.cpp:

/*
Program name:Combat of Death
Description source file: this class loads 3ds models
Copyright (C) 2005 Hylke Donker

This program 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.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/

/**
\file 3DS.cpp
\brief The cpp file of 3DS.h

This is the place were all the functions are 'defined'
*/

#include "3DS.h"

// constructor, enables and set properties of texture coordinate generation and set the current frame
Model::Model()
{
curFrame = 0; // current frame of our model
if(glIsEnabled(GL_LIGHTING))
lightEnabled = true;
else
lightEnabled = false;
}

// destructor, free up memory and disable texture generation
Model::~Model()
{
if(file) // if the file isn't freed yet
lib3ds_file_free(file); //free up memory
//disable texture generation
for(unsigned int i = 0;i < textureIndices.size();i++)
glDeleteTextures(1, &amp;textureIndices.at(i));
}

// load the model, and if the texture has textures, then apply them on the geometric primitives
void Model::loadFile(const char *name)
{
filename = name;
// load file
file = lib3ds_file_load(filename);
if(!file) // if we were not able to load the file
{
// give some errors
string event = "Error loading: ";
string online = "On line 61 in file ";
online.append(__FILE__);
event.append(filename);
cout << event << endl;
cout << online << endl;
CoDlog.comment("3DS Error");
CoDlog.event(event.c_str());
CoDlog.event(online.c_str());
exit(1);
}
lib3ds_file_eval(file, 0); // set current frame to 0
// apply texture to all meshes that have texels
Lib3dsMesh *mesh;
for(mesh = file->meshes;mesh != 0;mesh = mesh->next)
{
if(mesh->texels) //if there's texels for the mesh
ApplyTexture(mesh); //then apply texture to it
}
if(file->lights) //if we have lights in our model
CreateLightList();
}

void Model::CreateLightList()
{
lightListIndex = glGenLists(1);
glNewList(lightListIndex, GL_COMPILE_AND_EXECUTE);
Lib3dsLight *light; // temporary variable to store our lights
GLint curlight = GL_LIGHT0;
for(light = file->lights;light != 0;light = light->next)
{
if(light->off) //if our light is off
continue; //Move to the next light

GLfloat diff[4], amb[4], pos[4];

for(int j = 0;j < 3;j++)
{
diff[j] = light->color[j];
amb[j] = light->color[j] / 4.5; // We might wanna change this;
pos[j] = light->position[j];
}

diff[3] = amb[3] = pos[3] = 1.0;

curlight++;
// Start setting light
glLightfv(GL_LIGHT0, GL_DIFFUSE, diff); //set the diffuse color
glLightfv(GL_LIGHT0, GL_POSITION, pos); //set the position of the light
glLightfv(GL_LIGHT0, GL_AMBIENT, amb); // set the ambient color of the light
glLightfv(GL_LIGHT0, GL_SPECULAR, diff); // set the specular color of the light

if(light->spot) // if it's a light spot
{
for(int i = 0;i < 3;i++) // get position of the light
pos[i] = light->spot[i] - light->position[i];
pos[3] = light->spot[3] - light->position[3];
glLightfv(GL_LIGHT0, GL_SPOT_DIRECTION, pos); //specify that we have a spot at position 'pos'
}
}
glEndList();
}

// what is basicly does is, set the properties of the texture for our mesh
void Model::ApplyTexture(Lib3dsMesh *mesh)
{
for(unsigned int i = 0;i < mesh->faces;i++)
{
Lib3dsFace *f = &amp;mesh->faceL[i];
if(! f->material[0])
continue;
QImage img;
Lib3dsMaterial *mat;
bool found = false;
mat = lib3ds_file_material_by_name(file, f->material);
for(unsigned int i = 0;i < textureFilenames.size();i++)
{
if(strcmp(mat->texture1_map.name, textureFilenames.at(i).c_str()) == 0)
{
textureIndices.push_back(textureIndices.at(i));
textureFilenames.push_back(mat->texture1_map.name);
found = true;
break;
}
}
if(!found)
{
textureFilenames.push_back(mat->texture1_map.name);
if(!img.load(mat->texture1_map.name))
{
CoDlog.comment("3DS error");
CoDlog.event("Error loading 3ds texture, perhaps file format not supported?");
exit(1);
}
img = QGLWidget::convertToGLFormat(img);
GLuint tmpIndex; // temporary index to old the place of our texture
glGenTextures(1, &amp;tmpIndex); // allocate memory for one texture
textureIndices.push_back(tmpIndex); // add the index of our newly created texture to textureIndices
glBindTexture(GL_TEXTURE_2D, tmpIndex); // use our newest texture
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, img.width() , img.height(), GL_RGBA, GL_UNSIGNED_BYTE, img.bits()); // genereate MipMap levels for our texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // give the best result for texture magnification
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //give the best result for texture minification
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); // don't repeat texture
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); // don't repeat texture
}
}
}

// this code is rewritten from player.c example that came with lib3ds
// what it does is render a node from our model
void Model::renderNode(Lib3dsNode *node)
{
ASSERT(file); //this is for debugging
{
Lib3dsNode *tmp;
for(tmp = node->childs;tmp != 0;tmp = tmp->next)
renderNode(tmp); //render all child nodes of this note
}
if(node->type == LIB3DS_OBJECT_NODE) //check wheter the node is a 3ds node
{
if(! node->user.d) //Wheter we have a list or not, if not we're gonna create one
{
Lib3dsMesh *mesh = lib3ds_file_mesh_by_name(file, node->name); //get all the meshes of the current node
ASSERT(mesh); //for debugging in case we don't have a mesh
if(! mesh)
return;
node->user.d = glGenLists(1); //alocate memory for one list
/////////////////////////////////////////////////////////////
if(glGetError() != GL_NO_ERROR)
{
cout << "ERROR!\n";
qApp->exit(0);
}
/////////////////////////////////////////////////////////////
glNewList(node->user.d, GL_COMPILE); //here we create our list
{
unsigned p;
Lib3dsVector *normals;
normals = static_cast<float(*)[3]> (std::malloc (3*sizeof(Lib3dsVector)*mesh->faces)); //alocate memory for our normals
{
Lib3dsMatrix m;
lib3ds_matrix_copy(m, mesh->matrix); //copy the matrix of the mesh in our temporary matrix
lib3ds_matrix_inv(m);
glMultMatrixf(&amp;m[0][0]); //adjust our current matrix to the matrix of the mesh
}
lib3ds_mesh_calculate_normals(mesh, normals); //calculate the normals of the mesh
int j = 0;
for(p = 0;p < mesh->faces;p++)
{
Lib3dsFace *f = &amp;mesh->faceL[p];
Lib3dsMaterial *mat=0;
if(f->material[0]) //if the face of the mesh has material properties
mat = lib3ds_file_material_by_name(file, f->material); //read material properties from file
if(mat) //if we have material
{
static GLfloat ambient[4] = { 0.0, 0.0, 0.0, 1.0 };
glMaterialfv(GL_FRONT, GL_AMBIENT, ambient); // Ambient color
glMaterialfv(GL_FRONT, GL_DIFFUSE, mat->diffuse); //diffuse color
glMaterialfv(GL_FRONT, GL_SPECULAR, mat->specular); //specular color
float shine;
shine = pow(2, 10.0 * mat->shininess);
if(shine > 128.0)
shine = 128.0;
glMaterialf(GL_FRONT, GL_SHININESS, shine);
}
else // if we do not have material properties, we have to set them manually
{
GLfloat diff[4] = { 0.75, 0.75, 0.75, 1.0 }; // color: white/grey
GLfloat amb[4] = { 0.25, 0.25, 0.25, 1.0 }; //color: black/dark gray
GLfloat spec[4] = { 0.0, 0.0, 0.0, 1.0 }; //color: completly black
glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
glMaterialfv(GL_FRONT, GL_AMBIENT, amb);
glMaterialfv(GL_FRONT, GL_AMBIENT, spec);
}
{
if(mesh->texels)
{
glBindTexture(GL_TEXTURE_2D, textureIndices.at(j));
j++;
}
glBegin(GL_TRIANGLES);
for(int i = 0;i < 3;i++)
{
glNormal3fv(normals[3*p+i]); //set normal vector of that point
if(mesh->texels)
glTexCoord2f(mesh->texelL[f->points[i]][0], mesh->texelL[f->points[i]][1]);
glVertex3fv(mesh->pointL[f->points[i]].pos); //Draw the damn triangle
}
glEnd();
}
}
free(normals); //free up memory
}
glEndList(); // end of list
}
if(node->user.d) // if we have created a link list(with glNewList)
{
Lib3dsObjectData *tmpdat;
glPushMatrix(); //save transformation values
tmpdat = &amp;node->data.object; // get the position data
glMultMatrixf(&amp;node->matrix[0][0]); //adjust matrix according to the node
glTranslatef(-tmpdat->pivot[0], -tmpdat->pivot[1], -tmpdat->pivot[2]); //move to the right place;
glCallList(node->user.d); //render node
glPopMatrix(); //return transformation original values
}
}
}

// this function actually renders the model at place (x, y, z) and then rotated around the y axis by 'angle' degrees
void Model::RenderModel()
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glShadeModel(GL_SMOOTH);

if(file->lights) //if we have lights in the model
{
EnableLights(); //enable all lights
glCallList(lightListIndex); //set lights.
}

Lib3dsNode *nodes;
for(nodes = file->nodes;nodes != 0;nodes = nodes->next) // Render all nodes
renderNode(nodes);


if(file->lights)
DisableLights(); // disable lighting, we don't want it have it enabled longer than necessary

curFrame++;
if(curFrame > file->frames) //if the next frame doesn't exist, go to frame 0
curFrame = 0;
lib3ds_file_eval(file, curFrame); // set current frame

glDisable(GL_CULL_FACE);
glShadeModel(GL_FLAT);
}

void Model::EnableLights()
{
glEnable(GL_LIGHTING);
GLuint lightNum = GL_LIGHT0;
Lib3dsLight *light;
for(light = file->lights;light != 0;light = light->next)
{
if(!glIsEnabled(lightNum))
glEnable(lightNum);
lightNum++;
}
}

void Model::DisableLights()
{
glDisable(GL_LIGHTING);
GLuint lightNum = GL_LIGHT0;
Lib3dsLight *light;
for(light = file->lights;light != 0;light = light->next)
{
if(glIsEnabled(lightNum))
glDisable(lightNum);
lightNum++;
}
}

Lib3dsFile * Model::get3DSPointer()
{
return file;
}

string Model::getFilename()
{
string returnvalue = filename;
return returnvalue;
}3DS.h:

/*
Program name:Combat of Death
Description header file: this class loads 3ds models
Copyright (C) 2005 Hylke Donker

This program 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.

This program 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 this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
*/

/**
\file 3DS.h
\brief The 3ds model loader

All models are loaded and renderd using this class
*/

#ifndef HEADER_3DS
#define HEADER_3DS

#include <lib3ds/file.h>
#include <lib3ds/node.h>
#include <lib3ds/mesh.h>
#include <lib3ds/vector.h>
#include <lib3ds/matrix.h>
#include <lib3ds/material.h>
#include <lib3ds/light.h>
#include "qt_headers.h"
#include "cpp_headers.h"
#include "other_headers.h"
#include "extern_vars.h"
#include "logfile.h"

/**
\brief 3DS model loader and render

This class can load a model, and then apply a texture on it to finally render it
*/
class Model
{
public:
/**
\brief Constructor of this class

Model() is the constructor of this class, and enables texture generation and sets how that should be done, and sets the current frame variable to 0
*/
Model();
/**
\brief Destructor of this class

The destructor disables texture generation mode and free's the memory of the model, if it's not already freed.
*/
~Model();
/**
\brief Loads the file

It loads the file 'name', sets the current frame to 0 and if the model has textures, it will be applied to the model

\param name Contains the name of the to be loaded file
*/
void loadFile(const char *name);
/**
\brief create lighting list

Creates a display list that sets all the information for the lights.
*/
void CreateLightList();
/**
\brief renders nodes

It renders the node specified by the argument and sets material properties to the node if nescesary

\param node Contains the node to be renderd
*/
void renderNode(Lib3dsNode *node);
/**
\brief Enable lights

Enables all lights in the model if not already enabled
*/
void EnableLights();
/**
\brief Enable lights

Disables all lights in the model if not already disabled
*/
void DisableLights();
/**
\brief Actually renders the model

It renders the model, by rendering node by node using the renderNode function.But before it's renderd it's translated to (x,y,z) and then rotates it angle degrees

\sa renderNode()
*/
void RenderModel();
/**
\brief Apply the texture

It applies a texture to mesh ,according to the data that mesh contains

\param mesh That's the mesh on which the texture should be applied
*/
void ApplyTexture(Lib3dsMesh *mesh);
Lib3dsFile * get3DSPointer();
string getFilename();
private:
Lib3dsFile *file; /**< file holds the data of the model */
const char *filename; /**< It's the filename of the model */
int curFrame; /**< curFrame keeps track of the current frame that shuold be renderd */
vector<GLuint> textureIndices; /**< this variable holds the texture indicies */
vector<string> textureFilenames; /**< Holds the filenames of the textures, so I can see wheter a texture is used multiple times or not */
bool lightEnabled; /**< wheter light was enabled before this class. */
GLuint lightListIndex;
};

#endifIf you found somebugs in my code, please tell me :-).
Hylke

deepha
11-09-2005, 04:49 AM
Hi
thanks for ur reply Mr.Hylke Donker .I downloaded ur code and complied .It's giving error while including string and vector headers. how to proceed further.kindly guide me.

jide
11-10-2005, 03:04 AM
Don't use those headers of course:


#include "qt_headers.h"
#include "cpp_headers.h"
#include "other_headers.h"
#include "extern_vars.h"
#include "logfile.h"But use those you need depending on your language (C or C++) and whether you use glut or everything else for your window.

Ehsan Kamrani
11-10-2005, 06:45 AM
Originally posted by deepha:
hi,
I would like to know how to import a 3D model into my application (rendering) using lib3ds import library.please give ur views.
regards,
deepha.Dear Deepha
I use from the NeHe's code to load the MS3D models. After many researches in the net, i understood that the definition of the MS3D files are very well defined.Please take a look at lesson 35 of the NeHe tutorials: NeHe.gamedev.net

In the other hand, if you want to manage the animation of your characters, i think that cal 3d is one of the best choices for you. you can download it at: http://cal3d.sourceforge.net/
I have used from this API in my win32 applications. Although is a greate API, but you can only use from this API to animate the objects that have a skeleton. So its not a good way to load your static objects with CAL3D.
Regards
-Ehsan-

deepha
11-10-2005, 08:52 PM
Hi ,
Now i complied the 3ds class in cygwin platform.Now, the error message reads as

In member function `void Model::loadFile(const char*)':
374: `CoDlog' undeclared (first use this function)
374: (Each undeclared identifier is reported only once for each function it appears in.)
In member function `void Model::ApplyTexture(Lib3dsMesh*)':
433: `QImage' undeclared (first use this function)
433: parse error before `;' token
451: `img' undeclared (first use this function)
457: `QGLWidget' undeclared (first use this function)
457: parse error before `::' token
462: `gluBuild2DMipmaps' undeclared (first use this function)
In member function `void Model::renderNode(Lib3dsNode*)':
495: `qApp' undeclared (first use this function)

how to eliminate the errors.please help

deepha
11-11-2005, 12:57 AM
hi,
I found that i have to include the qt library headers in my code. i downloaded the qt 3.3.3.tar.bz2( i am using cygwin platform) from net.
let me know how to unzip the qt library.
regards,
deepha

jide
11-11-2005, 02:06 AM
Originally posted by deepha:
hi,
I found that i have to include the qt library headers in my code. i downloaded the qt 3.3.3.tar.bz2( i am using cygwin platform) from net.
let me know how to unzip the qt library.
regards,
deephaYou downloaded the linux version of qt, download the windows free version (only for making free projects) at this address:

http://www.trolltech.com/download/qt/windows.html

Please note that QT is no more a real free library but if you also make free projects. I advise you not to use qt and choose other libraries for managing windows, images and so on.