app-emulation/wine: add direct draw hack and the dib engine

git-svn-id: https://svn.disconnected-by-peer.at/svn/linamh/trunk/linamh@1438 6952d904-891a-0410-993b-d76249ca496b
This commit is contained in:
geos_one
2009-08-01 09:30:00 +00:00
parent 1b2a80cabc
commit 23245f3322
15 changed files with 19955 additions and 2 deletions

View File

@@ -0,0 +1,185 @@
DIB Engine: Hook the engine between GDI32 and Display driver
From: Massimo Del Fedele <max@veneto.com>
---
dlls/gdi32/driver.c | 139 +++++++++++++++++++++++++++++++++++++++++++++------
1 files changed, 123 insertions(+), 16 deletions(-)
diff --git a/dlls/gdi32/driver.c b/dlls/gdi32/driver.c
index 20d3f36..95a69c7 100644
--- a/dlls/gdi32/driver.c
+++ b/dlls/gdi32/driver.c
@@ -3,6 +3,7 @@
*
* Copyright 1994 Bob Amstadt
* Copyright 1996, 2001 Alexandre Julliard
+ * Copyright 2009 Massimo Del Fedele
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -25,6 +26,7 @@
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
+#include <stdlib.h>
#include "windef.h"
#include "winbase.h"
#include "winreg.h"
@@ -220,6 +222,104 @@ static struct graphics_driver *create_driver( HMODULE module )
/**********************************************************************
+ * Load_Dib_Driver
+ *
+ * Check if we want the DIB engine and try to load it
+ */
+static HMODULE Load_Dib_Driver(void)
+{
+ HMODULE module;
+
+ static const char *winedib_drv = "winedib.drv";
+
+ /* we do want use DIB Engine ? */
+ BOOL driverRequired = TRUE;
+
+ /* already checked env/registry for DIB driver ? */
+ BOOL envChecked = FALSE;
+
+ char *winedib;
+ char buffer[10];
+
+ /* environment variable WINEDIB takes precedence */
+ if( (winedib = getenv("WINEDIB")) != NULL)
+ {
+ if(!strcasecmp(winedib, "ON") ||
+ !strcasecmp(winedib, "TRUE") ||
+ !strcasecmp(winedib, "ENABLE") ||
+ !strcasecmp(winedib, "ENABLED")
+ )
+ {
+ TRACE("DIB Engine enabled by environment\n");
+ envChecked = TRUE;
+ driverRequired = TRUE;
+ }
+ else if(!strcasecmp(winedib, "OFF") ||
+ !strcasecmp(winedib, "FALSE") ||
+ !strcasecmp(winedib, "DISABLE") ||
+ !strcasecmp(winedib, "DISABLED")
+ )
+ {
+ TRACE("DIB Engine disabled by environment\n");
+ envChecked = TRUE;
+ driverRequired = FALSE;
+ }
+ else
+ ERR("Bad WINEDIB environment variable\n");
+ }
+
+ /* no WINEDIB environment var found or wrong value, we check registry */
+ if(!envChecked)
+ {
+ HKEY hkey;
+ buffer[0] = 0;
+ if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\DIB Engine", &hkey ))
+ {
+ DWORD type, count = sizeof(buffer);
+ RegQueryValueExA( hkey, "Enable", 0, &type, (LPBYTE) buffer, &count );
+ RegCloseKey( hkey );
+ }
+ if(*buffer)
+ {
+ /* registry value found, must be Y or y to enable driver, N or n to disable */
+ if(!strncasecmp(buffer, "Y", 1))
+ {
+ TRACE("DIB Engine enabled by registry\n");
+ envChecked = TRUE;
+ driverRequired = TRUE;
+ }
+ else if(!strncasecmp(buffer, "N", 1))
+ {
+ TRACE("DIB Engine disabled by registry\n");
+ envChecked = TRUE;
+ driverRequired = FALSE;
+ }
+ }
+ }
+
+ /* none of above, we assume we don't want to use engine */
+ if(!envChecked)
+ {
+ TRACE("DIB Engine disabled by default\n");
+ envChecked = TRUE;
+ driverRequired = FALSE;
+ }
+
+ /* if DIB Engine is required, try to load it
+ * otherwise just return NULL module */
+ if(driverRequired)
+ {
+ if( (module = LoadLibraryA( winedib_drv )) != 0)
+ TRACE("Succesfully loaded DIB Engine\n");
+ else
+ ERR("Couldn't load DIB Engine\n");
+ return module;
+ }
+ else
+ return 0;
+}
+
+/**********************************************************************
* load_display_driver
*
* Special case for loading the display driver: get the name from the config file
@@ -235,25 +335,32 @@ static struct graphics_driver *load_display_driver(void)
display_driver->count++;
return display_driver;
}
-
- strcpy( buffer, "x11" ); /* default value */
- /* @@ Wine registry key: HKCU\Software\Wine\Drivers */
- if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hkey ))
+
+ /* check at first if DIB engine is present and if we want
+ * to use it */
+ if( (module = Load_Dib_Driver()) == 0)
{
- DWORD type, count = sizeof(buffer);
- RegQueryValueExA( hkey, "Graphics", 0, &type, (LPBYTE) buffer, &count );
- RegCloseKey( hkey );
- }
+ /* no DIB Engine loaded, just load normal display driver */
+
+ strcpy( buffer, "x11" ); /* default value */
+ /* @@ Wine registry key: HKCU\Software\Wine\Drivers */
+ if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Drivers", &hkey ))
+ {
+ DWORD type, count = sizeof(buffer);
+ RegQueryValueExA( hkey, "Graphics", 0, &type, (LPBYTE) buffer, &count );
+ RegCloseKey( hkey );
+ }
- name = buffer;
- while (name)
- {
- next = strchr( name, ',' );
- if (next) *next++ = 0;
+ name = buffer;
+ while (name)
+ {
+ next = strchr( name, ',' );
+ if (next) *next++ = 0;
- snprintf( libname, sizeof(libname), "wine%s.drv", name );
- if ((module = LoadLibraryA( libname )) != 0) break;
- name = next;
+ snprintf( libname, sizeof(libname), "wine%s.drv", name );
+ if ((module = LoadLibraryA( libname )) != 0) break;
+ name = next;
+ }
}
if (!(display_driver = create_driver( module )))

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,512 @@
DIB Engine: implement AlphaBlend
From: Massimo Del Fedele <max@veneto.com>
---
dlls/winedib.drv/bitblt.c | 88 ++++++++--
dlls/winedib.drv/dibdrv.h | 2
dlls/winedib.drv/primitives.c | 12 +
dlls/winedib.drv/primitives_bitblt.c | 287 ++++++++++++++++++++++++++++++++++
4 files changed, 370 insertions(+), 19 deletions(-)
diff --git a/dlls/winedib.drv/bitblt.c b/dlls/winedib.drv/bitblt.c
index 20cdcaa..c0227a0 100644
--- a/dlls/winedib.drv/bitblt.c
+++ b/dlls/winedib.drv/bitblt.c
@@ -150,34 +150,84 @@ BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT width
xDst, yDst, widthDst, heightDst,
physDevSrc, physDevSrc->hasDIB ? "DIB-" : "DDB", physDevSrc->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevSrc->physBitmap) : "",
xSrc, ySrc, widthSrc, heightSrc));
+
- if(physDevDst->hasDIB && physDevSrc->hasDIB)
+ /* if sizes are null or negative, returns false */
+ if(widthSrc <= 0 || heightSrc <= 0 || widthDst <= 0 || heightDst <= 0)
{
- /* DIB section selected in both source and dest DC, use DIB Engine */
- ONCE(FIXME("STUB\n"));
- res = TRUE;
+ res = FALSE;
+ goto fin;
}
- else if(!physDevDst->hasDIB && !physDevSrc->hasDIB)
+
+ /* source sould be a 32 bit DIB */
+ if(!physDevSrc)
{
- /* DDB selected in noth source and dest DC, use X11 driver */
- res = _DIBDRV_GetDisplayDriver()->pAlphaBlend(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
- physDevSrc->X11PhysDev, xSrc, ySrc, widthSrc, heightSrc,
- blendfn);
+ FIXME("Null source bitmap -- shouldn't happen\n");
+ res = FALSE;
+ goto fin;
}
- else if(physDevSrc->hasDIB)
+ else if(!physDevSrc->hasDIB)
{
- /* DIB on source, DDB on dest -- must convert source DIB to DDB and use X11 driver for blit */
- ONCE(FIXME("TEMPORARY - fallback to X11 driver\n"));
- res = _DIBDRV_GetDisplayDriver()->pAlphaBlend(physDevDst->X11PhysDev, xDst, yDst, widthDst, heightDst,
- physDevSrc->X11PhysDev, xSrc, ySrc, widthSrc, heightSrc,
- blendfn);
+ FIXME("DDB source bitmap -- shouldn't happen\n");
+ res = FALSE;
+ goto fin;
}
- else /* if(physDevDst->hasDIB) */
+
+ if(physDevDst->hasDIB)
{
- /* DDB on source, DIB on dest -- must convert source DDB to DIB and use the engine for blit */
- ONCE(FIXME("STUB\n"));
- res = TRUE;
+ /* DIB section selected in dest DC, use DIB Engine */
+ MAYBE(TRACE("Blending DIB->DIB\n"));
+ res = physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
+ physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
+ }
+ else
+ {
+ /* DDB selected on dest DC -- must double-convert */
+ HBITMAP tmpDIB, stock;
+ HDC tmpDC;
+ MAYBE(TRACE("Blending DIB->DDB\n"));
+
+ /* converts dest DDB onto a temporary DIB -- just the needed part */
+ tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, xDst, yDst, widthDst, heightDst);
+ if(!tmpDIB)
+ {
+ ERR("Couldn't convert dest DDB to DIB\n");
+ res = FALSE;
+ goto fin;
+ }
+
+ /* selects the temporary DIB into a temporary DC */
+ tmpDC = CreateCompatibleDC(physDevDst->hdc);
+ if(!tmpDC)
+ {
+ ERR("Couldn't create temporary DC\n");
+ DeleteObject(tmpDIB);
+ res = FALSE;
+ goto fin;
+ }
+ stock = SelectObject(tmpDC, tmpDIB);
+ if(!stock)
+ {
+ ERR("Couldn't select temporary DIB into temporary DC\n");
+ DeleteDC(tmpDC);
+ DeleteObject(tmpDIB);
+ res = FALSE;
+ goto fin;
+ }
+
+ /* blends source DIB onto temp DIB and re-blits onto dest DC */
+ res = GdiAlphaBlend(tmpDC, 0, 0, widthDst, heightDst, physDevSrc->hdc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
+ if(!res)
+ MAYBE(TRACE("AlphaBlend failed\n"));
+ else
+ res = BitBlt(physDevDst->hdc, xDst, yDst, widthDst, heightDst, tmpDC, 0, 0, SRCCOPY);
+
+ /* frees resources */
+ SelectObject(tmpDC, stock);
+ DeleteDC(tmpDC);
+ DeleteObject(tmpDIB);
}
+fin:
return res;
}
diff --git a/dlls/winedib.drv/dibdrv.h b/dlls/winedib.drv/dibdrv.h
index 773941e..c801d96 100644
--- a/dlls/winedib.drv/dibdrv.h
+++ b/dlls/winedib.drv/dibdrv.h
@@ -94,6 +94,8 @@ typedef struct _DIBDRV_PRIMITIVE_FUNCS
BOOL (* PutLine) ( struct _DIBDRVBITMAP *bmp, int line, int startx, int width, void *buf);
/* BitBlt primitives */
+ BOOL (* AlphaBlend) ( struct _DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, int widthDst, int heightDst,
+ const struct _DIBDRVPHYSDEV *physDevSrc, int xSrc, int ySrc, int widthSrc, int heightSrc, BLENDFUNCTION blendFn );
BOOL (* BitBlt) ( struct _DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, int width, int height,
const struct _DIBDRVPHYSDEV *physDevSrc, int xSrc, int ySrc, DWORD rop );
BOOL (* StretchBlt) ( struct _DIBDRVPHYSDEV *physDevDst, int xDst, int yDst, int widthDst, int heightDst,
diff --git a/dlls/winedib.drv/primitives.c b/dlls/winedib.drv/primitives.c
index cbad239..a2fa04a 100644
--- a/dlls/winedib.drv/primitives.c
+++ b/dlls/winedib.drv/primitives.c
@@ -133,6 +133,10 @@ BOOL _DIBDRV_StretchBlt_generic(DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
INT widthDst, INT heightDst, const DIBDRVPHYSDEV *physDevSrc,
INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop);
+BOOL _DIBDRV_AlphaBlend_generic(DIBDRVPHYSDEV *physDevDst, int xDst, int yDst,
+ int widthDst, int heightDst, const DIBDRVPHYSDEV *physDevSrc,
+ int xSrc, int ySrc, int widthSrc, int heightSrc, BLENDFUNCTION blendFn );
+
/* ------------------------------------------------------------*/
/* FREETYPE FONT BITMAP BLITTING */
void _DIBDRV_freetype_blit_8888 (DIBDRVPHYSDEV *dib, int x, int y, FT_Bitmap *bmp);
@@ -156,6 +160,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB32_RGB =
_DIBDRV_SolidVLine32,
_DIBDRV_GetLine32_RGB,
_DIBDRV_PutLine32_RGB,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_32_RGB
@@ -172,6 +177,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB32_BITFIELDS =
_DIBDRV_SolidVLine32,
_DIBDRV_GetLine32_BITFIELDS,
_DIBDRV_PutLine32_BITFIELDS,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_32_BITFIELDS
@@ -188,6 +194,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB24 =
_DIBDRV_SolidVLine24,
_DIBDRV_GetLine24,
_DIBDRV_PutLine24,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_24
@@ -204,6 +211,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB16_RGB =
_DIBDRV_SolidVLine16,
_DIBDRV_GetLine16_RGB,
_DIBDRV_PutLine16_RGB,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_16_RGB
@@ -220,6 +228,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB16_BITFIELDS =
_DIBDRV_SolidVLine16,
_DIBDRV_GetLine16_BITFIELDS,
_DIBDRV_PutLine16_BITFIELDS,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_16_BITFIELDS
@@ -236,6 +245,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB8 =
_DIBDRV_SolidVLine8,
_DIBDRV_GetLine8,
_DIBDRV_PutLine8,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_8
@@ -252,6 +262,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB4 =
_DIBDRV_SolidVLine4,
_DIBDRV_GetLine4,
_DIBDRV_PutLine4,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_4
@@ -268,6 +279,7 @@ DIBDRV_PRIMITIVE_FUNCS DIBDRV_funcs_DIB1 =
_DIBDRV_SolidVLine1,
_DIBDRV_GetLine1,
_DIBDRV_PutLine1,
+ _DIBDRV_AlphaBlend_generic,
_DIBDRV_BitBlt_generic,
_DIBDRV_StretchBlt_generic,
_DIBDRV_freetype_blit_1
diff --git a/dlls/winedib.drv/primitives_bitblt.c b/dlls/winedib.drv/primitives_bitblt.c
index da48352..7540dad 100644
--- a/dlls/winedib.drv/primitives_bitblt.c
+++ b/dlls/winedib.drv/primitives_bitblt.c
@@ -80,6 +80,293 @@ static void StretchLine(DWORD *dst, int dstWidth, DWORD *src, int srcWidth)
memcpy(dst, src, 4 * srcWidth);
}
+/* premultiply alpha channel on a line by a constant alpha
+ note : it seems that pixels are already premultiplied
+ by alpha channel content */
+static void PemultiplyLine(DWORD *dst, int width, BYTE constAlpha)
+{
+ int i = width;
+ BYTE *alphaPnt = (BYTE *)dst + 3;
+
+ /* small optimization for 0 and 255 values of constAlpha */
+
+ /* fully transparent -- just sets all pix to 0 */
+ if(constAlpha == 0)
+ {
+ while(i--)
+ *dst++ = 0;
+ return;
+ }
+
+ /* fully opaque, just do nothing */
+ if(constAlpha == 255)
+ return;
+
+ /* intermediate -- premultiply alpha values */
+ while(i--)
+ {
+ *alphaPnt = MulDiv(*alphaPnt, constAlpha, 255);
+ alphaPnt += 4;
+ }
+ return;
+
+}
+
+/* alpha blends a source line onto a destination line
+ preconditions :
+ 1) source and dest widths must be the same
+ 2) source line should be already premultiplied by constant alpha */
+static void BlendLine(DWORD *dst, DWORD *src, int width)
+{
+ int i = width;
+ BYTE *blueDst = (BYTE *)dst;
+ BYTE *greenDst = blueDst + 1;
+ BYTE *redDst = greenDst + 1;
+ BYTE *blueSrc = (BYTE *)src;
+ BYTE *greenSrc = blueSrc + 1;
+ BYTE *redSrc = greenSrc + 1;
+ BYTE *alphaSrc = redSrc + 1;
+ BYTE alpha;
+
+ /* still don't know if it must take in account an eventual dest
+ alpha channel..... */
+ while(i--)
+ {
+ alpha = 255 - *alphaSrc;
+
+ *blueDst = *blueSrc + MulDiv(*blueDst, alpha, 255);
+ *greenDst = *greenSrc + MulDiv(*greenDst, alpha, 255);
+ *redDst = *redSrc + MulDiv(*redDst, alpha, 255);
+
+ blueSrc += 4;
+ greenSrc += 4;
+ redSrc += 4;
+ alphaSrc += 4;
+ blueDst += 4;
+ greenDst += 4;
+ redDst += 4;
+ }
+
+}
+
+/* ------------------------------------------------------------*/
+/* ALPHABLEND PRIMITIVES */
+BOOL _DIBDRV_AlphaBlend_generic(DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
+ INT widthDst, INT heightDst, const DIBDRVPHYSDEV *physDevSrc,
+ INT xSrc, INT ySrc, int widthSrc, int heightSrc, BLENDFUNCTION blendFn)
+{
+ /* flags indicating wether source should be stretched */
+ BOOL horStretch = (widthSrc != widthDst);
+ BOOL verStretch = (heightSrc != heightDst);
+
+ /* constant alpha value */
+ BYTE constAlpha = blendFn.SourceConstantAlpha;
+
+ /* source and dest bitmaps */
+ const DIBDRVBITMAP *srcBmp = &physDevSrc->physBitmap;
+ DIBDRVBITMAP *dstBmp = &physDevDst->physBitmap;
+
+ /* source and destination line buffers */
+ DWORD *sBuf = HeapAlloc(GetProcessHeap(), 0, abs(srcBmp->stride));
+ DWORD *dBuf = HeapAlloc(GetProcessHeap(), 0, abs(dstBmp->stride));
+
+ int ys = ySrc;
+ int yd = yDst;
+ int iLine;
+ int delta;
+
+ /* in order to optimize a bit, we divide the routine in 4 parts,
+ depending on stretching modes */
+ if(!horStretch && !verStretch)
+ {
+ /* simplest case, no stretching needed */
+ MAYBE(TRACE("No stretching\n"));
+ for(iLine = 0; iLine < heightSrc; iLine++, ys++, yd++)
+ {
+ /* load source and dest lines */
+ srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf);
+ dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ /* premultiply source by constant and pixel alpha */
+ PemultiplyLine(sBuf, widthSrc, constAlpha);
+
+ /* blends source on dest */
+ BlendLine(dBuf, sBuf, widthSrc);
+
+ /* puts dest line back */
+ dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf);
+ }
+ }
+ else if (horStretch && !verStretch)
+ {
+ /* just horizontal stretching needed */
+ DWORD *strBuf = HeapAlloc(GetProcessHeap(), 0, abs(dstBmp->stride));
+ MAYBE(TRACE("Horizontal stretching\n"));
+
+ for(iLine = 0; iLine < heightSrc; iLine++, ys++, yd++)
+ {
+ /* load source and dest lines */
+ srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf);
+ dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ /* stretch source line to match dest one */
+ StretchLine(strBuf, widthDst, sBuf, widthSrc);
+
+ /* premultiply source by constant and pixel alpha */
+ PemultiplyLine(strBuf, widthDst, constAlpha);
+
+ /* blends source on dest */
+ BlendLine(dBuf, sBuf, widthDst);
+
+ /* puts dest line back */
+ dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf);
+ }
+ HeapFree(GetProcessHeap(), 0, strBuf);
+ }
+ else if (!horStretch && verStretch)
+ {
+ /* just vertical stretching needed */
+ MAYBE(TRACE("Vertical stretching\n"));
+
+ if(heightSrc > heightDst)
+ {
+ iLine = 0;
+ delta = 0;
+ while(iLine < heightDst)
+ {
+ /* load source and dest lines */
+ srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf);
+ dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ /* premultiply source by constant and pixel alpha */
+ PemultiplyLine(sBuf, widthSrc, constAlpha);
+
+ /* blends source on dest */
+ BlendLine(dBuf, sBuf, widthDst);
+
+ /* puts dest line back */
+ dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ while(delta < heightSrc)
+ {
+ ys++;
+ delta += heightDst;
+ }
+ delta -= heightSrc;
+ yd++;
+ iLine++;
+ }
+ }
+ else if(heightSrc < heightDst)
+ {
+ iLine = 0;
+ delta = 0;
+ while(iLine < heightSrc)
+ {
+ /* load source line */
+ srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf);
+
+ /* premultiply source by constant and pixel alpha */
+ PemultiplyLine(sBuf, widthSrc, constAlpha);
+
+ while(delta < heightDst)
+ {
+ /* load dest line */
+ dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ /* blends source on dest */
+ BlendLine(dBuf, sBuf, widthDst);
+
+ /* puts dest line back */
+ dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf);
+ yd++;
+ delta += heightSrc;
+ }
+ delta -= heightDst;
+ ys++;
+ iLine++;
+ }
+ }
+ }
+ else
+ {
+ DWORD *strBuf = HeapAlloc(GetProcessHeap(), 0, abs(dstBmp->stride));
+ /* both stretching needed -- generic case */
+ MAYBE(TRACE("Horizontal and vertical stretching\n"));
+
+ if(heightSrc > heightDst)
+ {
+ iLine = 0;
+ delta = 0;
+ while(iLine < heightDst)
+ {
+ /* load source and dest lines */
+ srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf);
+ dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ /* stretch source line to match dest one */
+ StretchLine(strBuf, widthDst, sBuf, widthSrc);
+
+ /* premultiply source by constant and pixel alpha */
+ PemultiplyLine(strBuf, widthDst, constAlpha);
+
+ /* blends source on dest */
+ BlendLine(dBuf, strBuf, widthDst);
+
+ /* puts dest line back */
+ dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ while(delta < heightSrc)
+ {
+ ys++;
+ delta += heightDst;
+ }
+ delta -= heightSrc;
+ yd++;
+ iLine++;
+ }
+ }
+ else if(heightSrc < heightDst)
+ {
+ iLine = 0;
+ delta = 0;
+ while(iLine < heightSrc)
+ {
+ /* load source line */
+ srcBmp->funcs->GetLine(srcBmp, ys, xSrc, widthSrc, sBuf);
+
+ /* stretch source line to match dest one */
+ StretchLine(strBuf, widthDst, sBuf, widthSrc);
+
+ /* premultiply source by constant and pixel alpha */
+ PemultiplyLine(strBuf, widthDst, constAlpha);
+
+ while(delta < heightDst)
+ {
+ /* load dest line */
+ dstBmp->funcs->GetLine(dstBmp, yd, xDst, widthDst, dBuf);
+
+ /* blends source on dest */
+ BlendLine(dBuf, strBuf, widthDst);
+
+ /* puts dest line back */
+ dstBmp->funcs->PutLine(dstBmp, yd, xDst, widthDst, dBuf);
+ yd++;
+ delta += heightSrc;
+ }
+ delta -= heightDst;
+ ys++;
+ iLine++;
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, strBuf);
+ }
+
+ HeapFree(GetProcessHeap(), 0, sBuf);
+ HeapFree(GetProcessHeap(), 0, dBuf);
+ return TRUE;
+}
+
/* ------------------------------------------------------------*/
/* BLITTING PRIMITIVES */
BOOL _DIBDRV_BitBlt_generic(DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,

View File

@@ -0,0 +1,560 @@
DIB Engine: Add clipping on xxxBlt and AlphaBlend
From: Massimo Del Fedele <max@veneto.com>
---
dlls/winedib.drv/bitblt.c | 332 +++++++++++++++++++++++++++++++++++++------
dlls/winedib.drv/clipping.c | 42 +++++
dlls/winedib.drv/dc.c | 14 ++
dlls/winedib.drv/dibdrv.h | 6 +
4 files changed, 341 insertions(+), 53 deletions(-)
diff --git a/dlls/winedib.drv/bitblt.c b/dlls/winedib.drv/bitblt.c
index c0227a0..05c9392 100644
--- a/dlls/winedib.drv/bitblt.c
+++ b/dlls/winedib.drv/bitblt.c
@@ -33,6 +33,26 @@ static inline void intSwap(int *a, int *b)
*b = tmp;
}
+static inline void setRect(RECT *r, int x1, int y1, int x2, int y2)
+{
+ r->left = x1;
+ r->top = y1;
+ r->right = x2;
+ r->bottom = y2;
+}
+
+static inline void setPoint(POINT *p, int x, int y)
+{
+ p->x = x;
+ p->y = y;
+}
+
+static inline void setSize(SIZE *sz, int cx, int cy)
+{
+ sz->cx = cx;
+ sz->cy = cy;
+}
+
/* clips a source and destination areas to their respective clip rectangles
returning both source and dest modified; result is TRUE if clipping
leads to a non null rectangle, FALSE otherwise */
@@ -130,13 +150,158 @@ static BOOL BitBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *sz, RECT*srcClip, RECT*
leads to a non null rectangle, FALSE otherwise */
static BOOL StretchBlt_ClipAreas(POINT *ps, POINT *pd, SIZE *szSrc, SIZE *szDst, RECT*srcClip, RECT*dstClip)
{
- ONCE(FIXME("TO DO\n"));
+ int xs1, ys1, xs2, ys2;
+ int xsc1, ysc1, xsc2, ysc2;
+ int xd1, yd1, xd2, yd2;
+ int xdc1, ydc1, xdc2, ydc2;
+ int ws, hs, wd, hd, dx, dy;
+ int mulh, divh, mulv, divv;
+
+ /* extract sizes */
+ ws = szSrc->cx; hs = szSrc->cy;
+ wd = szDst->cx; hd = szDst->cy;
+
+ /* if sizes null or negative, just return false */
+ /* FIXME : add support for mirror stretch */
+ if(ws <= 0 || hs <= 0 || wd <= 0 || hd <= 0)
+ return FALSE;
+
+ /* stores scaling factors from source rect to dest one */
+ mulh = wd; divh = ws;
+ mulv = hd; divv = hs;
+
+ /* extract dest area data */
+ xd1 = pd->x;
+ yd1 = pd->y;
+ xd2 = xd1 + wd;
+ yd2 = yd1 + hd;
+
+ /* extract source data */
+ xs1 = ps->x;
+ ys1 = ps->y;
+ xs2 = xs1 + ws;
+ ys2 = ys1 + hs;
+
+ /* if source clip area is not null, do first clipping on it */
+ if(srcClip)
+ {
+ /* extract source clipping area */
+ xsc1 = srcClip->left;
+ ysc1 = srcClip->top;
+ xsc2 = srcClip->right;
+ ysc2 = srcClip->bottom;
+
+ /* order clip area rectangle points */
+ if(xsc1 > xsc2) intSwap(&xsc1, &xsc2);
+ if(ysc1 > ysc2) intSwap(&ysc1, &ysc2);
+
+ /* clip on source clipping start point */
+ if(xs1 < xsc1) { dx = xsc1 - xs1; ws -= dx; xd1 += MulDiv(dx, mulh, divh); xs1 = xsc1; }
+ if(ys1 < ysc1) { dy = ysc1 - ys1; hs -= dy; yd1 += MulDiv(dy, mulv, divv); ys1 = ysc1; }
+
+ /* clip on source clipping end point */
+ if(xs2 > xsc2) { dx = xs2 - xsc2; ws -= dx; xd2 -= MulDiv(dx, mulh, divh); xs2 = xsc2; }
+ if(ys2 > ysc2) { dy = ys2 - ysc2; hs -= dy; yd2 -= MulDiv(dy, mulv, divv); ys2 = ysc2; }
+
+ /* if already zero area, return false */
+ if(ws <= 0 || hs <= 0)
+ return FALSE;
+ wd = xd2 - xd1;
+ hd = yd2 - yd1;
+ }
+ /* now do clipping on destination area */
+ if(dstClip)
+ {
+ /* extract destination clipping area */
+ xdc1 = dstClip->left;
+ ydc1 = dstClip->top;
+ xdc2 = dstClip->right;
+ ydc2 = dstClip->bottom;
+
+ /* order clip area rectangle points */
+ if(xdc1 > xdc2) intSwap(&xdc1, &xdc2);
+ if(ydc1 > ydc2) intSwap(&ydc1, &ydc2);
+
+ /* clip on dest clipping start point */
+ if(xd1 < xdc1) { dx = xdc1 - xd1; wd -= dx; xs1 += MulDiv(dx, divh, mulh); xd1 = xdc1; }
+ if(yd1 < ydc1) { dy = ydc1 - yd1; hd -= dy; ys1 += MulDiv(dy, divv, mulv); yd1 = ydc1; }
+
+ /* clip on dest clipping end point */
+ if(xd2 > xdc2) { dx = xd2 - xdc2; wd -= dx; xs2 -= MulDiv(dx, divh, mulh); xd2 = xdc2; }
+ if(yd2 > ydc2) { dy = yd2 - ydc2; hd -= dy; ys2 -= MulDiv(dy, divv, mulv); yd2 = ydc2; }
+
+ /* if already zero area, return false */
+ if(wd <= 0 || hd <= 0)
+ return FALSE;
+
+ ws = xs2 - xs1;
+ hs = ys2 - ys1;
+ }
+
+ /* sets clipped/translated points and sizes and returns TRUE */
+ ps->x = xs1; ps->y = ys1;
+ pd->x = xd1; pd->y = yd1;
+ szSrc->cx = ws; szSrc->cy = hs;
+ szDst->cx = wd; szDst->cy = hd;
+
return TRUE;
}
/***********************************************************************
+ * _DIBDRV_InternalAlphaBlend
+ */
+BOOL _DIBDRV_InternalAlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
+ DIBDRVPHYSDEV *physDevSrc, INT xSrc, INT ySrc, INT widthSrc, INT heightSrc,
+ BLENDFUNCTION blendfn)
+{
+ BOOL res;
+ POINT pd, ps;
+ SIZE szSrc, szDst;
+ int iRec;
+ RECT dstClip, srcClip;
+
+ /* first clip on physical DC sizes */
+ setPoint(&pd, xDst, yDst);
+ setPoint(&ps, xSrc, ySrc);
+ setSize(&szDst, widthDst, heightDst);
+ setSize(&szSrc, widthSrc, heightSrc);
+ setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
+ if(physDevSrc)
+ {
+ setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
+ res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
+ }
+ else
+ res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
+ if(!res)
+ return FALSE;
+ xDst = pd.x; yDst = pd.y;
+ xSrc = ps.x; ySrc = ps.y;
+ widthDst = szDst.cx; heightDst = szDst.cy;
+ widthSrc = szSrc.cx; heightSrc = szSrc.cy;
+
+ /* then, do blitting for each dest clip area (no clipping on source) */
+ res = FALSE;
+ for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
+ {
+ RECT *r = physDevDst->regionRects + iRec;
+ setRect(&dstClip, r->left, r->top, r->right, r->bottom);
+ setPoint(&pd, xDst, yDst);
+ setPoint(&ps, xSrc, ySrc);
+ setSize(&szDst, widthDst, heightDst);
+ setSize(&szSrc, widthSrc, heightSrc);
+ if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
+ continue;
+ if(physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
+ physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, blendfn))
+ res = TRUE;
+ }
+ return res;
+}
+
+/***********************************************************************
* DIBDRV_AlphaBlend
*/
BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT widthDst, INT heightDst,
@@ -145,6 +310,11 @@ BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT width
{
BOOL res;
+ POINT pd = {xDst, yDst};
+ POINT ps = {xSrc, ySrc};
+ SIZE szDst = {widthDst, heightDst};
+ SIZE szSrc = {widthSrc, heightSrc};
+
MAYBE(TRACE("physDevDst:%p(%s%s), xDst:%d, yDst:%d, widthDst:%d, heightDst:%d, physDevSrc:%p(%s%s), xSrc:%d, ySrc:%d, widthSrc:%d, heightSrc:%d\n",
physDevDst, physDevDst->hasDIB ? "DIB-" : "DDB", physDevDst->hasDIB ? _DIBDRVBITMAP_GetFormatName(&physDevDst->physBitmap) : "",
xDst, yDst, widthDst, heightDst,
@@ -177,16 +347,24 @@ BOOL DIBDRV_AlphaBlend( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst, INT width
{
/* DIB section selected in dest DC, use DIB Engine */
MAYBE(TRACE("Blending DIB->DIB\n"));
- res = physDevDst->physBitmap.funcs->AlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
- physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
+ res = _DIBDRV_InternalAlphaBlend(physDevDst, xDst, yDst, widthDst, heightDst,
+ physDevSrc, xSrc, ySrc, widthSrc, heightSrc, blendfn);
}
else
{
/* DDB selected on dest DC -- must double-convert */
HBITMAP tmpDIB, stock;
HDC tmpDC;
+ RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
MAYBE(TRACE("Blending DIB->DDB\n"));
+ /* clip blit area */
+ res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, 0);
+ if(!res)
+ goto fin;
+ xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
+ xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
+
/* converts dest DDB onto a temporary DIB -- just the needed part */
tmpDIB = _DIBDRV_ConvertDevDDBtoDIB(physDevDst->hdc, physDevSrc->hdc, xDst, yDst, widthDst, heightDst);
if(!tmpDIB)
@@ -232,8 +410,55 @@ fin:
}
/***********************************************************************
- * DIBDRV_BitBlt
+ * _DIBDRV_InternalBitBlt
*/
+BOOL _DIBDRV_InternalBitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
+ INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
+ INT xSrc, INT ySrc, DWORD rop )
+{
+ BOOL res;
+ POINT pd, ps;
+ SIZE sz;
+ int iRec;
+ RECT dstClip, srcClip;
+
+ /* first clip on physical DC sizes */
+ setPoint(&pd, xDst, yDst);
+ setPoint(&ps, xSrc, ySrc);
+ setSize(&sz, width, height);
+ setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
+ if(physDevSrc)
+ {
+ setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
+ res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
+ }
+ else
+ res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
+ if(!res)
+ return FALSE;
+ xDst = pd.x; yDst = pd.y;
+ xSrc = ps.x; ySrc = ps.y;
+ width = sz.cx; height = sz.cy;
+
+ /* then, do blitting for each dest clip area (no clipping on source) */
+ res = FALSE;
+ for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
+ {
+ RECT *r = physDevDst->regionRects + iRec;
+ setRect(&dstClip, r->left, r->top, r->right, r->bottom);
+ setPoint(&pd, xDst, yDst);
+ setPoint(&ps, xSrc, ySrc);
+ setSize(&sz, width, height);
+ if(!BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip))
+ continue;
+ if(physDevDst->physBitmap.funcs->BitBlt(physDevDst, pd.x, pd.y, sz.cx, sz.cy, physDevSrc, ps.x, ps.y, rop))
+ res = TRUE;
+ }
+ return res;
+}
+
+/***********************************************************************
+ * DIBDRV_BitBlt */
BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
INT width, INT height, DIBDRVPHYSDEV *physDevSrc,
INT xSrc, INT ySrc, DWORD rop )
@@ -254,26 +479,13 @@ BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
if(physDevDst->hasDIB)
{
/* DIB section selected in dest DC, use DIB Engine */
-
/* clip blit area */
RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
if(!physDevSrc || physDevSrc->hasDIB)
{
- /* clip blit area */
- if(physDevSrc)
- {
- RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
- res = BitBlt_ClipAreas(&ps, &pd, &sz, &srcClip, &dstClip);
- }
- else
- res = BitBlt_ClipAreas(&ps, &pd, &sz, 0, &dstClip);
- if(!res)
- goto noBlt2;
- xDst = pd.x; yDst = pd.y; width = sz.cx; height = sz.cy; xSrc = ps.x; ySrc = ps.y;
-
/* source is null or has a DIB, no need to convert anyting */
- res = physDevDst->physBitmap.funcs->BitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
+ res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, ySrc, rop);
}
else
{
@@ -309,8 +521,7 @@ BOOL DIBDRV_BitBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
goto noBlt1;
}
SelectObject(physDevSrc->hdc, dib);
- res = physDevDst->physBitmap.funcs->BitBlt(physDevDst, xDst, yDst, width, height,
- physDevSrc, xSrc, 0, rop);
+ res = _DIBDRV_InternalBitBlt(physDevDst, xDst, yDst, width, height, physDevSrc, xSrc, 0, rop);
SelectObject(physDevSrc->hdc, ddb);
DeleteObject(dib);
noBlt1:
@@ -410,6 +621,58 @@ noBlt3:
}
/***********************************************************************
+ * _DIBDRV_InternalStretchBlt
+ */
+BOOL _DIBDRV_InternalStretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
+ INT widthDst, INT heightDst, DIBDRVPHYSDEV *physDevSrc,
+ INT xSrc, INT ySrc, int widthSrc, int heightSrc, DWORD rop )
+{
+ BOOL res;
+ POINT pd, ps;
+ SIZE szSrc, szDst;
+ int iRec;
+ RECT dstClip, srcClip;
+
+ /* first clip on physical DC sizes */
+ setPoint(&pd, xDst, yDst);
+ setPoint(&ps, xSrc, ySrc);
+ setSize(&szDst, widthDst, heightDst);
+ setSize(&szSrc, widthSrc, heightSrc);
+ setRect(&dstClip, 0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height);
+ if(physDevSrc)
+ {
+ setRect(&srcClip, 0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height);
+ res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
+ }
+ else
+ res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
+ if(!res)
+ return FALSE;
+ xDst = pd.x; yDst = pd.y;
+ xSrc = ps.x; ySrc = ps.y;
+ widthDst = szDst.cx; heightDst = szDst.cy;
+ widthSrc = szSrc.cx; heightSrc = szSrc.cy;
+
+ /* then, do blitting for each dest clip area (no clipping on source) */
+ res = FALSE;
+ for(iRec = 0; iRec < physDevDst->regionRectCount; iRec++)
+ {
+ RECT *r = physDevDst->regionRects + iRec;
+ setRect(&dstClip, r->left, r->top, r->right, r->bottom);
+ setPoint(&pd, xDst, yDst);
+ setPoint(&ps, xSrc, ySrc);
+ setSize(&szDst, widthDst, heightDst);
+ setSize(&szSrc, widthSrc, heightSrc);
+ if(!StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip))
+ continue;
+ if(physDevDst->physBitmap.funcs->StretchBlt(physDevDst, pd.x, pd.y, szDst.cx, szDst.cy,
+ physDevSrc, ps.x, ps.y, szSrc.cx, szSrc.cy, rop))
+ res = TRUE;
+ }
+ return res;
+}
+
+/***********************************************************************
* DIBDRV_StretchBlt
*/
BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
@@ -439,38 +702,15 @@ BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
{
/* DIB section selected in dest DC, use DIB Engine */
- /* clip blit area */
- RECT dstClip = {0, 0, physDevDst->physBitmap.width, physDevDst->physBitmap.height};
-
if(!physDevSrc || physDevSrc->hasDIB)
{
- /* clip blit area */
- if(physDevSrc)
- {
- RECT srcClip = {0, 0, physDevSrc->physBitmap.width, physDevSrc->physBitmap.height};
- res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, &srcClip, &dstClip);
- }
- else
- res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
- if(!res)
- goto noBlt2;
- xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
- xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
-
/* source is null or has a DIB, no need to convert anyting */
- res = physDevDst->physBitmap.funcs->StretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
+ res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst, physDevSrc, xSrc, ySrc, widthSrc, heightSrc, rop);
}
else
{
/* source is a DDB, must convert it to DIB */
- /* don't clip on source */
- res = StretchBlt_ClipAreas(&ps, &pd, &szSrc, &szDst, 0, &dstClip);
- if(!res)
- goto noBlt2;
- xDst = pd.x; yDst = pd.y; widthDst = szDst.cx; heightDst = szDst.cy;
- xSrc = ps.x; ySrc = ps.y; widthSrc = szSrc.cx; heightSrc = szSrc.cy;
-
/* we must differentiate from 2 cases :
1) source DC is a memory DC
2) source DC is a device DC */
@@ -495,8 +735,8 @@ BOOL DIBDRV_StretchBlt( DIBDRVPHYSDEV *physDevDst, INT xDst, INT yDst,
goto noBlt1;
}
SelectObject(physDevSrc->hdc, dib);
- res = physDevDst->physBitmap.funcs->StretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
- physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
+ res = _DIBDRV_InternalStretchBlt(physDevDst, xDst, yDst, widthDst, heightDst,
+ physDevSrc, xSrc, 0, widthSrc, heightSrc, rop);
SelectObject(physDevSrc->hdc, ddb);
DeleteObject(dib);
noBlt1:
diff --git a/dlls/winedib.drv/clipping.c b/dlls/winedib.drv/clipping.c
index 81dec25..ed10b92 100644
--- a/dlls/winedib.drv/clipping.c
+++ b/dlls/winedib.drv/clipping.c
@@ -25,22 +25,50 @@
WINE_DEFAULT_DEBUG_CHANNEL(dibdrv);
-
/***********************************************************************
* DIBDRV_SetDeviceClipping
*/
void DIBDRV_SetDeviceClipping( DIBDRVPHYSDEV *physDev, HRGN vis_rgn, HRGN clip_rgn )
{
+ RGNDATA *data;
+ DWORD size;
+ int iRect;
+
MAYBE(TRACE("physDev:%p, vis_rgn:%p, clip_rgn:%p\n", physDev, vis_rgn, clip_rgn));
- if(physDev->hasDIB)
+ /* sets the region for X11 driver anyways... we may change bitmap later on */
+ _DIBDRV_GetDisplayDriver()->pSetDeviceClipping(physDev->X11PhysDev, vis_rgn, clip_rgn);
+
+ /* then we set the region for DIB engine, same reason */
+
+ CombineRgn( physDev->region, vis_rgn, clip_rgn, clip_rgn ? RGN_AND : RGN_COPY );
+
+ /* get region rectangles */
+ if(!(size = GetRegionData(physDev->region, 0, NULL)))
+ return;
+ data = HeapAlloc(GetProcessHeap(), 0, size);
+ if (!GetRegionData(physDev->region, size, data))
{
- /* DIB section selected in, use DIB Engine */
- ONCE(FIXME("STUB\n"));
+ HeapFree( GetProcessHeap(), 0, data );
+ return;
}
- else
+
+ /* frees any previous regions rectangles in DC */
+ if(physDev->regionData)
+ HeapFree(GetProcessHeap(), 0, physDev->regionData);
+
+ /* sets the rectangles on physDev */
+ physDev->regionData = data;
+ physDev->regionRects = (RECT *)data->Buffer;
+ physDev->regionRectCount = data->rdh.nCount;
+
+ if(TRACE_ON(dibdrv))
{
- /* DDB selected in, use X11 driver */
- _DIBDRV_GetDisplayDriver()->pSetDeviceClipping(physDev->X11PhysDev, vis_rgn, clip_rgn);
+ TRACE("Region dump : %d rectangles\n", physDev->regionRectCount);
+ for(iRect = 0; iRect < physDev->regionRectCount; iRect++)
+ {
+ RECT *r = physDev->regionRects + iRect;
+ TRACE("Rect #%03d, x1:%4d, y1:%4d, x2:%4d, y2:%4d\n", iRect, r->left, r->top, r->right, r->bottom);
+ }
}
}
diff --git a/dlls/winedib.drv/dc.c b/dlls/winedib.drv/dc.c
index 6184677..8212d42 100644
--- a/dlls/winedib.drv/dc.c
+++ b/dlls/winedib.drv/dc.c
@@ -165,6 +165,12 @@ BOOL DIBDRV_CreateDC( HDC hdc, DIBDRVPHYSDEV **pdev, LPCWSTR driver, LPCWSTR dev
/* clears pen and brush */
physDev->rop2 = R2_COPYPEN;
+
+ /* clipping region */
+ physDev->region = CreateRectRgn( 0, 0, 0, 0 );
+ physDev->regionData = NULL;
+ physDev->regionRects = NULL;
+ physDev->regionRectCount = 0;
physDev->backgroundColor = 0;
_DIBDRV_CalcAndXorMasks(physDev->rop2, 0, &physDev->backgroundAnd, &physDev->backgroundXor);
@@ -228,6 +234,14 @@ BOOL DIBDRV_DeleteDC( DIBDRVPHYSDEV *physDev )
physDev->brushAnds = NULL;
physDev->brushXors = NULL;
+ /* frees clipping region */
+ DeleteObject(physDev->region);
+ if(physDev->regionData)
+ HeapFree(GetProcessHeap(), 0, physDev->regionData);
+ physDev->regionData = NULL;
+ physDev->regionRects = NULL;
+ physDev->regionRectCount = 0;
+
/* frees DIB Engine device */
HeapFree(GetProcessHeap(), 0, physDev);
diff --git a/dlls/winedib.drv/dibdrv.h b/dlls/winedib.drv/dibdrv.h
index c801d96..b0f128e 100644
--- a/dlls/winedib.drv/dibdrv.h
+++ b/dlls/winedib.drv/dibdrv.h
@@ -204,6 +204,12 @@ typedef struct _DIBDRVPHYSDEV
/* active ROP2 */
INT rop2;
+
+ /* clipping region and its rectangles */
+ HRGN region;
+ RGNDATA *regionData;
+ RECT *regionRects;
+ int regionRectCount;
/* background color and active ROP2 precalculated
AND and XOR values for it */

View File

@@ -0,0 +1,463 @@
DIB Engine: Implement Polygon
From: Massimo Del Fedele <max@veneto.com>
---
dlls/winedib.drv/graphics.c | 405 ++++++++++++++++++++++++++++++++++++++++++-
1 files changed, 395 insertions(+), 10 deletions(-)
diff --git a/dlls/winedib.drv/graphics.c b/dlls/winedib.drv/graphics.c
index 8dda082..e416488 100644
--- a/dlls/winedib.drv/graphics.c
+++ b/dlls/winedib.drv/graphics.c
@@ -36,6 +36,281 @@ static inline void OrderInt(int *i1, int *i2)
}
}
+#define LEFT_SIDE 1
+#define TOP_SIDE 2
+#define RIGHT_SIDE 4
+#define BOTTOM_SIDE 8
+
+/* clips a line segment by a rectangular window */
+static inline BYTE outCodes(const POINT *p, const RECT *r)
+{
+ BYTE Code = 0;
+
+ if(p->y < r->top)
+ Code |= TOP_SIDE;
+ else if(p->y >= r->bottom)
+ Code |= BOTTOM_SIDE;
+ if(p->x >= r->right)
+ Code |= RIGHT_SIDE;
+ else if(p->x < r->left)
+ Code |= LEFT_SIDE;
+ return Code;
+}
+
+static BOOL ClipLine(const POINT *p1, const POINT *p2, const RECT *r, POINT *pc1, POINT *pc2)
+{
+ BYTE outCode1,outCode2;
+ int tmp;
+ BYTE tmpCode;
+
+ pc1->x = p1->x; pc1->y = p1->y;
+ pc2->x = p2->x; pc2->y = p2->y;
+ while(TRUE)
+ {
+ outCode1 = outCodes(pc1, r);
+ outCode2 = outCodes(pc2, r);
+ if(outCode1 & outCode2)
+ return FALSE;
+ if(!outCode1 && !outCode2)
+ return TRUE;
+ if(!outCode1)
+ {
+ tmp = pc1->x; pc1->x = pc2->x; pc2->x = tmp;
+ tmp = pc1->y; pc1->y = pc2->y; pc2->y = tmp;
+ tmpCode = outCode1; outCode1 = outCode2; outCode2 = tmpCode;
+ }
+ if(outCode1 & TOP_SIDE)
+ {
+ pc1->x += MulDiv(pc2->x - pc1->x, r->top - pc1->y, pc2->y - pc1->y);
+ pc1->y = r->top;
+ }
+ else if(outCode1 & BOTTOM_SIDE)
+ {
+ pc1->x += MulDiv(pc2->x - pc1->x, r->bottom - 1 - pc1->y, pc2->y - pc1->y);
+ pc1->y = r->bottom - 1;
+ }
+ else if(outCode1 & RIGHT_SIDE)
+ {
+ pc1->y += MulDiv(pc2->y - pc1->y, r->right - 1 - pc1->x, pc2->x - pc1->x);
+ pc1->x = r->right - 1;
+ }
+ else if(outCode1 & LEFT_SIDE)
+ {
+ pc1->y += MulDiv(pc2->y - pc1->y, r->left - pc1->x, pc2->x - pc1->x);
+ pc1->x = r->left;
+ }
+ }
+}
+
+/* Clips a polygon by an horizontal/vertical line
+ which indicates the side :
+*/
+static inline BOOL PointInside(const POINT *p, const RECT *r, BYTE side)
+{
+ switch(side)
+ {
+ case 1: /* left */
+ return p->x >= r->left;
+ case 2: /* top */
+ return p->y >= r->top;
+ case 4: /* right */
+ return p->x < r->right;
+ case 8: /* bottom */
+ return p->y < r->bottom;
+ default:
+ return FALSE;
+ }
+}
+
+static inline void SideIntersect(const POINT *p1, const POINT *p2, const RECT *r, BYTE side, POINT *inters)
+{
+ switch( side )
+ {
+ case LEFT_SIDE: /* left */
+ inters->x = r->left;
+ inters->y = MulDiv(p2->y - p1->y, r->left - p1->x, p2->x - p1->x) + p1->y;
+ break;
+ case TOP_SIDE: /* top */
+ inters->x = MulDiv(p2->x - p1->x, r->top - p1->y, p2->y - p1->y) + p1->x;
+ inters->y = r->bottom;
+ break;
+ case RIGHT_SIDE: /* right */
+ inters->x = r->right - 1;
+ inters->y = MulDiv(p2->y - p1->y, r->right - 1 - p1->x, p2->x - p1->x) + p1->y;
+ break;
+ case BOTTOM_SIDE: /* bottom */
+ inters->x = MulDiv(p2->x - p1->x, r->bottom - 1 - p1->y, p2->y - p1->y) + p1->x;
+ inters->y = r->bottom - 1;
+ break;
+ default:
+ break;
+ }
+}
+
+
+static BOOL ClipPolygonBySide(const POINT *pt, int count, const RECT *r, BYTE side, POINT **clipped, int *clippedCount)
+{
+ int iPoint;
+ const POINT *p1, *p2;
+ POINT *pOut;
+
+ if(!(*clipped = HeapAlloc(GetProcessHeap(), 0, sizeof(POINT) * count * 2)))
+ return FALSE;
+ pOut = *clipped;
+ *clippedCount = 0;
+
+ p1 = pt + count - 1;
+ p2 = pt;
+ for(iPoint = 0 ; iPoint < count ; iPoint++)
+ {
+ if(PointInside(p2, r, side))
+ {
+ /* point p is "inside" */
+ if(!PointInside(p1, r, side))
+ {
+ /* p is "inside" and s is "outside" */
+ SideIntersect(p2, p1, r, side, pOut++);
+ (*clippedCount)++;
+ }
+ pOut->x = p2->x;
+ pOut->y = p2->y;
+ pOut++;
+ (*clippedCount)++;
+ }
+ else if(PointInside( p1, r, side ))
+ {
+ /* s is "inside" and p is "outside" */
+ SideIntersect(p1, p2, r, side, pOut++);
+ (*clippedCount)++;
+ }
+ p1 = p2++;
+ }
+ return *clippedCount;
+}
+
+
+/* Clips a polygon by a rectangular window - returns a new polygon */
+static BOOL ClipPolygon(const POINT* pt, int count, const RECT *r, POINT **newPt, int *newCount)
+{
+ POINT *pc1, *pc2;
+ int count1, count2;
+ BOOL res;
+
+ if(!ClipPolygonBySide(pt, count, r, LEFT_SIDE, &pc1, &count1))
+ return FALSE;
+ res = ClipPolygonBySide(pc1, count1, r, TOP_SIDE, &pc2, &count2);
+ HeapFree(GetProcessHeap(), 0, pc1);
+ if(!res)
+ return FALSE;
+ res = ClipPolygonBySide(pc2, count2, r, RIGHT_SIDE, &pc1, &count1);
+ HeapFree(GetProcessHeap(), 0, pc2);
+ if(!res)
+ return FALSE;
+ res = ClipPolygonBySide(pc1, count1, r, BOTTOM_SIDE, &pc2, &count2);
+ HeapFree(GetProcessHeap(), 0, pc1);
+ if(!res)
+ return FALSE;
+
+ *newPt = pc2;
+ *newCount = count2;
+ return TRUE;
+}
+
+/* Intersects a line given by 2 points with an horizontal scan line at height y */
+static BOOL ScanLine(const POINT *p1, const POINT *p2, int ys, POINT *pRes)
+{
+ if(!pRes)
+ return FALSE;
+
+ /* if line lies completely over or under scan line, no intersection */
+ if((p1->y < ys && p2->y < ys) || (p1->y > ys && p2->y > ys))
+ return FALSE;
+
+ /* if line is parallel to x axis, we consider it not intersecting */
+ if(p1->y == p2->y)
+ return FALSE;
+
+ pRes->x = MulDiv(p2->x - p1->x, ys - p1->y, p2->y - p1->y) + p1->x;
+ pRes->y = ys;
+ return TRUE;
+}
+
+/* Gets an x-ordered list of intersection points of a scanline at position y
+ with a polygon/polyline */
+static BOOL ScanPolygon(const POINT *pt, int count, int ys, POINT **scans, int *scanCount)
+{
+ const POINT *p1, *p2;
+ POINT *pDest;
+ int iPoint;
+ POINT *ps1, *ps2;
+ int i, j, tmp;
+
+ /* if not at least 2 points, nothing to return */
+ if(count < 2)
+ return FALSE;
+
+ /* intersections count is AT MOST 'count'; we don't care to
+ allocate exact memory needed */
+ *scans = HeapAlloc(GetProcessHeap(), 0, sizeof(POINT)*count);
+ if(!*scans)
+ return FALSE;
+
+ /* builds unordered intersections */
+ pDest = *scans;
+ *scanCount = 0;
+ p2 = pt;
+ for(iPoint = 0; iPoint < count-1; iPoint++)
+ {
+ p1 = p2;
+ p2++;
+ if(ScanLine(p1, p2, ys, pDest))
+ {
+ pDest++;
+ (*scanCount)++;
+ }
+ }
+ p1 = p2;
+ p2 = pt;
+ if(ScanLine(p1, p2, ys, pDest))
+ {
+ pDest++;
+ (*scanCount)++;
+ }
+
+ /* now we sort the list -- duped point are left into
+ as they're needed for the scanline fill algorithm */
+ for(i = 0, ps1 = *scans; i < *scanCount -1; i++, ps1++)
+ for(j = i+1, ps2 = ps1+1; j < *scanCount; j++, ps2++)
+ if(ps2->x < ps1->x)
+ {
+ tmp = ps2->x;
+ ps2->x = ps1->x;
+ ps1->x = tmp;
+ tmp = ps2->y;
+ ps2->y = ps1->y;
+ ps1->y = tmp;
+ }
+
+ return TRUE;
+}
+
+/* gets bounding box of a polygon */
+void PolygonBoundingBox(const POINT *pt, int count, RECT *bBox)
+{
+ const POINT *p;
+ int iPoint;
+
+ bBox->left = MAXLONG; bBox->right = -MAXLONG;
+ bBox->top = MAXLONG; bBox->bottom = -MAXLONG;
+ for(p = pt, iPoint = 0; iPoint < count; iPoint++, p++)
+ {
+ if(p->x < bBox->left ) bBox->left = p->x;
+ if(p->x > bBox->right ) bBox->right = p->x;
+ if(p->y < bBox->top ) bBox->top = p->y;
+ if(p->y > bBox->bottom) bBox->bottom = p->y;
+ }
+}
+
/***********************************************************************
* DIBDRV_Arc
*/
@@ -291,45 +566,155 @@ BOOL DIBDRV_Pie( DIBDRVPHYSDEV *physDev, int left, int top, int right, int botto
/**********************************************************************
* DIBDRV_Polygon
*/
-BOOL DIBDRV_Polygon( DIBDRVPHYSDEV *physDev, const POINT* pt, int count )
+BOOL DIBDRV_Polygon( DIBDRVPHYSDEV *physDev, const POINT* ptw, int count )
{
BOOL res;
+ POINT *pt;
+ RECT *r;
+ int iRec;
+ POINT *clipped;
+ int clippedCount;
+ RECT bBox;
+ int ys;
+ POINT *scans;
+ int scanCount, iScan;
+ const POINT *p1, *p2;
+ int iPoint;
+ POINT pc1, pc2;
- MAYBE(TRACE("physDev:%p, pt:%p, count:%d\n", physDev, pt, count));
+ MAYBE(TRACE("physDev:%p, pt:%p, count:%d\n", physDev, ptw, count));
if(physDev->hasDIB)
{
/* DIB section selected in, use DIB Engine */
- ONCE(FIXME("STUB\n"));
- res = TRUE;
+
+ res = FALSE;
+
+ /* first converts all points to device coords */
+ if(!(pt = HeapAlloc(GetProcessHeap(), 0, sizeof(POINT) * count)))
+ goto fin;
+ memcpy(pt, ptw, sizeof(POINT) * count);
+ LPtoDP(physDev->hdc, pt, count);
+
+ /* cycle on all current clipping rectangles */
+ r = physDev->regionRects;
+ for(iRec = 0; iRec < physDev->regionRectCount; iRec++, r++)
+ {
+ /* filled area */
+ if(ClipPolygon(pt, count, r, &clipped, &clippedCount))
+ {
+ /* gets polygon bounding box -- for ytop and ybottom */
+ PolygonBoundingBox(clipped, clippedCount, &bBox);
+
+ /* gets all ordered intersections of polygon with
+ current scanline */
+ for(ys = bBox.top; ys < bBox.bottom; ys++)
+ {
+ if(ScanPolygon(clipped, clippedCount, ys, &scans, &scanCount))
+ {
+ if(scanCount >= 2)
+ {
+ res = TRUE;
+ p1 = scans;
+ p2 = p1+1;
+ iScan = 0;
+ while(iScan < scanCount - 1)
+ {
+ physDev->brushHLine(physDev, p1->x, p2->x, ys);
+ p1 +=2;
+ p2 +=2;
+ iScan +=2;
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, scans);
+ }
+ }
+ HeapFree(GetProcessHeap(), 0, clipped);
+ }
+
+ /* perimeter -- don't use PolyLine for speed */
+ p2 = pt;
+ for(iPoint = 0; iPoint < count -1; iPoint++)
+ {
+ p1 = p2++;
+ if(ClipLine(p1, p2, r, &pc1, &pc2))
+ {
+ res = TRUE;
+ physDev->penLine(physDev, pc1.x, pc1.y, pc2.x, pc2.y);
+ }
+ }
+ p1 = p2;
+ p2 = pt;
+ if(ClipLine(p1, p2, r, &pc1, &pc2))
+ {
+ res = TRUE;
+ physDev->penLine(physDev, pc1.x, pc1.y, pc2.x, pc2.y);
+ }
+ }
+
+ HeapFree(GetProcessHeap(), 0, pt);
+
}
else
{
/* DDB selected in, use X11 driver */
- res = _DIBDRV_GetDisplayDriver()->pPolygon(physDev->X11PhysDev, pt, count);
+ res = _DIBDRV_GetDisplayDriver()->pPolygon(physDev->X11PhysDev, ptw, count);
}
+fin:
return res;
}
/**********************************************************************
* DIBDRV_Polyline
*/
-BOOL DIBDRV_Polyline( DIBDRVPHYSDEV *physDev, const POINT* pt, int count )
+BOOL DIBDRV_Polyline( DIBDRVPHYSDEV *physDev, const POINT* ptw, int count )
{
BOOL res;
- MAYBE(TRACE("physDev:%p, pt:%p, count:%d\n", physDev, pt, count));
+ MAYBE(TRACE("physDev:%p, pt:%p, count:%d\n", physDev, ptw, count));
if(physDev->hasDIB)
{
/* DIB section selected in, use DIB Engine */
- ONCE(FIXME("STUB\n"));
- res = TRUE;
+ POINT *pt;
+ RECT *r;
+ POINT pc1, pc2;
+ int iRec, iPoint;
+
+ if(count < 2)
+ return FALSE;
+ res = FALSE;
+
+ /* first converts all points to device coords */
+ if(!(pt = HeapAlloc(GetProcessHeap(), 0, sizeof(POINT) * count)))
+ return FALSE;
+ memcpy(pt, ptw, sizeof(POINT) * count);
+ LPtoDP(physDev->hdc, pt, count);
+
+ r = physDev->regionRects;
+ for(iRec = 0; iRec < physDev->regionRectCount; iRec++)
+ {
+ const POINT *p2 = pt, *p1;
+ for(iPoint = 0; iPoint < count -1; iPoint++)
+ {
+ p1 = p2++;
+ if(ClipLine(p1, p2, r, &pc1, &pc2))
+ {
+ res = TRUE;
+ physDev->penLine(physDev, pc1.x, pc1.y, pc2.x, pc2.y);
+ }
+ }
+ r++;
+ }
+
+ HeapFree(GetProcessHeap(), 0, pt);
+
+ return res;
}
else
{
/* DDB selected in, use X11 driver */
- res = _DIBDRV_GetDisplayDriver()->pPolyline(physDev->X11PhysDev, pt, count);
+ res = _DIBDRV_GetDisplayDriver()->pPolyline(physDev->X11PhysDev, ptw, count);
}
return res;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,42 @@
diff -urN wine-1.1.24.orig/dlls/ddraw/ddraw.c wine-1.1.24/dlls/ddraw/ddraw.c
--- wine-1.1.24.orig/dlls/ddraw/ddraw.c 2009-03-27 18:31:22.000000000 +0000
+++ wine-1.1.24/dlls/ddraw/ddraw.c 2009-04-05 19:06:28.000000000 +0100
@@ -35,6 +35,7 @@
#include "winbase.h"
#include "winerror.h"
#include "wingdi.h"
+#include "winreg.h"
#include "wine/exception.h"
#include "ddraw.h"
@@ -45,6 +46,8 @@
WINE_DEFAULT_DEBUG_CHANNEL(ddraw);
+#define IS_OPTION_TRUE(ch) ((ch) == 'y' || (ch) == 'Y' || (ch) == 't' || (ch) == 'T' || (ch) == '1')
+
static BOOL IDirectDrawImpl_DDSD_Match(const DDSURFACEDESC2* requested, const DDSURFACEDESC2* provided);
static HRESULT IDirectDrawImpl_AttachD3DDevice(IDirectDrawImpl *This, IDirectDrawSurfaceImpl *primary);
static HRESULT IDirectDrawImpl_CreateNewSurface(IDirectDrawImpl *This, DDSURFACEDESC2 *pDDSD, IDirectDrawSurfaceImpl **ppSurf, UINT level);
@@ -476,7 +479,20 @@
!(This->devicewindow) &&
(hwnd != window) )
{
- This->dest_window = hwnd;
+ BYTE buffer[32];
+ DWORD size = sizeof(buffer);
+ HKEY hkey = 0;
+ HWND drawwin = hwnd;
+ /* @@ Wine registry key: HKCU\Software\Wine\Direct3D */
+ if (!RegOpenKeyA( HKEY_CURRENT_USER, "Software\\Wine\\Direct3D", &hkey)) {
+ if (!RegQueryValueExA( hkey, "DirectDrawDesktopHack", 0, NULL, buffer, &size)) {
+ if ( IS_OPTION_TRUE( buffer[0] ) ) {
+ TRACE("Enabling DirectDrawDesktopHack hack\n");
+ drawwin = GetDesktopWindow();
+ }
+ }
+ }
+ This->dest_window = drawwin;
}
}
else if(cooplevel & DDSCL_EXCLUSIVE)

View File

@@ -0,0 +1,5 @@
REGEDIT4
[HKEY_CURRENT_USER\Software\Wine\Direct3D]
"DirectDrawDesktopHack"="true"