1 //
2 // "$Id: fl_draw_pixmap.cxx 6026 2008-02-14 18:17:06Z matt $"
3 //
4 // Pixmap drawing code for the Fast Light Tool Kit (FLTK).
5 //
6 // Copyright 1998-2005 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
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 // Implemented without using the xpm library (which I can't use because
29 // it interferes with the color cube used by fl_draw_image).
30 // Current implementation is cheap and slow, and works best on a full-color
31 // display.  Transparency is not handled, and colors are dithered to
32 // the color cube.  Color index is achieved by adding the id
33 // characters together!  Also mallocs a lot of temporary memory!
34 // Notice that there is no pixmap file interface.  This is on purpose,
35 // as I want to discourage programs that require support files to work.
36 // All data needed by a program ui should be compiled in!!!
37 
38 #include <FL/Fl.H>
39 #include <FL/fl_draw.H>
40 #include <FL/x.H>
41 #include <stdio.h>
42 #include "flstring.h"
43 
44 static int ncolors, chars_per_pixel;
45 
fl_measure_pixmap(char * const * data,int & w,int & h)46 int fl_measure_pixmap(/*const*/ char* const* data, int &w, int &h) {
47   return fl_measure_pixmap((const char*const*)data,w,h);
48 }
49 
fl_measure_pixmap(const char * const * data,int & w,int & h)50 int fl_measure_pixmap(const char * const *data, int &w, int &h) {
51   int i = sscanf(data[0],"%d%d%d%d",&w,&h,&ncolors,&chars_per_pixel);
52   if (i<4 || w<=0 || h<=0 ||
53       chars_per_pixel!=1 && chars_per_pixel!=2) return w=0;
54   return 1;
55 }
56 
57 #ifdef U64
58 
59 // The callback from fl_draw_image to get a row of data passes this:
60 struct pixmap_data {
61   int w, h;
62   const uchar*const* data;
63   union {
64     U64 colors[256];
65     U64* byte1[256];
66   };
67 };
68 
69 // callback for 1 byte per pixel:
cb1(void * v,int x,int y,int w,uchar * buf)70 static void cb1(void*v, int x, int y, int w, uchar* buf) {
71   pixmap_data& d = *(pixmap_data*)v;
72   const uchar* p = d.data[y]+x;
73   U64* q = (U64*)buf;
74   for (int X=w; X>0; X-=2, p += 2) {
75     if (X>1) {
76 #  if WORDS_BIGENDIAN
77       *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
78 #  else
79       *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
80 #  endif
81     } else {
82 #  if WORDS_BIGENDIAN
83       *q++ = d.colors[p[0]]<<32;
84 #  else
85       *q++ = d.colors[p[0]];
86 #  endif
87     }
88   }
89 }
90 
91 // callback for 2 bytes per pixel:
cb2(void * v,int x,int y,int w,uchar * buf)92 static void cb2(void*v, int x, int y, int w, uchar* buf) {
93   pixmap_data& d = *(pixmap_data*)v;
94   const uchar* p = d.data[y]+2*x;
95   U64* q = (U64*)buf;
96   for (int X=w; X>0; X-=2) {
97     U64* colors = d.byte1[*p++];
98     int index = *p++;
99     if (X>1) {
100       U64* colors1 = d.byte1[*p++];
101       int index1 = *p++;
102 #  if WORDS_BIGENDIAN
103       *q++ = (colors[index]<<32) | colors1[index1];
104 #  else
105       *q++ = (colors1[index1]<<32) | colors[index];
106 #  endif
107     } else {
108 #  if WORDS_BIGENDIAN
109       *q++ = colors[index]<<32;
110 #  else
111       *q++ = colors[index];
112 #  endif
113     }
114   }
115 }
116 
117 #else // U32
118 
119 // The callback from fl_draw_image to get a row of data passes this:
120 struct pixmap_data {
121   int w, h;
122   const uchar*const* data;
123   union {
124     U32 colors[256];
125     U32* byte1[256];
126   };
127 };
128 
129 #  ifndef __APPLE_QUARTZ__
130 
131 // callback for 1 byte per pixel:
cb1(void * v,int x,int y,int w,uchar * buf)132 static void cb1(void*v, int x, int y, int w, uchar* buf) {
133   pixmap_data& d = *(pixmap_data*)v;
134   const uchar* p = d.data[y]+x;
135   U32* q = (U32*)buf;
136   for (int X=w; X--;) *q++ = d.colors[*p++];
137 }
138 
139 // callback for 2 bytes per pixel:
cb2(void * v,int x,int y,int w,uchar * buf)140 static void cb2(void*v, int x, int y, int w, uchar* buf) {
141   pixmap_data& d = *(pixmap_data*)v;
142   const uchar* p = d.data[y]+2*x;
143   U32* q = (U32*)buf;
144   for (int X=w; X--;) {
145     U32* colors = d.byte1[*p++];
146     *q++ = colors[*p++];
147   }
148 }
149 
150 #  endif  // !__APPLE_QUARTZ__
151 
152 #endif // U64 else U32
153 
154 uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
155 
fl_draw_pixmap(char * const * data,int x,int y,Fl_Color bg)156 int fl_draw_pixmap(/*const*/ char* const* data, int x,int y,Fl_Color bg) {
157   return fl_draw_pixmap((const char*const*)data,x,y,bg);
158 }
159 
fl_draw_pixmap(const char * const * di,int x,int y,Fl_Color bg)160 int fl_draw_pixmap(const char*const* di, int x, int y, Fl_Color bg) {
161   pixmap_data d;
162   if (!fl_measure_pixmap(di, d.w, d.h)) return 0;
163   const uchar*const* data = (const uchar*const*)(di+1);
164   int transparent_index = -1;
165 
166   if (ncolors < 0) {	// FLTK (non standard) compressed colormap
167     ncolors = -ncolors;
168     const uchar *p = *data++;
169     // if first color is ' ' it is transparent (put it later to make
170     // it not be transparent):
171     if (*p == ' ') {
172       uchar* c = (uchar*)&d.colors[(int)' '];
173 #ifdef U64
174       *(U64*)c = 0;
175 #  if WORDS_BIGENDIAN
176       c += 4;
177 #  endif
178 #endif
179       transparent_index = ' ';
180       Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
181       p += 4;
182       ncolors--;
183     }
184     // read all the rest of the colors:
185     for (int i=0; i < ncolors; i++) {
186       uchar* c = (uchar*)&d.colors[*p++];
187 #ifdef U64
188       *(U64*)c = 0;
189 #  if WORDS_BIGENDIAN
190       c += 4;
191 #  endif
192 #endif
193       *c++ = *p++;
194       *c++ = *p++;
195       *c++ = *p++;
196 #ifdef __APPLE_QUARTZ__
197       *c = 255;
198 #else
199       *c = 0;
200 #endif
201     }
202   } else {	// normal XPM colormap with names
203     if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1));
204     for (int i=0; i<ncolors; i++) {
205       const uchar *p = *data++;
206       // the first 1 or 2 characters are the color index:
207       int ind = *p++;
208       uchar* c;
209       if (chars_per_pixel>1) {
210 #ifdef U64
211 	U64* colors = d.byte1[ind];
212 	if (!colors) colors = d.byte1[ind] = new U64[256];
213 #else
214 	U32* colors = d.byte1[ind];
215 	if (!colors) colors = d.byte1[ind] = new U32[256];
216 #endif
217 	c = (uchar*)&colors[*p];
218 	ind = (ind<<8)|*p++;
219       } else {
220 	c = (uchar *)&d.colors[ind];
221       }
222       // look for "c word", or last word if none:
223       const uchar *previous_word = p;
224       for (;;) {
225 	while (*p && isspace(*p)) p++;
226 	uchar what = *p++;
227 	while (*p && !isspace(*p)) p++;
228 	while (*p && isspace(*p)) p++;
229 	if (!*p) {p = previous_word; break;}
230 	if (what == 'c') break;
231 	previous_word = p;
232 	while (*p && !isspace(*p)) p++;
233       }
234 #ifdef U64
235       *(U64*)c = 0;
236 #  if WORDS_BIGENDIAN
237       c += 4;
238 #  endif
239 #endif
240 #ifdef __APPLE_QUARTZ__
241       c[3] = 255;
242 #endif
243       if (!fl_parse_color((const char*)p, c[0], c[1], c[2])) {
244         // assume "None" or "#transparent" for any errors
245 	// "bg" should be transparent...
246 	Fl::get_color(bg, c[0], c[1], c[2]);
247 #ifdef __APPLE_QUARTZ__
248         c[3] = 0;
249 #endif
250 	transparent_index = ind;
251       }
252     }
253   }
254   d.data = data;
255 
256 #ifndef __APPLE_QUARTZ__
257 
258   // build the mask bitmap used by Fl_Pixmap:
259   if (fl_mask_bitmap && transparent_index >= 0) {
260     int W = (d.w+7)/8;
261     uchar* bitmap = new uchar[W * d.h];
262     *fl_mask_bitmap = bitmap;
263     for (int Y = 0; Y < d.h; Y++) {
264       const uchar* p = data[Y];
265       if (chars_per_pixel <= 1) {
266 	int dw = d.w;
267 	for (int X = 0; X < W; X++) {
268 	  uchar b = (dw-->0 && *p++ != transparent_index);
269 	  if (dw-->0 && *p++ != transparent_index) b |= 2;
270 	  if (dw-->0 && *p++ != transparent_index) b |= 4;
271 	  if (dw-->0 && *p++ != transparent_index) b |= 8;
272 	  if (dw-->0 && *p++ != transparent_index) b |= 16;
273 	  if (dw-->0 && *p++ != transparent_index) b |= 32;
274 	  if (dw-->0 && *p++ != transparent_index) b |= 64;
275 	  if (dw-->0 && *p++ != transparent_index) b |= 128;
276 	  *bitmap++ = b;
277 	}
278       } else {
279         uchar b = 0, bit = 1;
280 	for (int X = 0; X < d.w; X++) {
281 	  int ind = *p++;
282 	  ind = (ind<<8) | (*p++);
283 	  if (ind != transparent_index) b |= bit;
284 
285           if (bit < 128) bit <<= 1;
286 	  else {
287 	    *bitmap++ = b;
288 	    b = 0;
289 	    bit = 1;
290 	  }
291 	}
292 
293         if (bit > 1) *bitmap++ = b;
294       }
295     }
296   }
297 
298   fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4);
299 
300 #else // __APPLE_QUARTZ__
301 
302   bool transparent = (transparent_index>=0);
303   transparent = true;
304   U32 *array = new U32[d.w * d.h], *q = array;
305   for (int Y = 0; Y < d.h; Y++) {
306     const uchar* p = data[Y];
307     if (chars_per_pixel <= 1) {
308       for (int X = 0; X < d.w; X++) {
309         *q++ = d.colors[*p++];
310       }
311     } else {
312       for (int X = 0; X < d.w; X++) {
313         U32* colors = d.byte1[*p++];
314         *q++ = colors[*p++];
315       }
316     }
317   }
318   CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
319   CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L);
320   CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w,
321         lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast,
322         src, 0L, false, kCGRenderingIntentDefault);
323   CGColorSpaceRelease(lut);
324   CGDataProviderRelease(src);
325   CGRect rect = { { x, y} , { d.w, d.h } };
326   Fl_X::q_begin_image(rect, 0, 0, d.w, d.h);
327   CGContextDrawImage(fl_gc, rect, img);
328   Fl_X::q_end_image();
329   CGImageRelease(img);
330   delete array;
331 
332 #endif // !__APPLE_QUARTZ__
333 
334   if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i];
335   return 1;
336 }
337 
338 //
339 // End of "$Id: fl_draw_pixmap.cxx 6026 2008-02-14 18:17:06Z matt $".
340 //
341