Login
dossier > Jeux-Video > [C++/OpenGL] Génération d'un terrain 3D à partir d'un bitmap

[C++/OpenGL] Génération d'un terrain 3D à partir d'un bitmap

Lecture d'une image BMP

* Général *

Pour lire une image BMP, il faut l'ouvrir en lecture binaire, puis tout simplement récupérer les structures de données. Pour cela nous allons donc utiliser les outils fournis de base pour vraiment comprendre le fonctionnement des structures windows et celui des fichiers binaires (et de l'application des textures par la même occasion). Ensuite une fois notre image ouverte, on va récupérer les données des pixels dans un tableau à 2 dimensions.

 

* Quelques variables globales *

Le but ici est de faire quelque chose de simple pour comprendre le fonctionnement global et ensuite le perfectionner. On va donc coder ce générateur dans un optique d'avoir une application fonctionnelle pour maintenant mais pas forcément ayant une évolution future.

On proposera à l'utilisateur plusieurs options d'affichage :

  • Rotation de la scène
  • Affichage en mode texturé ou filaire
  • Nombre de polygones pour le terrain
  • Taille d'un polygone
  • Hauteur max du terrain

 

bool     CONFIG_filaire = true;	        // Filaire ou non 
int      CONFIG_hautmax = 12;           // Hauteur max en coordonnées   
int      CONFIG_max_points = 40;        // Nombre de poygones par côté
double   CONFIG_taille_carre = 40.0;    // Taille d'un poygone
bool     CONFIG_rotate = false;         // Terrain qui tourne ou non

 

 

* Lecture de l'image et récupération des informations *

 

FILE *BMPFile;
BITMAPFILEHEADER bfh;
BITMAPINFOHEADER bih;

unsigned char     *bitmapImage; 


On déclare simplement notre variable de traitement du fichier et de stockage des entêtes (cf page précédente). La variable bitmapImage est un pointeur vers des caractères non signés (donc une valeur comprise entre 0 et 255). Les données d'une image sont renvoyées comme un tableau d'octet. Pour y accéder il suffira de faire : bitmapImage [index_octet] et on aura la valeur de la couleur comprise entre 0 et 255 bien entendu.

 

BMPFile = fopen(filename, "rb");

On ouvre le fichier en mode "rb", lecture binaire pour pouvoir y récupérer les données brutes.

 

fread (&bfh, sizeof (BITMAPFILEHEADER), 1, BMPFile);
fread (&bih, sizeof (BITMAPINFOHEADER), 1, BMPFile);
fread (bitmapImage, 1, bih.biSizeImage, BMPFile);

fclose(BMPFile);

 

Cette étape consiste à stocker dans nos variables bfh et bih tous les (sizeof) octets lus. Sizeof (type) renvoyant donc la taille des structures. fread se déplace dans le fichier au fur et à mesure que la lecture se déroule. Les 2 entêtes se suivant, il est initule de se déplacer manuellement dans le fichier.

Les entêtes étant stockées, nous avons accès maintenant aux informations des structures, dont une vitale pour la récupération des données images : biSizeImage, la taille en octets des données.

La récupération étant terminée, on peut fermer le fichier.

 

* Exploitation des résultats *
 

Nous allons donc stocker nos valeurs dans un tableau de pixel de dimensions précisée plus haut dans les configurations. Ce tableau sera un tableau d'entiers appelé "map". Notre image fait 256x256 alors que notre tableau fera 40x40 de base (ce qui fait déjà 1600 points à placer, sachant qu'un point est lui même composé d'un rectangle composé de 2 triangles ... ). Il va donc falloir tout remettre à l'échelle. Voyons un peu ce que cela donne :

 

di = (di / CONFIG_max_points) * h;
dj = (dj / CONFIG_max_points) * w;

i = (int)di;
j = (int)dj;

return (int) ((bitmapImage[i*w*3+j*3]/256.0)*CONFIG_hautmax);

Avec di et dj, deux variables flottantes pour avoir une mise à l'échelle. On les convertit ensuite en entier et on va chercher la position du pixel en faisant le cacul suivant :

ligne x largeur x 3 + colonne x 3  

On multiplie par 3 car nous sommes dans une image en 24 bits, donc 1 octet par composant de couleur, et en N&B les 3 valeurs sont égales (R=V=B), on va donc ici récupérer la première valeur. Stockons maintenant les résultats.

Cette étape est relativement simple étant donné que nous avons tout ce qu'il nous faut : les pixels de l'image, la taille de notre image ... Une boucle imbriquée dans une autre fera l'affaire :

for(i=0;i < CONFIG_max_points;i++)
for(j=0;j < CONFIG_max_points;j++) 

map[i][j] = GetHauteur(i,j, bih.biWidth, bih.biHeight);

 

Voilà, nous avons donc une fonction prête à l'emploi qui lit un fichier Bitmap, récupère les pixels, et en extrait la valeur de la première couleur et qui met tout à l'échelle. Il ne reste maintenant plus qu'à afficher tout ça.


Réalisation

Code & Design : Sébastien Cardona

Page générée en : 0.018193s