fltk 1.3.0rc3
About: FLTK (Fast Light Tool Kit) is a cross-platform C++ GUI toolkit for UNIX/Linux (X11), Microsoft Windows, and MacOS X. Release candidate.
  SfR Fresh Dox: fltk-1.3.0rc3-source.tar.gz ("inofficial" and yet experimental doxygen-generated source code documentation)  

fl_draw_pixmap.cxx

Go to the documentation of this file.
00001 //
00002 // "$Id: fl_draw_pixmap.cxx 8190 2011-01-05 10:21:45Z manolo $"
00003 //
00004 // Pixmap drawing code for the Fast Light Tool Kit (FLTK).
00005 //
00006 // Copyright 1998-2010 by Bill Spitzak and others.
00007 //
00008 // This library is free software; you can redistribute it and/or
00009 // modify it under the terms of the GNU Library General Public
00010 // License as published by the Free Software Foundation; either
00011 // version 2 of the License, or (at your option) any later version.
00012 //
00013 // This library is distributed in the hope that it will be useful,
00014 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 // Library General Public License for more details.
00017 //
00018 // You should have received a copy of the GNU Library General Public
00019 // License along with this library; if not, write to the Free Software
00020 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
00021 // USA.
00022 //
00023 // Please report all bugs and problems on the following page:
00024 //
00025 //     http://www.fltk.org/str.php
00026 //
00027 
00028 // Implemented without using the xpm library (which I can't use because
00029 // it interferes with the color cube used by fl_draw_image).
00030 // Current implementation is cheap and slow, and works best on a full-color
00031 // display.  Transparency is not handled, and colors are dithered to
00032 // the color cube.  Color index is achieved by adding the id
00033 // characters together!  Also mallocs a lot of temporary memory!
00034 // Notice that there is no pixmap file interface.  This is on purpose,
00035 // as I want to discourage programs that require support files to work.
00036 // All data needed by a program ui should be compiled in!!!
00037 
00038 #include <FL/Fl.H>
00039 #include <FL/fl_draw.H>
00040 #include <FL/x.H>
00041 #include <stdio.h>
00042 #include "flstring.h"
00043 
00044 static int ncolors, chars_per_pixel;
00045 
00055 int fl_measure_pixmap(/*const*/ char* const* data, int &w, int &h) {
00056   return fl_measure_pixmap((const char*const*)data,w,h);
00057 }
00058 
00063 int fl_measure_pixmap(const char * const *cdata, int &w, int &h) {
00064   int i = sscanf(cdata[0],"%d%d%d%d",&w,&h,&ncolors,&chars_per_pixel);
00065   if (i<4 || w<=0 || h<=0 ||
00066       (chars_per_pixel!=1 && chars_per_pixel!=2) ) return w=0;
00067   return 1;
00068 }
00069 
00070 #ifdef U64
00071 
00072 // The callback from fl_draw_image to get a row of data passes this:
00073 struct pixmap_data {
00074   int w, h;
00075   const uchar*const* data;
00076   union {
00077     U64 colors[256];
00078     U64* byte1[256];
00079   };
00080 };
00081 
00082 // callback for 1 byte per pixel:
00083 static void cb1(void*v, int x, int y, int w, uchar* buf) {
00084   pixmap_data& d = *(pixmap_data*)v;
00085   const uchar* p = d.data[y]+x;
00086   U64* q = (U64*)buf;
00087   for (int X=w; X>0; X-=2, p += 2) {
00088     if (X>1) {
00089 #  if WORDS_BIGENDIAN
00090       *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
00091 #  else
00092       *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
00093 #  endif
00094     } else {
00095 #  if WORDS_BIGENDIAN
00096       *q++ = d.colors[p[0]]<<32;
00097 #  else
00098       *q++ = d.colors[p[0]];
00099 #  endif
00100     }
00101   }
00102 }
00103 
00104 // callback for 2 bytes per pixel:
00105 static void cb2(void*v, int x, int y, int w, uchar* buf) {
00106   pixmap_data& d = *(pixmap_data*)v;
00107   const uchar* p = d.data[y]+2*x;
00108   U64* q = (U64*)buf;
00109   for (int X=w; X>0; X-=2) {
00110     U64* colors = d.byte1[*p++];
00111     int index = *p++;
00112     if (X>1) {
00113       U64* colors1 = d.byte1[*p++];
00114       int index1 = *p++;
00115 #  if WORDS_BIGENDIAN
00116       *q++ = (colors[index]<<32) | colors1[index1];
00117 #  else
00118       *q++ = (colors1[index1]<<32) | colors[index];
00119 #  endif
00120     } else {
00121 #  if WORDS_BIGENDIAN
00122       *q++ = colors[index]<<32;
00123 #  else
00124       *q++ = colors[index];
00125 #  endif
00126     }
00127   }
00128 }
00129 
00130 #else // U32
00131 
00132 // The callback from fl_draw_image to get a row of data passes this:
00133 struct pixmap_data {
00134   int w, h;
00135   const uchar*const* data;
00136   union {
00137     U32 colors[256];
00138     U32* byte1[256];
00139   };
00140 };
00141 
00142 // callback for 1 byte per pixel:
00143 static void cb1(void*v, int x, int y, int w, uchar* buf) {
00144   pixmap_data& d = *(pixmap_data*)v;
00145   const uchar* p = d.data[y]+x;
00146   U32* q = (U32*)buf;
00147   for (int X=w; X--;) *q++ = d.colors[*p++];
00148 }
00149 
00150 // callback for 2 bytes per pixel:
00151 static void cb2(void*v, int x, int y, int w, uchar* buf) {
00152   pixmap_data& d = *(pixmap_data*)v;
00153   const uchar* p = d.data[y]+2*x;
00154   U32* q = (U32*)buf;
00155   for (int X=w; X--;) {
00156     U32* colors = d.byte1[*p++];
00157     *q++ = colors[*p++];
00158   }
00159 }
00160 
00161 #endif // U64 else U32
00162 
00163 uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
00164 
00174 int fl_draw_pixmap(/*const*/ char* const* data, int x,int y,Fl_Color bg) {
00175   return fl_draw_pixmap((const char*const*)data,x,y,bg);
00176 }
00177 
00178 #ifdef WIN32
00179 // to compute an unused color to be used for the pixmap background
00180 FL_EXPORT UINT win_pixmap_bg_color; // the RGB() of the pixmap background color
00181 static int color_count; // # of non-transparent colors used in pixmap
00182 static uchar *used_colors; // used_colors[3*i+j] j=0,1,2 are the RGB values of the ith used color
00183 
00184 static void make_unused_color(uchar &r, uchar &g, uchar &b)
00185 // makes an RGB triplet different from all the colors used in the pixmap
00186 // and compute win_pixmap_bg_color from this triplet
00187 {
00188   int i;
00189   r = 2; g = 3; b = 4;
00190   while (1) {
00191     for ( i = 0; i < color_count; i++) {
00192       if(used_colors[3*i] == r && used_colors[3*i+1] == g && used_colors[3*i+2] == b) break;
00193       }
00194     if (i >= color_count) {
00195       free(used_colors);
00196       win_pixmap_bg_color = RGB(r, g, b);
00197       return;
00198       }
00199     if (r < 255) r++;
00200     else {
00201       r = 0;
00202       if (g < 255) g++;
00203       else {
00204         g = 0;
00205         b++;
00206         }
00207       }
00208     }
00209 }
00210 #endif
00211 
00216 int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
00217   pixmap_data d;
00218   if (!fl_measure_pixmap(cdata, d.w, d.h)) return 0;
00219   const uchar*const* data = (const uchar*const*)(cdata+1);
00220   int transparent_index = -1;
00221   uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
00222 #ifdef WIN32
00223   color_count = 0;
00224   used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar));
00225 #endif
00226 
00227   if (ncolors < 0) {    // FLTK (non standard) compressed colormap
00228     ncolors = -ncolors;
00229     const uchar *p = *data++;
00230     // if first color is ' ' it is transparent (put it later to make
00231     // it not be transparent):
00232     if (*p == ' ') {
00233       uchar* c = (uchar*)&d.colors[(int)' '];
00234 #ifdef U64
00235       *(U64*)c = 0;
00236 #  if WORDS_BIGENDIAN
00237       c += 4;
00238 #  endif
00239 #endif
00240       transparent_index = ' ';
00241       Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
00242       transparent_c = c;
00243       p += 4;
00244       ncolors--;
00245     }
00246     // read all the rest of the colors:
00247     for (int i=0; i < ncolors; i++) {
00248       uchar* c = (uchar*)&d.colors[*p++];
00249 #ifdef U64
00250       *(U64*)c = 0;
00251 #  if WORDS_BIGENDIAN
00252       c += 4;
00253 #  endif
00254 #endif
00255 #ifdef WIN32
00256       used_colors[3*color_count] = *p;
00257       used_colors[3*color_count+1] = *(p+1);
00258       used_colors[3*color_count+2] = *(p+2);
00259       color_count++;
00260 #endif
00261       *c++ = *p++;
00262       *c++ = *p++;
00263       *c++ = *p++;
00264 #ifdef __APPLE_QUARTZ__
00265       *c = 255;
00266 #else
00267       *c = 0;
00268 #endif
00269     }
00270   } else {      // normal XPM colormap with names
00271     if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1));
00272     for (int i=0; i<ncolors; i++) {
00273       const uchar *p = *data++;
00274       // the first 1 or 2 characters are the color index:
00275       int ind = *p++;
00276       uchar* c;
00277       if (chars_per_pixel>1) {
00278 #ifdef U64
00279         U64* colors = d.byte1[ind];
00280         if (!colors) colors = d.byte1[ind] = new U64[256];
00281 #else
00282         U32* colors = d.byte1[ind];
00283         if (!colors) colors = d.byte1[ind] = new U32[256];
00284 #endif
00285         c = (uchar*)&colors[*p];
00286         ind = (ind<<8)|*p++;
00287       } else {
00288         c = (uchar *)&d.colors[ind];
00289       }
00290       // look for "c word", or last word if none:
00291       const uchar *previous_word = p;
00292       for (;;) {
00293         while (*p && isspace(*p)) p++;
00294         uchar what = *p++;
00295         while (*p && !isspace(*p)) p++;
00296         while (*p && isspace(*p)) p++;
00297         if (!*p) {p = previous_word; break;}
00298         if (what == 'c') break;
00299         previous_word = p;
00300         while (*p && !isspace(*p)) p++;
00301       }
00302 #ifdef U64
00303       *(U64*)c = 0;
00304 #  if WORDS_BIGENDIAN
00305       c += 4;
00306 #  endif
00307 #endif
00308 #ifdef __APPLE_QUARTZ__
00309       c[3] = 255;
00310 #endif
00311       int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
00312       if (parse) {
00313 #ifdef WIN32
00314         used_colors[3*color_count] = c[0];
00315         used_colors[3*color_count+1] = c[1];
00316         used_colors[3*color_count+2] = c[2];
00317         color_count++;
00318 #endif
00319         }
00320       else {
00321         // assume "None" or "#transparent" for any errors
00322         // "bg" should be transparent...
00323         Fl::get_color(bg, c[0], c[1], c[2]);
00324 #ifdef __APPLE_QUARTZ__
00325         c[3] = 0;
00326 #endif
00327         transparent_index = ind;
00328         transparent_c = c;
00329       }
00330     }
00331   }
00332   d.data = data;
00333 #ifdef WIN32
00334   if (transparent_c) {
00335     make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
00336   }
00337   else {
00338     uchar r, g, b;
00339     make_unused_color(r, g, b);
00340   }
00341 #endif
00342   
00343 #ifdef  __APPLE_QUARTZ__
00344   if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
00345     bool transparent = (transparent_index>=0);
00346     transparent = true;
00347     U32 *array = new U32[d.w * d.h], *q = array;
00348     for (int Y = 0; Y < d.h; Y++) {
00349       const uchar* p = data[Y];
00350       if (chars_per_pixel <= 1) {
00351         for (int X = 0; X < d.w; X++) {
00352           *q++ = d.colors[*p++];
00353         }
00354       } else {
00355         for (int X = 0; X < d.w; X++) {
00356           U32* colors = (U32*)d.byte1[*p++];
00357           *q++ = colors[*p++];
00358         }
00359       }
00360     }
00361     CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
00362     CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L);
00363     CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w,
00364                                    lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast,
00365                                    src, 0L, false, kCGRenderingIntentDefault);
00366     CGColorSpaceRelease(lut);
00367     CGDataProviderRelease(src);
00368     CGRect rect = { { x, y} , { d.w, d.h } };
00369     Fl_X::q_begin_image(rect, 0, 0, d.w, d.h);
00370     CGContextDrawImage(fl_gc, rect, img);
00371     Fl_X::q_end_image();
00372     CGImageRelease(img);
00373     delete array;
00374     }
00375   else {
00376 #endif // __APPLE_QUARTZ__
00377 
00378   // build the mask bitmap used by Fl_Pixmap:
00379   if (fl_mask_bitmap && transparent_index >= 0) {
00380     int W = (d.w+7)/8;
00381     uchar* bitmap = new uchar[W * d.h];
00382     *fl_mask_bitmap = bitmap;
00383     for (int Y = 0; Y < d.h; Y++) {
00384       const uchar* p = data[Y];
00385       if (chars_per_pixel <= 1) {
00386         int dw = d.w;
00387         for (int X = 0; X < W; X++) {
00388           uchar b = (dw-->0 && *p++ != transparent_index);
00389           if (dw-->0 && *p++ != transparent_index) b |= 2;
00390           if (dw-->0 && *p++ != transparent_index) b |= 4;
00391           if (dw-->0 && *p++ != transparent_index) b |= 8;
00392           if (dw-->0 && *p++ != transparent_index) b |= 16;
00393           if (dw-->0 && *p++ != transparent_index) b |= 32;
00394           if (dw-->0 && *p++ != transparent_index) b |= 64;
00395           if (dw-->0 && *p++ != transparent_index) b |= 128;
00396           *bitmap++ = b;
00397         }
00398       } else {
00399         uchar b = 0, bit = 1;
00400         for (int X = 0; X < d.w; X++) {
00401           int ind = *p++;
00402           ind = (ind<<8) | (*p++);
00403           if (ind != transparent_index) b |= bit;
00404 
00405           if (bit < 128) bit <<= 1;
00406           else {
00407             *bitmap++ = b;
00408             b = 0;
00409             bit = 1;
00410           }
00411         }
00412 
00413         if (bit > 1) *bitmap++ = b;
00414       }
00415     }
00416   }
00417 
00418   fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4);
00419 #ifdef __APPLE_QUARTZ__
00420     }
00421 #endif
00422 
00423   if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i];
00424   return 1;
00425 }
00426 
00427 //
00428 // End of "$Id: fl_draw_pixmap.cxx 8190 2011-01-05 10:21:45Z manolo $".
00429 //