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