Arcanum on cedega

Artur Komarov <[email protected]> Sun, 25 Sep 2005 19:07:51 +0400
Newsgroups gmane.comp.emulators.winex.devel
Message-ID <[email protected]>
--=-fjHrW5KRGmT7HO6R7HAd
Content-Type: text/plain
Content-Transfer-Encoding: 7bit

I created patch for cvs cedega based on wine.
It's fixes graphics corruption in game. (bit-blit transformation
implement)

next. game loading very slowly.
wine do it up to 100x faster.

i think it's in ntdll part. solutions expected?

-- 
Artur Komarov <[email protected]>

--=-fjHrW5KRGmT7HO6R7HAd
Content-Disposition: attachment; filename=cedega-blt.patch
Content-Type: text/x-patch; name=cedega-blt.patch; charset=UTF-8
Content-Transfer-Encoding: 7bit

diff -rub winex-old/dlls/ddraw/dsurface/dib.c winex/dlls/ddraw/dsurface/dib.c
--- winex-old/dlls/ddraw/dsurface/dib.c	2005-09-25 05:35:26.000000000 +0400
+++ winex/dlls/ddraw/dsurface/dib.c	2005-09-25 05:21:04.000000000 +0400
@@ -439,414 +439,454 @@
 			  LPDIRECTDRAWSURFACE7 src, LPRECT rsrc,
 			  DWORD dwFlags, LPDDBLTFX lpbltfx)
 {
-
     ICOM_THIS(IDirectDrawSurfaceImpl,iface);
+    RECT		xdst,xsrc;
     DDSURFACEDESC2	ddesc,sdesc;
     HRESULT		ret = DD_OK;
-    int bpp, srcheight, srcwidth, dstheight, dstwidth;
+    int bpp, srcheight, srcwidth, dstheight, dstwidth, width;
     int x, y;
     LPBYTE dbuf, sbuf;
-    DWORD keylow=0, keyhigh=0, xinc=0, yinc=0, fillcolor=0;
-
-    /* Clipper Data */
-    LPDIRECTDRAWCLIPPER dClipper;
-    LPRGNDATA lpDstClipList=NULL;
-    LPRECT    lpDstRects=NULL;
-    DWORD     drcount=0;
-    DWORD     dwSize=0;
-    RECT      DefaultDstClipRect;
-    RECT      DefaultSrcClipRect;
-    RECT      srect, drect;
-
-    /* Reset mode flags */
-    BYTE has_dclipper=0;
-    BYTE has_scaling=0;
-    BYTE has_scolorkey=0;
-    BYTE has_dcolorkey=0;
 
     TRACE("(%p)->(%p,%p,%p,%08lx,%p)\n", This,rdst,src,rsrc,dwFlags,lpbltfx);
 
-    CHECK_LOST(This);
+    if (TRACE_ON(ddraw)) {
+	if (rdst) TRACE("\tdestrect :%ldx%ld-%ldx%ld\n",rdst->left,rdst->top,rdst->right,rdst->bottom);
+	if (rsrc) TRACE("\tsrcrect  :%ldx%ld-%ldx%ld\n",rsrc->left,rsrc->top,rsrc->right,rsrc->bottom);
+	TRACE("\tflags: ");
+	DDRAW_dump_DDBLT(dwFlags);
+	if (dwFlags & DDBLT_DDFX) {
+	    TRACE("\tblitfx: ");
+	    DDRAW_dump_DDBLTFX(lpbltfx->dwDDFX);
+	}
+    }
+
+    /* First, check if the possible override function handles this case */
+    /* if (This->aux_blt != NULL) {
+        if (This->aux_blt(This, rdst, src, rsrc, dwFlags, lpbltfx) == DD_OK) return DD_OK;
+    } */
 
     DD_STRUCT_INIT(&ddesc);
     DD_STRUCT_INIT(&sdesc);
 
-     /* Make Some Checks */
-    if (dwFlags & (DDBLT_WAIT|DDBLT_ASYNC)){
-      static BOOL displayed = FALSE;
-      if (!displayed) {
-        FIXME("dwFlags DDBLT_WAIT and/or DDBLT_ASYNC: can't handle right now.\n");
-        displayed = TRUE;
-      }
-      dwFlags &= ~(DDBLT_WAIT|DDBLT_ASYNC);
-    }
-
     sdesc.dwSize = sizeof(sdesc);
     if (src) IDirectDrawSurface7_Lock(src, NULL, &sdesc, DDLOCK_READONLY, 0);
     ddesc.dwSize = sizeof(ddesc);
     IDirectDrawSurface7_Lock(iface,NULL,&ddesc,DDLOCK_WRITEONLY,0);
 
-    /* Default Clipping Rectangles */
-    DefaultDstClipRect.top = DefaultDstClipRect.left = 0;
-    DefaultDstClipRect.right = ddesc.dwWidth;
-    DefaultDstClipRect.bottom = ddesc.dwHeight;
-
-    if (src) {
-      DefaultSrcClipRect.right = sdesc.dwWidth;
-      DefaultSrcClipRect.bottom = sdesc.dwHeight;
+    if (rdst) {
+	memcpy(&xdst,rdst,sizeof(xdst));
     } else {
-      DefaultSrcClipRect.right = DefaultSrcClipRect.bottom = 0;
+	xdst.top	= 0;
+	xdst.bottom	= ddesc.dwHeight;
+	xdst.left	= 0;
+	xdst.right	= ddesc.dwWidth;
     }
-    DefaultSrcClipRect.top = DefaultSrcClipRect.left = 0;
 
-    /* Process Compressed Formats */
-    if (sdesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC)
-    {
-       if (ddesc.u4.ddpfPixelFormat.dwFlags & DDPF_FOURCC) {
-           if (sdesc.u4.ddpfPixelFormat.dwFourCC == ddesc.u4.ddpfPixelFormat.dwFourCC &&
-               sdesc.u1.dwLinearSize == ddesc.u1.dwLinearSize) {
-               memcpy(ddesc.lpSurface, sdesc.lpSurface, ddesc.u1.dwLinearSize);
+    if (rsrc) {
+	memcpy(&xsrc,rsrc,sizeof(xsrc));
            } else {
-               FIXME("trying to decompress %4.4s surface to %4.4s surface\n", (char*)&sdesc.u4.ddpfPixelFormat.dwFourCC,
-                                                                              (char*)&ddesc.u4.ddpfPixelFormat.dwFourCC);
-           }
+	if (src) {
+	    xsrc.top	= 0;
+	    xsrc.bottom	= sdesc.dwHeight;
+	    xsrc.left	= 0;
+	    xsrc.right	= sdesc.dwWidth;
        } else {
-           FIXME("software-decompression of %4.4s surface not supported\n", (char*)&sdesc.u4.ddpfPixelFormat.dwFourCC);
-           /* most compression algorithms are patented, which limits source distribution...
-            * patented software decompressors will only be available in the WineX binaries */
-           /* here, we'll just clear the destination surface */
-           memset(ddesc.lpSurface, 0, ddesc.u1.lPitch * ddesc.dwHeight);
+	    memset(&xsrc,0,sizeof(xsrc));
        }
-       goto release;
     }
 
-
-    /* Access Clippers and find clipping rectangles */
-    if (IDirectDrawSurface7_GetClipper(iface, &dClipper)==DD_OK) { /* Clipper Found */
-      /* Query clipper size */
-      if (IDirectDrawClipper_GetClipList(dClipper, &DefaultDstClipRect, NULL, &dwSize)==DD_OK) {
-        /* Allocate space for ClipList */
-        lpDstClipList = (LPRGNDATA)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize);
-        if (lpDstClipList && IDirectDrawClipper_GetClipList(dClipper, &DefaultDstClipRect, lpDstClipList, &dwSize)==DD_OK) {
-          has_dclipper = 1;
-          lpDstRects   = (LPRECT)lpDstClipList->Buffer; /* Pointer to rectangles */
-          drcount      = lpDstClipList->rdh.nCount; /* How many rectangles we have */
-          TRACE("Has ClipList %lu entries\n",drcount);
-	  if (TRACE_ON(ddraw)) {
-	    DWORD i;
-	    for (i=0; i<drcount; i++) {
-	      TRACE("%lu: (%d, %d, %d, %d)\n",i+1,lpDstRects[i].left,lpDstRects[i].top,
-		lpDstRects[i].right,lpDstRects[i].bottom);
+    /* First check for the validity of source / destination rectangles. This was
+       verified using a test application + by MSDN.
+    */
+    if ((src != NULL) &&
+	((xsrc.bottom > sdesc.dwHeight) || (xsrc.bottom < 0) ||
+	 (xsrc.top > sdesc.dwHeight) || (xsrc.top < 0) ||
+	 (xsrc.left > sdesc.dwWidth) || (xsrc.left < 0) ||
+	 (xsrc.right > sdesc.dwWidth) || (xsrc.right < 0) ||
+	 (xsrc.right < xsrc.left) || (xsrc.bottom < xsrc.top))) {
+        WARN("Application gave us bad source rectangle for Blt.\n");
+	return DDERR_INVALIDRECT;
+    }
+    /* For the Destination rect, it can be out of bounds on the condition that a clipper
+       is set for the given surface.
+    */
+    if ((This->clipper == NULL) &&
+	((xdst.bottom > ddesc.dwHeight) || (xdst.bottom < 0) ||
+	 (xdst.top > ddesc.dwHeight) || (xdst.top < 0) ||
+	 (xdst.left > ddesc.dwWidth) || (xdst.left < 0) ||
+	 (xdst.right > ddesc.dwWidth) || (xdst.right < 0) ||
+	 (xdst.right < xdst.left) || (xdst.bottom < xdst.top))) {
+        WARN("Application gave us bad destination rectangle for Blt without a clipper set.\n");
+	return DDERR_INVALIDRECT;
+    }
+    
+    /* Now handle negative values in the rectangles. Warning: only supported for now
+       in the 'simple' cases (ie not in any stretching / rotation cases).
+
+       First, the case where nothing is to be done.
+    */
+    if (((xdst.bottom <= 0) || (xdst.right <= 0) || (xdst.top >= (int) ddesc.dwHeight) || (xdst.left >= (int) ddesc.dwWidth)) ||
+        ((src != NULL) &&
+         ((xsrc.bottom <= 0) || (xsrc.right <= 0) || (xsrc.top >= (int) sdesc.dwHeight) || (xsrc.left >= (int) sdesc.dwWidth))))
+    {
+        TRACE("Nothing to be done !\n");
+        goto release;
 	    }
+
+    /* The easy case : the source-less blits.... */
+    if (src == NULL) {
+        RECT full_rect;
+        RECT temp_rect; /* No idea if intersect rect can be the same as one of the source rect */
+
+	full_rect.left   = 0;
+	full_rect.top    = 0;
+	full_rect.right  = ddesc.dwWidth;
+	full_rect.bottom = ddesc.dwHeight;
+        IntersectRect(&temp_rect, &full_rect, &xdst);
+        xdst = temp_rect;
+    } else {
+        /* Only handle clipping on the destination rectangle */
+        int clip_horiz = (xdst.left < 0) || (xdst.right  > (int) ddesc.dwWidth );
+        int clip_vert  = (xdst.top  < 0) || (xdst.bottom > (int) ddesc.dwHeight);
+        if (clip_vert || clip_horiz) {
+            /* Now check if this is a special case or not... */
+            if ((((xdst.bottom - xdst.top ) != (xsrc.bottom - xsrc.top )) && clip_vert ) ||
+                (((xdst.right  - xdst.left) != (xsrc.right  - xsrc.left)) && clip_horiz) ||
+                (dwFlags & DDBLT_DDFX)) {
+                WARN("Out of screen rectangle in special case. Not handled right now.\n");
+                goto release;
 	  }
 
+            if (clip_horiz) {
+              if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
+              if (xdst.right > ddesc.dwWidth) { xsrc.right -= (xdst.right - (int) ddesc.dwWidth); xdst.right = (int) ddesc.dwWidth; }
+            }
+            if (clip_vert) {
+                if (xdst.top < 0) { xsrc.top -= xdst.top; xdst.top = 0; }
+                if (xdst.bottom > ddesc.dwHeight) { xsrc.bottom -= (xdst.bottom - (int) ddesc.dwHeight); xdst.bottom = (int) ddesc.dwHeight; }
+            }
+            /* And check if after clipping something is still to be done... */
+            if ((xdst.bottom <= 0) || (xdst.right <= 0) || (xdst.top >= (int) ddesc.dwHeight) || (xdst.left >= (int) ddesc.dwWidth) ||
+                (xsrc.bottom <= 0) || (xsrc.right <= 0) || (xsrc.top >= (int) sdesc.dwHeight) || (xsrc.left >= (int) sdesc.dwWidth)) {
+                TRACE("Nothing to be done after clipping !\n");
+                goto release;
         }
       }
-      IDirectDrawClipper_Release(dClipper);
     }
 
-    /* Set Default clip-rectangle for destination if no cliplist defined */
-    if (!has_dclipper) {
-      drcount=1;
-      lpDstRects=&DefaultDstClipRect;
-    }
+    bpp = GET_BPP(ddesc);
+    srcheight = xsrc.bottom - xsrc.top;
+    srcwidth = xsrc.right - xsrc.left;
+    dstheight = xdst.bottom - xdst.top;
+    dstwidth = xdst.right - xdst.left;
+    width = (xdst.right - xdst.left) * bpp;
 
-    /* Check that input rectangles are valid, Use defaults if NULL */
-    if (rdst) {
-      if (__is_invalid(rdst)) { ret=DDERR_INVALIDRECT; goto error; }
-    } else { 
-      rdst = &DefaultDstClipRect; 
-    }
+    assert(width <= ddesc.u1.lPitch);
 
-    if (rsrc) {
-      if (__is_invalid(rsrc)) { ret=DDERR_INVALIDRECT; goto error; }
-    } else {
-      rsrc = &DefaultSrcClipRect;
-    }
+    dbuf = (BYTE*)ddesc.lpSurface+(xdst.top*ddesc.u1.lPitch)+(xdst.left*bpp);
 
-    /* Width & Height values for original src,dst-rectangles */
-    bpp = GET_BPP(ddesc);
-    srcheight = rsrc->bottom - rsrc->top;
-    srcwidth = rsrc->right - rsrc->left;
-    dstheight = rdst->bottom - rdst->top;
-    dstwidth = rdst->right - rdst->left;
-
-    /* Scaling configuration */
-    if (src && (srcwidth!=dstwidth || srcheight!=dstheight)) {
-       if (iface==src && (srcwidth>dstwidth || srcheight>dstheight)) {
-          FIXME("Can not selfcopy while enlarging.\n");
-          ret=DDERR_UNSUPPORTED; goto error;
-       }
-       if (iface==src && (rdst->left > 0 || rdst->top > 0)) {
-          FIXME("Can not perform this operation.\n");
-          ret=DDERR_UNSUPPORTED; goto error;
+    if (dwFlags & (DDBLT_WAIT|DDBLT_ASYNC))
+    {
+	static BOOL displayed = FALSE;
+	if (!displayed)
+	{
+	    FIXME("dwFlags DDBLT_WAIT and/or DDBLT_ASYNC: can't handle right now.\n");
+	    displayed = TRUE;
        }
-       xinc = (srcwidth << 16) / dstwidth;
-       yinc = (srcheight << 16) / dstheight;
-       has_scaling=1;
+        dwFlags &= ~(DDBLT_WAIT|DDBLT_ASYNC);
     }
 
-    /* Configure Special Operations */
-    if (dwFlags & DDBLT_ZBUFFER) { FIXME("Z-Buffer not supported\n"); ret=DDERR_UNSUPPORTED; goto error; }
-    if (dwFlags & DDBLT_COLORFILL) fillcolor=lpbltfx->u5.dwFillColor;
-    if (dwFlags & DDBLT_ROP) { /* Blt Raster Ops */
+    /* First, all the 'source-less' blits */
+    if (dwFlags & DDBLT_COLORFILL) {
+	ret = _Blt_ColorFill(dbuf, dstwidth, dstheight, bpp,
+			     ddesc.u1.lPitch, lpbltfx->u5.dwFillColor);
+	dwFlags &= ~DDBLT_COLORFILL;
+    }
+
+    if (dwFlags & DDBLT_DEPTHFILL)
+	FIXME("DDBLT_DEPTHFILL needs to be implemented!\n");
+    if (dwFlags & DDBLT_ROP) {
+	/* Catch some degenerate cases here */
       switch(lpbltfx->dwROP) {
-        case BLACKNESS: fillcolor=0;  dwFlags|=DDBLT_COLORFILL; break;
-        case WHITENESS: fillcolor=~0; dwFlags|=DDBLT_COLORFILL; break;
-        case SRCCOPY:   break;
-        case 0xAA0029: /* No-op */ break;
+	case BLACKNESS:
+	    ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,ddesc.u1.lPitch,0);
+	    break;
+	case 0xAA0029: /* No-op */
+	    break;
+	case WHITENESS:
+	    ret = _Blt_ColorFill(dbuf,dstwidth,dstheight,bpp,ddesc.u1.lPitch,~0);
+	    break;
+	case SRCCOPY: /* well, we do that below ? */
+	    break;
         default:
           FIXME("Unsupported raster op: %08lx  Pattern: %p\n", lpbltfx->dwROP, lpbltfx->u5.lpDDSPattern);
           goto error;
       }
       dwFlags &= ~DDBLT_ROP;
     }
-    if (dwFlags & DDBLT_DDFX) {  /* Blt FX */
-       ret = DDERR_UNSUPPORTED;
-       DDRAW_dump_DDBLTFX(lpbltfx->dwDDFX);
-       dwFlags &= ~DDBLT_DDFX;
-       goto error;
-    }
-
-    /* ColorKey Configuration */
-    if (dwFlags & (DDBLT_KEYSRC | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE | DDBLT_KEYDEST)) {
-      if (dwFlags & DDBLT_KEYSRCOVERRIDE) {
-        keylow  = lpbltfx->ddckSrcColorkey.dwColorSpaceLowValue;
-        keyhigh = lpbltfx->ddckSrcColorkey.dwColorSpaceHighValue;
-        dwFlags &= ~DDBLT_KEYSRCOVERRIDE;
-        has_scolorkey=1;
-      }
-      else if (dwFlags & DDBLT_KEYDESTOVERRIDE) {
-        keylow  = lpbltfx->ddckDestColorkey.dwColorSpaceLowValue;
-        keyhigh = lpbltfx->ddckDestColorkey.dwColorSpaceHighValue;
-        dwFlags &= ~DDBLT_KEYDESTOVERRIDE;
-        has_dcolorkey=1;
-      }
-      else if (dwFlags&DDBLT_KEYSRC) {
-        if (sdesc.dwFlags&DDSD_CKSRCBLT) {
-          keylow  = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
-          keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
-          has_scolorkey=1;
-        }
-        dwFlags &= ~DDBLT_KEYSRC;
-      }
-      else if (dwFlags&DDBLT_KEYDEST) {
-        if (ddesc.dwFlags&DDSD_CKDESTBLT) {
-          keylow  = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
-          keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
-          has_dcolorkey=1;
-        }
-        dwFlags &= ~DDBLT_KEYDEST;
-      }
-      if (has_scolorkey==0 && has_dcolorkey==0) goto release;
-    }
-
-    if (has_dcolorkey) {
-      FIXME("Destination colorkeying not implemented... disabled\n");
-      has_dcolorkey = has_scolorkey = 0;
-    }
-
-    /* Primary loop for clipping operations */
-    /* Rectangles in clip list shouldn't overlap */
-
-    TRACE("Start blitting %ld rectangles\n",drcount);
-
-    while (drcount) {
-      int w, h;
-      DWORD width;
-
-      drcount--;
-
-      if (has_dclipper) { /* We have a clipper */
-	RECT rect = lpDstRects[drcount];
-	if (__is_invalid(&rect)) { continue; }     /*** ABORT this iteration ***/
-
-	/* Compute operative rectangles srect and drect */
-	if (!src) {
-	  drect = __intersect(&rect, rdst); /* Sourceless Blits */
-	} else {
-	  int disx = rsrc->left - rdst->left;
-	  int disy = rsrc->top - rdst->top;
-
-	  drect = __intersect(&rect, rdst);               /* Destination clipping */
-	  if (__is_invalid(&drect)) { continue; }  /*** ABORT this iteration ***/
-	  srect = __intersect(&DefaultSrcClipRect, rsrc); /* Source clipping */
-	      
-	  OffsetRect(&drect, disx, disy);  /* Overlap and unscale for final combination */
-	  if (has_scaling) {
-	    __scale_rect(&drect, srcwidth, dstwidth, srcheight, dstheight);
-	  }
-	  drect = srect = __intersect(&srect, &drect); /* Combine source and distination */
-	  if (has_scaling) {
-	    __scale_rect(&drect, dstwidth, srcwidth, dstheight, srcheight); /* UnScale */
-	  }
-	  OffsetRect(&drect, -disx, -disy); /* UnTranslate */
-	  if (__is_invalid(&srect)) { continue; }  /*** ABORT this iteration ***/
+    if (dwFlags & DDBLT_DDROPS) {
+	FIXME("\tDdraw Raster Ops: %08lx  Pattern: %p\n", lpbltfx->dwDDROP, lpbltfx->u5.lpDDSPattern);
 	}
-      } else { /* No clipper */
-	if (rdst->left < DefaultDstClipRect.left ||
-	    rdst->top < DefaultDstClipRect.top ||
-	    rdst->right > DefaultDstClipRect.right ||
-	    rdst->bottom > DefaultDstClipRect.bottom) { continue; } /* ABORT this iteration */
-	drect = *rdst;
+    /* Now the 'with source' blits */
 	if (src) {
-	  if (rsrc->left < DefaultSrcClipRect.left ||
-	      rsrc->top < DefaultSrcClipRect.top ||
-	      rsrc->right > DefaultSrcClipRect.right ||
-	      rsrc->bottom > DefaultSrcClipRect.bottom) { continue; } /* ABORT this iteration */
-	  srect = *rsrc;
-	}
-      } /* clipper */
-
-      h = drect.bottom - drect.top;
-      w = drect.right - drect.left;
-      if (w<=0 || h<=0) { continue; }  /*** ABORT this iteration ***/
-      width = w*bpp;
-
-      if (!src) { /* Source-less operations */
+	LPBYTE sbase;
+	int sx, xinc, sy, yinc;
 
-	dbuf = (BYTE*)ddesc.lpSurface+(drect.top*ddesc.u1.lPitch)+(drect.left*bpp);
+	if (!dstwidth || !dstheight) /* hmm... stupid program ? */
+	    goto release;
+	sbase = (BYTE*)sdesc.lpSurface+(xsrc.top*sdesc.u1.lPitch)+xsrc.left*bpp;
+	xinc = (srcwidth << 16) / dstwidth;
+	yinc = (srcheight << 16) / dstheight;
 
-	if (dwFlags & DDBLT_COLORFILL) {
-	  ret = _Blt_ColorFill(dbuf, w, h, bpp, ddesc.u1.lPitch, fillcolor);
-	  if (ret != DD_OK) { goto error; }  /*** ERROR - ABORT ***/
+	if (!dwFlags) {
+	    /* No effects, we can cheat here */
+	    if (dstwidth == srcwidth) {
+		if (dstheight == srcheight) {
+		    /* No stretching in either direction. This needs to be as
+		     * fast as possible */
+		    sbuf = sbase;
+
+                    /* check for overlapping surfaces */
+                    if (src != iface || xdst.top < xsrc.top ||
+                        xdst.right <= xsrc.left || xsrc.right <= xdst.left)
+                    {
+                        /* no overlap, or dst above src, so copy from top downwards */
+                        for (y = 0; y < dstheight; y++)
+                        {
+                            memcpy(dbuf, sbuf, width);
+                            sbuf += sdesc.u1.lPitch;
+                            dbuf += ddesc.u1.lPitch;
 	}
-	/* This relies on the underlying hal driver to copy the z dib bits into the GL z-buffer */
-	if (dwFlags & DDBLT_DEPTHFILL) {
-	  ret = _Blt_ColorFill(dbuf, w, h, bpp, ddesc.u1.lPitch, lpbltfx->u5.dwFillDepth);
-	  if (ret != DD_OK) { goto error; }  /*** ERROR - ABORT ***/
 	}
-	if (dwFlags & DDBLT_DDROPS) {
-	  FIXME("\tDdraw Raster Ops: %08lx  Pattern: %p\n", lpbltfx->dwDDROP, lpbltfx->u5.lpDDSPattern);
-	  ret = DDERR_UNSUPPORTED;
-	  goto error;   /** UNSUPPORTED - ABORT ***/
+                    else if (xdst.top > xsrc.top)  /* copy from bottom upwards */
+                    {
+                        sbuf += (sdesc.u1.lPitch*dstheight);
+                        dbuf += (ddesc.u1.lPitch*dstheight);
+                        for (y = 0; y < dstheight; y++)
+                        {
+                            sbuf -= sdesc.u1.lPitch;
+                            dbuf -= ddesc.u1.lPitch;
+                            memcpy(dbuf, sbuf, width);
 	}
-
-      } else { /* Operations With Source */
-
-	LONG spitch = sdesc.u1.lPitch;
-	LONG dpitch = ddesc.u1.lPitch;
-	dbuf = (BYTE*)ddesc.lpSurface+(drect.top*ddesc.u1.lPitch)+(drect.left*bpp);
-	sbuf = (BYTE*)sdesc.lpSurface+(srect.top*sdesc.u1.lPitch)+(srect.left*bpp);
-
-	/* Copy Source to Destination */
-	if (!has_scaling) {  /* copy without scaling */
-
-	  if (!(has_scolorkey || has_dcolorkey)) { /* Copy without colorkey */
-
-	    /* Detect self-copies and ensure that we copy rows in the
-             * right order to avoid overwriting a row that is still needed.
-	     * (memmove is used to ensure that the pixels in a row are
-	     * copied in the right order.) */
-	    if (src == iface && srect.top < drect.top) {
-	      LPBYTE surf = (BYTE*)sdesc.lpSurface;
-	      sbuf = surf + (srect.bottom-1)*spitch + srect.left*bpp;
-	      dbuf = surf + (drect.top+h-1)*dpitch + drect.left*bpp;
-	      spitch = -spitch;
-	      dpitch = -dpitch;
 	    }
-	    for (y = 0; y < h; y++) {
+                    else /* src and dst overlapping on the same line, use memmove */
+                    {
+                        for (y = 0; y < dstheight; y++)
+                        {
 	      memmove(dbuf, sbuf, width);
-	      sbuf += spitch;
-	      dbuf += dpitch;
+                            sbuf += sdesc.u1.lPitch;
+                            dbuf += ddesc.u1.lPitch;
 	    }
-
-	  } else {  /* Copy with colorkey */
-
-	    switch (bpp) {
-	    case 1: COPYBOX_COLORKEY(BYTE)  break;
-	    case 2: COPYBOX_COLORKEY(WORD)  break;
-	    case 4: COPYBOX_COLORKEY(DWORD) break;
-	    default:
-	      FIXME("Color key blitting not supported for bpp %d\n",bpp*8);
-	      ret = DDERR_UNSUPPORTED; goto error;
 	    }
-	  } /* copy with colorkey */
-
-	} else { /* Copy with scaling */
-
-	  LPBYTE sbase;
-	  int sx, sy;
-	  sbase = (BYTE*)sdesc.lpSurface+(srect.top*sdesc.u1.lPitch)+srect.left*bpp;
-
-	  if (!has_scolorkey) {  /* copy without source color key */
-
-	    if (dstwidth == srcwidth) { /* Stretching in Y direction only */
-	      for (y = sy = 0; y < h; y++, sy += yinc) {
+		} else {
+		    /* Stretching in Y direction only */
+		    for (y = sy = 0; y < dstheight; y++, sy += yinc) {
 		  sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
-		  memmove(dbuf, sbuf, width);
+			memcpy(dbuf, sbuf, width);
 		  dbuf += ddesc.u1.lPitch;
 	      }
-	      
-	    } else { /* Stretch all directions */
-
+		}
+	    } else {
+		/* Stretching in X direction */
 	      int last_sy = -1;
-	      for (y = sy = 0; y < h; y++, sy += yinc) {
+		for (y = sy = 0; y < dstheight; y++, sy += yinc) {
 		sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
+
 		if ((sy >> 16) == (last_sy >> 16)) {
-		  /* this sourcerow is the same as last sourcerow copy already stretched row */
-		  memmove(dbuf, dbuf - ddesc.u1.lPitch, width);
-		}
-		else {
+			/* this sourcerow is the same as last sourcerow -
+			 * copy already stretched row
+			 */
+			memcpy(dbuf, dbuf - ddesc.u1.lPitch, width);
+		    } else {
+#define STRETCH_ROW(type) { \
+		    type *s = (type *) sbuf, *d = (type *) dbuf; \
+		    for (x = sx = 0; x < dstwidth; x++, sx += xinc) \
+		    d[x] = s[sx >> 16]; \
+		    break; }
+
 		  switch(bpp) {
-		  case 1: STRETCH_ROW(BYTE) break;
-		  case 2: STRETCH_ROW(WORD) break;
-		  case 4: STRETCH_ROW(DWORD) break;
-		  case 3: STRETCH_ROW_24 break;
+		    case 1: STRETCH_ROW(BYTE)
+		    case 2: STRETCH_ROW(WORD)
+		    case 4: STRETCH_ROW(DWORD)
+		    case 3: {
+			LPBYTE s,d = dbuf;
+			for (x = sx = 0; x < dstwidth; x++, sx+= xinc) {
+			    DWORD pixel;
+
+			    s = sbuf+3*(sx>>16);
+			    pixel = s[0]|(s[1]<<8)|(s[2]<<16);
+			    d[0] = (pixel    )&0xff;
+			    d[1] = (pixel>> 8)&0xff;
+			    d[2] = (pixel>>16)&0xff;
+			    d+=3;
+			}
+			break;
+		    }
 		  default:
 		    FIXME("Stretched blit not implemented for bpp %d!\n", bpp*8);
-		    ret = DDERR_UNSUPPORTED; goto error;
+			ret = DDERR_UNSUPPORTED;
+			goto error;
 		  }
+#undef STRETCH_ROW
 		}
 		dbuf += ddesc.u1.lPitch;
 		last_sy = sy;
 	      }
-	    } /* stretch all directions */
+	    }
+	} else {
+           LONG dstyinc = ddesc.u1.lPitch, dstxinc = bpp;
+           DWORD keylow = 0, keyhigh = 0;
+           if (dwFlags & (DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE)) {
 
-	  } else { /* copy with source color key (has_scolorkey) */
+	      if (dwFlags & DDBLT_KEYSRC) {
+		 keylow  = sdesc.ddckCKSrcBlt.dwColorSpaceLowValue;
+		 keyhigh = sdesc.ddckCKSrcBlt.dwColorSpaceHighValue;
+	      } else if (dwFlags & DDBLT_KEYDEST){
+		 keylow  = ddesc.ddckCKDestBlt.dwColorSpaceLowValue;
+		 keyhigh = ddesc.ddckCKDestBlt.dwColorSpaceHighValue;
+	      } else if (dwFlags & DDBLT_KEYSRCOVERRIDE) {
+		 keylow  = lpbltfx->ddckSrcColorkey.dwColorSpaceLowValue;
+		 keyhigh = lpbltfx->ddckSrcColorkey.dwColorSpaceHighValue;
+	      } else {
+		 keylow  = lpbltfx->ddckDestColorkey.dwColorSpaceLowValue;
+		 keyhigh = lpbltfx->ddckDestColorkey.dwColorSpaceHighValue;
+	      }
+              dwFlags &= ~(DDBLT_KEYSRC | DDBLT_KEYDEST | DDBLT_KEYSRCOVERRIDE | DDBLT_KEYDESTOVERRIDE);
+           }
 	    
-	    for (y = sy = 0; y < h; y++, sy += yinc) {
-	      sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
+           if (dwFlags & DDBLT_DDFX)  {
+              LPBYTE dTopLeft, dTopRight, dBottomLeft, dBottomRight, tmp;
+              LONG tmpxy;
+              dTopLeft     = dbuf;
+              dTopRight    = dbuf+((dstwidth-1)*bpp);
+              dBottomLeft  = dTopLeft+((dstheight-1)*ddesc.u1.lPitch);
+              dBottomRight = dBottomLeft+((dstwidth-1)*bpp);
+
+              if (lpbltfx->dwDDFX & DDBLTFX_ARITHSTRETCHY){
+                 /* I don't think we need to do anything about this flag */
+                 WARN("dwflags=DDBLT_DDFX nothing done for DDBLTFX_ARITHSTRETCHY\n");
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_MIRRORLEFTRIGHT) {
+                 tmp          = dTopRight;
+                 dTopRight    = dTopLeft;
+                 dTopLeft     = tmp;
+                 tmp          = dBottomRight;
+                 dBottomRight = dBottomLeft;
+                 dBottomLeft  = tmp;
+                 dstxinc = dstxinc *-1;
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_MIRRORUPDOWN) {
+                 tmp          = dTopLeft;
+                 dTopLeft     = dBottomLeft;
+                 dBottomLeft  = tmp;
+                 tmp          = dTopRight;
+                 dTopRight    = dBottomRight;
+                 dBottomRight = tmp;
+                 dstyinc = dstyinc *-1;
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_NOTEARING) {
+                 /* I don't think we need to do anything about this flag */
+                 WARN("dwflags=DDBLT_DDFX nothing done for DDBLTFX_NOTEARING\n");
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_ROTATE180) {
+                 tmp          = dBottomRight;
+                 dBottomRight = dTopLeft;
+                 dTopLeft     = tmp;
+                 tmp          = dBottomLeft;
+                 dBottomLeft  = dTopRight;
+                 dTopRight    = tmp;
+                 dstxinc = dstxinc * -1;
+                 dstyinc = dstyinc * -1;
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_ROTATE270) {
+                 tmp          = dTopLeft;
+                 dTopLeft     = dBottomLeft;
+                 dBottomLeft  = dBottomRight;
+                 dBottomRight = dTopRight;
+                 dTopRight    = tmp;
+                 tmpxy   = dstxinc;
+                 dstxinc = dstyinc;
+                 dstyinc = tmpxy;
+                 dstxinc = dstxinc * -1;
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_ROTATE90) {
+                 tmp          = dTopLeft;
+                 dTopLeft     = dTopRight;
+                 dTopRight    = dBottomRight;
+                 dBottomRight = dBottomLeft;
+                 dBottomLeft  = tmp;
+                 tmpxy   = dstxinc;
+                 dstxinc = dstyinc;
+                 dstyinc = tmpxy;
+                 dstyinc = dstyinc * -1;
+              }
+              if (lpbltfx->dwDDFX & DDBLTFX_ZBUFFERBASEDEST) {
+                 /* I don't think we need to do anything about this flag */
+                 WARN("dwflags=DDBLT_DDFX nothing done for DDBLTFX_ZBUFFERBASEDEST\n");
+              }
+              dbuf = dTopLeft;
+              dwFlags &= ~(DDBLT_DDFX);
+           }
+
+#define COPY_COLORKEY_FX(type) { \
+	    type *s = (type *) sbuf, *d = (type *) dbuf, *dx, tmp; \
+            for (y = sy = 0; y < dstheight; y++, sy += yinc) { \
+               (LPBYTE)s = sbase + (sy >> 16) * sdesc.u1.lPitch; \
+               (LPBYTE)dx = d; \
+	       for (x = sx = 0; x < dstwidth; x++, sx += xinc) { \
+		  tmp = s[sx >> 16]; \
+		  if (tmp < keylow || tmp > keyhigh) dx[0] = tmp; \
+                  (LPBYTE)dx += dstxinc; \
+	          } \
+               (LPBYTE)d += dstyinc; \
+	    } \
+            break; }
 
 	      switch (bpp) {
-		case 1: COPYROW_COLORKEY(BYTE) break;
-		case 2: COPYROW_COLORKEY(WORD) break;
-		case 4: COPYROW_COLORKEY(DWORD) break;
+	    case 1: COPY_COLORKEY_FX(BYTE)
+	    case 2: COPY_COLORKEY_FX(WORD)
+	    case 4: COPY_COLORKEY_FX(DWORD)
+ 	    case 3: {LPBYTE s,d = dbuf, dx;
+		for (y = sy = 0; y < dstheight; y++, sy += yinc) {
+		    sbuf = sbase + (sy >> 16) * sdesc.u1.lPitch;
+		    dx = d;
+		    for (x = sx = 0; x < dstwidth; x++, sx+= xinc) {
+			DWORD pixel;
+			s = sbuf+3*(sx>>16);
+			pixel = s[0]|(s[1]<<8)|(s[2]<<16);
+                        if (pixel < keylow || pixel > keyhigh){
+		            dx[0] = (pixel    )&0xff;
+			    dx[1] = (pixel>> 8)&0xff;
+			    dx[2] = (pixel>>16)&0xff;
+                        }
+		        dx+= dstxinc;
+		    }
+		    d += dstyinc;
+                }
+                break;}
 		default:
-		  FIXME("Color-keyed blit not implemented for bpp %d!\n",bpp*8);
+	       FIXME("%s color-keyed blit not implemented for bpp %d!\n",
+	          (dwFlags & DDBLT_KEYSRC) ? "Source" : "Destination", bpp*8);
 		  ret = DDERR_UNSUPPORTED;
 		  goto error;
+#undef COPY_COLORKEY_FX
+            }
 	      }
-	      dbuf += ddesc.u1.lPitch;
 	    }
-
-	  } /* has_scolorkey */
-
-	} /* has_scaling */
-
-      } /* has_srccopy */
-    } /* main loop ends */
 
 error:
-release:
-
-    /* clear checked flags */
-    if (dwFlags & DDBLT_COLORFILL) dwFlags &= ~DDBLT_COLORFILL;
-    if (dwFlags & DDBLT_DEPTHFILL) dwFlags &= ~DDBLT_DEPTHFILL;
-    if (dwFlags & DDBLT_DDROPS) dwFlags &= ~DDBLT_DDROPS;
-
     if (dwFlags && FIXME_ON(ddraw)) {
       FIXME("\tUnsupported flags: ");
       DDRAW_dump_DDBLT(dwFlags);
     }
 
-    if (lpDstClipList) HeapFree(GetProcessHeap(), 0, lpDstClipList);
-
+release:
     IDirectDrawSurface7_Unlock(iface,NULL);
     if (src) IDirectDrawSurface7_Unlock(src,NULL);
-    return ret;
+    return DD_OK;
 }
 
+
 #undef COPYBOX_COLORKEY
 #undef STRETCH_ROW
 #undef COPYROW_COLORKEY

--=-fjHrW5KRGmT7HO6R7HAd--