Add support for accelerated alpha blending under X11.
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@10628 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
This commit is contained in:
parent
4798d70ded
commit
c91e48149b
14
CHANGES
14
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
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
1
FL/x.H
1
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; \
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user