1 //
2 // "$Id$"
3 //
4 // Image drawing routines for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2010 by Bill Spitzak and others.
7 //
8 // This library is free software. Distribution and use rights are outlined in
9 // the file "COPYING" which should have been included with this file.  If this
10 // file is missing or damaged, see the license at:
11 //
12 //     http://www.fltk.org/COPYING.php
13 //
14 // Please report all bugs and problems on the following page:
15 //
16 //     http://www.fltk.org/str.php
17 //
18 
19 // I hope a simple and portable method of drawing color and monochrome
20 // images.  To keep this simple, only a single storage type is
21 // supported: 8 bit unsigned data, byte order RGB, and pixels are
22 // stored packed into rows with the origin at the top-left.  It is
23 // possible to alter the size of pixels with the "delta" argument, to
24 // add alpha or other information per pixel.  It is also possible to
25 // change the origin and direction of the image data by messing with
26 // the "delta" and "linedelta", making them negative, though this may
27 // defeat some of the shortcuts in translating the image for X.
28 
29 #ifdef WIN32
30 #  include "fl_draw_image_win32.cxx"
31 #elif defined(__APPLE__)
32 #  include "fl_draw_image_mac.cxx"
33 #else
34 
35 // A list of assumptions made about the X display:
36 
37 // bits_per_pixel must be one of 8, 16, 24, 32.
38 
39 // scanline_pad must be a power of 2 and greater or equal to 8.
40 
41 // PsuedoColor visuals must have 8 bits_per_pixel (although the depth
42 // may be less than 8).  This is the only limitation that affects any
43 // modern X displays, you can't use 12 or 16 bit colormaps.
44 
45 // The mask bits in TrueColor visuals for each color are
46 // contiguous and have at least one bit of each color.  This
47 // is not checked for.
48 
49 // For 24 and 32 bit visuals there must be at least 8 bits of each color.
50 
51 ////////////////////////////////////////////////////////////////
52 
53 #  include <FL/Fl.H>
54 #  include <FL/fl_draw.H>
55 #  include <FL/x.H>
56 #  include "Fl_XColor.H"
57 #  include "flstring.h"
58 
59 static XImage xi;	// template used to pass info to X
60 static int bytes_per_pixel;
61 static int scanline_add;
62 static int scanline_mask;
63 
64 static void (*converter)(const uchar *from, uchar *to, int w, int delta);
65 static void (*mono_converter)(const uchar *from, uchar *to, int w, int delta);
66 
67 static int dir;		// direction-alternator
68 static int ri,gi,bi;	// saved error-diffusion value
69 
70 #  if USE_COLORMAP
71 ////////////////////////////////////////////////////////////////
72 // 8-bit converter with error diffusion
73 
color8_converter(const uchar * from,uchar * to,int w,int delta)74 static void color8_converter(const uchar *from, uchar *to, int w, int delta) {
75   int r=ri, g=gi, b=bi;
76   int d, td;
77   if (dir) {
78     dir = 0;
79     from = from+(w-1)*delta;
80     to = to+(w-1);
81     d = -delta;
82     td = -1;
83   } else {
84     dir = 1;
85     d = delta;
86     td = 1;
87   }
88   for (; w--; from += d, to += td) {
89     r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
90     g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255;
91     b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255;
92     Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
93     Fl_XColor& xmap = fl_xmap[0][i];
94     if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
95     r -= xmap.r;
96     g -= xmap.g;
97     b -= xmap.b;
98     *to = uchar(xmap.pixel);
99   }
100   ri = r; gi = g; bi = b;
101 }
102 
mono8_converter(const uchar * from,uchar * to,int w,int delta)103 static void mono8_converter(const uchar *from, uchar *to, int w, int delta) {
104   int r=ri, g=gi, b=bi;
105   int d, td;
106   if (dir) {
107     dir = 0;
108     from = from+(w-1)*delta;
109     to = to+(w-1);
110     d = -delta;
111     td = -1;
112   } else {
113     dir = 1;
114     d = delta;
115     td = 1;
116   }
117   for (; w--; from += d, to += td) {
118     r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
119     g += from[0]; if (g < 0) g = 0; else if (g>255) g = 255;
120     b += from[0]; if (b < 0) b = 0; else if (b>255) b = 255;
121     Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
122     Fl_XColor& xmap = fl_xmap[0][i];
123     if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
124     r -= xmap.r;
125     g -= xmap.g;
126     b -= xmap.b;
127     *to = uchar(xmap.pixel);
128   }
129   ri = r; gi = g; bi = b;
130 }
131 
132 #  endif
133 
134 ////////////////////////////////////////////////////////////////
135 // 16 bit TrueColor converters with error diffusion
136 // Cray computers have no 16-bit type, so we use character pointers
137 // (which may be slow)
138 
139 #  ifdef U16
140 #    define OUTTYPE U16
141 #    define OUTSIZE 1
142 #    define OUTASSIGN(v) *t = v
143 #  else
144 #    define OUTTYPE uchar
145 #    define OUTSIZE 2
146 #    define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt)
147 #  endif
148 
color16_converter(const uchar * from,uchar * to,int w,int delta)149 static void color16_converter(const uchar *from, uchar *to, int w, int delta) {
150   OUTTYPE *t = (OUTTYPE *)to;
151   int d, td;
152   if (dir) {
153     dir = 0;
154     from = from+(w-1)*delta;
155     t = t+(w-1)*OUTSIZE;
156     d = -delta;
157     td = -OUTSIZE;
158   } else {
159     dir = 1;
160     d = delta;
161     td = OUTSIZE;
162   }
163   int r=ri, g=gi, b=bi;
164   for (; w--; from += d, t += td) {
165     r = (r&~fl_redmask)  +from[0]; if (r>255) r = 255;
166     g = (g&~fl_greenmask)+from[1]; if (g>255) g = 255;
167     b = (b&~fl_bluemask) +from[2]; if (b>255) b = 255;
168     OUTASSIGN((
169       ((r&fl_redmask)<<fl_redshift)+
170       ((g&fl_greenmask)<<fl_greenshift)+
171       ((b&fl_bluemask)<<fl_blueshift)
172       ) >> fl_extrashift);
173   }
174   ri = r; gi = g; bi = b;
175 }
176 
mono16_converter(const uchar * from,uchar * to,int w,int delta)177 static void mono16_converter(const uchar *from,uchar *to,int w, int delta) {
178   OUTTYPE *t = (OUTTYPE *)to;
179   int d, td;
180   if (dir) {
181     dir = 0;
182     from = from+(w-1)*delta;
183     t = t+(w-1)*OUTSIZE;
184     d = -delta;
185     td = -OUTSIZE;
186   } else {
187     dir = 1;
188     d = delta;
189     td = OUTSIZE;
190   }
191   uchar mask = fl_redmask & fl_greenmask & fl_bluemask;
192   int r=ri;
193   for (; w--; from += d, t += td) {
194     r = (r&~mask) + *from; if (r > 255) r = 255;
195     uchar m = r&mask;
196     OUTASSIGN((
197       (m<<fl_redshift)+
198       (m<<fl_greenshift)+
199       (m<<fl_blueshift)
200       ) >> fl_extrashift);
201   }
202   ri = r;
203 }
204 
205 // special-case the 5r6g5b layout used by XFree86:
206 
c565_converter(const uchar * from,uchar * to,int w,int delta)207 static void c565_converter(const uchar *from, uchar *to, int w, int delta) {
208   OUTTYPE *t = (OUTTYPE *)to;
209   int d, td;
210   if (dir) {
211     dir = 0;
212     from = from+(w-1)*delta;
213     t = t+(w-1)*OUTSIZE;
214     d = -delta;
215     td = -OUTSIZE;
216   } else {
217     dir = 1;
218     d = delta;
219     td = OUTSIZE;
220   }
221   int r=ri, g=gi, b=bi;
222   for (; w--; from += d, t += td) {
223     r = (r&7)+from[0]; if (r>255) r = 255;
224     g = (g&3)+from[1]; if (g>255) g = 255;
225     b = (b&7)+from[2]; if (b>255) b = 255;
226     OUTASSIGN(((r&0xf8)<<8) + ((g&0xfc)<<3) + (b>>3));
227   }
228   ri = r; gi = g; bi = b;
229 }
230 
m565_converter(const uchar * from,uchar * to,int w,int delta)231 static void m565_converter(const uchar *from,uchar *to,int w, int delta) {
232   OUTTYPE *t = (OUTTYPE *)to;
233   int d, td;
234   if (dir) {
235     dir = 0;
236     from = from+(w-1)*delta;
237     t = t+(w-1)*OUTSIZE;
238     d = -delta;
239     td = -OUTSIZE;
240   } else {
241     dir = 1;
242     d = delta;
243     td = OUTSIZE;
244   }
245   int r=ri;
246   for (; w--; from += d, t += td) {
247     r = (r&7) + *from; if (r > 255) r = 255;
248     OUTASSIGN((r>>3) * 0x841);
249   }
250   ri = r;
251 }
252 
253 ////////////////////////////////////////////////////////////////
254 // 24bit TrueColor converters:
255 
rgb_converter(const uchar * from,uchar * to,int w,int delta)256 static void rgb_converter(const uchar *from, uchar *to, int w, int delta) {
257   int d = delta-3;
258   for (; w--; from += d) {
259     *to++ = *from++;
260     *to++ = *from++;
261     *to++ = *from++;
262   }
263 }
264 
bgr_converter(const uchar * from,uchar * to,int w,int delta)265 static void bgr_converter(const uchar *from, uchar *to, int w, int delta) {
266   for (; w--; from += delta) {
267     uchar r = from[0];
268     uchar g = from[1];
269     *to++ = from[2];
270     *to++ = g;
271     *to++ = r;
272   }
273 }
274 
rrr_converter(const uchar * from,uchar * to,int w,int delta)275 static void rrr_converter(const uchar *from, uchar *to, int w, int delta) {
276   for (; w--; from += delta) {
277     *to++ = *from;
278     *to++ = *from;
279     *to++ = *from;
280   }
281 }
282 
283 ////////////////////////////////////////////////////////////////
284 // 32bit TrueColor converters on a 32 or 64-bit machine:
285 
286 #  ifdef U64
287 #    define STORETYPE U64
288 #    if WORDS_BIGENDIAN
289 #      define INNARDS32(f) \
290   U64 *t = (U64*)to; \
291   int w1 = w/2; \
292   for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = (i<<32)|(f);} \
293   if (w&1) *t++ = (U64)(f)<<32;
294 #    else
295 #      define INNARDS32(f) \
296   U64 *t = (U64*)to; \
297   int w1 = w/2; \
298   for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = ((U64)(f)<<32)|i;} \
299   if (w&1) *t++ = (U64)(f);
300 #    endif
301 #  else
302 #    define STORETYPE U32
303 #    define INNARDS32(f) \
304   U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f
305 #  endif
306 
rgbx_converter(const uchar * from,uchar * to,int w,int delta)307 static void rgbx_converter(const uchar *from, uchar *to, int w, int delta) {
308   INNARDS32((unsigned(from[0])<<24)+(from[1]<<16)+(from[2]<<8));
309 }
310 
xbgr_converter(const uchar * from,uchar * to,int w,int delta)311 static void xbgr_converter(const uchar *from, uchar *to, int w, int delta) {
312   INNARDS32((from[0])+(from[1]<<8)+(from[2]<<16));
313 }
314 
xrgb_converter(const uchar * from,uchar * to,int w,int delta)315 static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) {
316   INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2]));
317 }
318 
argb_premul_converter(const uchar * from,uchar * to,int w,int delta)319 static void argb_premul_converter(const uchar *from, uchar *to, int w, int delta) {
320   INNARDS32((unsigned(from[3]) << 24) +
321              (((from[0] * from[3]) / 255) << 16) +
322              (((from[1] * from[3]) / 255) << 8) +
323              ((from[2] * from[3]) / 255));
324 }
325 
bgrx_converter(const uchar * from,uchar * to,int w,int delta)326 static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) {
327   INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24));
328 }
329 
rrrx_converter(const uchar * from,uchar * to,int w,int delta)330 static void rrrx_converter(const uchar *from, uchar *to, int w, int delta) {
331   INNARDS32(unsigned(*from) * 0x1010100U);
332 }
333 
xrrr_converter(const uchar * from,uchar * to,int w,int delta)334 static void xrrr_converter(const uchar *from, uchar *to, int w, int delta) {
335   INNARDS32(*from * 0x10101U);
336 }
337 
338 static void
color32_converter(const uchar * from,uchar * to,int w,int delta)339 color32_converter(const uchar *from, uchar *to, int w, int delta) {
340   INNARDS32(
341     (from[0]<<fl_redshift)+(from[1]<<fl_greenshift)+(from[2]<<fl_blueshift));
342 }
343 
344 static void
mono32_converter(const uchar * from,uchar * to,int w,int delta)345 mono32_converter(const uchar *from,uchar *to,int w, int delta) {
346   INNARDS32(
347     (*from << fl_redshift)+(*from << fl_greenshift)+(*from << fl_blueshift));
348 }
349 
350 ////////////////////////////////////////////////////////////////
351 
figure_out_visual()352 static void figure_out_visual() {
353 
354   fl_xpixel(FL_BLACK); // setup fl_redmask, etc, in fl_color.cxx
355   fl_xpixel(FL_WHITE); // also make sure white is allocated
356 
357   static XPixmapFormatValues *pfvlist;
358   static int FL_NUM_pfv;
359   if (!pfvlist) pfvlist = XListPixmapFormats(fl_display,&FL_NUM_pfv);
360   XPixmapFormatValues *pfv;
361   for (pfv = pfvlist; pfv < pfvlist+FL_NUM_pfv; pfv++)
362     if (pfv->depth == fl_visual->depth) break;
363   xi.format = ZPixmap;
364   xi.byte_order = ImageByteOrder(fl_display);
365 //i.bitmap_unit = 8;
366 //i.bitmap_bit_order = MSBFirst;
367 //i.bitmap_pad = 8;
368   xi.depth = fl_visual->depth;
369   xi.bits_per_pixel = pfv->bits_per_pixel;
370 
371   if (xi.bits_per_pixel & 7) bytes_per_pixel = 0; // produce fatal error
372   else bytes_per_pixel = xi.bits_per_pixel/8;
373 
374   unsigned int n = pfv->scanline_pad/8;
375   if (pfv->scanline_pad & 7 || (n&(n-1)))
376     Fl::fatal("Can't do scanline_pad of %d",pfv->scanline_pad);
377   if (n < sizeof(STORETYPE)) n = sizeof(STORETYPE);
378   scanline_add = n-1;
379   scanline_mask = -n;
380 
381 #  if USE_COLORMAP
382   if (bytes_per_pixel == 1) {
383     converter = color8_converter;
384     mono_converter = mono8_converter;
385     return;
386   }
387   if (!fl_visual->red_mask)
388     Fl::fatal("Can't do %d bits_per_pixel colormap",xi.bits_per_pixel);
389 #  endif
390 
391   // otherwise it is a TrueColor visual:
392 
393   int rs = fl_redshift;
394   int gs = fl_greenshift;
395   int bs = fl_blueshift;
396 
397   switch (bytes_per_pixel) {
398 
399   case 2:
400     // All 16-bit TrueColor visuals are supported on any machine with
401     // 24 or more bits per integer.
402 #  ifdef U16
403     xi.byte_order = WORDS_BIGENDIAN;
404 #  else
405     xi.byte_order = 1;
406 #  endif
407     if (rs == 11 && gs == 6 && bs == 0 && fl_extrashift == 3) {
408       converter = c565_converter;
409       mono_converter = m565_converter;
410     } else {
411       converter = color16_converter;
412       mono_converter = mono16_converter;
413     }
414     break;
415 
416   case 3:
417     if (xi.byte_order) {rs = 16-rs; gs = 16-gs; bs = 16-bs;}
418     if (rs == 0 && gs == 8 && bs == 16) {
419       converter = rgb_converter;
420       mono_converter = rrr_converter;
421     } else if (rs == 16 && gs == 8 && bs == 0) {
422       converter = bgr_converter;
423       mono_converter = rrr_converter;
424     } else {
425       Fl::fatal("Can't do arbitrary 24bit color");
426     }
427     break;
428 
429   case 4:
430     if ((xi.byte_order!=0) != WORDS_BIGENDIAN)
431       {rs = 24-rs; gs = 24-gs; bs = 24-bs;}
432     if (rs == 0 && gs == 8 && bs == 16) {
433       converter = xbgr_converter;
434       mono_converter = xrrr_converter;
435     } else if (rs == 24 && gs == 16 && bs == 8) {
436       converter = rgbx_converter;
437       mono_converter = rrrx_converter;
438     } else if (rs == 8 && gs == 16 && bs == 24) {
439       converter = bgrx_converter;
440       mono_converter = rrrx_converter;
441     } else if (rs == 16 && gs == 8 && bs == 0) {
442       converter = xrgb_converter;
443       mono_converter = xrrr_converter;
444     } else {
445       xi.byte_order = WORDS_BIGENDIAN;
446       converter = color32_converter;
447       mono_converter = mono32_converter;
448     }
449     break;
450 
451   default:
452     Fl::fatal("Can't do %d bits_per_pixel",xi.bits_per_pixel);
453   }
454 
455 }
456 
457 #  define MAXBUFFER 0x40000 // 256k
458 
innards(const uchar * buf,int X,int Y,int W,int H,int delta,int linedelta,int mono,Fl_Draw_Image_Cb cb,void * userdata,const bool alpha)459 static void innards(const uchar *buf, int X, int Y, int W, int H,
460 		    int delta, int linedelta, int mono,
461 		    Fl_Draw_Image_Cb cb, void* userdata,
462 		    const bool alpha)
463 {
464   if (!linedelta) linedelta = W*abs(delta);
465 
466   int dx, dy, w, h;
467   fl_clip_box(X,Y,W,H,dx,dy,w,h);
468   if (w<=0 || h<=0) return;
469   dx -= X;
470   dy -= Y;
471 
472   if (!bytes_per_pixel) figure_out_visual();
473   const unsigned oldbpp = bytes_per_pixel;
474   const GC oldgc = fl_gc;
475   static GC gc32 = None;
476   xi.width = w;
477   xi.height = h;
478 
479   void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter;
480   if (mono) conv = mono_converter;
481   if (alpha) {
482     // This flag states the destination format is ARGB32 (big-endian), pre-multiplied.
483     bytes_per_pixel = 4;
484     conv = argb_premul_converter;
485     xi.depth = 32;
486     xi.bits_per_pixel = 32;
487 
488     // Do we need a new GC?
489     if (fl_visual->depth != 32) {
490       if (gc32 == None)
491         gc32 = XCreateGC(fl_display, fl_window, 0, NULL);
492       fl_gc = gc32;
493     }
494   }
495 
496   // See if the data is already in the right format.  Unfortunately
497   // some 32-bit x servers (XFree86) care about the unknown 8 bits
498   // and they must be zero.  I can't confirm this for user-supplied
499   // data, so the 32-bit shortcut is disabled...
500   // This can set bytes_per_line negative if image is bottom-to-top
501   // I tested it on Linux, but it may fail on other Xlib implementations:
502   if (buf && (
503 #  if 0	// set this to 1 to allow 32-bit shortcut
504       delta == 4 &&
505 #    if WORDS_BIGENDIAN
506       conv == rgbx_converter
507 #    else
508       conv == xbgr_converter
509 #    endif
510       ||
511 #  endif
512       conv == rgb_converter && delta==3
513       ) && !(linedelta&scanline_add)) {
514     xi.data = (char *)(buf+delta*dx+linedelta*dy);
515     xi.bytes_per_line = linedelta;
516 
517   } else {
518     int linesize = ((w*bytes_per_pixel+scanline_add)&scanline_mask)/sizeof(STORETYPE);
519     int blocking = h;
520     static STORETYPE *buffer;	// our storage, always word aligned
521     static long buffer_size;
522     {int size = linesize*h;
523     if (size > MAXBUFFER) {
524       size = MAXBUFFER;
525       blocking = MAXBUFFER/linesize;
526     }
527     if (size > buffer_size) {
528       delete[] buffer;
529       buffer_size = size;
530       buffer = new STORETYPE[size];
531     }}
532     xi.data = (char *)buffer;
533     xi.bytes_per_line = linesize*sizeof(STORETYPE);
534     if (buf) {
535       buf += delta*dx+linedelta*dy;
536       for (int j=0; j<h; ) {
537 	STORETYPE *to = buffer;
538 	int k;
539 	for (k = 0; j<h && k<blocking; k++, j++) {
540 	  conv(buf, (uchar*)to, w, delta);
541 	  buf += linedelta;
542 	  to += linesize;
543 	}
544 	XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
545       }
546     } else {
547       STORETYPE* linebuf = new STORETYPE[(W*delta+(sizeof(STORETYPE)-1))/sizeof(STORETYPE)];
548       for (int j=0; j<h; ) {
549 	STORETYPE *to = buffer;
550 	int k;
551 	for (k = 0; j<h && k<blocking; k++, j++) {
552 	  cb(userdata, dx, dy+j, w, (uchar*)linebuf);
553 	  conv((uchar*)linebuf, (uchar*)to, w, delta);
554 	  to += linesize;
555 	}
556 	XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
557       }
558 
559       delete[] linebuf;
560     }
561   }
562 
563   if (alpha) {
564     bytes_per_pixel = oldbpp;
565     xi.depth = fl_visual->depth;
566     xi.bits_per_pixel = oldbpp * 8;
567 
568     if (fl_visual->depth != 32) {
569       fl_gc = oldgc;
570     }
571   }
572 }
573 
draw_image(const uchar * buf,int x,int y,int w,int h,int d,int l)574 void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
575 
576   const bool alpha = !!(abs(d) & FL_IMAGE_WITH_ALPHA);
577   if (alpha) d ^= FL_IMAGE_WITH_ALPHA;
578   const int mono = (d>-3 && d<3);
579 
580   innards(buf,x,y,w,h,d,l,mono,0,0,alpha);
581 }
582 
draw_image(Fl_Draw_Image_Cb cb,void * data,int x,int y,int w,int h,int d)583 void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
584 		   int x, int y, int w, int h,int d) {
585 
586   const bool alpha = !!(abs(d) & FL_IMAGE_WITH_ALPHA);
587   if (alpha) d ^= FL_IMAGE_WITH_ALPHA;
588   const int mono = (d>-3 && d<3);
589 
590   innards(0,x,y,w,h,d,0,mono,cb,data,alpha);
591 }
592 
draw_image_mono(const uchar * buf,int x,int y,int w,int h,int d,int l)593 void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
594   innards(buf,x,y,w,h,d,l,1,0,0,0);
595 }
596 
draw_image_mono(Fl_Draw_Image_Cb cb,void * data,int x,int y,int w,int h,int d)597 void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
598 		   int x, int y, int w, int h,int d) {
599   innards(0,x,y,w,h,d,0,1,cb,data,0);
600 }
601 
fl_rectf(int x,int y,int w,int h,uchar r,uchar g,uchar b)602 void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
603   if (fl_visual->depth > 16) {
604     fl_color(r,g,b);
605     fl_rectf(x,y,w,h);
606   } else {
607     uchar c[3];
608     c[0] = r; c[1] = g; c[2] = b;
609     innards(c,x,y,w,h,0,0,0,0,0,0);
610   }
611 }
612 
613 #endif
614 
615 //
616 // End of "$Id$".
617 //
618