blob: 68f7df6f1fd566c1a515b8cf1c8fad6b50a28233 [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z manolo $"
3//
4// Pixmap drawing code 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// 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
44static int ncolors, chars_per_pixel;
45
46/**
47 Get the dimensions of a pixmap.
48 An XPM image contains the dimensions in its data. This function
49 returns te width and height.
50 \param[in] data pointer to XPM image data.
51 \param[out] w,h width and height of image
52 \returns non-zero if the dimensions were parsed OK
53 \returns 0 if there were any problems
54 */
55int fl_measure_pixmap(/*const*/ char* const* data, int &w, int &h) {
56 return fl_measure_pixmap((const char*const*)data,w,h);
57}
58
59/**
60 Get the dimensions of a pixmap.
61 \see fl_measure_pixmap(char* const* data, int &w, int &h)
62 */
63int fl_measure_pixmap(const char * const *cdata, int &w, int &h) {
64 int i = sscanf(cdata[0],"%d%d%d%d",&w,&h,&ncolors,&chars_per_pixel);
65 if (i<4 || w<=0 || h<=0 ||
66 (chars_per_pixel!=1 && chars_per_pixel!=2) ) return w=0;
67 return 1;
68}
69
70#ifdef U64
71
72// The callback from fl_draw_image to get a row of data passes this:
73struct pixmap_data {
74 int w, h;
75 const uchar*const* data;
76 union {
77 U64 colors[256];
78 U64* byte1[256];
79 };
80};
81
82// callback for 1 byte per pixel:
83static void cb1(void*v, int x, int y, int w, uchar* buf) {
84 pixmap_data& d = *(pixmap_data*)v;
85 const uchar* p = d.data[y]+x;
86 U64* q = (U64*)buf;
87 for (int X=w; X>0; X-=2, p += 2) {
88 if (X>1) {
89# if WORDS_BIGENDIAN
90 *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]];
91# else
92 *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]];
93# endif
94 } else {
95# if WORDS_BIGENDIAN
96 *q++ = d.colors[p[0]]<<32;
97# else
98 *q++ = d.colors[p[0]];
99# endif
100 }
101 }
102}
103
104// callback for 2 bytes per pixel:
105static void cb2(void*v, int x, int y, int w, uchar* buf) {
106 pixmap_data& d = *(pixmap_data*)v;
107 const uchar* p = d.data[y]+2*x;
108 U64* q = (U64*)buf;
109 for (int X=w; X>0; X-=2) {
110 U64* colors = d.byte1[*p++];
111 int index = *p++;
112 if (X>1) {
113 U64* colors1 = d.byte1[*p++];
114 int index1 = *p++;
115# if WORDS_BIGENDIAN
116 *q++ = (colors[index]<<32) | colors1[index1];
117# else
118 *q++ = (colors1[index1]<<32) | colors[index];
119# endif
120 } else {
121# if WORDS_BIGENDIAN
122 *q++ = colors[index]<<32;
123# else
124 *q++ = colors[index];
125# endif
126 }
127 }
128}
129
130#else // U32
131
132// The callback from fl_draw_image to get a row of data passes this:
133struct pixmap_data {
134 int w, h;
135 const uchar*const* data;
136 union {
137 U32 colors[256];
138 U32* byte1[256];
139 };
140};
141
142// callback for 1 byte per pixel:
143static void cb1(void*v, int x, int y, int w, uchar* buf) {
144 pixmap_data& d = *(pixmap_data*)v;
145 const uchar* p = d.data[y]+x;
146 U32* q = (U32*)buf;
147 for (int X=w; X--;) *q++ = d.colors[*p++];
148}
149
150// callback for 2 bytes per pixel:
151static void cb2(void*v, int x, int y, int w, uchar* buf) {
152 pixmap_data& d = *(pixmap_data*)v;
153 const uchar* p = d.data[y]+2*x;
154 U32* q = (U32*)buf;
155 for (int X=w; X--;) {
156 U32* colors = d.byte1[*p++];
157 *q++ = colors[*p++];
158 }
159}
160
161#endif // U64 else U32
162
163uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
164
165/**
166 Draw XPM image data, with the top-left corner at the given position.
167 The image is dithered on 8-bit displays so you won't lose color
168 space for programs displaying both images and pixmaps.
169 \param[in] data pointer to XPM image data
170 \param[in] x,y position of top-left corner
171 \param[in] bg background color
172 \returns 0 if there was any error decoding the XPM data.
173 */
174int fl_draw_pixmap(/*const*/ char* const* data, int x,int y,Fl_Color bg) {
175 return fl_draw_pixmap((const char*const*)data,x,y,bg);
176}
177
178#ifdef WIN32
179// to compute an unused color to be used for the pixmap background
180FL_EXPORT UINT win_pixmap_bg_color; // the RGB() of the pixmap background color
181static int color_count; // # of non-transparent colors used in pixmap
182static uchar *used_colors; // used_colors[3*i+j] j=0,1,2 are the RGB values of the ith used color
183
184static void make_unused_color(uchar &r, uchar &g, uchar &b)
185// makes an RGB triplet different from all the colors used in the pixmap
186// and compute win_pixmap_bg_color from this triplet
187{
188 int i;
189 r = 2; g = 3; b = 4;
190 while (1) {
191 for ( i = 0; i < color_count; i++) {
192 if(used_colors[3*i] == r && used_colors[3*i+1] == g && used_colors[3*i+2] == b) break;
193 }
194 if (i >= color_count) {
195 free(used_colors);
196 win_pixmap_bg_color = RGB(r, g, b);
197 return;
198 }
199 if (r < 255) r++;
200 else {
201 r = 0;
202 if (g < 255) g++;
203 else {
204 g = 0;
205 b++;
206 }
207 }
208 }
209}
210#endif
211
212/**
213 Draw XPM image data, with the top-left corner at the given position.
214 \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
215 */
216int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
217 pixmap_data d;
218 if (!fl_measure_pixmap(cdata, d.w, d.h)) return 0;
219 const uchar*const* data = (const uchar*const*)(cdata+1);
220 int transparent_index = -1;
221 uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
222#ifdef WIN32
223 color_count = 0;
224 used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar));
225#endif
226
227 if (ncolors < 0) { // FLTK (non standard) compressed colormap
228 ncolors = -ncolors;
229 const uchar *p = *data++;
230 // if first color is ' ' it is transparent (put it later to make
231 // it not be transparent):
232 if (*p == ' ') {
233 uchar* c = (uchar*)&d.colors[(int)' '];
234#ifdef U64
235 *(U64*)c = 0;
236# if WORDS_BIGENDIAN
237 c += 4;
238# endif
239#endif
240 transparent_index = ' ';
241 Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
242 transparent_c = c;
243 p += 4;
244 ncolors--;
245 }
246 // read all the rest of the colors:
247 for (int i=0; i < ncolors; i++) {
248 uchar* c = (uchar*)&d.colors[*p++];
249#ifdef U64
250 *(U64*)c = 0;
251# if WORDS_BIGENDIAN
252 c += 4;
253# endif
254#endif
255#ifdef WIN32
256 used_colors[3*color_count] = *p;
257 used_colors[3*color_count+1] = *(p+1);
258 used_colors[3*color_count+2] = *(p+2);
259 color_count++;
260#endif
261 *c++ = *p++;
262 *c++ = *p++;
263 *c++ = *p++;
264#ifdef __APPLE_QUARTZ__
265 *c = 255;
266#else
267 *c = 0;
268#endif
269 }
270 } else { // normal XPM colormap with names
271 if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1));
272 for (int i=0; i<ncolors; i++) {
273 const uchar *p = *data++;
274 // the first 1 or 2 characters are the color index:
275 int ind = *p++;
276 uchar* c;
277 if (chars_per_pixel>1) {
278#ifdef U64
279 U64* colors = d.byte1[ind];
280 if (!colors) colors = d.byte1[ind] = new U64[256];
281#else
282 U32* colors = d.byte1[ind];
283 if (!colors) colors = d.byte1[ind] = new U32[256];
284#endif
285 c = (uchar*)&colors[*p];
286 ind = (ind<<8)|*p++;
287 } else {
288 c = (uchar *)&d.colors[ind];
289 }
290 // look for "c word", or last word if none:
291 const uchar *previous_word = p;
292 for (;;) {
293 while (*p && isspace(*p)) p++;
294 uchar what = *p++;
295 while (*p && !isspace(*p)) p++;
296 while (*p && isspace(*p)) p++;
297 if (!*p) {p = previous_word; break;}
298 if (what == 'c') break;
299 previous_word = p;
300 while (*p && !isspace(*p)) p++;
301 }
302#ifdef U64
303 *(U64*)c = 0;
304# if WORDS_BIGENDIAN
305 c += 4;
306# endif
307#endif
308#ifdef __APPLE_QUARTZ__
309 c[3] = 255;
310#endif
311 int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
312 if (parse) {
313#ifdef WIN32
314 used_colors[3*color_count] = c[0];
315 used_colors[3*color_count+1] = c[1];
316 used_colors[3*color_count+2] = c[2];
317 color_count++;
318#endif
319 }
320 else {
321 // assume "None" or "#transparent" for any errors
322 // "bg" should be transparent...
323 Fl::get_color(bg, c[0], c[1], c[2]);
324#ifdef __APPLE_QUARTZ__
325 c[3] = 0;
326#endif
327 transparent_index = ind;
328 transparent_c = c;
329 }
330 }
331 }
332 d.data = data;
333#ifdef WIN32
334 if (transparent_c) {
335 make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
336 }
337 else {
338 uchar r, g, b;
339 make_unused_color(r, g, b);
340 }
341#endif
342
343#ifdef __APPLE_QUARTZ__
344 if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
345 bool transparent = (transparent_index>=0);
346 transparent = true;
347 U32 *array = new U32[d.w * d.h], *q = array;
348 for (int Y = 0; Y < d.h; Y++) {
349 const uchar* p = data[Y];
350 if (chars_per_pixel <= 1) {
351 for (int X = 0; X < d.w; X++) {
352 *q++ = d.colors[*p++];
353 }
354 } else {
355 for (int X = 0; X < d.w; X++) {
356 U32* colors = (U32*)d.byte1[*p++];
357 *q++ = colors[*p++];
358 }
359 }
360 }
361 CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
362 CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L);
363 CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w,
364 lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast,
365 src, 0L, false, kCGRenderingIntentDefault);
366 CGColorSpaceRelease(lut);
367 CGDataProviderRelease(src);
368 CGRect rect = { { x, y} , { d.w, d.h } };
369 Fl_X::q_begin_image(rect, 0, 0, d.w, d.h);
370 CGContextDrawImage(fl_gc, rect, img);
371 Fl_X::q_end_image();
372 CGImageRelease(img);
373 delete[] array;
374 }
375 else {
376#endif // __APPLE_QUARTZ__
377
378 // build the mask bitmap used by Fl_Pixmap:
379 if (fl_mask_bitmap && transparent_index >= 0) {
380 int W = (d.w+7)/8;
381 uchar* bitmap = new uchar[W * d.h];
382 *fl_mask_bitmap = bitmap;
383 for (int Y = 0; Y < d.h; Y++) {
384 const uchar* p = data[Y];
385 if (chars_per_pixel <= 1) {
386 int dw = d.w;
387 for (int X = 0; X < W; X++) {
388 uchar b = (dw-->0 && *p++ != transparent_index);
389 if (dw-->0 && *p++ != transparent_index) b |= 2;
390 if (dw-->0 && *p++ != transparent_index) b |= 4;
391 if (dw-->0 && *p++ != transparent_index) b |= 8;
392 if (dw-->0 && *p++ != transparent_index) b |= 16;
393 if (dw-->0 && *p++ != transparent_index) b |= 32;
394 if (dw-->0 && *p++ != transparent_index) b |= 64;
395 if (dw-->0 && *p++ != transparent_index) b |= 128;
396 *bitmap++ = b;
397 }
398 } else {
399 uchar b = 0, bit = 1;
400 for (int X = 0; X < d.w; X++) {
401 int ind = *p++;
402 ind = (ind<<8) | (*p++);
403 if (ind != transparent_index) b |= bit;
404
405 if (bit < 128) bit <<= 1;
406 else {
407 *bitmap++ = b;
408 b = 0;
409 bit = 1;
410 }
411 }
412
413 if (bit > 1) *bitmap++ = b;
414 }
415 }
416 }
417
418 fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4);
419#ifdef __APPLE_QUARTZ__
420 }
421#endif
422
423 if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i];
424 return 1;
425}
426
427//
428// End of "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z manolo $".
429//