Sign in to follow this  

[.net] Is there a faster way using GDI+? (done)

This topic is 4395 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I was optimistic that I could port my old VB6 rpg to C# without too much headache. Even masking was made simple using GDI+, but I have run into a problem that I am hoping some people have experience with. It seems to be pretty slow (at least the way I'm using it). This is my drawing loop. Is the DrawImage function extremely slow? Is there an alternative way to draw from an image to the graphic?
Bitmap bmp = new Bitmap(@"Background.bmp");
Room room = new Room(1);
Bitmap BackBuffer;
Graphics DrawingArea;

// in the form construction area
BackBuffer = new Bitmap(800, 600);
DrawingArea = Graphics.FromImage(BackBuffer);

void DrawMap(Bitmap bmp, Room r)
{
    for (int x = 0; x < 30; ++x)
    {
        for (int y = 0; y < 20; ++y)
        {

            Rectangle rect = new Rectangle(x * 30, y * 30, 30, 30);
            Pair p = r.getGround(posx + x, posy + y);
            DrawingArea.DrawImage(bmp, rect, (int)p.First * 30, (int)p.Second * 30, 30, 30, GraphicsUnit.Pixel);
        }
    }

    Graphics g = this.CreateGraphics();
    g.DrawImageUnscaled(BackBuffer, 0, 0);

}



[Edited by - nprz on December 30, 2005 4:09:26 PM]

Share this post


Link to post
Share on other sites
Funny to see this thread, I was just moaning to people about the speed of gdi+.

I think its fine for doing small window/forms based stuff, but I have serious doubts about it for anything even semi complex and realtime. I'm not using it directly for rendering my games, but instead just for loading and manipulating textures. Even here it seems to be amazingly slow. Case in point ==> [link]http://www.gamedev.net/community/forums/topic.asp?topic_id=365331&whichpage=1??[/link]

I would suggest either managed directx, or Tao.Sdl.

*EDIT* hmmm can't seem to get that url to show... can't be bothered to sort it out either..o well :) *EDIT*

Share this post


Link to post
Share on other sites
Hi. Consider using the BitBlt API from Win32. It's pretty easy to use and to tie into the GDI+. Here is some existing code I have modified which could help.


[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hObject, int nXDest, int nYDest, int nWidth,
int nHeight, IntPtr hObjSource, int nXSrc, int nYSrc, TernaryRasterOperations dwRop);

public enum TernaryRasterOperations
{
SRCCOPY = 0x00CC0020, /* dest = source*/
SRCPAINT = 0x00EE0086, /* dest = source OR dest*/
SRCAND = 0x008800C6, /* dest = source AND dest*/
SRCINVERT = 0x00660046, /* dest = source XOR dest*/
SRCERASE = 0x00440328, /* dest = source AND (NOT dest )*/
NOTSRCCOPY = 0x00330008, /* dest = (NOT source)*/
NOTSRCERASE = 0x001100A6, /* dest = (NOT src) AND (NOT dest) */
MERGECOPY = 0x00C000CA, /* dest = (source AND pattern)*/
MERGEPAINT = 0x00BB0226, /* dest = (NOT source) OR dest*/
PATCOPY = 0x00F00021, /* dest = pattern*/
PATPAINT = 0x00FB0A09, /* dest = DPSnoo*/
PATINVERT = 0x005A0049, /* dest = pattern XOR dest*/
DSTINVERT = 0x00550009, /* dest = (NOT dest)*/
BLACKNESS = 0x00000042, /* dest = BLACK*/
WHITENESS = 0x00FF0062, /* dest = WHITE*/
};

[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern IntPtr CreateCompatibleDC(IntPtr hDC);

[DllImport("gdi32.dll", ExactSpelling=true,
SetLastError=true)]
public static extern bool DeleteDC(IntPtr hdc);

[DllImport("gdi32.dll", ExactSpelling=true)]
public static extern IntPtr SelectObject(IntPtr hDC,
IntPtr hObject);

private void Blit(Image source, Image destination)
{
// Create a graphics object for the picture box
Graphics grphTarget = Graphics.FromImage(source);
// Get the picture box HDC
IntPtr grphTargetDc = grphTarget.GetHdc();

// Create a GDI device compatible DC from the DC of the GDI+ DC
IntPtr pSource = CreateCompatibleDC(grphTargetDc);
// Replaces the old DC with a DC to the bitmap of the picture in the picture box
SelectObject(pSource, ((Bitmap)destination).GetHbitmap());

// BitBlt ** Add loops here **
BitBlt(grphTargetDc, 0, 0, 32, 32, pSource, 0, 0, TernaryRasterOperations.SRCCOPY);

// Delete the GDI DC
DeleteDC(pSource);
// Release the target DC
grphTarget.ReleaseHdc(grphTargetDc);
// Dispose of the target graphic object
grphTarget.Dispose();
}



A little note about the code, please don't call Blit for every tile becuase that would hurt its performace greatly. Instead, add your loops inside the function, this means you only have to get the device contexts once per frame.

Hope that helps.

Share this post


Link to post
Share on other sites
Quote:
Original post by Shuryou
Hi. Consider using the BitBlt API from Win32. It's pretty easy to use and to tie into the GDI+. Here is some existing code I have modified which could help.

*** Source Snippet Removed ***
A little note about the code, please don't call Blit for every tile becuase that would hurt its performace greatly. Instead, add your loops inside the function, this means you only have to get the device contexts once per frame.

Hope that helps.


I love you [smile]. Thank you, that helped a ton!
I was searching earlier for how to do that but could never get it to work because I didn't know which Images to use, etc. With your function, I was able to use my Bitmap and Backbuffer and it was perfect.

@POedBoy: Even GDI methods for pixel manipulation were slow (GetPixel, SetPixel), unlike GDI methods for altering images (BitBlt).

Share this post


Link to post
Share on other sites
OK, I have an additional question in relation to Shuryou's post.
If I use BitBlt to draw then it seems that I lose any automatic transparency feature that I had.

Is there any way to do this without a huge slowdown and hopefully without having to create a mask of the bitmap?

If I have to make a mask, do I have to use black as the transparent color or can I use magenta?

Share this post


Link to post
Share on other sites
Quote:
Original post by nprz
OK, I have an additional question in relation to Shuryou's post.
If I use BitBlt to draw then it seems that I lose any automatic transparency feature that I had.

Is there any way to do this without a huge slowdown and hopefully without having to create a mask of the bitmap?

If I have to make a mask, do I have to use black as the transparent color or can I use magenta?


Unfortunately, the old GDI didn't have a really good way of dealing with transparency. So you will have to create mask bitmaps, but they can be any colour like magenta.

Now, drawing tiles I assume is what takes a lot of CPU time and BitBlt solved that, so do you think its possible you could use the GDI+ functions for drawing your sprites seeing as how there probably won't be as many?

If not, here is some code I found on how to mask an image:

SelectObject(hdcMem, g_hbmMask);
BitBlt(hdc, 0, 0, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCAND);

SelectObject(hdcMem, g_hbmBall);
BitBlt(hdc, 0, bm.bmHeight, bm.bmWidth, bm.bmHeight, hdcMem, 0, 0, SRCPAINT);

So the first BitBlt you draw the mask, and the second BitBlt you draw the image.

Share this post


Link to post
Share on other sites
Try using an "Optimized DoubleBuffer", I think this will speed up things a little but I'm not sure.
Setstyle(Controlstyles.OptimizedDoubleBuffer);

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Once again MS CLR fails to deliver on its promise, wasting yet another game developer's precious time.


Share this post


Link to post
Share on other sites
Quote:
Original post by Rob Loach
You're probably too late in the development of that to switch to SDL.NET, but it would most definately speed up things. [wink]


Hah, you think I'm too far to switch [smile]. Actually I'm not far at all, I want to make sure the game will run before trying to build it. So with SDL.NET I'm still forced to make a new window to run the program in or can I use the existing form and draw on top of it? If switching to SDL.NET means I have to use everything in SDL.NET, then I might as well learn DirectX [grin]. -edit- (Not serious about the DirectX thing), I think I might be able to manage with SDL.NET even if I can't use drag-drop controls for those forms.

@Shuryou: I plan on using the transparencies quite a bit and a forest of trees slows down the drawing if I use GDI+'s method. Also using that BitBlt method for transparencies require that I use black as my transparency color or it won't work.

@AP: I think Microsoft would rather me use their DirectX for making a game. I think I'm misusing their tools at the moment.

[Edited by - nprz on December 30, 2005 3:06:00 PM]

Share this post


Link to post
Share on other sites
OK, I switched to SDL and it runs fast and smooth, I wanted to post a screenshot of it but my host's (school) server is down so I will update this post with the screenshot whenever it comes back up. (I was also going to give a link to a previous screenshot of what I was making it from but alas, the host is down [sad])



[Edited by - nprz on December 31, 2005 11:15:27 PM]

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Once again MS CLR fails to deliver on its promise, wasting yet another game developer's precious time.


yeah. I'll go back to java and it's 3 second full screen blits. :-) Ok that was low, java isn't as bad as it used to be... but damn it used to be horrendously slow at ui graphics.

The problem is that the .net GDI implementation is a wrapper, so it uses interop to call unmanged functions in gdi dlls. This of course has to have things like stack checks and the like to make sure no one is exploiting it. So it ends up being rather slow. Even SetPixel needs to make calls to GDI dlls because of things like pallets and colour depths etc, so this method in perticular is really slow when used a lot. It's a shame I guess, but there probably wasn't any other way around it.

That said I'm sure avalon will just a tad faster :-) ..



Back on topic...

your game looks really cool npzr :-) keep up the good work

Share this post


Link to post
Share on other sites
Quote:
Original post by Anonymous Poster
Once again MS CLR fails to deliver on its promise, wasting yet another game developer's precious time.


Once again an anonymous poster comes in with an idiotic claim, wasting people's precious time.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
Quote:
Original post by SamLowry
Quote:
Original post by Anonymous Poster
Once again MS CLR fails to deliver on its promise, wasting yet another game developer's precious time.


Once again an anonymous poster comes in with an idiotic claim, wasting people's precious time.


Just like you did!

Share this post


Link to post
Share on other sites
I don't know how much of it we can really blame on Microsoft. I've got graphics programming books from as far back as the 1980s complaining about how slow drawing to the screen is. It's like so many people/groups have tried to address it but the oldest solutions seem to be the ones that end up working over and over :/

Share this post


Link to post
Share on other sites
I wouldn't blame Microsoft at all. They have made great improvements on DirectX, which is what games should be made on (or OpenGL). GDI+ is just to make life easier for those people who want to make shapes or draw lines.

I was just hoping they made some vast improvements since getting rid of the need for BitBlt, but SDL.NET filled the void very well. [smile]


Here is a more recent version of the editor, the "W" on the buildings and stuff means it acts as a wall for creatures.

[Edited by - nprz on January 4, 2006 3:23:09 PM]

Share this post


Link to post
Share on other sites

This topic is 4395 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this