Jump to content
  • Advertisement
Sign in to follow this  
nprz

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

This topic is 4731 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
Advertisement
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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!