Click here to Skip to main content
15,881,882 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi all!

I recently created a control that will zoom in and out of an image and will scroll on it (something like on google earth), but I cannot get a smooth rendering when it begins to animate.

By the way I used a for-loop for changing parameters and then refresh or invalidate a piece of the image and set the double buffer to true.
My for-loop statement is tuned but what should I do if I want to get a smoother rendering?

Am I going in the wrong direction?

Maybe I should use some unmanaged code?

Thanks in advance!
Posted
Updated 19-Jan-11 21:40pm
v4
Comments
Dalek Dave 20-Jan-11 3:40am    
Edited for Readability.

It is not exactly clear how you implemented it. Does your loop have some sort of frame limiter for example? Is the loop executed with a maximum of 30 times (frames) a second or are you hogging the processor like crazy? Using a refresh directly is not advisable and should stick with invalidate only. If that means that no screen updates are shown, it means that you prevent the normal program flow of updating your screen.

Another important thing is to do the processing in another loop. This not even helps when using a multi processor environment but keeps the message loop active during processing. When a user is requesting to zoom, you can then immediately set some flag indicating that the processing can be aborted. By skipping that unnecessary processing the program becomes more responsive to the user and processes request immediately. Don't forget to yield (or sleep(0)) within the thread and check the indicator flag. Also limit the thread from processing more than 30 frames per second and use the sleep method to release processor time:
Sleep(Max((1000 / 30) - ({time in milliseconds when done} - {time in milliseconds when started}), 0));


The Max method is used to ensure that no negative numbers are used. It is also easy to detect if the value is negative all the time and react to that by lowering the frames per second.

Good luck!



GDI
http://www.aspfree.com/c/a/Code-Examples/Handling-Animation-and-Bitmaps-Using-GDI-for-Image-Manipulation/[^]

2D "Nim" Game Development and Animation in C# (Part 2)[^]

2D Animated Charts[^]

DirectDraw:
Rotating Sprite Objects on DirectDraw Wrapper for C#[^]

Introduction to DirectDraw and Surface Blitting[^]
 
Share this answer
 
v2
Comments
Manfred Rudolf Bihy 18-Jan-11 14:56pm    
Moved from OP's answer:
dear nijboer it was helpful but is there any way to cash Image to force it to draw more quicker?
E.F. Nijboer 19-Jan-11 7:55am    
About caching. I don't know exactly what your program does. But if the image itself is not an animation itself but is just scrolling as one large image than you can reuse most of the image by moving it and update only a small part of the screen. let's say your view port is 800x600 and you scroll to the left 10 pixels on every frame update. You then simply take (10,0)-(800,600) and move that to (0,0)-(790,600) and only need to update (790,0)-(800,600) with a new part of the image. You can use the bitblt function for moving the image part that can be reused. Could this provide some solution?
E.F. Nijboer 19-Jan-11 8:22am    
Also added some links that might help you out.
Espen Harlinn 19-Jan-11 8:32am    
5+ Good links, not sure OP is willing to make the effort though
Dalek Dave 20-Jan-11 3:40am    
Very Good answer, with good links.
E.F. Nijboer is on to something - a for type of loop is probably not a good idea, and like the man says: don't do a refresh.

You can try the following:
Use a timer to invalidate the screen area occupied by your image, and only paint during the Paint event[^] or override the OnPaint method[^]

This will keep your application responsive to other user actions, and it's basically how the "old" windows api was designed to work. Multiple invalidations will be combined into a single WM_PAINT if the system for some reason is unable to keep up with the "animation frame rate".

If you hvan't put to much work into this at this stage, consider moving your solution to WPF, where stuff like this finds ready implementations in the framework.

If you are using a PictureBox for your image you can solve your problem using the approach outlined in this article:
http://www.java2s.com/Tutorial/VB/0300__2D-Graphics/Programthatanimatesaseriesofimages.htm[^]

It's essentially using the approach I outlined above. Setting the PictureBox.Image property invalidates the PictureBox control.

If it's worth the effort you can use DirectX or TAO[^] to get hardware accelerated performance. Quadratic surface, image as texture, and so on...


Regards
Espen Harlinn
 
Share this answer
 
v3
Comments
Sergey Alexandrovich Kryukov 18-Jan-11 10:58am    
My 5.
Espen Harlinn 18-Jan-11 11:01am    
Well, thank you SAKryukov :)
Manfred Rudolf Bihy 18-Jan-11 14:57pm    
Moved from OP's answer:
Thanks Harlinn but i used all of these (except change format to 32bppPArgb) and this problem still persists (animated zoom in/out is not smooth)
Any other suggestion ?
Manfred Rudolf Bihy 18-Jan-11 14:58pm    
Espins comment to OP's "answer":
How much effort are you willing to put into this? I usually try to provide simple answers, since that's usually what people actually want. Are you developing your own custom component?
Espen Harlinn 18-Jan-11 15:03pm    
If he is willing to spend a couple of days on it, he could create something using TAO or DirectX ...
To optimize performance and keep animation smooth you need two things:
1) Keep using double buffering;
2) Do not use Refresh (of course), but don't use Invalidate() as well: use Invalidate with parameters: invalidate only a part of your scene.

Oh, yes, if you can -- move to WPF -- much better for animation (of different sorts, not only using available animation-related library classes).

As Marcus added a note on the use of thread (BackgroundWorker or explicitly created thread) -- thank you Markus -- I want to add a note.

The body of the animation thread should do two things: it should periodically update the data used in Paint event and then perform invalidation. Important to remember: Invalidate method should be called on UI thread, so the animation thread should perform inter-thread invocation:

C#
MyCanvasControl.Invoke(new System.Action<Control>(
    (Control control) => {
        control.Invalidate(sceneSubset);
    }), MyCanvasControl);


Note, that is the rendering data is updated due to the UI user, invalidation should be done immediately on UI thread through a direct call to Invalidate, no use of any thread synchronization primitive needed: Invoke takes care of it.

Finally, it's the best to avoid using of the timer.
 
Share this answer
 
v5
Comments
Espen Harlinn 18-Jan-11 10:31am    
5+ Heading in the same direction :)
fjdiewornncalwe 18-Jan-11 12:03pm    
Definitely the right direction. I think he would be wise to use some background workers to do his state and data handling, and another for his UI using double buffering techniques, so that they are somewhat independent of each other.
Sergey Alexandrovich Kryukov 18-Jan-11 13:57pm    
Thank you Marcus, this is another good point. I would say: it's the best to avoid use of the timer. Actually, I will add the note to my answer...
Espen Harlinn 18-Jan-11 14:50pm    
Actually I think this one of those places where the standard WM_TIMER has a lot going for it. If the system is busy, it will hurt the animation, otherwise - when there is cycles to burn it will be able to take advantage of the available processing power.
Sergey Alexandrovich Kryukov 18-Jan-11 15:00pm    
You see, as to timing, thread provides flexibility is saving time. The thread is sleeping big part of its activity. The actual sleep time is a bit more that specified and is extended it the CPUs are more busy. This is good, compared to the timer. The timer event will be fired anyway, but there is a change that a previous handler is not. Not only this is dangerous (not so bad with thorough programming, but why bother?); this is also more wasteful in terms of CPU time. Please, no timers -- a thread is better.
i did all of these
but i want more some thing more than double buffering
this line of code in OnPaint method make computer to its knees

e.Graphics.DrawImage(Picture, ClientRectangle, rect, GraphicsUnit.Pixel);

i should refresh all the screen for zoom in/out (am i right?)
and it should be refreshed 20Times in a loop

please tell me what is renderer? is that any relation with my problem?
 
Share this answer
 
Comments
Espen Harlinn 19-Jan-11 8:57am    
Only invalidate the rectangle occupied by the image using Control.Invalidate http://msdn.microsoft.com/en-us/library/8dtk06x2.aspx
Refresh is way too expensive. Windows tries it's best to optimize painting - See WM_PAINT http://msdn.microsoft.com/en-us/library/dd145213(VS.85).aspx
E.F. Nijboer 19-Jan-11 9:16am    
Are you doing the actual processing in a thread like I mentioned? And can it abort? The user might zoom fast in small steps while your program tries to create all unnecessary frames in between. Aborting/updating in between would be faster this way. If you do not use multi threaded then each step is a message that is processed and drawn to the screen in the paint event. That can take up quite some time and builds up more and more work. Those in between are not actually needed and can be skipped because only the last one (the zoom actual state) is important and should be shown on screen.
Another trick is to simply wait for about 100 or 200 milliseconds after the user requested a zoom action before start painting again and reset this time if the user wants to zoom any further. With this you wait until the user is done zooming (using the scrollwheel for example) before start processing and painting.
Espen Harlinn 19-Jan-11 10:05am    
I guess that he is trying to do this with quite large files - not exactly on the level of sprite animations that GDI+ can comfortably execute at 20+ fps.
E.F. Nijboer 19-Jan-11 12:19pm    
It should be perfectly possible for the same reason it is possible to move around screens in window XP without any holdup or stuttering. If it is just moving around a large image it should be no problem.
Espen Harlinn 19-Jan-11 14:35pm    
You're absolutely right - it's the probably the scaling thats killing the performance
If your having trouble with the speed of your rendering so that the animation looks jumpy, you can use XNA to render onto that panel. It's a little more effort rendering everything with textures and 2D quads but the end result is worth it.

But simply put create a panel that you want to render onto, and initialise a GraphicsDevice withe the window handle of that panel.

PresentationParameters pp = new PresentationParameters();
pp.BackBufferCount = 1;
pp.IsFullScreen = false;
pp.SwapEffect = SwapEffect.Copy;
pp.BackBufferWidth = width of render area;
pp.BackBufferHeight = size of render area;
pp.PresentationInterval = PresentInterval.One;
pp.BackBufferFormat = SurfaceFormat.Color;
pp.MultiSampleType = MultiSampleType.None;

GraphicsDevice m_device = new GraphicsDevice(GraphicsAdapter.DefaultAdapter, DeviceType.Hardware, myPane.Handle, pp);


After that you are free to use your graphics device to render directly onto your panel at any time with hardware acceleration, although you should probably use it from the OnPaint of the panel, so that you can redraw when necessary.
 
Share this answer
 
i am using vs2008 .net framework 3.5 sp3 but here is no reference for microsoft.xna.framework. or something like that.
so should i download "Microsoft XNA Game Studio 3.1"? u know it tokes 73mb!!! this means 24 hour downloading for me (in this desert) :-D
how can i have only xna dlls and just run it?
sorry if it`s a foolish question... ;P
 
Share this answer
 
dear Nijboer & Harlinn & Genius and others
1) i should animate the zoom in/out (not only drawing the zoomed image) because "boss said" :sigh:
2) i used Timer because thread managing was hard to implement for me (i am sill working on it but it *should be thread safe *using Invoke and *terminate thread after OnMouseKeyUp and some other issues)
3) i inflate a rectangle on my zoomable image and use draw image to only show the inflated rectangle on my control
4) after all of these it going harder (i should run sum threads to draw cars on my image)!!!
i am thinking to change total solution with XNA or some thing like that
by the way , is WPF a better solution than XNA? (please attention that it should deal with many many threads , mouse and keyboard events) and totally it going harder to manage
thanks all :-O
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900