blob: b02448597e4ba77df6fc0b1c971aca10599ef7a4 [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
DRC2ff39b82011-07-28 08:38:59 +000070uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here
71
72/**
73 Draw XPM image data, with the top-left corner at the given position.
74 The image is dithered on 8-bit displays so you won't lose color
75 space for programs displaying both images and pixmaps.
76 \param[in] data pointer to XPM image data
77 \param[in] x,y position of top-left corner
78 \param[in] bg background color
79 \returns 0 if there was any error decoding the XPM data.
80 */
81int fl_draw_pixmap(/*const*/ char* const* data, int x,int y,Fl_Color bg) {
82 return fl_draw_pixmap((const char*const*)data,x,y,bg);
83}
84
85#ifdef WIN32
86// to compute an unused color to be used for the pixmap background
87FL_EXPORT UINT win_pixmap_bg_color; // the RGB() of the pixmap background color
88static int color_count; // # of non-transparent colors used in pixmap
89static uchar *used_colors; // used_colors[3*i+j] j=0,1,2 are the RGB values of the ith used color
90
91static void make_unused_color(uchar &r, uchar &g, uchar &b)
92// makes an RGB triplet different from all the colors used in the pixmap
93// and compute win_pixmap_bg_color from this triplet
94{
95 int i;
96 r = 2; g = 3; b = 4;
97 while (1) {
98 for ( i = 0; i < color_count; i++) {
99 if(used_colors[3*i] == r && used_colors[3*i+1] == g && used_colors[3*i+2] == b) break;
100 }
101 if (i >= color_count) {
102 free(used_colors);
103 win_pixmap_bg_color = RGB(r, g, b);
104 return;
105 }
106 if (r < 255) r++;
107 else {
108 r = 0;
109 if (g < 255) g++;
110 else {
111 g = 0;
112 b++;
113 }
114 }
115 }
116}
117#endif
118
DRC685f17e2011-07-28 09:23:00 +0000119int fl_convert_pixmap(const char*const* cdata, uchar* out, Fl_Color bg) {
120 int w, h;
DRC2ff39b82011-07-28 08:38:59 +0000121 const uchar*const* data = (const uchar*const*)(cdata+1);
122 int transparent_index = -1;
123 uchar *transparent_c = (uchar *)0; // such that transparent_c[0,1,2] are the RGB of the transparent color
DRC685f17e2011-07-28 09:23:00 +0000124
125 if (!fl_measure_pixmap(cdata, w, h))
126 return 0;
127
128 if ((chars_per_pixel < 1) || (chars_per_pixel > 2))
129 return 0;
130
DRCe334a8a2011-10-04 02:09:13 +0000131 uchar (*colors)[4] = new uchar [1<<(chars_per_pixel*8)][4];
DRC685f17e2011-07-28 09:23:00 +0000132
DRC2ff39b82011-07-28 08:38:59 +0000133#ifdef WIN32
134 color_count = 0;
135 used_colors = (uchar *)malloc(abs(ncolors)*3*sizeof(uchar));
136#endif
137
DRC685f17e2011-07-28 09:23:00 +0000138 if (ncolors < 0) {
139 // FLTK (non standard) compressed colormap
DRC2ff39b82011-07-28 08:38:59 +0000140 ncolors = -ncolors;
141 const uchar *p = *data++;
142 // if first color is ' ' it is transparent (put it later to make
143 // it not be transparent):
144 if (*p == ' ') {
DRC685f17e2011-07-28 09:23:00 +0000145 uchar* c = colors[(int)' '];
DRC2ff39b82011-07-28 08:38:59 +0000146 transparent_index = ' ';
147 Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0;
148 transparent_c = c;
149 p += 4;
150 ncolors--;
151 }
152 // read all the rest of the colors:
153 for (int i=0; i < ncolors; i++) {
DRC685f17e2011-07-28 09:23:00 +0000154 uchar* c = colors[*p++];
DRC2ff39b82011-07-28 08:38:59 +0000155#ifdef WIN32
156 used_colors[3*color_count] = *p;
157 used_colors[3*color_count+1] = *(p+1);
158 used_colors[3*color_count+2] = *(p+2);
159 color_count++;
160#endif
161 *c++ = *p++;
162 *c++ = *p++;
163 *c++ = *p++;
DRC2ff39b82011-07-28 08:38:59 +0000164 *c = 255;
DRC2ff39b82011-07-28 08:38:59 +0000165 }
DRC685f17e2011-07-28 09:23:00 +0000166 } else {
167 // normal XPM colormap with names
DRC2ff39b82011-07-28 08:38:59 +0000168 for (int i=0; i<ncolors; i++) {
169 const uchar *p = *data++;
170 // the first 1 or 2 characters are the color index:
171 int ind = *p++;
172 uchar* c;
DRC685f17e2011-07-28 09:23:00 +0000173 if (chars_per_pixel>1)
174 ind = (ind<<8)|*p++;
175 c = colors[ind];
DRC2ff39b82011-07-28 08:38:59 +0000176 // look for "c word", or last word if none:
177 const uchar *previous_word = p;
178 for (;;) {
DRC685f17e2011-07-28 09:23:00 +0000179 while (*p && isspace(*p)) p++;
180 uchar what = *p++;
181 while (*p && !isspace(*p)) p++;
182 while (*p && isspace(*p)) p++;
183 if (!*p) {p = previous_word; break;}
184 if (what == 'c') break;
185 previous_word = p;
186 while (*p && !isspace(*p)) p++;
DRC2ff39b82011-07-28 08:38:59 +0000187 }
DRC2ff39b82011-07-28 08:38:59 +0000188 int parse = fl_parse_color((const char*)p, c[0], c[1], c[2]);
DRC685f17e2011-07-28 09:23:00 +0000189 c[3] = 255;
DRC2ff39b82011-07-28 08:38:59 +0000190 if (parse) {
191#ifdef WIN32
DRC685f17e2011-07-28 09:23:00 +0000192 used_colors[3*color_count] = c[0];
193 used_colors[3*color_count+1] = c[1];
194 used_colors[3*color_count+2] = c[2];
195 color_count++;
DRC2ff39b82011-07-28 08:38:59 +0000196#endif
DRC685f17e2011-07-28 09:23:00 +0000197 } else {
DRC2ff39b82011-07-28 08:38:59 +0000198 // assume "None" or "#transparent" for any errors
DRC685f17e2011-07-28 09:23:00 +0000199 // "bg" should be transparent...
200 Fl::get_color(bg, c[0], c[1], c[2]);
DRC2ff39b82011-07-28 08:38:59 +0000201 c[3] = 0;
DRC685f17e2011-07-28 09:23:00 +0000202 transparent_index = ind;
203 transparent_c = c;
DRC2ff39b82011-07-28 08:38:59 +0000204 }
205 }
206 }
DRC2ff39b82011-07-28 08:38:59 +0000207#ifdef WIN32
208 if (transparent_c) {
209 make_unused_color(transparent_c[0], transparent_c[1], transparent_c[2]);
210 }
211 else {
212 uchar r, g, b;
213 make_unused_color(r, g, b);
214 }
215#endif
DRC685f17e2011-07-28 09:23:00 +0000216
217 U32 *q = (U32*)out;
218 for (int Y = 0; Y < h; Y++) {
219 const uchar* p = data[Y];
220 if (chars_per_pixel <= 1) {
221 for (int X = 0; X < w; X++)
222 memcpy(q++, colors[*p++], 4);
223 } else {
224 for (int X = 0; X < w; X++) {
225 int ind = (*p++)<<8;
226 ind |= *p++;
227 memcpy(q++, colors[ind], 4);
DRC2ff39b82011-07-28 08:38:59 +0000228 }
229 }
DRC685f17e2011-07-28 09:23:00 +0000230 }
231
DRCe334a8a2011-10-04 02:09:13 +0000232 delete [] colors;
DRC685f17e2011-07-28 09:23:00 +0000233 return 1;
234}
235
236/**
237 Draw XPM image data, with the top-left corner at the given position.
238 \see fl_draw_pixmap(char* const* data, int x, int y, Fl_Color bg)
239 */
240int fl_draw_pixmap(const char*const* cdata, int x, int y, Fl_Color bg) {
241 int w, h;
242
243 if (!fl_measure_pixmap(cdata, w, h))
244 return 0;
245
DRCe334a8a2011-10-04 02:09:13 +0000246 uchar *buffer = new uchar[w*h*4];
DRC685f17e2011-07-28 09:23:00 +0000247
DRCe334a8a2011-10-04 02:09:13 +0000248 if (!fl_convert_pixmap(cdata, buffer, bg)) {
249 delete buffer;
DRC685f17e2011-07-28 09:23:00 +0000250 return 0;
DRCe334a8a2011-10-04 02:09:13 +0000251 }
DRC685f17e2011-07-28 09:23:00 +0000252
253 // FIXME: Hack until fl_draw_image() supports alpha properly
254#ifdef __APPLE_QUARTZ__
255 if (fl_graphics_driver->class_name() == Fl_Quartz_Graphics_Driver::class_id ) {
DRC2ff39b82011-07-28 08:38:59 +0000256 CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB();
DRC685f17e2011-07-28 09:23:00 +0000257 CGDataProviderRef src = CGDataProviderCreateWithData( 0L, buffer, w * h * 4, 0L);
258 CGImageRef img = CGImageCreate(w, h, 8, 4*8, 4*w,
259 lut, kCGImageAlphaLast,
260 src, 0L, false, kCGRenderingIntentDefault);
DRC2ff39b82011-07-28 08:38:59 +0000261 CGColorSpaceRelease(lut);
262 CGDataProviderRelease(src);
DRC685f17e2011-07-28 09:23:00 +0000263 CGRect rect = { { x, y }, { w, h } };
264 Fl_X::q_begin_image(rect, 0, 0, w, h);
DRC2ff39b82011-07-28 08:38:59 +0000265 CGContextDrawImage(fl_gc, rect, img);
266 Fl_X::q_end_image();
267 CGImageRelease(img);
DRC685f17e2011-07-28 09:23:00 +0000268 } else {
DRC2ff39b82011-07-28 08:38:59 +0000269#endif // __APPLE_QUARTZ__
DRC2ff39b82011-07-28 08:38:59 +0000270 // build the mask bitmap used by Fl_Pixmap:
DRC685f17e2011-07-28 09:23:00 +0000271 if (fl_mask_bitmap) {
272 int W = (w+7)/8;
273 uchar* bitmap = new uchar[W * h];
DRC2ff39b82011-07-28 08:38:59 +0000274 *fl_mask_bitmap = bitmap;
DRC685f17e2011-07-28 09:23:00 +0000275 const uchar *p = &buffer[3];
276 for (int Y = 0; Y < h; Y++) {
277 int dw = w;
278 for (int X = 0; X < W; X++) {
279 uchar b = 0;
280 for (int bit = 0x01;bit <= 0x80;bit<<=1) {
281 if (dw-- < 0)
282 break;
283 if (*p > 127)
284 b |= bit;
285 p += 4;
286 }
287 *bitmap++ = b;
DRC2ff39b82011-07-28 08:38:59 +0000288 }
289 }
290 }
291
DRC685f17e2011-07-28 09:23:00 +0000292 fl_draw_image(buffer, x, y, w, h, 4);
293
DRC2ff39b82011-07-28 08:38:59 +0000294#ifdef __APPLE_QUARTZ__
295 }
296#endif
297
DRCe334a8a2011-10-04 02:09:13 +0000298 delete buffer;
DRC2ff39b82011-07-28 08:38:59 +0000299 return 1;
300}
301
302//
303// End of "$Id: fl_draw_pixmap.cxx 8362 2011-02-02 18:39:34Z manolo $".
304//