Modifications à apporter à Visu pour le support 24 bits

Notes générales

J'ai fait ces modifs chez moi sur mon propre programme. Ces modifs consistent à faire fonctionner visu en 8 et 24 bits. Attention, ce code est minimal. Normalement il faudrait passer par les Visual X11 pour déterminer avec exactitude dans quel mode on se trouve. Voir mon cours X11 sur la couleur.

Pour la suite du cours, lorsqu'on dessinera nous-même nos lignes et polygones, il faudra aussi modifier la fonctionaallocateBuffers du fichier graphics.c Voir la fin de ce document pour voir ma version. Mais le mieux est d'attendre le cours sur le tracé de lignes et polygones.

Dans le fichier graphics.c

/*----------------------------------------*/
void init_graphics(int Wsizex, int Wsizey)
/*----------------------------------------*/
/* Ouvre une fenetre graphique de taille Wsizex, Wsizey */
{
  XSetWindowAttributes WAttribs;
  unsigned long WMask;

  if((display=XOpenDisplay(display_name))==NULL) {
    fprintf(stderr,"fenetre de base: ne peut pas se connecter ");
    fprintf(stderr,"au serveur %s\n",XDisplayName(display_name));
    exit(-1);
  }

  /* Initialiser la taille de la fenetre */
  width  = Wsizex;
  height = Wsizey;

  /* Recuperer les informations concernant l'ecran (root window) sur
     lequel on va afficher notre application. Le numero de l'ecran
     par defaut s'obtient a l'aide de la macro DefaultScreen() */

  screen = DefaultScreen(display);
  root   = RootWindow(display, screen);
  depth  = XDefaultDepth(display, screen);
  visual = DefaultVisual(display, screen);
  black  = BlackPixel(display, screen);
  white  = WhitePixel(display, screen);

  /* Allocation du double buffer */
  db = XCreatePixmap(display, root, width, height, depth);

  /* COLOR MODE */
  /* creation d'une colormap privee en niveaux de gris */
  if (depth<=8) {
    cmap = XCreateColormap(display, root, visual, AllocAll);
    Lut_16M(display, cmap);
  }
  printf("Color mode on!\n");

  WAttribs.save_under = True;
  WAttribs.border_pixel = 0;
  WAttribs.colormap = cmap;
  WAttribs.override_redirect = False;
  WAttribs.backing_store = Always;

  WMask= CWBorderPixel | CWBackingStore | CWSaveUnder |
    CWOverrideRedirect | CWColormap ;

  win=XCreateWindow(display,
      root,
      0, 0,
      (unsigned int) width, (unsigned int) height,
      0,
      CopyFromParent,
      CopyFromParent,
      CopyFromParent,
      WMask,
      &WAttribs);

  get_GC_color(win, &gc);

  /* selection des evenements que l'on desirera traiter pour cette fenetre */
  XSelectInput(display, win, ExposureMask | KeyPressMask |
        ButtonPressMask | ButtonReleaseMask | StructureNotifyMask |
        PointerMotionMask);

  /* Pour le double buffer */
  gcbg = XCreateGC(display, root, 0, NULL);
  XSetForeground(display, gcbg, white);

  /* affichage (mapping) de la fenetre, on mappe les differentes
     fenetres juste avant la gestion des evenements */

  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);

  /* appel de la boucle principale */
  mainloop();

  freeBuffers(&cam);
}

NOTE : Je ne souviens pas a quoi ressemble la fonction suivante chez vous... Si on ne parle pas de memset, ne modifiez rien.

/*------------------------------*/
static void clear_double_buffer()
/*------------------------------*/
/* Efface le contenu du double buffer */

{
  if(cam.use_pixmap)
    XFillRectangle(display, db, gcbg, 0, 0, cam.resX, cam.resY);
  else {
    /* la couleur. 0 = ecran noir */
    if (depth<=8)
      cam.image=(char *)memset(cam.image, 0, sizeof(char)*cam.resX*cam.resY);
    else
      cam.image=(char *)memset(cam.image, 0, sizeof(char)*cam.resX*cam.resY*4);
  }
}

Remarques concernant la fonction suivante : la macro RGBTO24 se trouve dans color.h. La structure Color aussi.
Par rappot à la version que vous avez, on indique la couleur des faces à cette fonction en passant un pointeur sur un objet de cette structure

La macro RGBTOONE permet de trouver dans une colormap spécialement formée de 256 couleurs, la couleur la plus
proche de la couleur R,G,B passée en paramètre. Utile pour le support des écrans 8 bits et le tramage des couleurs
qui fera l'objet d'un prochain cours.

dans color.h rajouter : #define RGBTO24(r,g,b) ((((unsigned long)(r))<<16)|(((unsigned long)(g))<<8)|(b))

/*-----------------------------------------------------------------------*/
static void FillFace(PIXEL *A, PIXEL *B, PIXEL *C, PIXEL *D, Color *color)
/*-----------------------------------------------------------------------*/
/* Dessine la face definie par les sommets A,B,C,D, en mode plein.
   Si C == D alors il s'agit d'un triangle */
{
  XPoint point[4];

  if (depth<=8)
    XSetForeground(display, gc, RGBTOONE( color->r, color->g, color->b ) );
  else
    XSetForeground(display, gc, RGBTO24( color->r, color->g, color->b ) );

  point[0].x = A->x;
  point[0].y = A->y;
  point[1].x = B->x;
  point[1].y = B->y;

  if(C != D) {
    point[2].x = C->x;
    point[2].y = C->y;
    point[3].x = D->x;
    point[3].y = D->y;

    XFillPolygon(display, db, gc, point, 4, Convex, CoordModeOrigin);
  }
  else {
    point[2].x = C->x;
    point[2].y = C->y;

    XFillPolygon(display, db, gc, point, 3, Convex, CoordModeOrigin);
  }
}

Dans color.h

Rajouter : #define RGBTO24(r,g,b) ((((unsigned long)(r))<<16)|(((unsigned long)(g))<<8)|(b))
 

Modifs à faire ultérieurement

...si on veut utiliser des XImages pour tracer rapidement lignes et polygones en ayant le contrôle total des couleurs des pixels de chaque ligne ou polygone. Voici ma fonction allocateBuffers qui alloue une XImage, elles ne fonctionneront pas simplement si vous les collez à la place des votres, car elles dépendent des noms des champs que j'ai rajouté dans la structure Camera pour gèrer le Z-Buffer et les XImages.

/*---------------------------------------*/
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);

  Shm_OK=0; // Si on utilise la memoire partagee, ca plante!

  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 */
    if (depth<=8)
      cam->image = (char *) malloc(cam->resX * cam->resY * sizeof(char));
    else
      cam->image = (char *) malloc(cam->resX * cam->resY * sizeof(char) * 4);
 

    /* Allocation d'une XImage 8 ou 24 bits dont les données sont stockées dans le buffer cam->image qu'on vient
       juste d'allouer */
    if (depth<=8)
      Image = XCreateImage(display, visual, 8, ZPixmap , 0,
      cam->image, cam->resX, cam->resY,
      8, 0);
    else {
      Image = XCreateImage(display, visual, 24, ZPixmap , 0,
      cam->image, cam->resX, cam->resY,
      8, 0);
    }
     if (!cam->image) {
      perror("L'allocation de cam->image a echouee!\n");
      exit(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 */
    if (depth<=8)
      Image = XShmCreateImage(display, visual ,8, ZPixmap ,
       NULL, &Shminfo, cam->resX, cam->resY);
    else
      Image = XShmCreateImage(display, visual , 24, 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;
  }
}