I have a C# .NET application with which I've created a custom image display control. Each image display represents its own display context and draws the image using glDrawPixels (Yes I know it would be better to use textures, I plan to in the futures but this app is already too far along and my time is limited).
I am now trying to have both images pan simultaneously. That is, when one image is moved down ten pixels, the second image moves down ten pixels. Like so:
imageOne.YPan -= 10;
imageTwo.YPan -= 10;
imageOne.Invalidate(); //This forces a redraw.
imageTwo.Invalidate(); //This forces a redraw.
Alright so here is the problem I am having. Only one of the images displays is redrawing. If I place a pause in between the two Invalidate calls and make the pause duration at least 110 milliseconds both will redraw, but not simultaneously. So it looks as if the second image is always trying to catch up to the first. Plus, a 110 millisecond pause slows down the motion too much.
I have tried placing the updating and invalidating of each image in its own thread but this did not help.
At the beginning of drawing I make the appropriate context is current, and at the end I am calling swapbuffers(). I tried adding a glFinish to the end of the draw function, but there was no change.
Could it be that its the graphics card that is the problem? I am stuck using an integrated gpu that only has openGL 1.4.
Hopefully, I have provided enough detail that the answer to my problem can be found.
Its difficult telling what's wrong with what you do since you give so little detail. Here are some pointers which may help.
- before doing something in a context, make sure you make it the current one. If you want to pan two contexts, make the first one current, pan it and then make the second one current and pan it. These is no real reason why this should not work.
- If it looks like there is a timing problem, adding glFinish() at strategic places may help weed the problem out
- As should always be done, on occasions call glError() and see that everything went well.
- I'm not sure how this is done in the framework you're talking about but you should make sure that both contexts get a swapBuffers() call for every frame.
Invalidate doesn't force an immediate redraw. It marks the window invalid, and when the message queue runs out of other messages, a paint message will be created and processed. But that won't happen until you finish processing the current message and return to the main message loop, and it may be delayed even more than that.
Generally OpenGL animation is an exception to the rule of doing all drawing inside Control.OnPaint (or in a handler for the Control.Paint event).
Related
I am running a Helix viewport and am catching a mousewheeled event with previewmousewheel to run a method. When debugging some changes I made to my methods I found out that when I set a breakpoint (anywhere between the catching of the mousewheeledevent and the subsequent applying of the zoom in the viewport) the amount of zoom from one detent of the mousewheel will increase continuously in proportion to the amount of time the program has been paused (basically the amount of time elapsed from the mousewheeledevent and the applying of the delta to the viewport). This makes debugging my changes the way I normally do seem not possible, though of course I can work around this.
The real problem is that now I realize that the zoom is completely erratic in this way, because some operations take longer than others between the event and the setting of the viewport, depending on what I'm doing.
This seems like a completely haphazard thing to have going on when I'm trying to make changes to a camera and completely control the camera behavior based on details specific to my program.
Is there any way to disable this from happening or mitigate it almost entirely?
The following code is a snippet from my program that seems to be the main driver of the issue, but I'm not sure I can just remove this method of keeping time in the program, because we definitely need an asynchronous timekeeper as far as I know.
private async Task DoWorkAsyncInfiniteLoop()
{
while (true)
{
if (Run)
{
Time.timeElapsed += Time.runSpeed;
Time.simTime += Time.runSpeed;
updateAll();
}
// don't run again for at least 200 milliseconds
await Task.Delay(Time.interval);
}
}
perhaps there is some lines I can add that will basically allow me to apply the zoom to the viewport without waiting for the await Task.Delay(Time.interval) line to run?
I must admit I'm not too clear on how that code works, but I do know that it stops at the await Task.Delay line before finally i hit "step into" (F11) one more time and it somehow just applies the monstrous zoom that was not wanted, without my seeing any code after that being run.
Any workarounds?
Try to set IsInertiaEnabled = false on viewport
My question might seem silly to you, but I realized that moving my applications form makes the code inside it run slower. E.g. when I load a bitmap image and apply some image editing algorithms on it, it takes about 22 secs for the whole process to finish. But if I move the form during execution, it adds some 3-4 extra seconds to the elapsed time. I was able to spot the delay using a Stopwatch. So how can I get around this behaviour, if possible at all?
This is just an hypothesis that requires your investigation, as you didn't post any code and thus it is impossible to really know what is going on.
Most probably you move the boundaries of the image outside the screen. When you move in again, the windowing engine will do some draw calls on those rectangles to be redrawn. The same happens on resize when you enlarge but not when you shrink the window.
If this is the case, then you will not experience any extra draw calls as long as you don't cover/uncover areas of the image.
So this is not an answer but in your place I would override the Paint() method and log how many excess calls are made. Based on this, I'd search for a solution, such as suppress those calls like this:
public override void Paint()
{
if (algorithmRunning)
{
return; // suppress any further computations
}
base.Paint(); // do actual redraws
}
This code is just an example, you'll have to fix it according to the MSDN documentation.
What you should NOT do is just hook into the OnPaint() event, because then you'll still have the actual Paint() method called.
This might be a very simple question, but I searched and found no other way to do it. It doesn't make sense to redraw the background on every Draw. Is there a way to draw some things and leave them on the screen?
I've tried to comment-out the
GraphicsDevice.Clear(Color.CornflowerBlue);
But that doesn't help. (What is its purpose?)
The dark purple colour you are seeing is used by XNA and DirectX to indicate an uninitialised buffer. XNA will also clear buffers to this colour to emulate the behaviour of the Xbox 360 or Windows Phone, so that if you build a game on Windows, it "just works" on those other platforms (or, rather, so it fails in the same way, so you can debug it).
XNA is double-buffered. You don't draw directly to the screen, but to a "backbuffer". The screen only displays the "front buffer". Every time GraphicsDevice.Present gets called (Game calls it for you in EndDraw), those two buffers get swapped, and what you were drawing gets displayed (and you get a fresh buffer to draw on).
I'm not sure why XNA marks the buffer as uninitialised when it gets swapped. I haven't come across this behaviour before - mostly because it's very unusual to want to swap buffers and preserve their contents.
Usually what you want to do is call Game.SupressDraw, when you know you're not going to modify the contents of the screen (saving both a call to Draw and a swap). See also answers here and here.
Keep in mind that clearing the screen with GraphicsDevice.Clear is extremely fast. And that XNA has no concept of "background" or "foreground" (you're always drawing on top of whatever is already in the buffer).
If you do have some expensive-to-render content that you want to re-use between frames, generally you would draw it into to a render target once, and then draw that to the screen each frame. But, as always, avoid premature optimisation! Graphics cards are designed specifically to redraw scenes every frame - they're pretty damn fast!
See this, if you want to just prevent it clearing the image you can do:
GraphicsDevice.GetType().GetField("lazyClearFlags", BindingFlags.NonPublic | BindingFlags.Instance).SetValue(GraphicsDevice, ClearOptions.DepthBuffer);
I am loading 640x480 Bitmaps into a picture box one after the other. When I do that my UI gets blocked. For example, if I was typing something in a text box which is on the same form where my picture box is, I would not be able to see the key that pressed right away, because the bitmap loading makes the UI very slow ..
How would one handle that ? is there any way around it ?
Any sample code would be great.
Thanks
A Picturebox is actually a fairly 'heavy' control in what it provides; it may not be the appropriate thing to use here. You might consider a much simpler container control, or drawing on the surface of the form itself.
If you want to consider BackgroundWorker or any other threaded technique here, keep in mind that the drawing itself must happen on the UI thread; there's no way around that.
If the loading of the images from disk is the source of the latency, you might consider loading the images into an in-memory bitmap on another thread, then signaling somehow to indicate that a new item is ready to be drawn. You would then invalidate the drawing surface, and add the new item as appropriate.
Also; if you are doing any scaling to the images, doing this in the background thread would be appropriate - that way, the drawing code itself only needs to draw an unscaled rect; Using the GDI+ DrawUnscaled functionality to copy a bitmap to an area of the exact same size is actually quite fast.
To get into anything more specific, like actual code, I would want to see code for how you are doing it now. I'm not even sure you are 'drawing' the images in the first place, rather than simply setting Picture/Image properties.
Use background worker so the gui is not freezed (async invoke the image display).
http://www.dreamincode.net/forums/topic/112547-using-the-backgroundworker-in-c%23/
Your second request is a bit more tricky, I guess short answer would be not to rely on gdi+ if that's what you are doing be cause it's known to be slow. How exactly do you load the image into the imagebox?
I need to load 101 bitmaps from the filesystem (they can't be built into the app as a resource as they will be changed for each run of the program) into a windows form application picturebox sequentially based on short duration timer events (500ms give or take) .
Essentially it should work like a slow animation but it is critical that every image be shown.
I've roughed out a simple application in C# to do this however it seems that the image loading and displaying is taking longer than the 500ms so some images are never displayed.
Is there some way I can avoid this? Preloading or creating 101 pictureboxes and showing and hiding?
Anybody have any suggestions?
What's taking the longest? Image loading or displaying? Are you loading each image when it needs displaying? A look at your code would be really valuable.
If you are certain that it will always be exactly 101 images, load them all into an array of System.Drawing.Bitmap first then have an iterator variable that gets incremented on each call of the Tick event of a Timer. Have this Tick event load the image from the array into the PictureBox using PictureBox.Image = myBitmapArray[iterator] If you increment the iterator using ++i%=101; you won't get an OutOfBounds error and the animation will loop.
Populate an array of Bitmap objects before starting the animation.
A couple of options... pick one or combine them:
(1) Use a lock and a counter to guarantee that when the event fires it's loading the next image in line.
(2) Disable the timer in the Tick event, then re-enable it after you've loaded the image. The result is that the images arrive 500ms after the last one is drawn, so if a picture takes one second to load, the images are drawn at t=1000ms, t=1500ms, t=3000ms, etc. All the images are drawn, and 500ms is guaranteed to pass between pictures, but the animation might appear slow.
(3) Do the above, but track the time the event starts, and after the image is drawn, set the next timer tick to be 500 - (Now - eventStart)... so that if the image takes 250ms to draw, the next timer tick will fire in 250ms. If Now - eventStart < 0, the next timer tick should fire immediately. The animation will take the minimum amount of time possible, but images could potentially flash by, appearing only for a few milliseconds.
(4) Use PictureBox.LoadAsync() to give you some multi-threading... the next event can be loading the image while the previous event is drawing. But you'll need a Mutex that you release in the LoadCompleted event that you wait on before calling LoadAsync(), if you need to guarantee the images are all drawn.
(5) I'm not sure if the drawing of the picture falls under the Layout category, but you can try calling SuspendLayout() and ResumeLayout() before/after loading the image
(6) Use an array of images, lock a counter, and use the .Image property of the PictureBox to let you pre-load the images. I believe this was suggested in another answer, also
HTH,
James
I don't have a concrete answer for you, but I would approach this by first determining if it's image loading, image display, or both actions that are taking too much time.
I would imagine that image loading is going to be relatively quick, even with pretty large image sizes, provided that the images are local and you have relatively decent hardware. My first attempt would involve loading all images from a thread sequentially so that you application doesn't have to wait for image display to complete before the next image loads.
If image display is taking a long time (and even on my really powerful workstation it's not all that fast for large images), then is it possible for you to scale the images before the application displays everything? Does your application need to deal with full resolution images? With the megapixel cameras these days, I can't image that you'd want to have all of the data present in the image files anyway, since the sizes can easily exceed monitor resolutions by a factor of 6.
Another thing that may be a concern is the size of the images. If the are all 18 Megapixel Images, I can see it taking either a lot of time or a lot of room.
You may want to resize them to the size of your display area when you initially load them up so that you aren't using 2 gigs of ram or waiting to read off the disk depending on how you implement it.