how to use lib3ds

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.

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.

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, &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 = &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, &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!
";
				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(&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 = &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 = &node->data.object; // get the position data
			glMultMatrixf(&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;
};

#endif

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

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.

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.

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-

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 functionvoid Model::renderNode(Lib3dsNode*)’:
495: `qApp’ undeclared (first use this function)

how to eliminate the errors.please help

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

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,
deepha

You 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.