Jusqu'à présent nous avons utilisé pour nos routines de dessin (DrawFace et FillFace) des fonctions X-Window et nous avons toujours dessiné dans un double buffer de type Pixmap.
Les avantages de cette méthode sont multiples :
Bien sûr il est possible d'utiliser la fonction XDrawPoint pour dessiner les polygones pixels par pixels, mais dans ce cas, aussi rapide le serveur X11 soit-il, il faudra pour chaque pixel de chaque facette un appel de fonction, passer 5 ou 6 paramètres etc... Les performances ne seront plus au rendez-vous !
Pourquoi les XImages peuvent nous rendre service
Avec X11, on peut dessiner dans trois types d'objets : dans des Windows, dans des Pixmaps (zone mémoire utilisable comme une Window) et dans des XImages qui sont des buffers mémoires de type (char *) encapsulés par X11, et que l'on peut recopier dans des fenêtres pour les afficher.
Seules quelques macros sont utilisables, comme XPutPixel ou XGetPixel, mais nous n'allons pas les utiliser. Vous pouvez consulter le cours X11 sur les XImages.
Avantages des XImages
Voici les modifications que je vous propose.
Remarques pour les gens de la maîtrise d'informatique ou de l'ESSI
: ces modifications sont toutes issues du programme situé dans ~buffa/cours/minfo/infographie/mon_prog/mon_prog
pour les maîtrises d'informatique, dans ~/src/cours/infographie/prog_test
pour les gens de l'ESSI..
typedef struct CameraStruct { ... int render_mode; /* Mode de rendu : fil de fer, gouraud, etc... */ int use_pixmap; /* Utilisation d'un pixmap comme buffer image ? */ /* Z-Buffer et buffer image */ char *image; /* Buffer contenant l'image finale, associé à une XImage */ } Camera;
case 'w': cam->render_mode = WIREFRAME; cam->use_pixmap = TRUE; reset_GC_Colors(); draw_object(obj, cam, &lumiere); printf("Render mode = WIREFRAME\n"); break;
Includes
#include <X11/extensions/XShm.h> #include <sys/shm.h>Variables globales
XImage *Image; Pixmap db; Window win; long Shm_Hard_Buffer_Flag; /* flag et variable utiles pour l'allocation de Image en shared memory */ XShmSegmentInfo Shminfo;Dans init_graphics()
... XMapWindow(display,win); /* Allocation du pixmap pour la visu fil de fer et flat shading, et d'une XImage pour la visu gouraud, phong et textures */ AllocateBuffers(cam); ...La fonction AllocateBuffers
/*---------------------------------------*/ static void AllocateBuffers(Camera *cam) /*---------------------------------------*/ /* Allocation des buffers de visualisation. Normalement, pour une scene complete, il faudrait faire ca pour chaque camera.*/ { /* Pour la shared memory X11 */ int CompletionType; long Shm_OK; /* Allocation du double buffer pour les modes de rendus simples */ db = XCreatePixmap(display, root, cam->resX, cam->resY, depth); /* Allocation du buffer cam->image, en Shared Memory X11 si possible */ Shm_OK = XShmQueryExtension(display); switch(Shm_OK) { case 0: /* On a pas pas pu allouer de Shared memory. On alloue donc le Z-Buffer manuellement a l'aide d'un malloc */ /* Allocation d'un buffer 8 bits */ cam->image = (char *) malloc(cam->resX * cam->resY * sizeof(char)); if (!cam->image) { perror("L'allocation de cam->image a echouee!\n"); exit(0); } /* Allocation d'une XImage 8 bits */ Image = XCreateImage(display, visual, 8, ZPixmap , 0, cam->image, cam->resX, cam->resY, 8, 0); /* Flag qui indique qu'on a pas alloue la Shared Memory */ Shm_Hard_Buffer_Flag = False; printf("Je n'ai pas reussi a allouer la Shared memory X11!\n"); break; case 1: /* On a pu allouer la Shared memory. Le Z-Buffer va donc se trouver dans cette zone */ Image = XShmCreateImage(display, visual ,8, ZPixmap , NULL, &Shminfo, cam->resX, cam->resY); Shminfo.shmid = shmget(IPC_PRIVATE, cam->resX * cam->resY * sizeof(char), IPC_CREAT | 0777); Shminfo.shmaddr = Image->data = cam->image = shmat(Shminfo.shmid, NULL, 0); if (!cam->image) { printf("Je n'ai pas reussi a allouer la Shared memory X11!\n"); exit(0); } else printf("Shared memory X11 allouee!\n"); Shminfo.readOnly = False; XShmAttach(display, &Shminfo); Shm_Hard_Buffer_Flag = True; CompletionType = XShmGetEventBase(display) + ShmCompletion; break; } }La fonction de désallocation (à appeler lors de la sortie du programme)
/*------------------------*/ void close_graphics(Camera *cam) /*------------------------*/ /* Libere les ressources allouees */ { switch (Shm_Hard_Buffer_Flag) { case True: { printf("Liberation de la memoire partagee\n"); XShmDetach(display, &Shminfo); XDestroyImage(Image); shmdt(Shminfo.shmaddr); shmctl(Shminfo.shmid, IPC_RMID, 0); break; } case False: { /* Le buffer image */ free(cam->image); XDestroyImage(Image); break; } } XCloseDisplay(display); }Dans mainloop()
... case 'q': close_graphics(cam); exit(1); break; ...Autres fonctions impliquées :
if(cam->use_pixmap)
XFillRectangle(display, db, gcbg,
0, 0, cam->resX, cam->resY);
else
/* la couleur. 0 = ecran noir */
cam->image = (char *)
memset(cam->image, 0, sizeof(char) *
cam->ResX
* cam->ResY);
}
/*---------------------------------*/
display_double_buffer(Camera *cam)
/*---------------------------------*/
/* Recopie le double buffer dans la fenetre graphique
*/
{
if(cam->use_pixmap)
XCopyArea(display, db, win, gc, 0,
0, cam->resX, cam->resY, 0, 0);
else {
if(Shm_Hard_Buffer_Flag) {
XShmPutImage(display,win,gc,Image,0,0,0,0,cam->resX,
cam->resY,NULL);
}
else {
XPutImage(display,win,gc,Image,0,0,0,0,cam->resX,
cam->resY);
}
}
XFlush(display);