ddraw fix

Lionel Ulmer lionel.ulmer at free.fr
Tue Nov 12 03:36:38 CST 2002


> Now I found this:
> 
> http://msdn.microsoft.com/archive/en-us/ddraw7/directdraw7/ddover_7ctz.asp
> 
> I read from there that source rect must be inside src.
> Destination _may_ be outside, only if something called 'clipper'
> is attached to dst.

OK, so according to my testings plus your MSDN findings, I attached a patch
that should match 'feature to feature' what the real DirectX does... It
certainly won't help you with your Grim problem though (BTW I tested it with
an application that set a clipper and it still works fine).

> Well, on my Grim Fandango testings it started when Calavera tried
> to walk to Big Boss cabinet (after talking Celso) - so near the end.

Do you have a save game for that so that I try it on my version of Grim (I
may even test it on my Windows box :-) ).

                            Lionel

-- 
		 Lionel Ulmer - http://www.bbrox.org/
-------------- next part --------------
--- ../wine_work_base/dlls/ddraw/dsurface/dib.c	Tue Nov 12 10:16:09 2002
+++ dlls/ddraw/dsurface/dib.c	Tue Nov 12 10:29:08 2002
@@ -388,27 +388,44 @@
 	if (src) {
 	    xsrc.top	= 0;
 	    xsrc.bottom	= sdesc.dwHeight;
 	    xsrc.left	= 0;
 	    xsrc.right	= sdesc.dwWidth;
 	} else {
 	    memset(&xsrc,0,sizeof(xsrc));
 	}
     }
 
-    if (xsrc.bottom > sdesc.dwHeight)
-	xsrc.bottom = sdesc.dwHeight;
-    if (xdst.bottom > ddesc.dwHeight)
-	xdst.bottom = ddesc.dwHeight;
-    
-    if (src) assert((xsrc.bottom-xsrc.top) <= sdesc.dwHeight);
-    assert((xdst.bottom-xdst.top) <= ddesc.dwHeight);
+    /* 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 > sdesc.dwHeight) || (xdst.bottom < 0) ||
+	 (xdst.top > sdesc.dwHeight) || (xdst.top < 0) ||
+	 (xdst.left > sdesc.dwWidth) || (xdst.left < 0) ||
+	 (xdst.right > sdesc.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))))
     {
@@ -421,42 +438,38 @@
         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 {
-        /* This is trickier as any update to one rectangle need to be propagated to the other */
-        int clip_horiz = (xdst.left < 0) || (xdst.right  > (int) ddesc.dwWidth ) || (xsrc.left < 0) || (xsrc.right  > (int) sdesc.dwWidth );
-        int clip_vert  = (xdst.top  < 0) || (xdst.bottom > (int) ddesc.dwHeight) || (xsrc.top  < 0) || (xsrc.bottom > (int) sdesc.dwHeight);
+        /* 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 (xsrc.left < 0) { xdst.left -= xsrc.left; xsrc.left = 0; }
               if (xdst.left < 0) { xsrc.left -= xdst.left; xdst.left = 0; }
-              if (xsrc.right > sdesc.dwWidth) { xdst.right -= (xsrc.right - (int) sdesc.dwWidth); xsrc.right = (int) sdesc.dwWidth; }
               if (xdst.right > ddesc.dwWidth) { xsrc.right -= (xdst.right - (int) ddesc.dwWidth); xdst.right = (int) ddesc.dwWidth; }
             }
             if (clip_vert) {
-                if (xsrc.top < 0) { xdst.top -= xsrc.top; xsrc.top = 0; }
                 if (xdst.top < 0) { xsrc.top -= xdst.top; xdst.top = 0; }
-                if (xsrc.bottom > sdesc.dwHeight) { xdst.bottom -= (xsrc.bottom - (int) sdesc.dwHeight); xsrc.bottom = (int) sdesc.dwHeight; }
                 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;
             }
         }
     }


More information about the wine-devel mailing list