Buffered images
BlitzMax Forums/Brucey's Modules/Buffered images
| ||
Hi! I want to draw an oscilloscope dynamically. I think it is better to use double buffered images to avoid flickering. My idea: A timer check all x milliseconds if a new audio signal is avariable. If it avraible then the oscilloscope is draw in a "Backbuffer Memory DC" and a OnPaint event is proceed manually. On the OnPaint event the "Backbuffer Memory DC" is drawn in a Picturebox(wxStaticBitmap or wxImage?) So how can I do that? Do I need a wxStaticBitmap or wxImage to draw a dynamic image? How can I create a memory DC and than show in the Picturebox? That you can imagine what I want to do: ![]() cu olli Edit: This is my first test. The DrawPanel should redefine its backgroundcolor every 100ms. But how can I release a OnPaint event manually? And the DrawPanel is not fully redrawn oO |
| ||
instead of Frame.Panel.OnPaint(XYZ) try Frame.Panel.Refresh() In your timer notify. Refresh sets the panel to a "dirty" state, which is then set for repainting. Also, you might be interested in replacing your wxPaintDC with wxAutoBufferedPaintDC which is a double-buffered version of it. You simply use it as usual, and it sorts out the buffering. (or so they say!) your create line would look like this : DC = New wxAutoBufferedPaintDC.CreatePaintDC(DrawPanel) |
| ||
Thank you! With Refresh it works fine... But however there are flickering: Use space to switch between slow and quick mode. Or should I set some style attributes in Create call of the DrawPanel? cu olli |
| ||
no flicker here Leopard 10.5 edit: do get a crash after quitting? Only happens after you have pressed space. |
| ||
For the GLcanvas I had to implement this to stop flicker on Win32:void MaxGLCanvas::OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { // Do nothing, to avoid flashing on MSW } I wonder if this is the issue for your panel... Perhaps we need to override that method by default - where the default will be to call the superclass implementation (which would redraw the background). Overriding it you could possibly choose to do nothing.... |
| ||
Just re-tested this on PC and there is visible tearing that you don’t see on the MAC. And the code doesn’t error after exit. So that must be MAC specific? |
| ||
And the code doesn’t error after exit. So that must be MAC specific? You need to Stop() the timer on Mac before you quit, otherwise the timer's parent object could be GC'd while the event itself is still live. |
| ||
Okay.. actually reading the docs on wxAutoBufferedDC reveals this snippet of useful information : "This wxDC derivative can be used inside of an OnPaint() event handler to achieve double-buffered drawing. Just create an object of this class instead of wxPaintDC and make sure wxWindow::SetBackgroundStyle is called with wxBG_STYLE_CUSTOM somewhere in the class initialization code, and that's all you have to do to (mostly) avoid flicker. " Add this to the OnInit() of your custom panel. SetBackgroundStyle(wxBG_STYLE_CUSTOM) Seems to help a bit. |
| ||
A large improvement here just some vsync issues. Looked on wxForum for solution and it only mentions wxGLCanvas in relation to vsync. |
| ||
Yeah, I don't think the vsync will be noticeable in Vertex's original example image as there won't be a lot of full-frame colour changing involved. |
| ||
you might be interested in this? http://wxcode.sourceforge.net/showcomp.php?name=wxPlotCtrl |
| ||
Thanks a lot! I actually solve the problem so: Type TOscilloscope Extends wxPanel Field Samples : Int[] Field Bitmap : wxBitmap Field Width : Int Field Height : Int Method OnInit() GetClientSize(Width, Height) Bitmap = New wxBitmap.CreateEmpty(Width, Height) ConnectAny(wxEVT_SIZE, OnSize) ConnectAny(wxEVT_PAINT, OnPaint) End Method Method Draw() Local DC : wxMemoryDC, .. Brush : wxBrush, .. Pen : wxPen Local IndexFactor : Float, .. SampleFactor : Float, .. Index : Int, .. X : Int, .. Y : Int ' Draw into bitmap DC = New wxMemoryDC.Create() DC.SelectObject(Self.Bitmap) Brush = New wxBrush.CreateFromColour(New wxColour.Create(188, 188, 188)) DC.SetBackground(Brush) DC.Clear() Pen = New wxPen.CreateFromColour(New wxColour.Create(200, 50, 50)) DC.SetPen(Pen) DC.DrawLine(0, -TRecorder.Threshold*Float(Height/2) + Height/2, .. Width, -TRecorder.Threshold*Float(Height/2) + Height/2) IndexFactor = Float(TRecorder.NumSamples)/Float(Width) SampleFactor = Float(Height)/Float($8000) Pen = New wxPen.CreateFromColour(New wxColour.Create(50, 50, 200)) DC.SetPen(Pen) If Self.Samples Then For X = 1 Until Width Index = X*IndexFactor If Index >= TRecorder.NumSamples Then Index = TRecorder.NumSamples - 1 Y = Int(Samples[Index]*SampleFactor) + Height/2 If Y < 0 Then Y = 0 If Y >= Height Then Y = Height - 1 DC.DrawLine(X, Height/2, X, Y) Next Else DC.DrawLine(0, Height/2, Width, Height/2) EndIf DC.SelectObject(wxNullBitmap) DC.Free() Refresh() End Method Function OnSize(E:wxEvent) Local Event : wxSizeEvent, .. _Self : TOscilloscope Event = wxSizeEvent(E) _Self = TOscilloscope(Event.Parent) ' Resize bitmap and draw into _Self.GetClientSize(_Self.Width, _Self.Height) _Self.Bitmap = New wxBitmap.CreateEmpty(_Self.Width, _Self.Height) _Self.Draw() End Function Function OnPaint(E:wxEvent) Local Event : wxPaintEvent, .. _Self : TOscilloscope, .. DC : wxPaintDC Event = wxPaintEvent(E) _Self = TOscilloscope(Event.Parent) DC = New wxPaintDC.Create(_Self) _Self.PrepareDC(DC) DC.DrawBitmap(_Self.Bitmap, 0, 0) DC.Free() End Function End Type I use a empty bitmap as backbuffer and draw into via wxMemoryDC. The bitmap is resized if the panel is resized. On the paint event the complete backbuffer is drawn. Also I have an extern timer event, that fill the oscilloscope with new sample data and than call Oscilloscope.Refresh() if there anough sample recordet. Seem to be flicker free in combination with SetBackgroundStyle(wxBG_STYLE_CUSTOM) (I must say I haven't realize the method with wxAutoBufferedPaintDC ^^) The wxPlotCtrl looks good but I think it is easyer for me to program my own control. But thank you! cu olli |
| ||
Vertex, that's very nice :-) Are you finding non-3D graphics context drawing fast enough? In general, I'm quite happy with GDI output for a lot of things, although I do miss anti-aliasing on Win32. |
| ||
For my purpose it is fast enough. The Oscilloscope and Autocorrelogram is drawn in fullscreen(~1600 x 1050) in realtime. For things like CAD(e.g. AutoCAD) or typeface editors(e.g. Fontlab) I would use Cairo or OpenVG that supports antialiasing. But a idea to antialiasing: Using supersampling. You render the GDI output in a double sized buffer and on the paint event, you use a bilinear filter to fit the buffer in the original size. On things that should not filtered, like images, you can use a mask for the buffer and the regions that not have set a bit would filtered by pointsampling. Also GDI supports a user zoom for very handy zooming. To flickering: I also have flickering :( The complete graphic is drawn in a backbuffer but the backbuffer is drawn pixel by pixel in the gadget. To avoid this I must use BufferedDC or AutoBufferedDC. Here is the result ![]() I love your wxWidget module, it is sooo cool :) cu olli |