rnd-19980906
[rocksndiamonds.git] / src / send.c
index e8f0ffd99879a79deb3d372e513cf2662d72bb65..56a65dc8efc527cb6f066f4201dcc6ea50ae3dc5 100644 (file)
@@ -22,8 +22,10 @@ Image *monochrome(Image *cimage)
   if (BITMAPP(cimage))
     return(NULL);
 
+  /*
   printf("  Converting to monochrome...");
   fflush(stdout);
+  */
 
   image= newBitImage(cimage->width, cimage->height);
   if (cimage->title)
@@ -59,7 +61,9 @@ Image *monochrome(Image *cimage)
     dp += dll; /* next row */
   }
 
+  /*
   printf("done\n");
+  */
 
   return(image);
 }
@@ -254,8 +258,10 @@ void compress(Image *image)
   if (!RGBP(image) || image->rgb.compressed)
     return;
 
+  /*
   printf("  Compressing colormap...");
   fflush(stdout);
+  */
 
   used = (unsigned char *)lcalloc(sizeof(unsigned char) * depthToColors(image->depth));
   dmask = (1 << image->depth) -1;      /* Mask any illegal bits for that depth */
@@ -335,6 +341,7 @@ void compress(Image *image)
   lfree(map);
   lfree(used);
 
+  /*
   if (badcount)
     printf("%d out-of-range pixels, ", badcount);
 
@@ -349,6 +356,7 @@ void compress(Image *image)
     printf("%d unique color%s\n",
           next_index, (next_index == 1 ? "" : "s"));
   }
+  */
 
   image->rgb.compressed= TRUE; /* don't do it again */
 }
@@ -413,71 +421,45 @@ static unsigned int bitsPerPixelAtDepth(Display *disp, int scrn,
   exit(1);
 }
 
-/*
-  visual: visual to use
-  ddepth: depth of the visual to use
-*/
-XImageInfo *imageToXImage(Display *disp,
-                         int scrn,
-                         Visual *visual,
-                         unsigned int ddepth,
-                         Image *image)
+XImageInfo *imageToXImage(Display *disp, int scrn, Visual *visual,
+                         unsigned int ddepth, Image *image)
 {
-  Pixel        *redvalue, *greenvalue, *bluevalue;
-  unsigned int  a, c=0, x, y, linelen, dpixlen, dbits;
-  XColor        xcolor;
-  XGCValues     gcv;
-  XImageInfo   *ximageinfo;
-  Image        *orig_image;
-
-  static Colormap our_default_cmap = 0;
-  static Pixel *our_default_index;
-  static int free_cmap_entries, max_cmap_entries;
-  int use_cmap_entry;
-
-  if (!our_default_cmap)
-  {
-#if 0
-    our_default_cmap = DefaultColormap(disp, scrn);
-#endif
-
-    our_default_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
-                                      visual, AllocNone);
-    our_default_index = (Pixel *)lmalloc(sizeof(Pixel) * NOFLASH_COLORS);
-
-    for (a=0; a<NOFLASH_COLORS; a++)   /* count entries we got */
-      if (!XAllocColorCells(disp, our_default_cmap, FALSE, NULL, 0,
-                           our_default_index + a, 1))
-       break;
-
-    free_cmap_entries = max_cmap_entries = a;
-
-    printf("We've got %d colormap entries.\n", free_cmap_entries);
+  static XColor xcolor_private[NOFLASH_COLORS];
+  static int colorcell_used[NOFLASH_COLORS];
+  static Colormap global_cmap = 0;
+  static Pixel *global_cmap_index;
+  static int num_cmap_entries, free_cmap_entries;
+  static private_cmap = FALSE;
+  Pixel *redvalue, *greenvalue, *bluevalue;
+  unsigned int a, c=0, x, y, linelen, dpixlen, dbits;
+  XColor xcolor;
+  XGCValues gcv;
+  XImageInfo *ximageinfo;
 
-    for(a=0; a<max_cmap_entries; a++)  /* copy default colors */
+  if (!global_cmap)
+  {
+    if (visual == DefaultVisual(disp, scrn))
+      global_cmap = DefaultColormap(disp, scrn);
+    else
     {
-      xcolor.pixel = *(our_default_index + a);
-      XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor);
-      XStoreColor(disp, our_default_cmap, &xcolor);
+      global_cmap = XCreateColormap(disp, RootWindow(disp, scrn),
+                                        visual, AllocNone);
+      private_cmap = TRUE;
     }
   }
 
-  xcolor.flags= DoRed | DoGreen | DoBlue;
-  redvalue= greenvalue= bluevalue= NULL;
-  orig_image= image;
-  ximageinfo= (XImageInfo *)lmalloc(sizeof(XImageInfo));
-  ximageinfo->disp= disp;
-  ximageinfo->scrn= scrn;
-  ximageinfo->depth= 0;
-  ximageinfo->drawable= None;
-  ximageinfo->index= NULL;
-  ximageinfo->rootimage= FALSE;        /* assume not */
-  ximageinfo->foreground= ximageinfo->background= 0;
-  ximageinfo->gc= NULL;
-  ximageinfo->ximage= NULL;
-
-  /* do color allocation
-   */
+  xcolor.flags = DoRed | DoGreen | DoBlue;
+  redvalue = greenvalue = bluevalue = NULL;
+  ximageinfo = (XImageInfo *)lmalloc(sizeof(XImageInfo));
+  ximageinfo->disp = disp;
+  ximageinfo->scrn = scrn;
+  ximageinfo->depth = 0;
+  ximageinfo->drawable = None;
+  ximageinfo->index = NULL;
+  ximageinfo->rootimage = FALSE;
+  ximageinfo->foreground = ximageinfo->background= 0;
+  ximageinfo->gc = NULL;
+  ximageinfo->ximage = NULL;
 
   switch (visual->class)
   {
@@ -490,19 +472,11 @@ XImageInfo *imageToXImage(Display *disp,
       unsigned int redbottom, greenbottom, bluebottom;
       unsigned int redtop, greentop, bluetop;
 
-      redvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
-      greenvalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
-      bluevalue= (Pixel *)lmalloc(sizeof(Pixel) * 256);
+      redvalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
+      greenvalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
+      bluevalue = (Pixel *)lmalloc(sizeof(Pixel) * 256);
 
-#if 1
-      if (visual == DefaultVisual(disp, scrn))
-       ximageinfo->cmap= DefaultColormap(disp, scrn);
-      else
-       ximageinfo->cmap= XCreateColormap(disp, RootWindow(disp, scrn),
-                                         visual, AllocNone);
-#else
-      ximageinfo->cmap = our_default_cmap;
-#endif
+      ximageinfo->cmap = global_cmap;
 
       retry_direct: /* tag we hit if a DirectColor allocation fails on
                     * default colormap */
@@ -510,8 +484,8 @@ XImageInfo *imageToXImage(Display *disp,
       /* calculate number of distinct colors in each band
        */
 
-      redcolors= greencolors= bluecolors= 1;
-      for (pixval= 1; pixval; pixval <<= 1)
+      redcolors = greencolors = bluecolors = 1;
+      for (pixval=1; pixval; pixval <<= 1)
       {
        if (pixval & visual->red_mask)
          redcolors <<= 1;
@@ -536,19 +510,19 @@ XImageInfo *imageToXImage(Display *disp,
       bluestep = 256 / bluecolors;
       redbottom = greenbottom = bluebottom = 0;
       redtop = greentop = bluetop = 0;
-      for (a= 0; a < visual->map_entries; a++)
+      for (a=0; a<visual->map_entries; a++)
       {
        if (redbottom < 256)
-         redtop= redbottom + redstep;
+         redtop = redbottom + redstep;
        if (greenbottom < 256)
-         greentop= greenbottom + greenstep;
+         greentop = greenbottom + greenstep;
        if (bluebottom < 256)
-         bluetop= bluebottom + bluestep;
+         bluetop = bluebottom + bluestep;
 
-       xcolor.red= (redtop - 1) << 8;
-       xcolor.green= (greentop - 1) << 8;
-       xcolor.blue= (bluetop - 1) << 8;
-       if (! XAllocColor(disp, ximageinfo->cmap, &xcolor))
+       xcolor.red = (redtop - 1) << 8;
+       xcolor.green = (greentop - 1) << 8;
+       xcolor.blue = (bluetop - 1) << 8;
+       if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
        {
          /* if an allocation fails for a DirectColor default visual then
           * we should create a private colormap and try again.
@@ -557,13 +531,10 @@ XImageInfo *imageToXImage(Display *disp,
          if ((visual->class == DirectColor) &&
              (visual == DefaultVisual(disp, scrn)))
          {
-#if 1
-           ximageinfo->cmap = XCreateColormap(disp, RootWindow(disp, scrn),
-                                              visual, AllocNone);
-#else
-           our_default_cmap = XCopyColormapAndFree(disp, our_default_cmap);
-           ximageinfo->cmap = our_default_cmap;
-#endif
+           global_cmap = XCopyColormapAndFree(disp, global_cmap);
+           ximageinfo->cmap = global_cmap;
+           private_cmap = TRUE;
+
            goto retry_direct;
          }
 
@@ -582,77 +553,152 @@ XImageInfo *imageToXImage(Display *disp,
         */
 
        while ((redbottom < 256) && (redbottom < redtop))
-         redvalue[redbottom++]= xcolor.pixel & visual->red_mask;
+         redvalue[redbottom++] = xcolor.pixel & visual->red_mask;
        while ((greenbottom < 256) && (greenbottom < greentop))
-         greenvalue[greenbottom++]= xcolor.pixel & visual->green_mask;
+         greenvalue[greenbottom++] = xcolor.pixel & visual->green_mask;
        while ((bluebottom < 256) && (bluebottom < bluetop))
-         bluevalue[bluebottom++]= xcolor.pixel & visual->blue_mask;
+         bluevalue[bluebottom++] = xcolor.pixel & visual->blue_mask;
       }
+      break;
     }
-    break;
 
-  default:     /* Not TrueColor or DirectColor */
+    case PseudoColor:
+
+      ximageinfo->cmap = global_cmap;
+      ximageinfo->index = (Pixel *)lmalloc(sizeof(Pixel) * image->rgb.used);
 
-    ximageinfo->index= (Pixel *)lmalloc(sizeof(Pixel) * (image->rgb.used+NOFLASH_COLORS));
+      for (a=0; a<image->rgb.used; a++)
+      {
+       XColor xcolor2;
+       unsigned short mask;
+       int color_found;
+       int i;
+  
+       xcolor.red = *(image->rgb.red + a);
+       xcolor.green = *(image->rgb.green + a);
+       xcolor.blue = *(image->rgb.blue + a);
+  
+       /* look if this color already exists in our colormap */
+       if (!XAllocColor(disp, ximageinfo->cmap, &xcolor))
+       {
+         if (!private_cmap)
+         {
+           /*
+           printf("switching to private colormap...\n");
+           */
+
+           /* we just filled up the default colormap -- get a private one
+              which contains all already allocated colors */
+
+           global_cmap = XCopyColormapAndFree(disp, global_cmap);
+           ximageinfo->cmap = global_cmap;
+           private_cmap = TRUE;
+
+           /* allocate the rest of the color cells read/write */
+           global_cmap_index =
+             (Pixel *)lmalloc(sizeof(Pixel) * NOFLASH_COLORS);
+           for (i=0; i<NOFLASH_COLORS; i++)
+             if (!XAllocColorCells(disp, global_cmap, FALSE, NULL, 0,
+                                   global_cmap_index + i, 1))
+               break;
+           num_cmap_entries = free_cmap_entries = i;
+
+           /*
+           printf("We've got %d free colormap entries.\n", free_cmap_entries);
+           */
+
+           /* to minimize colormap flashing, copy default colors and try
+              to keep them as near as possible to the old values */
+
+           for(i=0; i<num_cmap_entries; i++)
+           {
+             xcolor2.pixel = *(global_cmap_index + i);
+             XQueryColor(disp, DefaultColormap(disp, scrn), &xcolor2);
+             XStoreColor(disp, global_cmap, &xcolor2);
+             xcolor_private[xcolor2.pixel] = xcolor2;
+             colorcell_used[xcolor2.pixel] = FALSE;
+           }
 
+           /* now we have the default colormap private: all colors we
+              successfully allocated so far are read-only, which is okay,
+              because we don't want to change them anymore -- if we need
+              an existing color again, we get it by XAllocColor; all other
+              colors are read/write and we can set them by XStoreColor,
+              but we will try to overwrite those color cells with our new
+              color which are as close as possible to our new color */
+         }
 
-    /* get the colormap to use.
-     */
+         /* look for an existing default color close the one we want */
 
-    ximageinfo->cmap = our_default_cmap;
+         mask = 0xf000;
+         color_found = FALSE;
 
-    /* allocate colors shareable (if we can)
-     */
+         while (!color_found)
+         {
+           for (i=num_cmap_entries-1; i>=0; i--)
+           {
+             xcolor2.pixel = *(global_cmap_index + i);
+             xcolor2 = xcolor_private[xcolor2.pixel];
 
-    for (a= 0; a < image->rgb.used; a++)
-    {
-      int i;
-      XColor xcolor2;
+             if (colorcell_used[xcolor2.pixel])
+               continue;
 
-      xcolor.red= *(image->rgb.red + a);
-      xcolor.green= *(image->rgb.green + a);
-      xcolor.blue= *(image->rgb.blue + a);
+             if ((xcolor.red & mask) == (xcolor2.red & mask) &&
+                 (xcolor.green & mask) == (xcolor2.green & mask) &&
+                 (xcolor.blue & mask) == (xcolor2.blue & mask))
+             {
+               /*
+               printf("replacing color cell %ld with a close color\n",
+                      xcolor2.pixel);
+                      */
+               color_found = TRUE;
+               break;
+             }
+           }
 
-      for (i=max_cmap_entries-1; i>=free_cmap_entries; i--)
-      {
-       xcolor2.pixel = *(our_default_index + i);
-       XQueryColor(disp, ximageinfo->cmap, &xcolor2);
+           if (mask == 0x0000)
+             break;
 
-       if ((xcolor.red >> 8) == (xcolor2.red >> 8) &&
-           (xcolor.green >> 8) == (xcolor2.green >> 8) &&
-           (xcolor.blue >> 8) == (xcolor2.blue >> 8))
-         break;
-      }
+           mask = (mask << 1) & 0xffff;
+         }
 
-      use_cmap_entry = i;
+         if (!color_found)             /* no more free color cells */
+         {
+           printf("Sorry, cannot allocate enough colors!\n");
+           exit(0);
+         }
 
-      if (use_cmap_entry < free_cmap_entries)
-       free_cmap_entries--;
+         xcolor.pixel = xcolor2.pixel;
+         xcolor_private[xcolor.pixel] = xcolor;
+         colorcell_used[xcolor.pixel] = TRUE;
+         XStoreColor(disp, ximageinfo->cmap, &xcolor);
+         free_cmap_entries--;
+       }
 
-      if (free_cmap_entries < 0)
-      {
-       printf("imageToXImage: too many global colors!\n");
-       exit(0);
+       *(ximageinfo->index + a) = xcolor.pixel;
       }
 
-      xcolor.pixel = use_cmap_entry;
-      *(ximageinfo->index + a) = xcolor.pixel;
-      XStoreColor(disp, ximageinfo->cmap, &xcolor);
-    }
-
-    ximageinfo->no = a;    /* number of pixels allocated in default visual */
+      /*
+      printf("still %d free colormap entries\n", free_cmap_entries);
+      */
 
-    printf("still %d free colormap entries\n", free_cmap_entries);
+      ximageinfo->no = a;      /* number of pixels allocated for this image */
+      break;
+  
+    default:
+      printf("Sorry, only DirectColor, TrueColor and PseudoColor supported\n");
+      exit(0);
+      break;
   }
 
-
-
   /* create an XImage and related colormap based on the image type
    * we have.
    */
 
+  /*
   printf("  Building XImage...");
   fflush(stdout);
+  */
 
   switch (image->type)
   {
@@ -779,7 +825,9 @@ XImageInfo *imageToXImage(Display *disp,
     }
   }
 
+  /*
   printf("done\n");
+  */
 
   if (redvalue)
   {
@@ -788,8 +836,6 @@ XImageInfo *imageToXImage(Display *disp,
     lfree((byte *)bluevalue);
   }
 
-  if (image != orig_image)
-    freeImage(image);
   return(ximageinfo);
 }