summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES14
-rw-r--r--FL/Fl_Device.H3
-rw-r--r--FL/x.H1
-rw-r--r--src/Fl_Double_Window.cxx34
-rw-r--r--src/Fl_Image.cxx15
-rw-r--r--src/fl_draw_image.cxx55
6 files changed, 105 insertions, 17 deletions
diff --git a/CHANGES b/CHANGES
index 049b2db8c..2ce0477c8 100644
--- a/CHANGES
+++ b/CHANGES
@@ -5,10 +5,10 @@ CHANGES IN FLTK 1.3.4 RELEASED: ??? ?? ????
- Added full support of true subwindows to the Mac OS X platform.
Window nesting to any depth is possible. An Fl_Gl_Window window or
subwindow can contain Fl_Window's as subwindows.
- - Added the Fl_Shared_Image::scale(width, height) function which gives
- a shared image its own drawing size, independently of the size of the
- underlying image. This improves much image drawing on high resolution
- surfaces such as Laser printers, PDF files, or Apple retina displays.
+ - Added the Fl_Shared_Image::scale(width, height) function which gives
+ a shared image its own drawing size, independently of the size of the
+ underlying image. This improves much image drawing on high resolution
+ surfaces such as Laser printers, PDF files, or Apple retina displays.
Other improvements
@@ -23,8 +23,10 @@ CHANGES IN FLTK 1.3.4 RELEASED: ??? ?? ????
(i.e. when called) - only destruction is delayed as before.
- The PostScript code output when printing images under Linux/Unix
is quite smaller due to use of lossless compression techniques.
- - The Linux/Unix printer dialog now uses BSD-style printing commands
- (lpr/lpq) when SystemV-style commands (lp/lpstat) are not available.
+ - The Linux/Unix printer dialog now uses BSD-style printing commands
+ (lpr/lpq) when SystemV-style commands (lp/lpstat) are not available.
+ - Drawing alpha-blended images under X11 is now accelerated with
+ Xrender.
Bug fixes
diff --git a/FL/Fl_Device.H b/FL/Fl_Device.H
index 4d048d179..df66e7a75 100644
--- a/FL/Fl_Device.H
+++ b/FL/Fl_Device.H
@@ -525,6 +525,9 @@ public:
int height();
int descent();
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
+#if ! defined(FL_DOXYGEN)
+ void copy_offscreen_with_alpha(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy);
+#endif
};
#endif
diff --git a/FL/x.H b/FL/x.H
index f1f23f918..336acff9e 100644
--- a/FL/x.H
+++ b/FL/x.H
@@ -84,6 +84,7 @@ extern FL_EXPORT ulong fl_event_time;
// off-screen pixmaps: create, destroy, draw into, copy to window:
typedef ulong Fl_Offscreen;
# define fl_create_offscreen(w,h) XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, fl_visual->depth)
+# define fl_create_offscreen_with_alpha(w,h) XCreatePixmap(fl_display, RootWindow(fl_display, fl_screen), w, h, 32)
// begin/end are macros that save the old state in local variables:
# define fl_begin_offscreen(pixmap) \
Window _sw=fl_window; fl_window=pixmap; \
diff --git a/src/Fl_Double_Window.cxx b/src/Fl_Double_Window.cxx
index 99ba3e7d1..f85af930b 100644
--- a/src/Fl_Double_Window.cxx
+++ b/src/Fl_Double_Window.cxx
@@ -129,14 +129,44 @@ void Fl_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen
#if defined(USE_X11)
+#ifdef HAVE_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
void Fl_Xlib_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, Fl_Offscreen pixmap, int srcx, int srcy) {
XCopyArea(fl_display, pixmap, fl_window, fl_gc, srcx, srcy, w, h, x, y);
}
+void Fl_Xlib_Graphics_Driver::copy_offscreen_with_alpha(int x, int y, int w, int h,
+ Fl_Offscreen pixmap, int srcx, int srcy) {
+#ifdef HAVE_XRENDER
+ XRenderPictureAttributes srcattr;
+ memset(&srcattr, 0, sizeof(XRenderPictureAttributes));
+ XRenderPictFormat *srcfmt = XRenderFindStandardFormat(fl_display, PictStandardARGB32);
+ XRenderPictFormat *dstfmt = XRenderFindStandardFormat(fl_display, PictStandardRGB24);
+
+ Picture src = XRenderCreatePicture(fl_display, pixmap, srcfmt, 0, &srcattr);
+ Picture dst = XRenderCreatePicture(fl_display, fl_window, dstfmt, 0, &srcattr);
+
+ if (!src || !dst) {
+ fprintf(stderr, "Failed to create Render pictures (%lu %lu)\n", src, dst);
+ return;
+ }
+
+ const Fl_Region clipr = fl_clip_region();
+ if (clipr)
+ XRenderSetPictureClipRegion(fl_display, dst, clipr);
+
+ XRenderComposite(fl_display, PictOpOver, src, None, dst, srcx, srcy, 0, 0,
+ x, y, w, h);
+
+ XRenderFreePicture(fl_display, src);
+ XRenderFreePicture(fl_display, dst);
+#endif
+}
-// maybe someone feels inclined to implement alpha blending on X11?
char fl_can_do_alpha_blending() {
- return 0;
+ return Fl_X::xrender_supported();
}
#elif defined(WIN32)
diff --git a/src/Fl_Image.cxx b/src/Fl_Image.cxx
index 340b1bcd4..4dea195db 100644
--- a/src/Fl_Image.cxx
+++ b/src/Fl_Image.cxx
@@ -711,6 +711,12 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, in
fl_begin_offscreen((Fl_Offscreen)img->id_);
fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d(), img->ld());
fl_end_offscreen();
+ } else if (img->d() == 4 && fl_can_do_alpha_blending()) {
+ img->id_ = fl_create_offscreen_with_alpha(img->w(), img->h());
+ fl_begin_offscreen((Fl_Offscreen)img->id_);
+ fl_draw_image(img->array, 0, 0, img->w(), img->h(), img->d() | FL_IMAGE_WITH_ALPHA,
+ img->ld());
+ fl_end_offscreen();
}
}
if (img->id_) {
@@ -726,9 +732,12 @@ void Fl_Xlib_Graphics_Driver::draw(Fl_RGB_Image *img, int XP, int YP, int WP, in
int oy = Y-cy; if (oy < 0) oy += img->h();
XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy);
}
-
- copy_offscreen(X, Y, W, H, img->id_, cx, cy);
-
+
+ if (img->d() == 4 && fl_can_do_alpha_blending())
+ copy_offscreen_with_alpha(X, Y, W, H, img->id_, cx, cy);
+ else
+ copy_offscreen(X, Y, W, H, img->id_, cx, cy);
+
if (img->mask_) {
// put the old clip region back
XSetClipOrigin(fl_display, fl_gc, 0, 0);
diff --git a/src/fl_draw_image.cxx b/src/fl_draw_image.cxx
index 68ff5505d..2562e473e 100644
--- a/src/fl_draw_image.cxx
+++ b/src/fl_draw_image.cxx
@@ -316,6 +316,13 @@ 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((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));
}
@@ -451,7 +458,8 @@ static void figure_out_visual() {
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)
+ Fl_Draw_Image_Cb cb, void* userdata,
+ const bool alpha)
{
if (!linedelta) linedelta = W*delta;
@@ -462,11 +470,28 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
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
@@ -534,21 +559,39 @@ static void innards(const uchar *buf, int X, int Y, int W, int H,
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){
- innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0);
+
+ 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) {
- innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data);
+
+ 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);
+ 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);
+ 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) {
@@ -558,7 +601,7 @@ void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) {
} else {
uchar c[3];
c[0] = r; c[1] = g; c[2] = b;
- innards(c,x,y,w,h,0,0,0,0,0);
+ innards(c,x,y,w,h,0,0,0,0,0,0);
}
}