From c6de2dd3ef9e9a3c17ce210ff1775bd6e183d738 Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Fri, 15 Sep 2006 15:35:16 +0000 Subject: Implemented alpha blending for WIN32. I believe that I did it in a way that is compatible even with Windows 95, but please let me know if you have any concerns. Cygwin not tested, but hopefully OK. git-svn-id: file:///fltk/svn/fltk/branches/branch-1.1@5430 ea41ed52-d2ee-0310-a9c1-e6b18d33e121 --- CHANGES | 1 + FL/fl_draw.H | 1 + src/Fl_Double_Window.cxx | 44 ++++++++++++++++++++++++++++- src/Fl_Image.cxx | 2 +- src/fl_draw_image_win32.cxx | 68 ++++++++++++++++++++++++++++++++------------- 5 files changed, 94 insertions(+), 22 deletions(-) diff --git a/CHANGES b/CHANGES index 9efe11724..dd16b6fb4 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,6 @@ CHANGES IN FLTK 1.1.8 + - Implemented alpha blending for WIN32 - Updated documentation (STR #1420, STR #1421) - Fixed font caching issue (STR #1415) - Fixed crash in fl_file_chooser (STR #1410) diff --git a/FL/fl_draw.H b/FL/fl_draw.H index bfd3ef26f..509826ef4 100644 --- a/FL/fl_draw.H +++ b/FL/fl_draw.H @@ -178,6 +178,7 @@ typedef void (*Fl_Draw_Image_Cb)(void*,int,int,int,uchar*); FL_EXPORT void fl_draw_image(Fl_Draw_Image_Cb, void*, int,int,int,int, int delta=3); FL_EXPORT void fl_draw_image_mono(Fl_Draw_Image_Cb, void*, int,int,int,int, int delta=1); FL_EXPORT void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b); +FL_EXPORT char fl_can_do_alpha_blending(); FL_EXPORT uchar *fl_read_image(uchar *p, int x,int y, int w, int h, int alpha=0); diff --git a/src/Fl_Double_Window.cxx b/src/Fl_Double_Window.cxx index 54fd2b935..4e5f7bf1b 100644 --- a/src/Fl_Double_Window.cxx +++ b/src/Fl_Double_Window.cxx @@ -76,6 +76,28 @@ void Fl_Double_Window::show() { // Code used to switch output to an off-screen window. See macros in // win32.H which save the old state in local variables. +typedef struct { BYTE a; BYTE b; BYTE c; BYTE d; } FL_BLENDFUNCTION; +typedef BOOL (WINAPI* fl_alpha_blend_func) + (HDC,int,int,int,int,HDC,int,int,int,int,FL_BLENDFUNCTION); +static fl_alpha_blend_func fl_alpha_blend = NULL; + +/* + * This function checks if the version of MSWindows that we + * curently run on supports alpha blending for bitmap transfers + * and finds the required function if so. + */ +char fl_can_do_alpha_blending() { + static char been_here = 0; + static char can_do = 0; + if (been_here) return can_do; + HMODULE hMod = LoadLibrary("MSIMG32.DLL"); + if (!hMod) return 0; + fl_alpha_blend = (fl_alpha_blend_func)GetProcAddress(hMod, "AlphaBlend"); + if (!fl_alpha_blend) return 0; + can_do = 1; + return 1; +} + HDC fl_makeDC(HBITMAP bitmap) { HDC new_gc = CreateCompatibleDC(fl_gc); SetTextAlign(new_gc, TA_BASELINE|TA_LEFT); @@ -88,10 +110,15 @@ HDC fl_makeDC(HBITMAP bitmap) { } void fl_copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { + static FL_BLENDFUNCTION blendfunc = { 0, 0, 255, 1}; + HDC new_gc = CreateCompatibleDC(fl_gc); int save = SaveDC(new_gc); SelectObject(new_gc, bitmap); - BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); + if (fl_can_do_alpha_blending()) + fl_alpha_blend(fl_gc, x, y, w, h, new_gc, srcx, srcy, w, h, blendfunc); + else + BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); RestoreDC(new_gc, save); DeleteDC(new_gc); } @@ -100,6 +127,10 @@ extern void fl_restore_clip(); #elif defined(__APPLE_QD__) +char fl_can_do_alpha_blending() { + return 0; +} + GWorldPtr fl_create_offscreen(int w, int h) { GWorldPtr gw; Rect bounds; @@ -173,6 +204,10 @@ extern void fl_restore_clip(); #elif defined(__APPLE_QUARTZ__) +char fl_can_do_alpha_blending() { + return 1; +} + Fl_Offscreen fl_create_offscreen(int w, int h) { void *data = calloc(w*h,4); CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); @@ -254,6 +289,13 @@ void fl_end_offscreen() { extern void fl_restore_clip(); +#else // X11 + +// maybe someone feels inclined to implement alpha blending on X11? +char fl_can_do_alpha_blending() { + return 0; +} + #endif // Fl_Overlay_Window relies on flush(1) copying the back buffer to the diff --git a/src/Fl_Image.cxx b/src/Fl_Image.cxx index 60e56078a..f1247512a 100644 --- a/src/Fl_Image.cxx +++ b/src/Fl_Image.cxx @@ -352,7 +352,7 @@ void Fl_RGB_Image::draw(int XP, int YP, int WP, int HP, int cx, int cy) { fl_begin_offscreen((Fl_Offscreen)id); fl_draw_image(array, 0, 0, w(), h(), d(), ld()); fl_end_offscreen(); - if (d() == 2 || d() == 4) { + if (d() == 2 || d() == 4 && !fl_can_do_alpha_blending()) { mask = fl_create_alphamask(w(), h(), d(), ld(), array); } #endif diff --git a/src/fl_draw_image_win32.cxx b/src/fl_draw_image_win32.cxx index a47cbfc10..f55ca9720 100644 --- a/src/fl_draw_image_win32.cxx +++ b/src/fl_draw_image_win32.cxx @@ -112,13 +112,17 @@ static void monodither(uchar* to, const uchar* from, int w, int delta) { #endif // USE_COLORMAP static void innards(const uchar *buf, int X, int Y, int W, int H, - int delta, int linedelta, int mono, + int delta, int linedelta, int depth, Fl_Draw_Image_Cb cb, void* userdata) { #if USE_COLORMAP char 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; @@ -144,7 +148,7 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, } } else #endif - if (mono) { + if (depth<3) { for (int i=0; i<256; i++) { bmi.bmiColors[i].rgbBlue = (uchar)i; bmi.bmiColors[i].rgbGreen = (uchar)i; @@ -154,11 +158,11 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, } bmi.bmiHeader.biWidth = w; #if USE_COLORMAP - bmi.bmiHeader.biBitCount = mono|indexed ? 8 : 24; - int pixelsize = mono|indexed ? 1 : 3; + bmi.bmiHeader.biBitCount = indexed ? 8 : depth*8; + int pixelsize = indexed ? 1 : depth; #else - bmi.bmiHeader.biBitCount = mono ? 8 : 24; - int pixelsize = mono ? 1 : 3; + bmi.bmiHeader.biBitCount = depth*8; + int pixelsize = depth; #endif int linesize = (pixelsize*w+3)&~3; @@ -200,22 +204,44 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, uchar *to = (uchar*)buffer+(blocking-k-1)*linesize; #if USE_COLORMAP if (indexed) { - if (mono) + if (depth<3) monodither(to, from, w, delta); else dither(to, from, w, delta); to += w; } else #endif - if (mono) { - for (int i=w; i--; from += delta) *to++ = *from; - } else { - for (int i=w; i--; from += delta, to += 3) { - uchar r = from[0]; - to[0] = from[2]; - to[1] = from[1]; - to[2] = r; - } + { + int i; + switch (depth) { + case 1: + for (i=w; i--; from += delta) *to++ = *from; + break; + case 2: + for (i=w; i--; from += delta) { + *to++ = *from; + *to++ = *from; + } + 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; + } } } SetDIBitsToDevice(fl_gc, x, y+j-k, w, k, 0, 0, 0, k, @@ -230,19 +256,21 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, } } +static int fl_abs(int v) { return v<0 ? -v : v; } + void fl_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); + innards(buf,x,y,w,h,d,l,fl_abs(d),0,0); } void fl_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); + innards(0,x,y,w,h,d,0,fl_abs(d),cb,data); } void fl_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,fl_abs(d),0,0); } void fl_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,fl_abs(d),cb,data); } void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { -- cgit v1.2.3