Accueil > > > RENDU SUR TEXTURE [OPENGL] [VC++]
RENDU SUR TEXTURE [OPENGL] [VC++]
Information sur la source
Description
Voilà un petit exemple utilisant la GLUT (pour la création de la fenêtre) qui va vous permettre de créer toutes sortes d'effets spéciaux. En fait le rendu sur texture c'est simplement rendre une image (que l'on affiche pas à l'écran) et copier cette image dans une texture que l'on affichera dans une scène. cela peut vous servir à réaliser une caméra embarqué dans un véhicule, un écran d'ordinateur ou tout autre chose qui aurait besoin d'une texture qui change et en 3D ! Le tout est commenté allègrement ! @+
Source
- Le ZIP ou :
-
- #include <gl/glut.h> // Header pour la GLUT (incluant les headers window.h, glu.h et gl.h)
- #include <gl/glaux.h> // Header pour les fonctions GL auxiliares (chargement texture bitmap, ...)
-
- typedef unsigned short int USHORT;
-
- float rot = 0.0; // Variable pour la rotation
-
- unsigned int textures[1] = {0}; // Stock la texture
-
- USHORT screenWidth = 300; // Largeur de notre fenêtre
- USHORT screenHeight = 300; // Hauteur de notre fenêtre
- USHORT viewportSize = 256; // Taille de notre texture (on donnera cette taille
- // a glViewport() afin de copier l'écran dans la texture vide
- // qui possède cette taille)
-
- void createEmptyTexture(unsigned int textureArray[], int size, int channels, int type, int textureID)
- {
- // Déclare et initialise une variable qui sera capable d'héberger momentanément
- // les données de l'image de texture
- unsigned int *pTexture = NULL;
- pTexture = new unsigned int [size * size * channels];
- memset(pTexture, 0, size * size * channels * sizeof(unsigned int));
-
- glGenTextures(1, &textureArray[textureID]); // Génére un nom de texture
- glBindTexture(GL_TEXTURE_2D, textureArray[textureID]); // Active la texture que nous venons de générer
-
- // Définit une texture 2D avec une seule résolution (0)
- glTexImage2D(GL_TEXTURE_2D, 0, channels, size, size, 0, type, GL_UNSIGNED_INT, pTexture);
-
- //Définit les paramètres du traitement de la texture
- glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
-
- // La texture est maintenant stocké dans la amémoire de la carte graphique,
- // nous pouvons donc la supprimer
- delete [] pTexture;
- }
-
- void affichage () // Affiche la scène
- {
- rot+=0.5; //Incrémente la variable de rotation
-
- glClearColor(0.0f, 0.0f, 0.0f, 0.5); // Couleur d'arrière-plan du rendu sur texture
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Efface le tampon chromatique et le tampon de profondeur
- glLoadIdentity();
-
- glTranslatef(0.0, 0.0, -2.0);
-
- glClearColor(0.0f, 0.0f, 1.0f, 1.0); // Couleur d'arrière-plan de la scène
-
-
- /* Cette partie va nous permettre de dessiner la scène qui sera ensuite copier dans notre texture vide.
- Le principe est de redimensionner la surface de rendu de OpenGL (glViewport()) à la taille de notre
- texture pour que la surface entière puisse être copiée entièrement dans notre texture vide.
- Nous copions le rendu vers la texture à l'aide de :
-
- glCopyTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width,
- GLsizei height, Glint border, GLenum format, GLenum type, const GLvoid *texels)
-
- target : positionné avec les constantes GL_TEXTURE_2D ou GL_PROXY_TEXTURE_2D
- level : nombre de résolutions de la texture (pour une seule mettre 0)
- internalFormat : indique les composants RVBA, valeurs de luminance ou d'intensité pour
- la description des texels d'une image. Il existe 38 constantes symboliques :
- -GL_ALPHAx (x = rien, 4, 8, 12, 16)
- -GL_LUMINANCEx ( x= rien, 4, 8, 12, 16)
- -GL_LUMINANCEx_ALPHAx (x = rien, 4, 8, 12, 16)
- -GL_LUMINANCE6_ALPHA2, GL_LUMINANCE12_ALPHA4
- -GL_INTENSITYx (x = rien, 4, 8, 12, 16)
- -GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, GL_RGB16
- -GL_RGBAx (x = rien, 2, 4, 8, 12, 16)
- -GL_RGB5_A1, GL_RGB10_A2
- ex : GL_R3_G3_B2 demande que les texels soient composés de 3 bites de vert
- , 3 bits de rouge et 2 bits de bleu mais OpenGL peut ne pas vous
- donner satisfaction car il est uniquement obligé de choisir une représentation
- interne se rapprochant le plus possible de ce qu'on lui demande.
- Ainsi Gl_LUMINANCE, GL_RGBA, .. sont sympathique dans la mesure où ils ne
- nous demandent pas de spécifier une résolution
- width et height : fournissent les dimensions de l'image de texture
- border : indique la largeur de la bordure (soit 1 ou 0)
- format et type : décrivent le format et le type de donnée des données de l'image de texture
- Voici les constantes symboliques que prend format :
- -GL_COLOR_INDEX, GL_RGB, GL_RGBA, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA
- Voici les constantes pour type :
- GL_BYTE, GL_UNSIGNES_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT
- GL_FLOAT, GL_BITMAP ou un type de données pixel compactés.
- texels : héberge les données de l'image de texture en décrivant la texture et la bordure
-
- Ensuite nous redimensionnont la surface de rendu de OpenGL à notre écran.
- Voilà nous disposons de notre rendu sur texture.
- Ici l'exemple est simple mais vous pouvez faire d'autres effets que nous verrons plus tard
- dans d'autres tutoriaux ...
- */
-
- glPushMatrix();
- glRotatef(rot, 0.4f, 0.1f, 1.0f);
-
- glViewport(0, 0, viewportSize, viewportSize);
-
- glDisable(GL_TEXTURE_2D);
-
- glutSolidCube(1.0);
-
- glEnable(GL_TEXTURE_2D);
-
- glBindTexture(GL_TEXTURE_2D,textures[0]);
-
- glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, viewportSize, viewportSize, 0);
-
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- glViewport(0, 0, screenWidth , screenHeight );
-
- glPopMatrix();
-
- // Ici nous créons un ensemble de 4 polygones carrés afin de rendre la texture que nous avons 'fabriquée' précédemment
-
- glPushMatrix();
-
- glTranslatef(0.0, 0.0, 2.0);
- glRotatef(rot, 0.0f, 1.0f, 0.0f);
- glTranslatef(0.0, 0.0, -2.0);
-
- glBindTexture(GL_TEXTURE_2D, textures[0]);
-
- for (USHORT i = 1; i <= 4; i++)
- {
- glTranslatef(0.0, 0.0, 2.0);
- glRotatef(90.0, 0.0f, 1.0f, 0.0f);
- glTranslatef(0.0, 0.0, -2.0);
-
- glBegin(GL_QUADS);
- glTexCoord2f( 1, 0.0f); glVertex3f(-1, -1, 0);
- glTexCoord2f( 1, 1); glVertex3f(-1, 1, 0);
- glTexCoord2f(0.0f, 1); glVertex3f( 1, 1, 0);
- glTexCoord2f(0.0f, 0.0f); glVertex3f( 1, -1, 0);
- glEnd();
- }
-
- glPopMatrix();
-
- glutSwapBuffers(); // Echange des tampons image
- // (celui sur lequel on a dessiné s'affiche
- // pendant nous dessinerons sur l'autre)
- }
-
- void redimension (int w, int h) // Notre fonction de redimension de la fenêtre
- {
- screenWidth = w;
- screenHeight = h;
- glViewport(0, 0, w, h); // Nous ordonnons a OpenGL d'utiliser toutes la surface de la fenêtre pour afficher
-
- glMatrixMode(GL_PROJECTION); // Sélection de la matrice de projection
- glLoadIdentity(); // Initialise la matrice de projection
- if (h==0) // Calcul de la perspective
- gluPerspective(80, (float) w, 1.0, 30.0);
- else
- gluPerspective(65, (float) w / (float) h, 1.0, 30.0);
-
- glMatrixMode(GL_MODELVIEW); // Sélection de la matrice de modélisation-visualisation
- glLoadIdentity(); // Initialise la matrice de modélisation-visualisation
- }
-
- void clavier (unsigned char key, int x, int y) // Fonction de gestion du clavier
- {
- switch (key) {
- case 27: // Touche 'ESCAPE'
- exit (0); // Sort de notre programme
- break;
- }
- }
-
- void init()
- {
- // Paramètre la lumière 0
- float lightAmbient[] = {1.0, 1.0, 1.0, 1.0};
- glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
- float lightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
- glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
- float lightPosition[] = {0.0, 0.0, 0.0, 1.0};
- glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
-
- glEnable(GL_LIGHT0); // Active la lumière 0
- glEnable(GL_LIGHTING); // Active la gestion de l'éclairage
-
- glEnable (GL_DEPTH_TEST); // Active le test de profondeur
- glEnable (GL_TEXTURE_2D); // Active la gestion des textures
-
- createEmptyTexture(textures, viewportSize, 3, GL_RGB, 0);// NOUVEAU : Crée notre texture vide
- }
-
- void main (int argc, char** argv) // Fonction principale (première fonction appelée)
- {
- glutInit (&argc, argv); // Initialisation de la GLUT
- glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // Affichage en mode RGBAlpha, double tampon image et un tampon de profondeur
- glutInitWindowSize (300, 300); // Taille de la fenêtre
- glutCreateWindow ("Rendu sur texture avec OpenGL"); // Titre de la fenêtre (ou argv[0])
- init ();
- glutDisplayFunc (affichage); // Spécifie la fonction avec laquelle on veut afficher
- glutReshapeFunc (redimension); // Spécifie la fonction avec laquelle on veut redimensionner la fenêtre
- glutKeyboardFunc (clavier); // Spécifie la fonction avec laquelle on veut gérer les entrés au clavier
- glutIdleFunc (affichage); // Spécifie la fonction à exécuter si aucun autre événement n'est en attente
- glutMainLoop (); // Démarre la GLUT en entrant dans une boucle infinie
- }
Le ZIP ou :
#include <gl/glut.h> // Header pour la GLUT (incluant les headers window.h, glu.h et gl.h)
#include <gl/glaux.h> // Header pour les fonctions GL auxiliares (chargement texture bitmap, ...)
typedef unsigned short int USHORT;
float rot = 0.0; // Variable pour la rotation
unsigned int textures[1] = {0}; // Stock la texture
USHORT screenWidth = 300; // Largeur de notre fenêtre
USHORT screenHeight = 300; // Hauteur de notre fenêtre
USHORT viewportSize = 256; // Taille de notre texture (on donnera cette taille
// a glViewport() afin de copier l'écran dans la texture vide
// qui possède cette taille)
void createEmptyTexture(unsigned int textureArray[], int size, int channels, int type, int textureID)
{
// Déclare et initialise une variable qui sera capable d'héberger momentanément
// les données de l'image de texture
unsigned int *pTexture = NULL;
pTexture = new unsigned int [size * size * channels];
memset(pTexture, 0, size * size * channels * sizeof(unsigned int));
glGenTextures(1, &textureArray[textureID]); // Génére un nom de texture
glBindTexture(GL_TEXTURE_2D, textureArray[textureID]); // Active la texture que nous venons de générer
// Définit une texture 2D avec une seule résolution (0)
glTexImage2D(GL_TEXTURE_2D, 0, channels, size, size, 0, type, GL_UNSIGNED_INT, pTexture);
//Définit les paramètres du traitement de la texture
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
// La texture est maintenant stocké dans la amémoire de la carte graphique,
// nous pouvons donc la supprimer
delete [] pTexture;
}
void affichage () // Affiche la scène
{
rot+=0.5; //Incrémente la variable de rotation
glClearColor(0.0f, 0.0f, 0.0f, 0.5); // Couleur d'arrière-plan du rendu sur texture
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Efface le tampon chromatique et le tampon de profondeur
glLoadIdentity();
glTranslatef(0.0, 0.0, -2.0);
glClearColor(0.0f, 0.0f, 1.0f, 1.0); // Couleur d'arrière-plan de la scène
/* Cette partie va nous permettre de dessiner la scène qui sera ensuite copier dans notre texture vide.
Le principe est de redimensionner la surface de rendu de OpenGL (glViewport()) à la taille de notre
texture pour que la surface entière puisse être copiée entièrement dans notre texture vide.
Nous copions le rendu vers la texture à l'aide de :
glCopyTexImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width,
GLsizei height, Glint border, GLenum format, GLenum type, const GLvoid *texels)
target : positionné avec les constantes GL_TEXTURE_2D ou GL_PROXY_TEXTURE_2D
level : nombre de résolutions de la texture (pour une seule mettre 0)
internalFormat : indique les composants RVBA, valeurs de luminance ou d'intensité pour
la description des texels d'une image. Il existe 38 constantes symboliques :
-GL_ALPHAx (x = rien, 4, 8, 12, 16)
-GL_LUMINANCEx ( x= rien, 4, 8, 12, 16)
-GL_LUMINANCEx_ALPHAx (x = rien, 4, 8, 12, 16)
-GL_LUMINANCE6_ALPHA2, GL_LUMINANCE12_ALPHA4
-GL_INTENSITYx (x = rien, 4, 8, 12, 16)
-GL_RGB, GL_R3_G3_B2, GL_RGB4, GL_RGB5, GL_RGB8, GL_RGB10, GL_RGB12, GL_RGB16
-GL_RGBAx (x = rien, 2, 4, 8, 12, 16)
-GL_RGB5_A1, GL_RGB10_A2
ex : GL_R3_G3_B2 demande que les texels soient composés de 3 bites de vert
, 3 bits de rouge et 2 bits de bleu mais OpenGL peut ne pas vous
donner satisfaction car il est uniquement obligé de choisir une représentation
interne se rapprochant le plus possible de ce qu'on lui demande.
Ainsi Gl_LUMINANCE, GL_RGBA, .. sont sympathique dans la mesure où ils ne
nous demandent pas de spécifier une résolution
width et height : fournissent les dimensions de l'image de texture
border : indique la largeur de la bordure (soit 1 ou 0)
format et type : décrivent le format et le type de donnée des données de l'image de texture
Voici les constantes symboliques que prend format :
-GL_COLOR_INDEX, GL_RGB, GL_RGBA, GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA, GL_LUMINANCE, GL_LUMINANCE_ALPHA
Voici les constantes pour type :
GL_BYTE, GL_UNSIGNES_BYTE, GL_SHORT, GL_UNSIGNED_SHORT, GL_INT, GL_UNSIGNED_INT
GL_FLOAT, GL_BITMAP ou un type de données pixel compactés.
texels : héberge les données de l'image de texture en décrivant la texture et la bordure
Ensuite nous redimensionnont la surface de rendu de OpenGL à notre écran.
Voilà nous disposons de notre rendu sur texture.
Ici l'exemple est simple mais vous pouvez faire d'autres effets que nous verrons plus tard
dans d'autres tutoriaux ...
*/
glPushMatrix();
glRotatef(rot, 0.4f, 0.1f, 1.0f);
glViewport(0, 0, viewportSize, viewportSize);
glDisable(GL_TEXTURE_2D);
glutSolidCube(1.0);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D,textures[0]);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, viewportSize, viewportSize, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, screenWidth , screenHeight );
glPopMatrix();
// Ici nous créons un ensemble de 4 polygones carrés afin de rendre la texture que nous avons 'fabriquée' précédemment
glPushMatrix();
glTranslatef(0.0, 0.0, 2.0);
glRotatef(rot, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0, 0.0, -2.0);
glBindTexture(GL_TEXTURE_2D, textures[0]);
for (USHORT i = 1; i <= 4; i++)
{
glTranslatef(0.0, 0.0, 2.0);
glRotatef(90.0, 0.0f, 1.0f, 0.0f);
glTranslatef(0.0, 0.0, -2.0);
glBegin(GL_QUADS);
glTexCoord2f( 1, 0.0f); glVertex3f(-1, -1, 0);
glTexCoord2f( 1, 1); glVertex3f(-1, 1, 0);
glTexCoord2f(0.0f, 1); glVertex3f( 1, 1, 0);
glTexCoord2f(0.0f, 0.0f); glVertex3f( 1, -1, 0);
glEnd();
}
glPopMatrix();
glutSwapBuffers(); // Echange des tampons image
// (celui sur lequel on a dessiné s'affiche
// pendant nous dessinerons sur l'autre)
}
void redimension (int w, int h) // Notre fonction de redimension de la fenêtre
{
screenWidth = w;
screenHeight = h;
glViewport(0, 0, w, h); // Nous ordonnons a OpenGL d'utiliser toutes la surface de la fenêtre pour afficher
glMatrixMode(GL_PROJECTION); // Sélection de la matrice de projection
glLoadIdentity(); // Initialise la matrice de projection
if (h==0) // Calcul de la perspective
gluPerspective(80, (float) w, 1.0, 30.0);
else
gluPerspective(65, (float) w / (float) h, 1.0, 30.0);
glMatrixMode(GL_MODELVIEW); // Sélection de la matrice de modélisation-visualisation
glLoadIdentity(); // Initialise la matrice de modélisation-visualisation
}
void clavier (unsigned char key, int x, int y) // Fonction de gestion du clavier
{
switch (key) {
case 27: // Touche 'ESCAPE'
exit (0); // Sort de notre programme
break;
}
}
void init()
{
// Paramètre la lumière 0
float lightAmbient[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_AMBIENT, lightAmbient);
float lightDiffuse[] = {1.0, 1.0, 1.0, 1.0};
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightDiffuse);
float lightPosition[] = {0.0, 0.0, 0.0, 1.0};
glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
glEnable(GL_LIGHT0); // Active la lumière 0
glEnable(GL_LIGHTING); // Active la gestion de l'éclairage
glEnable (GL_DEPTH_TEST); // Active le test de profondeur
glEnable (GL_TEXTURE_2D); // Active la gestion des textures
createEmptyTexture(textures, viewportSize, 3, GL_RGB, 0);// NOUVEAU : Crée notre texture vide
}
void main (int argc, char** argv) // Fonction principale (première fonction appelée)
{
glutInit (&argc, argv); // Initialisation de la GLUT
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); // Affichage en mode RGBAlpha, double tampon image et un tampon de profondeur
glutInitWindowSize (300, 300); // Taille de la fenêtre
glutCreateWindow ("Rendu sur texture avec OpenGL"); // Titre de la fenêtre (ou argv[0])
init ();
glutDisplayFunc (affichage); // Spécifie la fonction avec laquelle on veut afficher
glutReshapeFunc (redimension); // Spécifie la fonction avec laquelle on veut redimensionner la fenêtre
glutKeyboardFunc (clavier); // Spécifie la fonction avec laquelle on veut gérer les entrés au clavier
glutIdleFunc (affichage); // Spécifie la fonction à exécuter si aucun autre événement n'est en attente
glutMainLoop (); // Démarre la GLUT en entrant dans une boucle infinie
}
Conclusion
La connaissance appartient à tous !
Sources du même auteur
Sources de la même categorie
Commentaires et avis
|
Derniers Blogs
ETENDRE LE TEAM WEB ACCESS DE TFS 2012 - STEP 0ETENDRE LE TEAM WEB ACCESS DE TFS 2012 - STEP 0 par Philess
L'extensibilité du Team Web Access
Le Web Access (site d'équipe) de Team Foundation Server a été complètement réécrit dans la version 2012 avec pas moins de 400.000 lignes de JavaScript. Ce nouveau modèle a été pensé pour offrir de grandes...
Cliquez pour lire la suite de l'article par Philess SIMULER FACILEMENT L'ENVOI DE MAILSIMULER FACILEMENT L'ENVOI DE MAIL par JeremyJeanson
il m'a été demandé, à plusieurs reprises, comment je faisais pour simuler l'envoi de mail lors de mes démos de Workflow Foundation. Ma solution est plutôt simple : j'utilise la configuration par défaut du SmtpClient et j'oriente les mails vers un dossier ...
Cliquez pour lire la suite de l'article par JeremyJeanson VOTEZ POUR LE TOP 10 DES INFLUENCEURS SHAREPOINT FRANCOPHONES !VOTEZ POUR LE TOP 10 DES INFLUENCEURS SHAREPOINT FRANCOPHONES ! par Patrick Guimonet
Si ce n'est déjà fait (comme plus de 600 personnes déjà), il est encore temps de voter pour le concours TOP 10 des influenceurs SharePoint francophones ! Il est organisé par harmon.ie et accessible ici : http://harmon.ie/top-...
Cliquez pour lire la suite de l'article par Patrick Guimonet [CONF'SHAREPOINT] DERNIER RAPPEL ! :-)[CONF'SHAREPOINT] DERNIER RAPPEL ! :-) par Patrick Guimonet
La Conf'SharePoint en chiffres c'est : 3 jours de SharePoint ! 4 parcours et 60 sessions 17 partenaires représentant toutes les fac...
Cliquez pour lire la suite de l'article par Patrick Guimonet
Forum
PB PACMAN C++PB PACMAN C++ par garfield95
Cliquez pour lire la suite par garfield95
Logiciels
Easy-Planning (4.5.0.11)EASY-PLANNING (4.5.0.11)Easy-Planning permet de créer des plannings sous la représentation de diagrammes et est adapté a... Cliquez pour télécharger Easy-Planning CVEasy (3.1.0.51)CVEASY (3.1.0.51)PHMSD-CVEasy est un logiciel d'aide à la rédaction de CV d'une simplicité déconcertante.
PHMSD-C... Cliquez pour télécharger CVEasy LettresFaciles 2011 (8.6.0.31)LETTRESFACILES 2011 (8.6.0.31)LettresFaciles est un logiciel facilitant la création et la rédaction de lettres types.
Son inte... Cliquez pour télécharger LettresFaciles 2011 sDEVIS-FACTURES vlPRO (8.4.2.62)SDEVIS-FACTURES VLPRO (8.4.2.62)sDEVIS-FACTURES vlPRO a été mis au point pour les particuliers, créateurs, entrepreneurs, artisa... Cliquez pour télécharger sDEVIS-FACTURES vlPRO Devis-Factures PHMSD (2.1.0.11)DEVIS-FACTURES PHMSD (2.1.0.11)Configuration minimale
Nécessite Windows™ 2000, XP, Windows 7, 8, Vista (Service Pack à... Cliquez pour télécharger Devis-Factures PHMSD
|