|
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_image.cxx 8128 2010-12-28 15:17:23Z manolo $" 00003 // 00004 // Image drawing routines 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 // I hope a simple and portable method of drawing color and monochrome 00029 // images. To keep this simple, only a single storage type is 00030 // supported: 8 bit unsigned data, byte order RGB, and pixels are 00031 // stored packed into rows with the origin at the top-left. It is 00032 // possible to alter the size of pixels with the "delta" argument, to 00033 // add alpha or other information per pixel. It is also possible to 00034 // change the origin and direction of the image data by messing with 00035 // the "delta" and "linedelta", making them negative, though this may 00036 // defeat some of the shortcuts in translating the image for X. 00037 00038 #ifdef WIN32 00039 # include "fl_draw_image_win32.cxx" 00040 #elif defined(__APPLE__) 00041 # include "fl_draw_image_mac.cxx" 00042 #else 00043 00044 // A list of assumptions made about the X display: 00045 00046 // bits_per_pixel must be one of 8, 16, 24, 32. 00047 00048 // scanline_pad must be a power of 2 and greater or equal to 8. 00049 00050 // PsuedoColor visuals must have 8 bits_per_pixel (although the depth 00051 // may be less than 8). This is the only limitation that affects any 00052 // modern X displays, you can't use 12 or 16 bit colormaps. 00053 00054 // The mask bits in TrueColor visuals for each color are 00055 // contiguous and have at least one bit of each color. This 00056 // is not checked for. 00057 00058 // For 24 and 32 bit visuals there must be at least 8 bits of each color. 00059 00061 00062 # include <FL/Fl.H> 00063 # include <FL/fl_draw.H> 00064 # include <FL/x.H> 00065 # include "Fl_XColor.H" 00066 # include "flstring.h" 00067 00068 static XImage xi; // template used to pass info to X 00069 static int bytes_per_pixel; 00070 static int scanline_add; 00071 static int scanline_mask; 00072 00073 static void (*converter)(const uchar *from, uchar *to, int w, int delta); 00074 static void (*mono_converter)(const uchar *from, uchar *to, int w, int delta); 00075 00076 static int dir; // direction-alternator 00077 static int ri,gi,bi; // saved error-diffusion value 00078 00079 # if USE_COLORMAP 00080 00081 // 8-bit converter with error diffusion 00082 00083 static void color8_converter(const uchar *from, uchar *to, int w, int delta) { 00084 int r=ri, g=gi, b=bi; 00085 int d, td; 00086 if (dir) { 00087 dir = 0; 00088 from = from+(w-1)*delta; 00089 to = to+(w-1); 00090 d = -delta; 00091 td = -1; 00092 } else { 00093 dir = 1; 00094 d = delta; 00095 td = 1; 00096 } 00097 for (; w--; from += d, to += td) { 00098 r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; 00099 g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255; 00100 b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255; 00101 Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); 00102 Fl_XColor& xmap = fl_xmap[0][i]; 00103 if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);} 00104 r -= xmap.r; 00105 g -= xmap.g; 00106 b -= xmap.b; 00107 *to = uchar(xmap.pixel); 00108 } 00109 ri = r; gi = g; bi = b; 00110 } 00111 00112 static void mono8_converter(const uchar *from, uchar *to, int w, int delta) { 00113 int r=ri, g=gi, b=bi; 00114 int d, td; 00115 if (dir) { 00116 dir = 0; 00117 from = from+(w-1)*delta; 00118 to = to+(w-1); 00119 d = -delta; 00120 td = -1; 00121 } else { 00122 dir = 1; 00123 d = delta; 00124 td = 1; 00125 } 00126 for (; w--; from += d, to += td) { 00127 r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; 00128 g += from[0]; if (g < 0) g = 0; else if (g>255) g = 255; 00129 b += from[0]; if (b < 0) b = 0; else if (b>255) b = 255; 00130 Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); 00131 Fl_XColor& xmap = fl_xmap[0][i]; 00132 if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);} 00133 r -= xmap.r; 00134 g -= xmap.g; 00135 b -= xmap.b; 00136 *to = uchar(xmap.pixel); 00137 } 00138 ri = r; gi = g; bi = b; 00139 } 00140 00141 # endif 00142 00144 // 16 bit TrueColor converters with error diffusion 00145 // Cray computers have no 16-bit type, so we use character pointers 00146 // (which may be slow) 00147 00148 # ifdef U16 00149 # define OUTTYPE U16 00150 # define OUTSIZE 1 00151 # define OUTASSIGN(v) *t = v 00152 # else 00153 # define OUTTYPE uchar 00154 # define OUTSIZE 2 00155 # define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt) 00156 # endif 00157 00158 static void color16_converter(const uchar *from, uchar *to, int w, int delta) { 00159 OUTTYPE *t = (OUTTYPE *)to; 00160 int d, td; 00161 if (dir) { 00162 dir = 0; 00163 from = from+(w-1)*delta; 00164 t = t+(w-1)*OUTSIZE; 00165 d = -delta; 00166 td = -OUTSIZE; 00167 } else { 00168 dir = 1; 00169 d = delta; 00170 td = OUTSIZE; 00171 } 00172 int r=ri, g=gi, b=bi; 00173 for (; w--; from += d, t += td) { 00174 r = (r&~fl_redmask) +from[0]; if (r>255) r = 255; 00175 g = (g&~fl_greenmask)+from[1]; if (g>255) g = 255; 00176 b = (b&~fl_bluemask) +from[2]; if (b>255) b = 255; 00177 OUTASSIGN(( 00178 ((r&fl_redmask)<<fl_redshift)+ 00179 ((g&fl_greenmask)<<fl_greenshift)+ 00180 ((b&fl_bluemask)<<fl_blueshift) 00181 ) >> fl_extrashift); 00182 } 00183 ri = r; gi = g; bi = b; 00184 } 00185 00186 static void mono16_converter(const uchar *from,uchar *to,int w, int delta) { 00187 OUTTYPE *t = (OUTTYPE *)to; 00188 int d, td; 00189 if (dir) { 00190 dir = 0; 00191 from = from+(w-1)*delta; 00192 t = t+(w-1)*OUTSIZE; 00193 d = -delta; 00194 td = -OUTSIZE; 00195 } else { 00196 dir = 1; 00197 d = delta; 00198 td = OUTSIZE; 00199 } 00200 uchar mask = fl_redmask & fl_greenmask & fl_bluemask; 00201 int r=ri; 00202 for (; w--; from += d, t += td) { 00203 r = (r&~mask) + *from; if (r > 255) r = 255; 00204 uchar m = r&mask; 00205 OUTASSIGN(( 00206 (m<<fl_redshift)+ 00207 (m<<fl_greenshift)+ 00208 (m<<fl_blueshift) 00209 ) >> fl_extrashift); 00210 } 00211 ri = r; 00212 } 00213 00214 // special-case the 5r6g5b layout used by XFree86: 00215 00216 static void c565_converter(const uchar *from, uchar *to, int w, int delta) { 00217 OUTTYPE *t = (OUTTYPE *)to; 00218 int d, td; 00219 if (dir) { 00220 dir = 0; 00221 from = from+(w-1)*delta; 00222 t = t+(w-1)*OUTSIZE; 00223 d = -delta; 00224 td = -OUTSIZE; 00225 } else { 00226 dir = 1; 00227 d = delta; 00228 td = OUTSIZE; 00229 } 00230 int r=ri, g=gi, b=bi; 00231 for (; w--; from += d, t += td) { 00232 r = (r&7)+from[0]; if (r>255) r = 255; 00233 g = (g&3)+from[1]; if (g>255) g = 255; 00234 b = (b&7)+from[2]; if (b>255) b = 255; 00235 OUTASSIGN(((r&0xf8)<<8) + ((g&0xfc)<<3) + (b>>3)); 00236 } 00237 ri = r; gi = g; bi = b; 00238 } 00239 00240 static void m565_converter(const uchar *from,uchar *to,int w, int delta) { 00241 OUTTYPE *t = (OUTTYPE *)to; 00242 int d, td; 00243 if (dir) { 00244 dir = 0; 00245 from = from+(w-1)*delta; 00246 t = t+(w-1)*OUTSIZE; 00247 d = -delta; 00248 td = -OUTSIZE; 00249 } else { 00250 dir = 1; 00251 d = delta; 00252 td = OUTSIZE; 00253 } 00254 int r=ri; 00255 for (; w--; from += d, t += td) { 00256 r = (r&7) + *from; if (r > 255) r = 255; 00257 OUTASSIGN((r>>3) * 0x841); 00258 } 00259 ri = r; 00260 } 00261 00263 // 24bit TrueColor converters: 00264 00265 static void rgb_converter(const uchar *from, uchar *to, int w, int delta) { 00266 int d = delta-3; 00267 for (; w--; from += d) { 00268 *to++ = *from++; 00269 *to++ = *from++; 00270 *to++ = *from++; 00271 } 00272 } 00273 00274 static void bgr_converter(const uchar *from, uchar *to, int w, int delta) { 00275 for (; w--; from += delta) { 00276 uchar r = from[0]; 00277 uchar g = from[1]; 00278 *to++ = from[2]; 00279 *to++ = g; 00280 *to++ = r; 00281 } 00282 } 00283 00284 static void rrr_converter(const uchar *from, uchar *to, int w, int delta) { 00285 for (; w--; from += delta) { 00286 *to++ = *from; 00287 *to++ = *from; 00288 *to++ = *from; 00289 } 00290 } 00291 00293 // 32bit TrueColor converters on a 32 or 64-bit machine: 00294 00295 # ifdef U64 00296 # define STORETYPE U64 00297 # if WORDS_BIGENDIAN 00298 # define INNARDS32(f) \ 00299 U64 *t = (U64*)to; \ 00300 int w1 = (w+1)/2; \ 00301 for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = (i<<32)|(f);} 00302 # else 00303 # define INNARDS32(f) \ 00304 U64 *t = (U64*)to; \ 00305 int w1 = (w+1)/2; \ 00306 for (; w1--; from += delta) {U64 i=f; from+= delta; *t++ = ((U64)(f)<<32)|i;} 00307 # endif 00308 # else 00309 # define STORETYPE U32 00310 # define INNARDS32(f) \ 00311 U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f 00312 # endif 00313 00314 static void rgbx_converter(const uchar *from, uchar *to, int w, int delta) { 00315 INNARDS32((unsigned(from[0])<<24)+(from[1]<<16)+(from[2]<<8)); 00316 } 00317 00318 static void xbgr_converter(const uchar *from, uchar *to, int w, int delta) { 00319 INNARDS32((from[0])+(from[1]<<8)+(from[2]<<16)); 00320 } 00321 00322 static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) { 00323 INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2])); 00324 } 00325 00326 static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) { 00327 INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24)); 00328 } 00329 00330 static void rrrx_converter(const uchar *from, uchar *to, int w, int delta) { 00331 INNARDS32(unsigned(*from) * 0x1010100U); 00332 } 00333 00334 static void xrrr_converter(const uchar *from, uchar *to, int w, int delta) { 00335 INNARDS32(*from * 0x10101U); 00336 } 00337 00338 static void 00339 color32_converter(const uchar *from, uchar *to, int w, int delta) { 00340 INNARDS32( 00341 (from[0]<<fl_redshift)+(from[1]<<fl_greenshift)+(from[2]<<fl_blueshift)); 00342 } 00343 00344 static void 00345 mono32_converter(const uchar *from,uchar *to,int w, int delta) { 00346 INNARDS32( 00347 (*from << fl_redshift)+(*from << fl_greenshift)+(*from << fl_blueshift)); 00348 } 00349 00351 00352 static void figure_out_visual() { 00353 00354 fl_xpixel(FL_BLACK); // setup fl_redmask, etc, in fl_color.cxx 00355 fl_xpixel(FL_WHITE); // also make sure white is allocated 00356 00357 static XPixmapFormatValues *pfvlist; 00358 static int FL_NUM_pfv; 00359 if (!pfvlist) pfvlist = XListPixmapFormats(fl_display,&FL_NUM_pfv); 00360 XPixmapFormatValues *pfv; 00361 for (pfv = pfvlist; pfv < pfvlist+FL_NUM_pfv; pfv++) 00362 if (pfv->depth == fl_visual->depth) break; 00363 xi.format = ZPixmap; 00364 xi.byte_order = ImageByteOrder(fl_display); 00365 //i.bitmap_unit = 8; 00366 //i.bitmap_bit_order = MSBFirst; 00367 //i.bitmap_pad = 8; 00368 xi.depth = fl_visual->depth; 00369 xi.bits_per_pixel = pfv->bits_per_pixel; 00370 00371 if (xi.bits_per_pixel & 7) bytes_per_pixel = 0; // produce fatal error 00372 else bytes_per_pixel = xi.bits_per_pixel/8; 00373 00374 unsigned int n = pfv->scanline_pad/8; 00375 if (pfv->scanline_pad & 7 || (n&(n-1))) 00376 Fl::fatal("Can't do scanline_pad of %d",pfv->scanline_pad); 00377 if (n < sizeof(STORETYPE)) n = sizeof(STORETYPE); 00378 scanline_add = n-1; 00379 scanline_mask = -n; 00380 00381 # if USE_COLORMAP 00382 if (bytes_per_pixel == 1) { 00383 converter = color8_converter; 00384 mono_converter = mono8_converter; 00385 return; 00386 } 00387 if (!fl_visual->red_mask) 00388 Fl::fatal("Can't do %d bits_per_pixel colormap",xi.bits_per_pixel); 00389 # endif 00390 00391 // otherwise it is a TrueColor visual: 00392 00393 int rs = fl_redshift; 00394 int gs = fl_greenshift; 00395 int bs = fl_blueshift; 00396 00397 switch (bytes_per_pixel) { 00398 00399 case 2: 00400 // All 16-bit TrueColor visuals are supported on any machine with 00401 // 24 or more bits per integer. 00402 # ifdef U16 00403 xi.byte_order = WORDS_BIGENDIAN; 00404 # else 00405 xi.byte_order = 1; 00406 # endif 00407 if (rs == 11 && gs == 6 && bs == 0 && fl_extrashift == 3) { 00408 converter = c565_converter; 00409 mono_converter = m565_converter; 00410 } else { 00411 converter = color16_converter; 00412 mono_converter = mono16_converter; 00413 } 00414 break; 00415 00416 case 3: 00417 if (xi.byte_order) {rs = 16-rs; gs = 16-gs; bs = 16-bs;} 00418 if (rs == 0 && gs == 8 && bs == 16) { 00419 converter = rgb_converter; 00420 mono_converter = rrr_converter; 00421 } else if (rs == 16 && gs == 8 && bs == 0) { 00422 converter = bgr_converter; 00423 mono_converter = rrr_converter; 00424 } else { 00425 Fl::fatal("Can't do arbitrary 24bit color"); 00426 } 00427 break; 00428 00429 case 4: 00430 if ((xi.byte_order!=0) != WORDS_BIGENDIAN) 00431 {rs = 24-rs; gs = 24-gs; bs = 24-bs;} 00432 if (rs == 0 && gs == 8 && bs == 16) { 00433 converter = xbgr_converter; 00434 mono_converter = xrrr_converter; 00435 } else if (rs == 24 && gs == 16 && bs == 8) { 00436 converter = rgbx_converter; 00437 mono_converter = rrrx_converter; 00438 } else if (rs == 8 && gs == 16 && bs == 24) { 00439 converter = bgrx_converter; 00440 mono_converter = rrrx_converter; 00441 } else if (rs == 16 && gs == 8 && bs == 0) { 00442 converter = xrgb_converter; 00443 mono_converter = xrrr_converter; 00444 } else { 00445 xi.byte_order = WORDS_BIGENDIAN; 00446 converter = color32_converter; 00447 mono_converter = mono32_converter; 00448 } 00449 break; 00450 00451 default: 00452 Fl::fatal("Can't do %d bits_per_pixel",xi.bits_per_pixel); 00453 } 00454 00455 } 00456 00457 # define MAXBUFFER 0x40000 // 256k 00458 00459 static void innards(const uchar *buf, int X, int Y, int W, int H, 00460 int delta, int linedelta, int mono, 00461 Fl_Draw_Image_Cb cb, void* userdata) 00462 { 00463 if (!linedelta) linedelta = W*delta; 00464 00465 int dx, dy, w, h; 00466 fl_clip_box(X,Y,W,H,dx,dy,w,h); 00467 if (w<=0 || h<=0) return; 00468 dx -= X; 00469 dy -= Y; 00470 00471 if (!bytes_per_pixel) figure_out_visual(); 00472 xi.width = w; 00473 xi.height = h; 00474 00475 void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter; 00476 if (mono) conv = mono_converter; 00477 00478 // See if the data is already in the right format. Unfortunately 00479 // some 32-bit x servers (XFree86) care about the unknown 8 bits 00480 // and they must be zero. I can't confirm this for user-supplied 00481 // data, so the 32-bit shortcut is disabled... 00482 // This can set bytes_per_line negative if image is bottom-to-top 00483 // I tested it on Linux, but it may fail on other Xlib implementations: 00484 if (buf && ( 00485 # if 0 // set this to 1 to allow 32-bit shortcut 00486 delta == 4 && 00487 # if WORDS_BIGENDIAN 00488 conv == rgbx_converter 00489 # else 00490 conv == xbgr_converter 00491 # endif 00492 || 00493 # endif 00494 conv == rgb_converter && delta==3 00495 ) && !(linedelta&scanline_add)) { 00496 xi.data = (char *)(buf+delta*dx+linedelta*dy); 00497 xi.bytes_per_line = linedelta; 00498 00499 } else { 00500 int linesize = ((w*bytes_per_pixel+scanline_add)&scanline_mask)/sizeof(STORETYPE); 00501 int blocking = h; 00502 static STORETYPE *buffer; // our storage, always word aligned 00503 static long buffer_size; 00504 {int size = linesize*h; 00505 if (size > MAXBUFFER) { 00506 size = MAXBUFFER; 00507 blocking = MAXBUFFER/linesize; 00508 } 00509 if (size > buffer_size) { 00510 delete[] buffer; 00511 buffer_size = size; 00512 buffer = new STORETYPE[size]; 00513 }} 00514 xi.data = (char *)buffer; 00515 xi.bytes_per_line = linesize*sizeof(STORETYPE); 00516 if (buf) { 00517 buf += delta*dx+linedelta*dy; 00518 for (int j=0; j<h; ) { 00519 STORETYPE *to = buffer; 00520 int k; 00521 for (k = 0; j<h && k<blocking; k++, j++) { 00522 conv(buf, (uchar*)to, w, delta); 00523 buf += linedelta; 00524 to += linesize; 00525 } 00526 XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k); 00527 } 00528 } else { 00529 STORETYPE* linebuf = new STORETYPE[(W*delta+(sizeof(STORETYPE)-1))/sizeof(STORETYPE)]; 00530 for (int j=0; j<h; ) { 00531 STORETYPE *to = buffer; 00532 int k; 00533 for (k = 0; j<h && k<blocking; k++, j++) { 00534 cb(userdata, dx, dy+j, w, (uchar*)linebuf); 00535 conv((uchar*)linebuf, (uchar*)to, w, delta); 00536 to += linesize; 00537 } 00538 XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k); 00539 } 00540 00541 delete[] linebuf; 00542 } 00543 } 00544 } 00545 00546 void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ 00547 innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0); 00548 } 00549 void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data, 00550 int x, int y, int w, int h,int d) { 00551 innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); 00552 } 00553 void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ 00554 innards(buf,x,y,w,h,d,l,1,0,0); 00555 } 00556 void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data, 00557 int x, int y, int w, int h,int d) { 00558 innards(0,x,y,w,h,d,0,1,cb,data); 00559 } 00560 00561 void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { 00562 if (fl_visual->depth > 16) { 00563 fl_color(r,g,b); 00564 fl_rectf(x,y,w,h); 00565 } else { 00566 uchar c[3]; 00567 c[0] = r; c[1] = g; c[2] = b; 00568 innards(c,x,y,w,h,0,0,0,0,0); 00569 } 00570 } 00571 00572 #endif 00573 00574 // 00575 // End of "$Id: fl_draw_image.cxx 8128 2010-12-28 15:17:23Z manolo $". 00576 //