summaryrefslogtreecommitdiff
path: root/src/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers')
-rw-r--r--src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx337
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx2
-rw-r--r--src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_image.cxx24
-rw-r--r--src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx167
-rw-r--r--src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx605
5 files changed, 1134 insertions, 1 deletions
diff --git a/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx
new file mode 100644
index 000000000..465e73dca
--- /dev/null
+++ b/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx
@@ -0,0 +1,337 @@
+//
+// "$Id$"
+//
+// WIN32 image drawing code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2012 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+// I hope a simple and portable method of drawing color and monochrome
+// images. To keep this simple, only a single storage type is
+// supported: 8 bit unsigned data, byte order RGB, and pixels are
+// stored packed into rows with the origin at the top-left. It is
+// possible to alter the size of pixels with the "delta" argument, to
+// add alpha or other information per pixel. It is also possible to
+// change the origin and direction of the image data by messing with
+// the "delta" and "linedelta", making them negative, though this may
+// defeat some of the shortcuts in translating the image for X.
+
+// Unbelievably (since it conflicts with how most PC software works)
+// Micro$oft picked a bottom-up and BGR storage format for their
+// DIB images. I'm pretty certain there is a way around this, but
+// I can't find any other than the brute-force method of drawing
+// each line as a separate image. This may also need to be done
+// if the delta is any amount other than 1, 3, or 4.
+
+////////////////////////////////////////////////////////////////
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/Fl_Printer.H>
+#include <FL/fl_draw.H>
+#include <FL/x.H>
+
+#define MAXBUFFER 0x40000 // 256k
+
+#if USE_COLORMAP
+
+// error-diffusion dither into the FLTK colormap
+static void dither(uchar* to, const uchar* from, int w, int delta) {
+ static int ri, gi, bi, dir;
+ int r=ri, g=gi, b=bi;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ to = to+(w-1);
+ d = -delta;
+ td = -1;
+ } else {
+ dir = 1;
+ d = delta;
+ td = 1;
+ }
+ for (; w--; from += d, to += td) {
+ r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
+ int rr = r*FL_NUM_RED/256;
+ r -= rr*255/(FL_NUM_RED-1);
+ g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255;
+ int gg = g*FL_NUM_GREEN/256;
+ g -= gg*255/(FL_NUM_GREEN-1);
+ b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255;
+ int bb = b*FL_NUM_BLUE/256;
+ b -= bb*255/(FL_NUM_BLUE-1);
+ *to = uchar(FL_COLOR_CUBE+(bb*FL_NUM_RED+rr)*FL_NUM_GREEN+gg);
+ }
+ ri = r; gi = g; bi = b;
+}
+
+// error-diffusion dither into the FLTK colormap
+static void monodither(uchar* to, const uchar* from, int w, int delta) {
+ static int ri,dir;
+ int r=ri;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ to = to+(w-1);
+ d = -delta;
+ td = -1;
+ } else {
+ dir = 1;
+ d = delta;
+ td = 1;
+ }
+ for (; w--; from += d, to += td) {
+ r += *from; if (r < 0) r = 0; else if (r>255) r = 255;
+ int rr = r*FL_NUM_GRAY/256;
+ r -= rr*255/(FL_NUM_GRAY-1);
+ *to = uchar(FL_GRAY_RAMP+rr);
+ }
+ ri = r;
+}
+
+#endif // USE_COLORMAP
+
+static void innards(const uchar *buf, int X, int Y, int W, int H,
+ int delta, int linedelta, int depth,
+ Fl_Draw_Image_Cb cb, void* userdata)
+{
+ char indexed = 0;
+
+#if USE_COLORMAP
+ indexed = (fl_palette != 0);
+#endif
+
+ if (depth==0) depth = 3;
+ if (indexed || !fl_can_do_alpha_blending())
+ depth = (depth-1)|1;
+
+ if (!linedelta) linedelta = W*delta;
+
+ int x, y, w, h;
+ fl_clip_box(X,Y,W,H,x,y,w,h);
+ if (w<=0 || h<=0) return;
+ if (buf) buf += (x-X)*delta + (y-Y)*linedelta;
+
+ static U32 bmibuffer[256+12];
+ BITMAPINFO &bmi = *((BITMAPINFO*)bmibuffer);
+ if (!bmi.bmiHeader.biSize) {
+ bmi.bmiHeader.biSize = sizeof(bmi)-4; // does it use this to determine type?
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biXPelsPerMeter = 0;
+ bmi.bmiHeader.biYPelsPerMeter = 0;
+ bmi.bmiHeader.biClrUsed = 0;
+ bmi.bmiHeader.biClrImportant = 0;
+ }
+#if USE_COLORMAP
+ if (indexed) {
+ for (short i=0; i<256; i++) {
+ *((short*)(bmi.bmiColors)+i) = i;
+ }
+ } else
+#endif
+ if (depth<3) {
+ RGBQUAD *bmi_colors = &bmi.bmiColors[0]; // suppress warning (STR #3199)
+ for (int i=0; i<256; i++) {
+ bmi_colors[i].rgbBlue = (uchar)i; // bmi.bmiColors[i]...
+ bmi_colors[i].rgbGreen = (uchar)i;
+ bmi_colors[i].rgbRed = (uchar)i;
+ bmi_colors[i].rgbReserved = (uchar)0; // must be zero
+ }
+ }
+ bmi.bmiHeader.biWidth = w;
+#if USE_COLORMAP
+ bmi.bmiHeader.biBitCount = indexed ? 8 : depth*8;
+ int pixelsize = indexed ? 1 : depth;
+#else
+ bmi.bmiHeader.biBitCount = depth*8;
+ int pixelsize = depth;
+#endif
+ if (depth==2) { // special case: gray with alpha
+ bmi.bmiHeader.biBitCount = 32;
+ pixelsize = 4;
+ }
+ int linesize = (pixelsize*w+3)&~3;
+
+ static U32* buffer;
+ static long buffer_size;
+ int blocking = h;
+ {int size = linesize*h;
+ // when printing, don't limit buffer size not to get a crash in StretchDIBits
+ if (size > MAXBUFFER && Fl_Surface_Device::surface() == Fl_Display_Device::display_device()) {
+ size = MAXBUFFER;
+ blocking = MAXBUFFER/linesize;
+ }
+ if (size > buffer_size) {
+ delete[] buffer;
+ buffer_size = size;
+ buffer = new U32[(size+3)/4];
+ }}
+ bmi.bmiHeader.biHeight = blocking;
+ static U32* line_buffer;
+ if (!buf) {
+ int size = W*delta;
+ static int line_buf_size;
+ if (size > line_buf_size) {
+ delete[] line_buffer;
+ line_buf_size = size;
+ line_buffer = new U32[(size+3)/4];
+ }
+ }
+ for (int j=0; j<h; ) {
+ int k;
+ for (k = 0; j<h && k<blocking; k++, j++) {
+ const uchar* from;
+ if (!buf) { // run the converter:
+ cb(userdata, x-X, y-Y+j, w, (uchar*)line_buffer);
+ from = (uchar*)line_buffer;
+ } else {
+ from = buf;
+ buf += linedelta;
+ }
+ uchar *to = (uchar*)buffer+(blocking-k-1)*linesize;
+#if USE_COLORMAP
+ if (indexed) {
+ if (depth<3)
+ monodither(to, from, w, delta);
+ else
+ dither(to, from, w, delta);
+ to += w;
+ } else
+#endif
+ {
+ int i;
+ switch (depth) {
+ case 1:
+ for (i=w; i--; from += delta) *to++ = *from;
+ break;
+ case 2:
+ for (i=w; i--; from += delta, to += 4) {
+ uchar a = from[1];
+ uchar gray = (from[0]*a)>>8;
+ to[0] = gray;
+ to[1] = gray;
+ to[2] = gray;
+ to[3] = a;
+ }
+ break;
+ case 3:
+ for (i=w; i--; from += delta, to += 3) {
+ uchar r = from[0];
+ to[0] = from[2];
+ to[1] = from[1];
+ to[2] = r;
+ }
+ break;
+ case 4:
+ for (i=w; i--; from += delta, to += 4) {
+ uchar a = from[3];
+ uchar r = from[0];
+ to[0] = (from[2]*a)>>8;
+ to[1] = (from[1]*a)>>8;
+ to[2] = (r*a)>>8;
+ to[3] = from[3];
+ }
+ break;
+ }
+ }
+ }
+ if (Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) {
+ // if print context, device and logical units are not equal, so SetDIBitsToDevice
+ // does not do the expected job, whereas StretchDIBits does it.
+ StretchDIBits(fl_gc, x, y+j-k, w, k, 0, 0, w, k,
+ (LPSTR)((uchar*)buffer+(blocking-k)*linesize),
+ &bmi,
+#if USE_COLORMAP
+ indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS
+#else
+ DIB_RGB_COLORS
+#endif
+ , SRCCOPY );
+ delete[] buffer;
+ buffer = NULL;
+ buffer_size = 0;
+ }
+ else {
+ SetDIBitsToDevice(fl_gc, x, y+j-k, w, k, 0, 0, 0, k,
+ (LPSTR)((uchar*)buffer+(blocking-k)*linesize),
+ &bmi,
+#if USE_COLORMAP
+ indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS
+#else
+ DIB_RGB_COLORS
+#endif
+ );
+ }
+ }
+}
+
+static int fl_abs(int v) { return v<0 ? -v : v; }
+
+void Fl_GDI_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
+ if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
+ d ^= FL_IMAGE_WITH_ALPHA;
+ innards(buf,x,y,w,h,d,l,fl_abs(d),0,0);
+ } else {
+ innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0);
+ }
+}
+
+void Fl_GDI_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
+ int x, int y, int w, int h,int d) {
+ if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
+ d ^= FL_IMAGE_WITH_ALPHA;
+ innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
+ } else {
+ innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
+ }
+}
+
+void Fl_GDI_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
+ if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
+ d ^= FL_IMAGE_WITH_ALPHA;
+ innards(buf,x,y,w,h,d,l,1,0,0);
+ } else {
+ innards(buf,x,y,w,h,d,l,1,0,0);
+ }
+}
+
+void Fl_GDI_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
+ int x, int y, int w, int h,int d) {
+ if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) {
+ d ^= FL_IMAGE_WITH_ALPHA;
+ innards(0,x,y,w,h,d,0,1,cb,data);
+ } else {
+ innards(0,x,y,w,h,d,0,1,cb,data);
+ }
+}
+
+void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
+#if USE_COLORMAP
+ // use the error diffusion dithering code to produce a much nicer block:
+ if (fl_palette) {
+ uchar c[3];
+ c[0] = r; c[1] = g; c[2] = b;
+ innards(c,x,y,w,h,0,0,0,0,0);
+ return;
+ }
+#endif
+ fl_color(r,g,b);
+ fl_rectf(x,y,w,h);
+}
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx
index afba28c73..0fe187d91 100644
--- a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx
@@ -73,7 +73,7 @@ int Fl_OpenGL_Graphics_Driver::descent() {
}
int Fl_OpenGL_Graphics_Driver::height() {
- return (int)(size_*0.8);
+ return (int)(size_);
}
void Fl_OpenGL_Graphics_Driver::text_extents(const char *str, int n, int& dx, int& dy, int& w, int& h)
diff --git a/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_image.cxx b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_image.cxx
new file mode 100644
index 000000000..4cb96e6f5
--- /dev/null
+++ b/src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_image.cxx
@@ -0,0 +1,24 @@
+//
+// "$Id$"
+//
+// Image drawing routines for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+// FIXME add code to draw various imge types in OpenGL
+
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx
new file mode 100644
index 000000000..87fcbc068
--- /dev/null
+++ b/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx
@@ -0,0 +1,167 @@
+//
+// "$Id$"
+//
+// MacOS image drawing code for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2012 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+////////////////////////////////////////////////////////////////
+
+#include <config.h>
+#include <FL/Fl.H>
+#include <FL/fl_draw.H>
+#include <FL/Fl_Printer.H>
+#include <FL/x.H>
+
+#define MAXBUFFER 0x40000 // 256k
+
+static void dataReleaseCB(void *info, const void *data, size_t size)
+{
+ delete[] (uchar *)data;
+}
+
+/*
+ * draw an image based on the input parameters
+ *
+ * buf: image source data
+ * X, Y: position (in buffer?!)
+ * W, H: size of picture (in pixel?)
+ * delta: distance from pixel to pixel in buf in bytes
+ * linedelta: distance from line to line in buf in bytes
+ * mono: if set, pixel is one byte - if zero, pixel is 3 byte
+ * cb: callback to copy image data into (RGB?) buffer
+ * buf: pointer to first byte in image source
+ * x, y: position in buffer
+ * w: width (in bytes?)
+ * dst: destination buffer
+ * userdata: ?
+ */
+static void innards(const uchar *buf, int X, int Y, int W, int H,
+ int delta, int linedelta, int mono,
+ Fl_Draw_Image_Cb cb, void* userdata)
+{
+ if (!linedelta) linedelta = W*delta;
+
+ const void *array = buf;
+ uchar *tmpBuf = 0;
+ if (cb || Fl_Surface_Device::surface() != Fl_Display_Device::display_device()) {
+ tmpBuf = new uchar[ H*W*delta ];
+ if (cb) {
+ for (int i=0; i<H; i++) {
+ cb(userdata, 0, i, W, tmpBuf+i*W*delta);
+ }
+ } else {
+ uchar *p = tmpBuf;
+ for (int i=0; i<H; i++) {
+ memcpy(p, buf+i*linedelta, W*delta);
+ p += W*delta;
+ }
+ }
+ array = (void*)tmpBuf;
+ linedelta = W*delta;
+ }
+ // create an image context
+ CGColorSpaceRef lut = 0;
+ if (delta<=2)
+ lut = CGColorSpaceCreateDeviceGray();
+ else
+ lut = CGColorSpaceCreateDeviceRGB();
+ // a release callback is necessary when the fl_gc is a print context because the image data
+ // must be kept until the page is closed. Thus tmpBuf can't be deleted here. It's too early.
+ CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, linedelta*H,
+ tmpBuf ? dataReleaseCB : NULL
+ );
+ CGImageRef img = CGImageCreate( W, H, 8, 8*delta, linedelta,
+ lut, delta&1?kCGImageAlphaNone:kCGImageAlphaNoneSkipLast,
+ //lut, delta&1?kCGImageAlphaNone:kCGImageAlphaLast,
+ src, 0L, false, kCGRenderingIntentDefault);
+ // draw the image into the destination context
+ if (img) {
+ CGRect rect = CGRectMake( X, Y, W, H);
+ Fl_X::q_begin_image(rect, 0, 0, W, H);
+ CGContextDrawImage(fl_gc, rect, img);
+ Fl_X::q_end_image();
+ // release all allocated resources
+ CGImageRelease(img);
+ }
+ CGColorSpaceRelease(lut);
+ CGDataProviderRelease(src);
+ if (img) return; // else fall through to slow mode
+ // following the very save (and very slow) way to write the image into the give port
+ CGContextSetShouldAntialias(fl_gc, false);
+ if ( cb )
+ {
+ uchar *tmpBuf = new uchar[ W*4 ];
+ for ( int i=0; i<H; i++ )
+ {
+ uchar *src = tmpBuf;
+ cb( userdata, 0, i, W, tmpBuf );
+ for ( int j=0; j<W; j++ )
+ {
+ if ( mono )
+ { fl_color( src[0], src[0], src[0] ); }
+ else
+ { fl_color( src[0], src[1], src[2] ); }
+ CGContextMoveToPoint(fl_gc, X+j, Y+i);
+ CGContextAddLineToPoint(fl_gc, X+j, Y+i);
+ CGContextStrokePath(fl_gc);
+ src+=delta;
+ }
+ }
+ delete[] tmpBuf;
+ }
+ else
+ {
+ for ( int i=0; i<H; i++ )
+ {
+ const uchar *src = buf+i*linedelta;
+ for ( int j=0; j<W; j++ )
+ {
+ if ( mono )
+ fl_color( src[0], src[0], src[0] );
+ else
+ fl_color( src[0], src[1], src[2] );
+ CGContextMoveToPoint(fl_gc, X+j, Y+i);
+ CGContextAddLineToPoint(fl_gc, X+j, Y+i);
+ CGContextStrokePath(fl_gc);
+ src += delta;
+ }
+ }
+ }
+ CGContextSetShouldAntialias(fl_gc, true);
+}
+
+void Fl_Quartz_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
+ innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0);
+}
+void Fl_Quartz_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
+ int x, int y, int w, int h,int d) {
+ innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
+}
+void Fl_Quartz_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
+ innards(buf,x,y,w,h,d,l,1,0,0);
+}
+void Fl_Quartz_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
+ int x, int y, int w, int h,int d) {
+ innards(0,x,y,w,h,d,0,1,cb,data);
+}
+
+void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
+ fl_color(r,g,b);
+ fl_rectf(x,y,w,h);
+}
+
+//
+// End of "$Id$".
+//
diff --git a/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx
new file mode 100644
index 000000000..5ec63fd06
--- /dev/null
+++ b/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx
@@ -0,0 +1,605 @@
+//
+// "$Id$"
+//
+// Image drawing routines for the Fast Light Tool Kit (FLTK).
+//
+// Copyright 1998-2010 by Bill Spitzak and others.
+//
+// This library is free software. Distribution and use rights are outlined in
+// the file "COPYING" which should have been included with this file. If this
+// file is missing or damaged, see the license at:
+//
+// http://www.fltk.org/COPYING.php
+//
+// Please report all bugs and problems on the following page:
+//
+// http://www.fltk.org/str.php
+//
+
+// I hope a simple and portable method of drawing color and monochrome
+// images. To keep this simple, only a single storage type is
+// supported: 8 bit unsigned data, byte order RGB, and pixels are
+// stored packed into rows with the origin at the top-left. It is
+// possible to alter the size of pixels with the "delta" argument, to
+// add alpha or other information per pixel. It is also possible to
+// change the origin and direction of the image data by messing with
+// the "delta" and "linedelta", making them negative, though this may
+// defeat some of the shortcuts in translating the image for X.
+
+
+// A list of assumptions made about the X display:
+
+// bits_per_pixel must be one of 8, 16, 24, 32.
+
+// scanline_pad must be a power of 2 and greater or equal to 8.
+
+// PsuedoColor visuals must have 8 bits_per_pixel (although the depth
+// may be less than 8). This is the only limitation that affects any
+// modern X displays, you can't use 12 or 16 bit colormaps.
+
+// The mask bits in TrueColor visuals for each color are
+// contiguous and have at least one bit of each color. This
+// is not checked for.
+
+// For 24 and 32 bit visuals there must be at least 8 bits of each color.
+
+////////////////////////////////////////////////////////////////
+
+# include <FL/Fl.H>
+# include <FL/fl_draw.H>
+# include <FL/x.H>
+# include "Fl_XColor.H"
+# include "flstring.h"
+
+static XImage xi; // template used to pass info to X
+static int bytes_per_pixel;
+static int scanline_add;
+static int scanline_mask;
+
+static void (*converter)(const uchar *from, uchar *to, int w, int delta);
+static void (*mono_converter)(const uchar *from, uchar *to, int w, int delta);
+
+static int dir; // direction-alternator
+static int ri,gi,bi; // saved error-diffusion value
+
+# if USE_COLORMAP
+////////////////////////////////////////////////////////////////
+// 8-bit converter with error diffusion
+
+static void color8_converter(const uchar *from, uchar *to, int w, int delta) {
+ int r=ri, g=gi, b=bi;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ to = to+(w-1);
+ d = -delta;
+ td = -1;
+ } else {
+ dir = 1;
+ d = delta;
+ td = 1;
+ }
+ for (; w--; from += d, to += td) {
+ r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
+ g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255;
+ b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255;
+ Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
+ Fl_XColor& xmap = fl_xmap[0][i];
+ if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
+ r -= xmap.r;
+ g -= xmap.g;
+ b -= xmap.b;
+ *to = uchar(xmap.pixel);
+ }
+ ri = r; gi = g; bi = b;
+}
+
+static void mono8_converter(const uchar *from, uchar *to, int w, int delta) {
+ int r=ri, g=gi, b=bi;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ to = to+(w-1);
+ d = -delta;
+ td = -1;
+ } else {
+ dir = 1;
+ d = delta;
+ td = 1;
+ }
+ for (; w--; from += d, to += td) {
+ r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255;
+ g += from[0]; if (g < 0) g = 0; else if (g>255) g = 255;
+ b += from[0]; if (b < 0) b = 0; else if (b>255) b = 255;
+ Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256);
+ Fl_XColor& xmap = fl_xmap[0][i];
+ if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);}
+ r -= xmap.r;
+ g -= xmap.g;
+ b -= xmap.b;
+ *to = uchar(xmap.pixel);
+ }
+ ri = r; gi = g; bi = b;
+}
+
+# endif
+
+////////////////////////////////////////////////////////////////
+// 16 bit TrueColor converters with error diffusion
+// Cray computers have no 16-bit type, so we use character pointers
+// (which may be slow)
+
+# ifdef U16
+# define OUTTYPE U16
+# define OUTSIZE 1
+# define OUTASSIGN(v) *t = v
+# else
+# define OUTTYPE uchar
+# define OUTSIZE 2
+# define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt)
+# endif
+
+static void color16_converter(const uchar *from, uchar *to, int w, int delta) {
+ OUTTYPE *t = (OUTTYPE *)to;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ t = t+(w-1)*OUTSIZE;
+ d = -delta;
+ td = -OUTSIZE;
+ } else {
+ dir = 1;
+ d = delta;
+ td = OUTSIZE;
+ }
+ int r=ri, g=gi, b=bi;
+ for (; w--; from += d, t += td) {
+ r = (r&~fl_redmask) +from[0]; if (r>255) r = 255;
+ g = (g&~fl_greenmask)+from[1]; if (g>255) g = 255;
+ b = (b&~fl_bluemask) +from[2]; if (b>255) b = 255;
+ OUTASSIGN((
+ ((r&fl_redmask)<<fl_redshift)+
+ ((g&fl_greenmask)<<fl_greenshift)+
+ ((b&fl_bluemask)<<fl_blueshift)
+ ) >> fl_extrashift);
+ }
+ ri = r; gi = g; bi = b;
+}
+
+static void mono16_converter(const uchar *from,uchar *to,int w, int delta) {
+ OUTTYPE *t = (OUTTYPE *)to;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ t = t+(w-1)*OUTSIZE;
+ d = -delta;
+ td = -OUTSIZE;
+ } else {
+ dir = 1;
+ d = delta;
+ td = OUTSIZE;
+ }
+ uchar mask = fl_redmask & fl_greenmask & fl_bluemask;
+ int r=ri;
+ for (; w--; from += d, t += td) {
+ r = (r&~mask) + *from; if (r > 255) r = 255;
+ uchar m = r&mask;
+ OUTASSIGN((
+ (m<<fl_redshift)+
+ (m<<fl_greenshift)+
+ (m<<fl_blueshift)
+ ) >> fl_extrashift);
+ }
+ ri = r;
+}
+
+// special-case the 5r6g5b layout used by XFree86:
+
+static void c565_converter(const uchar *from, uchar *to, int w, int delta) {
+ OUTTYPE *t = (OUTTYPE *)to;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ t = t+(w-1)*OUTSIZE;
+ d = -delta;
+ td = -OUTSIZE;
+ } else {
+ dir = 1;
+ d = delta;
+ td = OUTSIZE;
+ }
+ int r=ri, g=gi, b=bi;
+ for (; w--; from += d, t += td) {
+ r = (r&7)+from[0]; if (r>255) r = 255;
+ g = (g&3)+from[1]; if (g>255) g = 255;
+ b = (b&7)+from[2]; if (b>255) b = 255;
+ OUTASSIGN(((r&0xf8)<<8) + ((g&0xfc)<<3) + (b>>3));
+ }
+ ri = r; gi = g; bi = b;
+}
+
+static void m565_converter(const uchar *from,uchar *to,int w, int delta) {
+ OUTTYPE *t = (OUTTYPE *)to;
+ int d, td;
+ if (dir) {
+ dir = 0;
+ from = from+(w-1)*delta;
+ t = t+(w-1)*OUTSIZE;
+ d = -delta;
+ td = -OUTSIZE;
+ } else {
+ dir = 1;
+ d = delta;
+ td = OUTSIZE;
+ }
+ int r=ri;
+ for (; w--; from += d, t += td) {
+ r = (r&7) + *from; if (r > 255) r = 255;
+ OUTASSIGN((r>>3) * 0x841);
+ }
+ ri = r;
+}
+
+////////////////////////////////////////////////////////////////
+// 24bit TrueColor converters:
+
+static void rgb_converter(const uchar *from, uchar *to, int w, int delta) {
+ int d = delta-3;
+ for (; w--; from += d) {
+ *to++ = *from++;
+ *to++ = *from++;
+ *to++ = *from++;
+ }
+}
+
+static void bgr_converter(const uchar *from, uchar *to, int w, int delta) {
+ for (; w--; from += delta) {
+ uchar r = from[0];
+ uchar g = from[1];
+ *to++ = from[2];
+ *to++ = g;
+ *to++ = r;
+ }
+}
+
+static void rrr_converter(const uchar *from, uchar *to, int w, int delta) {
+ for (; w--; from += delta) {
+ *to++ = *from;
+ *to++ = *from;
+ *to++ = *from;
+ }
+}
+
+////////////////////////////////////////////////////////////////
+// 32bit TrueColor converters on a 32 or 64-bit machine:
+
+# ifdef U64
+# define STORETYPE U64
+# if WORDS_BIGENDIAN
+# define INNARDS32(f) \
+ U64 *t = (U64*)to; \
+ int w1 = w/2; \
+ for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = (i<<32)|(f);} \
+ if (w&1) *t++ = (U64)(f)<<32;
+# else
+# define INNARDS32(f) \
+ U64 *t = (U64*)to; \
+ int w1 = w/2; \
+ for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = ((U64)(f)<<32)|i;} \
+ if (w&1) *t++ = (U64)(f);
+# endif
+# else
+# define STORETYPE U32
+# define INNARDS32(f) \
+ U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f
+# endif
+
+static void rgbx_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32((unsigned(from[0])<<24)+(from[1]<<16)+(from[2]<<8));
+}
+
+static void xbgr_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32((from[0])+(from[1]<<8)+(from[2]<<16));
+}
+
+static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2]));
+}
+
+static void argb_premul_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32((unsigned(from[3]) << 24) +
+ (((from[0] * from[3]) / 255) << 16) +
+ (((from[1] * from[3]) / 255) << 8) +
+ ((from[2] * from[3]) / 255));
+}
+
+static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24));
+}
+
+static void rrrx_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32(unsigned(*from) * 0x1010100U);
+}
+
+static void xrrr_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32(*from * 0x10101U);
+}
+
+static void
+color32_converter(const uchar *from, uchar *to, int w, int delta) {
+ INNARDS32(
+ (from[0]<<fl_redshift)+(from[1]<<fl_greenshift)+(from[2]<<fl_blueshift));
+}
+
+static void
+mono32_converter(const uchar *from,uchar *to,int w, int delta) {
+ INNARDS32(
+ (*from << fl_redshift)+(*from << fl_greenshift)+(*from << fl_blueshift));
+}
+
+////////////////////////////////////////////////////////////////
+
+static void figure_out_visual() {
+
+ fl_xpixel(FL_BLACK); // setup fl_redmask, etc, in fl_color.cxx
+ fl_xpixel(FL_WHITE); // also make sure white is allocated
+
+ static XPixmapFormatValues *pfvlist;
+ static int FL_NUM_pfv;
+ if (!pfvlist) pfvlist = XListPixmapFormats(fl_display,&FL_NUM_pfv);
+ XPixmapFormatValues *pfv;
+ for (pfv = pfvlist; pfv < pfvlist+FL_NUM_pfv; pfv++)
+ if (pfv->depth == fl_visual->depth) break;
+ xi.format = ZPixmap;
+ xi.byte_order = ImageByteOrder(fl_display);
+//i.bitmap_unit = 8;
+//i.bitmap_bit_order = MSBFirst;
+//i.bitmap_pad = 8;
+ xi.depth = fl_visual->depth;
+ xi.bits_per_pixel = pfv->bits_per_pixel;
+
+ if (xi.bits_per_pixel & 7) bytes_per_pixel = 0; // produce fatal error
+ else bytes_per_pixel = xi.bits_per_pixel/8;
+
+ unsigned int n = pfv->scanline_pad/8;
+ if (pfv->scanline_pad & 7 || (n&(n-1)))
+ Fl::fatal("Can't do scanline_pad of %d",pfv->scanline_pad);
+ if (n < sizeof(STORETYPE)) n = sizeof(STORETYPE);
+ scanline_add = n-1;
+ scanline_mask = -n;
+
+# if USE_COLORMAP
+ if (bytes_per_pixel == 1) {
+ converter = color8_converter;
+ mono_converter = mono8_converter;
+ return;
+ }
+ if (!fl_visual->red_mask)
+ Fl::fatal("Can't do %d bits_per_pixel colormap",xi.bits_per_pixel);
+# endif
+
+ // otherwise it is a TrueColor visual:
+
+ int rs = fl_redshift;
+ int gs = fl_greenshift;
+ int bs = fl_blueshift;
+
+ switch (bytes_per_pixel) {
+
+ case 2:
+ // All 16-bit TrueColor visuals are supported on any machine with
+ // 24 or more bits per integer.
+# ifdef U16
+ xi.byte_order = WORDS_BIGENDIAN;
+# else
+ xi.byte_order = 1;
+# endif
+ if (rs == 11 && gs == 6 && bs == 0 && fl_extrashift == 3) {
+ converter = c565_converter;
+ mono_converter = m565_converter;
+ } else {
+ converter = color16_converter;
+ mono_converter = mono16_converter;
+ }
+ break;
+
+ case 3:
+ if (xi.byte_order) {rs = 16-rs; gs = 16-gs; bs = 16-bs;}
+ if (rs == 0 && gs == 8 && bs == 16) {
+ converter = rgb_converter;
+ mono_converter = rrr_converter;
+ } else if (rs == 16 && gs == 8 && bs == 0) {
+ converter = bgr_converter;
+ mono_converter = rrr_converter;
+ } else {
+ Fl::fatal("Can't do arbitrary 24bit color");
+ }
+ break;
+
+ case 4:
+ if ((xi.byte_order!=0) != WORDS_BIGENDIAN)
+ {rs = 24-rs; gs = 24-gs; bs = 24-bs;}
+ if (rs == 0 && gs == 8 && bs == 16) {
+ converter = xbgr_converter;
+ mono_converter = xrrr_converter;
+ } else if (rs == 24 && gs == 16 && bs == 8) {
+ converter = rgbx_converter;
+ mono_converter = rrrx_converter;
+ } else if (rs == 8 && gs == 16 && bs == 24) {
+ converter = bgrx_converter;
+ mono_converter = rrrx_converter;
+ } else if (rs == 16 && gs == 8 && bs == 0) {
+ converter = xrgb_converter;
+ mono_converter = xrrr_converter;
+ } else {
+ xi.byte_order = WORDS_BIGENDIAN;
+ converter = color32_converter;
+ mono_converter = mono32_converter;
+ }
+ break;
+
+ default:
+ Fl::fatal("Can't do %d bits_per_pixel",xi.bits_per_pixel);
+ }
+
+}
+
+# define MAXBUFFER 0x40000 // 256k
+
+static void innards(const uchar *buf, int X, int Y, int W, int H,
+ int delta, int linedelta, int mono,
+ Fl_Draw_Image_Cb cb, void* userdata,
+ const bool alpha)
+{
+ if (!linedelta) linedelta = W*delta;
+
+ int dx, dy, w, h;
+ fl_clip_box(X,Y,W,H,dx,dy,w,h);
+ if (w<=0 || h<=0) return;
+ dx -= X;
+ dy -= Y;
+
+ if (!bytes_per_pixel) figure_out_visual();
+ const unsigned oldbpp = bytes_per_pixel;
+ const GC oldgc = fl_gc;
+ static GC gc32 = None;
+ xi.width = w;
+ xi.height = h;
+
+ void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter;
+ if (mono) conv = mono_converter;
+ if (alpha) {
+ // This flag states the destination format is ARGB32 (big-endian), pre-multiplied.
+ bytes_per_pixel = 4;
+ conv = argb_premul_converter;
+ xi.depth = 32;
+ xi.bits_per_pixel = 32;
+
+ // Do we need a new GC?
+ if (fl_visual->depth != 32) {
+ if (gc32 == None)
+ gc32 = XCreateGC(fl_display, fl_window, 0, NULL);
+ fl_gc = gc32;
+ }
+ }
+
+ // See if the data is already in the right format. Unfortunately
+ // some 32-bit x servers (XFree86) care about the unknown 8 bits
+ // and they must be zero. I can't confirm this for user-supplied
+ // data, so the 32-bit shortcut is disabled...
+ // This can set bytes_per_line negative if image is bottom-to-top
+ // I tested it on Linux, but it may fail on other Xlib implementations:
+ if (buf && (
+# if 0 // set this to 1 to allow 32-bit shortcut
+ delta == 4 &&
+# if WORDS_BIGENDIAN
+ conv == rgbx_converter
+# else
+ conv == xbgr_converter
+# endif
+ ||
+# endif
+ conv == rgb_converter && delta==3
+ ) && !(linedelta&scanline_add)) {
+ xi.data = (char *)(buf+delta*dx+linedelta*dy);
+ xi.bytes_per_line = linedelta;
+
+ } else {
+ int linesize = ((w*bytes_per_pixel+scanline_add)&scanline_mask)/sizeof(STORETYPE);
+ int blocking = h;
+ static STORETYPE *buffer; // our storage, always word aligned
+ static long buffer_size;
+ {int size = linesize*h;
+ if (size > MAXBUFFER) {
+ size = MAXBUFFER;
+ blocking = MAXBUFFER/linesize;
+ }
+ if (size > buffer_size) {
+ delete[] buffer;
+ buffer_size = size;
+ buffer = new STORETYPE[size];
+ }}
+ xi.data = (char *)buffer;
+ xi.bytes_per_line = linesize*sizeof(STORETYPE);
+ if (buf) {
+ buf += delta*dx+linedelta*dy;
+ for (int j=0; j<h; ) {
+ STORETYPE *to = buffer;
+ int k;
+ for (k = 0; j<h && k<blocking; k++, j++) {
+ conv(buf, (uchar*)to, w, delta);
+ buf += linedelta;
+ to += linesize;
+ }
+ XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
+ }
+ } else {
+ STORETYPE* linebuf = new STORETYPE[(W*delta+(sizeof(STORETYPE)-1))/sizeof(STORETYPE)];
+ for (int j=0; j<h; ) {
+ STORETYPE *to = buffer;
+ int k;
+ for (k = 0; j<h && k<blocking; k++, j++) {
+ cb(userdata, dx, dy+j, w, (uchar*)linebuf);
+ conv((uchar*)linebuf, (uchar*)to, w, delta);
+ to += linesize;
+ }
+ XPutImage(fl_display,fl_window,fl_gc, &xi, 0, 0, X+dx, Y+dy+j-k, w, k);
+ }
+
+ delete[] linebuf;
+ }
+ }
+
+ if (alpha) {
+ bytes_per_pixel = oldbpp;
+ xi.depth = fl_visual->depth;
+ xi.bits_per_pixel = oldbpp * 8;
+
+ if (fl_visual->depth != 32) {
+ fl_gc = oldgc;
+ }
+ }
+}
+
+void Fl_Xlib_Graphics_Driver::draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){
+
+ const bool alpha = !!(d & FL_IMAGE_WITH_ALPHA);
+ d &= ~FL_IMAGE_WITH_ALPHA;
+
+ innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0,alpha);
+}
+void Fl_Xlib_Graphics_Driver::draw_image(Fl_Draw_Image_Cb cb, void* data,
+ int x, int y, int w, int h,int d) {
+
+ const bool alpha = !!(d & FL_IMAGE_WITH_ALPHA);
+ d &= ~FL_IMAGE_WITH_ALPHA;
+
+ innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data,alpha);
+}
+void Fl_Xlib_Graphics_Driver::draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){
+ innards(buf,x,y,w,h,d,l,1,0,0,0);
+}
+void Fl_Xlib_Graphics_Driver::draw_image_mono(Fl_Draw_Image_Cb cb, void* data,
+ int x, int y, int w, int h,int d) {
+ innards(0,x,y,w,h,d,0,1,cb,data,0);
+}
+
+void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
+ if (fl_visual->depth > 16) {
+ fl_color(r,g,b);
+ fl_rectf(x,y,w,h);
+ } else {
+ uchar c[3];
+ c[0] = r; c[1] = g; c[2] = b;
+ innards(c,x,y,w,h,0,0,0,0,0,0);
+ }
+}
+
+//
+// End of "$Id$".
+//