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