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