Jump to content
  • Advertisement
Sign in to follow this  
rafehi

Map editor running very slowly (Visual C#)

This topic is 3079 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'm attempting to create a simple map editor in Visual C#. It's pretty much my first ever Windows application and it's going fairly slowly but I'm making solid progress.

However, after adding a grid to my map I noticed that it was running extremely slowly. It works fine when not drawing the grid but is very sluggish when I turn it on.

The tiles are 32x32 and I draw the grid in the picturebox's paint event as follows:

void mapEditorPicture_Paint(object sender, PaintEventArgs e)
{
// Draw the tiles
e.Graphics.DrawImage(cursor, cursorMap.X * dimensions - 1,
cursorMap.Y * dimensions - 1);

if (tileMapPicture.Image != null)
{
// GraphicsUnit units = GraphicsUnit.World;

//// RectangleF bmpRectangleF = tileMapPicture.Image.GetBounds(ref units);
//// Rectangle bmpRectangle = Rectangle.Round(bmpRectangleF);

e.Graphics.DrawImage(tileMapPicture.Image,
new Rectangle(cursorMap.X * dimensions,
cursorMap.Y * dimensions, dimensions, dimensions),
new Rectangle(cursorTile.X * dimensions, cursorTile.Y * dimensions,
dimensions, dimensions),
GraphicsUnit.Pixel);
}

// Draw the grid
if (mapGridCheck.Checked)
{
DrawGrid(mapEditorPicture.Size.Width, mapEditorPicture.Size.Height,
e.Graphics);
}
}

// Code for drawing the gridcells
private void DrawGrid(int width, int height, Graphics graphics)
{
for (int i = 0; i < width; i++)
{
for (int j = 0; j < height; j++)
{
Point point = new Point(dimensions * i, dimensions * j);
graphics.DrawImage(gridCell, point);
}
}
}




I'm guessing the problem is the thousands of iterations it must go through every time the paint method is called (3000 for a 100x30 grid). Am I using the paint event correctly?

Even when scrolling it seems to be extremely slow when the grid is on, telling me that it's repainting then too.

A couple of solutions that I've thought up are:
1. Only drawing a grid for the visible part of the picture, so instead of 3000 iterations, it might only be 300.
2. Drawing the grid in another picturebox on top of the first (sort of like a new layer), so that the only time it has to redraw the grid is when it is toggled on/off.

Is there a better way to go about this? Also, once I've got my tiles displaying properly, I'm guessing I'll run into the same problem. Is there am inbuilt way to get the paint event to redraw ONLY the parts of the screen that need redrawing? For example, if I place a tile at (0,0) it'll only redraw that single tile as everything else is unchanged? As well as only drawing what's actually displayed on the screen and not everything else? Or will I have to code it up myself?

Share this post


Link to post
Share on other sites
Advertisement
What does the profiler tell you?

You can guess what the bottlenecks are (and generally be wrong about it) or you can use a profiler to isolate the bottlenecks, measure them, and compare the results after your changes.

If you don't have a version of Visual Studio that includes the profiler, you can use the free command line version. Google can help you find several others of the VS Profiler isn't enough.



You've already likely hit on one of the offenders, since all those function calls do have overhead. Drawing on a per-pixel basis can be very slow. Consider doing the whole thing in fewer function calls, or only drawing it once and storing the results. But without actual profiler numbers, you are just guessing at the root cause.

Share this post


Link to post
Share on other sites
rafehi when you draw your grid are you drawing a grid image on top of your map, if you are then this is probably the reason why it is so slow, I think it would be easier if you just drew lines.

So if your mapEditor picture is 640 * 640 say and your tiles are 32 * 32 then you would only have to draw 20 lines across the way and 20 lines down the way. That would be your grid.

When I drew a grid for my editor(done in C++ with SDL and guichan) this is what I did.
I'm using tiles of 64 * 64

w = width, q = height, 640 = width of map, 1280 = height of map.


for(int i = 0; i < mapHeight; i++)
{
graphics->drawLine(0, w, 640, w);
w += 64;
}

for(int j = 0; j < mapWidth; j++)
{
graphics->drawLine(q, 0, q, 1280);
q += 64;
}




Share this post


Link to post
Share on other sites
Quote:
Original post by frob
What does the profiler tell you?

You can guess what the bottlenecks are (and generally be wrong about it) or you can use a profiler to isolate the bottlenecks, measure them, and compare the results after your changes.

If you don't have a version of Visual Studio that includes the profiler, you can use the free command line version. Google can help you find several others of the VS Profiler isn't enough.



You've already likely hit on one of the offenders, since all those function calls do have overhead. Drawing on a per-pixel basis can be very slow. Consider doing the whole thing in fewer function calls, or only drawing it once and storing the results. But without actual profiler numbers, you are just guessing at the root cause.


I've never used a profiler and I've got VSEE, so it's not included. I downloaded the CLR profiler and all I got was an unhandled expection error...

Share this post


Link to post
Share on other sites
Quote:
Original post by popcorn
rafehi when you draw your grid are you drawing a grid image on top of your map, if you are then this is probably the reason why it is so slow, I think it would be easier if you just drew lines.

So if your mapEditor picture is 640 * 640 say and your tiles are 32 * 32 then you would only have to draw 20 lines across the way and 20 lines down the way. That would be your grid.

When I drew a grid for my editor(done in C++ with SDL and guichan) this is what I did.
I'm using tiles of 64 * 64

w = width, q = height, 640 = width of map, 1280 = height of map.

*** Source Snippet Removed ***


Thanks for that, it's definitely a much faster implementation than mine.

But it doesn't really solve the problem. When I draw the tiles themselves, I've got no choice but to do it tile by tile and so I'm guessing I'll encounter the problem again.

Frob, what other option do I have but per pixel drawing? Also, what do you mean by storing the results?

Share this post


Link to post
Share on other sites
Quote:
Original post by rafehi
Quote:
Original post by frob
What does the profiler tell you?

You can guess what the bottlenecks are (and generally be wrong about it) or you can use a profiler to isolate the bottlenecks, measure them, and compare the results after your changes.

If you don't have a version of Visual Studio that includes the profiler, you can use the free command line version. Google can help you find several others of the VS Profiler isn't enough.



You've already likely hit on one of the offenders, since all those function calls do have overhead. Drawing on a per-pixel basis can be very slow. Consider doing the whole thing in fewer function calls, or only drawing it once and storing the results. But without actual profiler numbers, you are just guessing at the root cause.


I've never used a profiler and I've got VSEE, so it's not included. I downloaded the CLR profiler and all I got was an unhandled expection error...

Thats cause its a pretty crappily piece of crappish.

try out http://code.google.com/p/slimtune/

Share this post


Link to post
Share on other sites
Alright, using SlimTunes and looking at the results (not really sure how to interpret), I'm getting ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop (int, int, int)
as taking up well over 80% of the time. No idea what that is?

My old drawing function was taking ~15% of time whereas using popcorn's implentation, that's dropped to well below 1%. Working much faster too.

Any reason why the FPushMessageLoop is no high?

Share this post


Link to post
Share on other sites
I'm no .Net guru, but just some random thoughts:

I would try implementing the 2 optimization methods in your first post if you haven't already. #1 may be especially important: you want to reduce the number of blits as much as possible. Only draw the tiles or grid lines that are within the map viewport. This should make a significant difference in performance.

Also, make sure you are not unnecessarily invalidating the map viewport somewhere else so that OnPaint() is getting called too often.

I've had some speed issues with blitting images under System.Drawing, but I don't remember exactly the problem. I believe it had to do with alpha blending (transparency) - I think the solution I found (through trial and error) was to use PNG's with the alpha channel instead of using a color keyed transparency. You don't seem to be using alpha, however, so this probably doesn't apply.

I'm not sure about the FPushMessageLoop(). I've never used SlimTune, but I know that some profilers introduce extra overhead into the executable - perhaps this is what you are seeing? Have you tried to execute the revised code without the profiler to subjectively measure the performance difference?

Of course, there is always the option of going a completely different route. GDI+ may not be the best tool for performance graphics. I know, for example, that XNA integrates easily with Winforms, and there are even some very in-depth tutorials on building a tile map editor using this technique. However, an inefficient algorithm will perform badly no matter how much hardware acceleration you put up against, so it may be worth your while to investigate further.

Good luck!

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!