OpenGL:3dsloader
Un article de Games Creators Network.
Sommaire |
[modifier] Introduction
Le fichier .3ds est un format binaire, chaque instruction a une entête :
- un opcode que nous appelerons chunk_id
- la taille de tout ce que l'instruction contient que nous appellerons chunk_lenght
- chunk_id vaut 2 octet, nous choisirons le format unsigned short pour le stocker.
-chunk_lenght vaut 4 octet, nous choisirons le format unsigned int pour le stocker
[modifier] Les opcodes principaux
0x4D4D : opcode principal 0x3D3D : opcode de l'éditeur des objets 0x4000 : opcode qui crée un nouveau mesh 3d 0xafff : opcode de l'éditeur de matériaux 0xb000 : opcode des animations
[modifier] Structure qui va contenir l'objet .3ds
Nous allons construire une structure pour contenir l'objet .3ds. L'objet .3ds contiendra au départ le nombre de mesh et les meshs.
typedef struct object3ds{ int num_mesh; mesh3ds *mesh; }object3ds;
L'objet mesh contiendra le nom du mesh, le nombre de vectrices, les vectrices, le nombre de faces et les faces.
typedef struct mesh3ds{ char name[20]; unsigned short num_vectrices; vectrice3ds *vectrices; unsigned short num_faces; face3ds *faces; }mesh3ds;
Une vectrice 3ds contient 3 floats : les points x,y,z.
typedef struct vectrice3ds{ float x,y,z; }vectrice3ds;
Une face 3ds contient les id des vectrices : a,b,c.
typedef struct face3ds{ unsigned short a,b,c; }face3ds;
[modifier] Initialisation
Nous allons créer la fonction d'initialisation de l'objet .3ds : on initialise 1000 meshs (cette valeur peut etre modifiée).
void init3ds(object3ds *objet3d){ objet3d->num_mesh=0; objet3d->mesh = (mesh3ds*)malloc(sizeof(mesh3ds)*1000); }
[modifier] La fonction de chargement du fichier .3ds
Nous allons charger le fichier .3ds :
void Load_3ds(object3ds *objet3d,char *filename){
D'abord, nous initialisons l'objet :
init3ds(objet3d);
On crée 2 variables pour l'entête :
unsigned short chunk_id; unsigned int chunk_lenght;
On ouvre le fichier :
FILE *fichier = fopen(filename,"rb");
On lit l'entête :
fread (&chunk_id, 2, 1, fichier); fread (&chunk_lenght, 4, 1, fichier);
On teste l'id et on charge la fonction pour le opcode principal, on donne la taille :
switch(chunk_id){ case 0x4d4d:{ MainChunk(objet3d,fichier,chunk_lenght-6); break; }
Si ce n'est pas ca, le fichier n'est pas un fichier .3ds, on quitte :
default: { fclose(fichier); return -1; }
On finit la fonction de chargement
} return 1; }
[modifier] La fonction principale
La fonction principale prend en paramètre : l'objet .3ds, le fichier, la taille a lire.
int MainChunk(object3ds *objet3d, FILE *fichier, unsigned int lenght) {
nous allons commencer par stocker la position où nous nous trouvons dans le fichier :
int start = ftell(fichier);
ensuite, on crée 2 variables comme pour la fonction précédente :
unsigned short chunk_id; unsigned int chunk_lenght;
on crée une boucle principale :
while (ftell(fichier) < start + lenght){
on lit l'entête :
fread (&chunk_id, 2, 1, fichier); fread (&chunk_lenght, 4, 1, fichier);
on lit l'id :
switch(chunk_id){
si c'est 0x3d3d, on ouvre la fonction 3d editor
case 0x3d3d:{ EditorChunk(objet3d, fichier, chunk_lenght-6); break; }
au même niveau, il y a le keyframer(pour les animations) mais nous ne les gérons pas pour l'instant donc, on appelle fseek(fichier, chunk_lenght-6, SEEK_CUR);
case 0xb000:{ //KeyframerChunk(objet3d,fichier, chunk_lenght-6); fseek(fichier, chunk_lenght-6, SEEK_CUR); break; }
si c'est autre chose :
default: { fseek(fichier, chunk_lenght-6, SEEK_CUR); }
ensuite on ferme la fonction, on utilise fseek(fichier, start+lenght, SEEK_SET); pour arriver au bon endroit dans le fichier. noralement, ce n'est pas nécessaire mais ca peut éviter des bugs :
} } fseek(fichier, start+lenght, SEEK_SET); }
[modifier] la fonction editorchunk ()
nous allons voir maintenant la fonction Editor Chunk
on commence :
int EditorChunk(object3ds *objet3d, FILE *fichier, unsigned int lenght) { int start = ftell(fichier); unsigned short chunk_id; unsigned int chunk_lenght; while (ftell(fichier) < start + lenght){ fread (&chunk_id, 2, 1, fichier); fread (&chunk_lenght, 4, 1, fichier); switch(chunk_id){
nous allons voir maintenant la première vraie instruction : 0x4000
case 0x4000:{ objet3d->num_mesh++; int num=objet3d->num_mesh-1; char temp; int i = 0; do { fread (&temp, 1, 1, fichier); objet3d->mesh[num].name[i] = temp; i++; }while(temp != '\0'); ObjetBlockChunk(objet3d,fichier, chunk_lenght-6-i); break; }
ensuite, les matériaux(qu'on gérera plus tard) :
case 0xAFFF:{ //MaterialBlocChunk(objet3d, fichier, chunk_lenght-6); fseek(fichier, chunk_lenght-6, SEEK_CUR); break; }
sinon :
default:{ fseek(fichier, chunk_lenght-6, SEEK_CUR); }
on ferme la fonction :
} } fseek(fichier, start+lenght, SEEK_SET); return 1; }
[modifier] la fonction ObjetBlockChunk()
cette partie est assez longue, je crée donc une nouvelle page pour que ce soit plus lisible : 3dsloader:ObjetBlocChunk

