|
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) ![]() |
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 //