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