Jump to content
  • Advertisement
Sign in to follow this  
hylke2

OpenGL lib3ds

This topic is 4853 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello, I'm currently writing a class that both loads and renders a 3ds model. I'm using OpenGL to render the model, but I have a problem. I want to apply textures textures on the model, so I figured that
Quote:
file->meshes->texelsL
would contain the texels for my texture. So what I did was, I've made a loop that loops through all the meshes of my lib3ds model, and if it has texels(if(mesh->texels)) then I create a texture for that mesh and save the texture index in a vector. Although I don't exactly know what they mean with nodes and meshes(and what there differences are), I'm pretty sure that a model can be build of thousands of meshes right? and if you have multiple models, it can easily get up to 10000 meshes. And I'm pretty sure that OpenGL doesn't support that many textures. So my question is, how can I do this by, in example, using 1 texture for a model? Thanx in advance, Hylke

Share this post


Link to post
Share on other sites
Advertisement
All texture and color data is kept in a Lib3dsMaterial objects. One Lib3dsMaterial for each material in a file.

You can get the name of a meshes material by checking is faceL.material property like this.
mesh3ds->faceL[0].material
That will return the string name of the material.

Each mesh has can have no more than one material. But you can have 10 meshes in a file each with the same material and the same texture.

Share this post


Link to post
Share on other sites
Hmm...
I've browsed faceL(using the online documentation of lib3ds) and I couldn't find anything which could contain the texels.
But don't you have a better idea than just creating a texture for each mesh?
Thanx Hylke

Share this post


Link to post
Share on other sites
hi,
i tried to use lib3ds, too, but i have some problems with files without cameras.
How can i load these files. I have written a loader like the "player" example only that it ignores the camera. but it doesn't work.
Are there any other examples or tutorials?

undo

Share this post


Link to post
Share on other sites
Hello Undo,
As far as I know(and I've searched a lot for it) there aren't lib3ds tutorials on the net.
If you want mine, you can have it.
I'Il post it here.
Note that I haven't tested it wheter it renders the models correctly, and it might be extremely buggy(which is probably the case):

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"

/**
\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

\param x The number of units to be translated on the x axis
\param y The number of units to be translated on the y axis
\param z The number of units to be translated on the z axis
\param angle The number of degrees to be rotated after the translation
\sa renderNode()
*/

void RenderModel(GLfloat x, GLfloat y, GLfloat z, GLfloat angle);
/**
\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);
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 */
bool lightEnabled; /**< wheter light was enabled before this class. */
GLuint lightListIndex;
};

#endif






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
// set properties of texture coordinate generation for both x and y coordinates
glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
// if not already enabled, enable texture generation
if(! glIsEnabled(GL_TEXTURE_GEN_S))
glEnable(GL_TEXTURE_GEN_S);
if(! glIsEnabled(GL_TEXTURE_GEN_T));
glEnable(GL_TEXTURE_GEN_T);
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
glDisable(GL_TEXTURE_GEN_S);
glDisable(GL_TEXTURE_GEN_T);
}

// 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
cout << "Error loading: " << filename << "!\n";
cout << "On line " << __LINE__ -1 << " in file " << __FILE__ << endl;
qApp->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;

glEnable(curlight);
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 = light->spot - light->position;
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)
{
if(mesh->texels) //if we have texels
{
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, textureIndices.at(textureIndices.size()-1)); // use our newest texture
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, (int)pow(mesh->texels, 0.5) /*square root of pixels*/, (int)pow(mesh->texels, 0.5), GL_RGB, GL_FLOAT,
mesh->texelL); // 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(&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 curIndex = 0;

if(mesh->texels)
{
if(! glIsEnabled(GL_TEXTURE_2D))
glEnable(GL_TEXTURE_2D);
int j = 0;
Lib3dsMesh *tmpmesh;
for(tmpmesh = file->meshes;tmpmesh != 0;tmpmesh = tmpmesh->next)
{
if(strcmp(tmpmesh->name, mesh->name) == 0)
break;
else if(tmpmesh->texels)
j++;
}
glBindTexture(GL_TEXTURE_2D, textureIndices.at(j));
curIndex++;
}

for(p = 0;p < mesh->faces;p++)
{
Lib3dsFace *f = &mesh->faceL

;
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);
}
{
glBegin(GL_TRIANGLES);
for(int i = 0;i < 3;i++)
{
glNormal3fv(normals[3*p*i]); //set normal vector of that point
glVertex3fv(mesh->pointL[f->points].pos); //Draw point of the mesh
}
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(GLfloat x, GLfloat y, GLfloat z, GLfloat angle)
{
glPushMatrix(); // save transformation values
glTranslatef(x, y, z); // move to place (x,y,z)
glRotatef(angle, 0.0, 1.0, 0.0); // rotate 'angle' degrees around the y axis

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);

glPopMatrix();

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
}

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

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




Note that the header has alot of comments, they're used for doxygen so it can create proper documentation.
If you found bugs and know how to fix it, please let me know.
Hylke

Please use the source tags when posting lots of code

[Edited by - _the_phantom_ on July 26, 2005 8:58:08 AM]

Share this post


Link to post
Share on other sites
thanx for your code. it looks similiar to mine.
there is one minor problem in your constructor.

if(! glIsEnabled(GL_TEXTURE_GEN_T)); // this semicolon too much
glEnable(GL_TEXTURE_GEN_T);

i found out that my 3ds files don't contain any nodes so nothing is diplayed.
do you know where to get proper files for testing?

to your question:
i have no idea of the 3ds-file's structure but it looks as though you have to create a texture for each mesh. and if you only load a model, there shouldn't be too much textures (i'm thinking of the mesh as the actual model)

Share this post


Link to post
Share on other sites
Quote:
Original post by undo
thanx for your code. it looks similiar to mine.

No problem :-)
Quote:

there is one minor problem in your constructor.

if(! glIsEnabled(GL_TEXTURE_GEN_T)); // this semicolon too much
glEnable(GL_TEXTURE_GEN_T);

Ok thanx.
Quote:

i found out that my 3ds files don't contain any nodes so nothing is diplayed.
do you know where to get proper files for testing?

http://www.amazing3d.com/modfree.html
Maybe you can find something there.
Quote:

to your question:
i have no idea of the 3ds-file's structure but it looks as though you have to create a texture for each mesh. and if you only load a model, there shouldn't be too much textures (i'm thinking of the mesh as the actual model)

Ok, thanx.

Share this post


Link to post
Share on other sites
hi,
now that I can load models I ran into the same problems with textures.
I don't know how to read the texture name from the Lib3dsMaterial, but you forgot to set the texture coordinates. Maybe setting these will solve your problems.
Simply change this in your renderNode(...)

glBegin(GL_TRIANGLES);
for(int i = 0;i < 3;i++)
{
glNormal3fv(normals[3*p*i]); //set normal vector of that point
// add this line to set the coordinates
glTexCoord2f(mesh->texelL[face->points][0],mesh->texelL[face->points][1]);
glVertex3fv(mesh->pointL[f->points].pos); //Draw point of the mesh
}
glEnd();

it works for me when I load a texture manually.
I have to find a way to load the texture specified in the 3ds file

Share this post


Link to post
Share on other sites
Quote:
but you forgot to set the texture coordinates

I did that in my class using texture coordinate generation.

Quote:
I have to find a way to load the texture specified in the 3ds file

Could you tell me where I can find the name of the texture?
Because I found out that the function:
gluBuild2DMipmaps(GL_TEXTURE_2D, GL_RGB, (int)pow(mesh->texels, 0.5) , (int)pow(mesh->texels, 0.5), GL_RGBA, GL_FLOAT, mesh->texelL);
Gave a segmentation fault, and mesh->texelL didn't appear to hold the pixels(which is, I think, the problem of the segmentation fault).

But for file loading I use QT, and there are also some other libraries that can do it for you(in example SDL).

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!