/* * The Helium Toolkit * * Copyright (C) 1996-2000 Edouard Thiel * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License; see http://www.lif-sud.univ-mrs.fr/~thiel/helium/LICENSE */ /* * gui/xi.c - 10/07/1999 * * Calcule et affiche des Ximage. */ #include typedef union { Ulong l; Ushort s[2]; Uchar c[4]; } Ent421; static Ulong c_LUTR[256], c_LUTG[256], c_LUTB[256]; static int c_decaR, c_decaG, c_decaB, c_multR, c_multG, c_multB, c_bpp, c_byte, c_client_bo, c_server_bo, c_mode_lut, c_cas = 0, c_n0, c_n1, c_n2, c_n3; enum { C_ERROR, C_BPP8_LUT, C_BPP16_LUT, C_BPP24_LUT, C_BPP32_LUT, C_BPP24_RAW, C_BPP32_RAW }; static char *c_cas_strings[] = { "C_ERROR", "C_BPP8_LUT", "C_BPP16_LUT", "C_BPP24_LUT", "C_BPP32_LUT", "C_BPP24_RAW", "C_BPP32_RAW" }; /*------------------- I N T E R F A C E - P U B L I Q U E --------------------*/ /* * Cree une XImage */ XImage *HeCreateXi (int width, int height) { int size = width * height; XImage *xi = NULL; /* Création XImage v.2 p.170 * On met bitmap_pad = 8 systematiquement */ xi = XCreateImage (he_display, he_default_visual, he_default_depth, ZPixmap, 0, NULL, width, height, 8, 0); if (xi == NULL) return NULL; /* Allocation data */ xi->data = (char *) malloc (size * c_byte); if (xi->data == NULL) { HeError ("HeCreateXi: malloc error for %d bytes\n", size * c_byte); XDestroyImage (xi); return NULL; } return xi; } /* * Destruit une XImage */ void HeDestroyXi (XImage *xi) { /* Libère xi et xi->data v.2 p.196 */ if (xi != NULL) XDestroyImage (xi); } /* * Affiche xi en x, y */ void HePutXi (Window win, GC gc, XImage *xi, int x, int y) { /* Affichage image v.2 p.478 */ if (xi != NULL) XPutImage (he_display, win, gc, xi, 0, 0, x, y, xi->width, xi->height); } /* * Affiche une partie de xi en x, y * x,y sont les coordonnees dans win ; * sub_x, sub_y, sub_w, sub_h sont les coordonnees dans xi. */ void HePutSubXi(Window win, GC gc, XImage *xi, int x, int y, int sub_x, int sub_y, int sub_w, int sub_h) { /* Affichage image v.2 p.478 */ if (xi != NULL) XPutImage (he_display, win, gc, xi, sub_x, sub_y, x, y, sub_w < xi->width ? sub_w : xi->width, sub_h < xi->height ? sub_h : xi->height); } /* * Calcule xi->data a partir des images tabR, tabG, tabB. * Attention ces images doivent avoir exactement la meme taille que * a l'appel de HeCreateXi. */ void HeRGBtoXi (XImage *xi, Uchar *tabR, Uchar *tabG, Uchar *tabB) { int r, t, size; char *data; Ent421 val; if (xi == NULL || tabR == NULL || tabG == NULL || tabB == NULL) return; size = xi->width * xi->height; data = xi->data; /* Calcul data */ switch (c_cas) { case C_BPP8_LUT : for (t = 0; t < size; t++) { val.l = c_LUTR[tabR[t]] | c_LUTG[tabG[t]] | c_LUTB[tabB[t]]; data[t*c_byte ] = val.c[c_n0]; } break; case C_BPP16_LUT : for (t = 0; t < size; t++) { val.l = c_LUTR[tabR[t]] | c_LUTG[tabG[t]] | c_LUTB[tabB[t]]; r = t*c_byte; data[r ] = val.c[c_n0]; data[r+1] = val.c[c_n1]; } break; case C_BPP24_LUT : for (t = 0; t < size; t++) { val.l = c_LUTR[tabR[t]] | c_LUTG[tabG[t]] | c_LUTB[tabB[t]]; r = t*c_byte; data[r ] = val.c[c_n0]; data[r+1] = val.c[c_n1]; data[r+2] = val.c[c_n2]; } break; case C_BPP32_LUT : for (t = 0; t < size; t++) { val.l = c_LUTR[tabR[t]] | c_LUTG[tabG[t]] | c_LUTB[tabB[t]]; r = t*c_byte; data[r ] = val.c[c_n0]; data[r+1] = val.c[c_n1]; data[r+2] = val.c[c_n2]; data[r+3] = val.c[c_n3]; } break; case C_BPP24_RAW : for (t = 0; t < size; t++) { r = t*c_byte; data[r+c_n0] = tabR[t]; data[r+c_n1] = tabG[t]; data[r+c_n2] = tabB[t]; } break; case C_BPP32_RAW : for (t = 0; t < size; t++) { r = t*c_byte; data[r+c_n0] = tabR[t]; data[r+c_n1] = tabG[t]; data[r+c_n2] = tabB[t]; data[r+c_n3] = 0; } break; default : HeError ("HeRGBtoXi: case missed in switch\n"); } } /* * Colorie le fond de xi avec une couleur RGB. */ void HeSetXiBg (XImage *xi, Uchar R, Uchar G, Uchar B) { int r, t, size; char *data; Ent421 val; if (xi == NULL) return; size = xi->width * xi->height; data = xi->data; /* Calcul data */ switch (c_cas) { case C_BPP8_LUT : val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; for (t = 0; t < size; t++) { data[t*c_byte ] = val.c[c_n0]; } break; case C_BPP16_LUT : val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; for (t = 0; t < size; t++) { r = t*c_byte; data[r ] = val.c[c_n0]; data[r+1] = val.c[c_n1]; } break; case C_BPP24_LUT : val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; for (t = 0; t < size; t++) { r = t*c_byte; data[r ] = val.c[c_n0]; data[r+1] = val.c[c_n1]; data[r+2] = val.c[c_n2]; } break; case C_BPP32_LUT : val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; for (t = 0; t < size; t++) { r = t*c_byte; data[r ] = val.c[c_n0]; data[r+1] = val.c[c_n1]; data[r+2] = val.c[c_n2]; data[r+3] = val.c[c_n3]; } break; case C_BPP24_RAW : for (t = 0; t < size; t++) { r = t*c_byte; data[r+c_n0] = R; data[r+c_n1] = G; data[r+c_n2] = B; } break; case C_BPP32_RAW : for (t = 0; t < size; t++) { r = t*c_byte; data[r+c_n0] = R; data[r+c_n1] = G; data[r+c_n2] = B; data[r+c_n3] = 0; } break; default : HeError ("HeSetXiBg: case missed in switch\n"); } } /* * Change un pixel dans une XImage. * Attention, xi doit etre non NULL. * * L'adresse de la fonction est initialisee dans HeXiInit(). * * C'est 50% moins efficace que HeRGBtoXi sur toute une image, * mais cela evite d'allouer des images tabR, tabG, tabB. */ void (*HeSetXiPixel)(XImage *xi, int offset, Uchar R, Uchar G, Uchar B); /*-------------------- F O N C T I O N S - P R I V E E S ---------------------*/ /* * Fonctions dont l'une est affectee a HeSetXiPixel dans HeXiInit(). */ void HeSetXiPixel_BPP8_LUT (XImage *xi, int t, Uchar R, Uchar G, Uchar B) { Ent421 val; val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; xi->data[t*c_byte ] = val.c[c_n0]; } void HeSetXiPixel_BPP16_LUT (XImage *xi, int t, Uchar R, Uchar G, Uchar B) { int r = t*c_byte; Ent421 val; val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; xi->data[r ] = val.c[c_n0]; xi->data[r+1] = val.c[c_n1]; } void HeSetXiPixel_BPP24_LUT (XImage *xi, int t, Uchar R, Uchar G, Uchar B) { int r = t*c_byte; Ent421 val; val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; xi->data[r ] = val.c[c_n0]; xi->data[r+1] = val.c[c_n1]; xi->data[r+2] = val.c[c_n2]; } void HeSetXiPixel_BPP32_LUT (XImage *xi, int t, Uchar R, Uchar G, Uchar B) { int r = t*c_byte; Ent421 val; val.l = c_LUTR[R] | c_LUTG[G] | c_LUTB[B]; xi->data[r ] = val.c[c_n0]; xi->data[r+1] = val.c[c_n1]; xi->data[r+2] = val.c[c_n2]; xi->data[r+3] = val.c[c_n3]; } void HeSetXiPixel_BPP24_RAW (XImage *xi, int t, Uchar R, Uchar G, Uchar B) { int r = t*c_byte; xi->data[r+c_n0] = R; xi->data[r+c_n1] = G; xi->data[r+c_n2] = B; } void HeSetXiPixel_BPP32_RAW (XImage *xi, int t, Uchar R, Uchar G, Uchar B) { int r = t*c_byte; xi->data[r+c_n0] = R; xi->data[r+c_n1] = G; xi->data[r+c_n2] = B; xi->data[r+c_n3] = 0; } /* * Init du module : HeXiInit(FALSE); * * Dans le mode LUT, on utilise les précalculs sur les masques ; * dans le mode RAW, on recopie directement les octets (+ efficace, mais pas * toujours possible). */ void HeXiInit (int force_lut) { XImage *xi; int i; Ent421 val; /* On créé une XImage pour extraire des paramètres (v.2 p.170). */ xi = XCreateImage (he_display, he_default_visual, he_default_depth, ZPixmap, 0, NULL, 16, 16, 8, 0); if (xi == NULL) { HeError ("HeXiInit: can't create temporary XImage, init failed\n"); return; } c_bpp = xi->bits_per_pixel; c_byte = c_bpp / 8; HeXiAnalyseMask (xi->red_mask, &c_multR, &c_decaR); HeXiAnalyseMask (xi->green_mask, &c_multG, &c_decaG); HeXiAnalyseMask (xi->blue_mask, &c_multB, &c_decaB); /* * Calcul des LUT */ if (force_lut) c_mode_lut = 1; else c_mode_lut = (!(c_multR == 255 && c_multG == 255 && c_multB == 255)); if (c_mode_lut) for (i = 0; i < 256; i++) { c_LUTR[i] = (i * c_multR / 255) << c_decaR; c_LUTG[i] = (i * c_multG / 255) << c_decaG; c_LUTB[i] = (i * c_multB / 255) << c_decaB; } /* Calcul du cas */ switch (c_bpp) { case 8 : c_cas = C_BPP8_LUT; HeError ("HeXiInit: can't display XImages for depth <= 8\n"); break; case 16 : c_cas = C_BPP16_LUT; break; case 24 : c_cas = (c_mode_lut) ? C_BPP24_LUT : C_BPP24_RAW; break; case 32 : c_cas = (c_mode_lut) ? C_BPP32_LUT : C_BPP32_RAW; break; default : c_cas = C_ERROR; } /* Test du byte order : * LSBFirst = Little-endian = PC i86 : 0 1 2 3 * MSBFirst = Big-endian = SGI/Sun/Mac : 3 2 1 0 * * Non géré : le Middle ou PDP endian de DEC : 2 3 0 1 */ val.l = 1; c_client_bo = (val.c[0] == 1) ? LSBFirst : MSBFirst; c_server_bo = xi->byte_order; /* Calcul des constantes c_n0, .. c_n3 * * Attention, elles ne jouent pas le même rôle selon le mode : * - Mode LUT : numéros d'octets dans un long * - Mode RAW : offset dans data[] */ if (c_mode_lut) { /* Côté client, on numérote les octets dans un long */ if (c_client_bo == LSBFirst) { c_n0 = 0; c_n1 = 1; c_n2 = 2; c_n3 = 3; } else { c_n0 = 3; c_n1 = 2; c_n2 = 1; c_n3 = 0; } /* Côté server, on échange c_byte octets à mettre dans data */ if (c_server_bo == MSBFirst) HeXiPermuteN (&c_n0, &c_n1, &c_n2, &c_n3, c_byte); } else { /* On récupère la position de R,G,B dans le masque */ c_n0 = c_decaR/8; c_n1 = c_decaG/8; c_n2 = c_decaB/8; /* Position du 0 pour compléter, la somme faisant toujours 6 */ c_n3 = 6 - c_n0 - c_n1 - c_n2; /* Côté server, on soustrait les offsets à c_byte-1 */ if (c_server_bo == MSBFirst) { c_n0 = c_byte-1 - c_n0; c_n1 = c_byte-1 - c_n1; c_n2 = c_byte-1 - c_n2; c_n3 = c_byte-1 - c_n3; } } /* Detruit XImage temporaire */ XDestroyImage (xi); /* Choix de HeSetXiPixel() */ switch (c_cas) { case C_BPP8_LUT : HeSetXiPixel = HeSetXiPixel_BPP8_LUT ; break; case C_BPP16_LUT : HeSetXiPixel = HeSetXiPixel_BPP16_LUT; break; case C_BPP24_LUT : HeSetXiPixel = HeSetXiPixel_BPP24_LUT; break; case C_BPP32_LUT : HeSetXiPixel = HeSetXiPixel_BPP32_LUT; break; case C_BPP24_RAW : HeSetXiPixel = HeSetXiPixel_BPP24_RAW; break; case C_BPP32_RAW : HeSetXiPixel = HeSetXiPixel_BPP32_RAW; break; default : HeError ("HeXiInit: case missed in switch for HeSetXiPixel\n"); } } /* * Analyse un masque R, G ou B pour calculer mult et deca. */ void HeXiAnalyseMask (Ulong mask, int *mult, int *deca) { int i; for (i = 0; i < 32; i++) if (mask & 1L << i) break; *deca = i; *mult = mask >> i; } /* * Permute 2 entiers. */ void HeXiPermute2 (int *a, int *b) { int tmp; tmp = *a; *a = *b; *b = tmp; } /* * Permute les n 1ers entiers parmi a,b,c,d */ void HeXiPermuteN (int *a, int *b, int *c, int *d, int n) { switch (n) { case 2 : HeXiPermute2 (a, b); break; case 3 : HeXiPermute2 (a, c); break; case 4 : HeXiPermute2 (a, d); HeXiPermute2 (b, c); break; } } /* * Affiche infos de debugage */ void HeXiDebug () { printf ("HeXiDebug:\n"); printf (" client = %s ", c_client_bo == LSBFirst ? "PC" : "MAC"); printf (" server = %s\n", c_server_bo == LSBFirst ? "PC" : "MAC"); printf (" depth = %d bpp = %d bytes = %d\n", he_default_depth, c_bpp, c_byte); printf (" RGB = %d << %d %d << %d %d << %d\n", c_multR, c_decaR, c_multG, c_decaG, c_multB, c_decaB); printf (" cas = %s (%d %d %d %d)\n", c_cas_strings[c_cas], c_n0, c_n1, c_n2, c_n3); }