Article     Discussion     Modifier     Historique     Forums     Salon IRC

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

 

Rechercher
Installer l'extension de recherche Plus d'informations

 

Comprendre
Tu me dis, j'oublie. Tu m'enseignes, je me souviens. Tu m'impliques, j'apprends. - Benjamin Franklin

 

Partager
La connaissance est la seule chose qui s'accroit lorsqu'on la partage. - Sacha Boudjema

 

Créer
L'imagination est plus importante que la connaissance. - Albert Einstein

 

 

Le wiki en images Le wiki en images Image du mois: «Snowball: un prototype de jeu développé avec NeL.