Managed DirectDraw: Negative values for DrawFast()

pseud0

Newcomer
Joined
Mar 16, 2004
Messages
2
Ok, So I'm new to DirectDraw. Been working a lot with GapiDraw (for PocketPC) previously. With Gapi you can use DrawFast on a surface with negative values if you've set a clipper to the surface, but when I use negative X and Y coords for the DDraw DrawFast it's a crash and burn. How do I get around this?

Example:
Code:
private void InizializeDirectDraw() {[INDENT]...
device = new Device();
...
primarySurface = new Surface( desc, device );
...
clipper = new Clipper( device );
clipper.Window = this;
primarySurface.Clipper = clipper;
...
// draw a new blue (default it seems) bitmap
imageSurface = new Surface( new Bitmap(100,100), desc, device );
[/INDENT]
}
// called every 30 ms from a timer
private void Render() {[INDENT]...
[COLOR=Red]secondarySurface.DrawFast( 0, 0, imageSurface, DrawFastFlags.Wait );[/COLOR]
...
[/INDENT]
}
Now... If I change the secondarySurface.DrawFast(0, 0, imageSurface, DrawFastFlasgs.Wait); to say; secondarySurface.DrawFast(-10, -10, imageSurface, DrawFastFlasgs.Wait); then the program crashes on rendering the surface.

How do I get around this? Is there a problem with the clipper?
I'm happy for ANY help or suggestions. It seems hard to believe that noone has every drawn anything off the left of the screen, but I can't find any information on it at all. :(
Thanks!
 
This happens when you attempt to draw beyond the size of the backbuffer. You could probably get by this by giving the backbuffer a clipper as well, but that would severely cripple the frame rate of your application.

The only way I know of to get around this is to create a routine which returns the appropriate rectangle area of the graphic to be drawn. That way instead of drawing the entire graphic, you're only drawing the portion which is being displayed.

EDIT:
There's nothing wrong with the clipper. As you notice, the clipper is for the primary surface, not the backbuffer.
 
You can actually do this yourself if you like, as wyrd said, however, by my calculations the Clipper is about as fast as doing it yourself (probably wouldnt be if you could do it in ASM or something). Anyway, What you need to do is set up the clipping area of your Clipper(s). You can attach it to any surface you want clipped drawing to occur on.

Use the ClipList property on the clipper to do this, simply pass it a set of rectangles. I THINK the basic idea is that you set up a cliplist on the back surface, and just attach the front surface clipper to the window.
 
The ClipList is already set to the Window rectangle (when you specify Clipper.Window = control).

I've went ahead and created a seperate Clipper for the Backbuffer and tried running the application again. I still got the same exact error when trying to draw outside of backbuffer.

EDIT:
Unless I'm mistaken, this makes sense. After all, when you create a surface of a certain size, it creates just enough space in memory to hold that data. If you try to draw outside of the buffer, then you'd actually be drawing on other data. That is, of course, a bad thing.
 
Yeah, this is true, you WANT your front surface's clipper to be clipping the window. However, your back surface's clipper (should you decided to use a clipper and Draw, instead of self clipping and DrawFast), you should set a ClipList on.

This way all your clipping is done for you on your back surface. You cannot use DrawFast however, you must use Draw. DrawFast does not support Clippers. Still not sure which is the fastest.
 
Well, here's a method I created to do source and destination area calculations (coordiantes the x,y coords based on window position and then sets the correct src rectangle for drawing so you don't draw outside of the buffer);

Code:
/// <summary>
/// Calculates the destination and source areas which are to be used for drawing.
/// </summary>
/// <param name="dest">Destination area.</param>
/// <param name="src">Source area.</param>
/// <param name="window">Window to calculate for.</param>
/// <returns>True on success, false otherwise.</returns>
public bool CalcDrawingAreas(ref Rectangle dest, ref Rectangle src, Control window)
{
	// Calculate actual drawing coordinates.
	Point p = window.PointToScreen(new Point(dest.X, dest.Y));
	dest.X = p.X;
	dest.Y = p.Y;

	// Get window area.
	Rectangle area = new Rectangle(window.Location, window.Size);

	// Cannot draw to a destination that is outside of the window area.
	if (!dest.IntersectsWith(area)) {
		return false;
	}

	// Only draw the source area which is within the window area.
	if (dest.Left < area.Left) {
		int difference = area.Left - dest.Left;

		src.X += difference;
		src.Width -= difference;

		dest.X = area.Left;
	}
	if (dest.Top < area.Top) {
		int difference = area.Top - dest.Top;

		src.Y += difference;
		src.Height -= difference;

		dest.Y = area.Top;
	}
	if (area.Right < dest.Right) {
		src.Width -= dest.Right - area.Right;
	}
	if (area.Bottom < dest.Bottom) {
		src.Height -= dest.Bottom - area.Bottom;
	}

	// Correct destination and source size need to be identical.
	dest.Width = src.Width;
	dest.Height = src.Height;

	// Area calculation was successful.
	return true;
}

Simple usage;

Code:
Rectangle src = _sprite.GetArea(0);
Rectangle dest = new Rectangle(-10, -10, src.Width, src.Height);

if (this.CalcDrawingAreas(ref dest, ref src, window)) {
	backbuffer.DrawFast(dest.X, dest.Y, _sprite.Surface, src, DrawFastFlags.DoNotWait | DrawFastFlags.SourceColorKey);
}
 
Last edited:
I did some minor benchmarking. Drawing the sprite 1,000 times at coordinates -10, -10 with both clipper using Draw, and my Calc method using DrawFast.

Draw + Clipper on Backbuffer = ~30fps.
DrawFast + Calc Method = ~55fps.

I think I'll take my calc method. :)

EDIT:
Another bench;

Draw + Calc Method = ~43fps.

I think it's fairly obvious that the clipper is sloooow. Avoid it where possible.
 
Last edited:
I went ahead and tried out D3D for 2d stuff. It turns out to not only solve all of these problems, but also gives you a nice little performance boost.
 
wyrd said:
I went ahead and tried out D3D for 2d stuff. It turns out to not only solve all of these problems, but also gives you a nice little performance boost.

Any Examples?

EDIT: Actually, no matter I sussed it, wow, that was easy. Humm.
 
Last edited:
One question about Sprites... does anyone have any idea if DX handles large sprites properly on old cards that do not support large textures? I am guessing not?
 
Back
Top