diff options
Diffstat (limited to 'src/drivers')
| -rw-r--r-- | src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx | 337 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_font.cxx | 2 | ||||
| -rw-r--r-- | src/drivers/OpenGL/Fl_OpenGL_Graphics_Driver_image.cxx | 24 | ||||
| -rw-r--r-- | src/drivers/Quartz/Fl_Quartz_Graphics_Driver_image.cxx | 167 | ||||
| -rw-r--r-- | src/drivers/Xlib/Fl_Xlib_Graphics_Driver_image.cxx | 605 |
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$". +// |
