Graphics drawing / flicker question

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
7 messages Options
Reply | Threaded
Open this post in threaded view
|

Graphics drawing / flicker question

Ole Martin Halck
Hello all,

As someone relatively new to Dolphin -- and a _total_ newbie to digging into
Windows -- I have a question for you. I haven't found an answer to exactly
this problem in the news archive, Wiki etc, but if it's there, a pointer is
as good as a full answer for me.

I have a view that requires redrawing following certain user input events.
The view is put together mainly by a number of gif/jpeg pictures, which
together cover the whole view. To reduce unwanted flicker, the contents of
the view are first written to a bitmap through its canvas, before being
copied onto the view. This, BTW, is done by overriding #refreshContents to

self updateCachedBitmap
^super refreshContents

-- and simply letting #onPaintRequired copy the cached bitmap onto the view.

This works mostly as expected (and the slight delay from the user input to
the update is no problem). The only small cosmetic problem left is that
Dolphin -- or, most probably, Windows -- whites out the view before copying
the bitmap onto it, causing a short "blink". I would very much like to
eliminate this as well.

Off the top of my head, I can think of two approaches for achieving this:

1) Calculate which parts of the view actually need updating, and performing
some #invalidateRect: magic, or something.
2) Tricking Dolphin -- or, most probably, Windows -- into not erasing the
view before the new one is copied from the bitmap.

The first one should not be all that difficult, but requires a lot of work,
especially if the look of the view is to be changed in the future. Thus, my
question is: Is there a simple way to implement the second approach?

Finally, I would like to congratulate OA on their product. The Value
Edition, which I've purchased, is simply incredible VFM.

--
Best regards,
Ole Martin Halck


Reply | Threaded
Open this post in threaded view
|

Re: Graphics drawing / flicker question

Ian Bartholomew-4
Ole,

> Hello all,

Welcome

[snips]

> Off the top of my head, I can think of two approaches for achieving this:
>
> 1) Calculate which parts of the view actually need updating, and
> performing some #invalidateRect: magic, or something.
> 2) Tricking Dolphin -- or, most probably, Windows -- into not erasing the
> view before the new one is copied from the bitmap.
>
> The first one should not be all that difficult, but requires a lot of
> work,especially if the look of the view is to be changed in the future.
> Thus, my question is: Is there a simple way to implement the second
> approach?

Try replacing your #refreshContents with

self updateCachedBitmap.
self invalidateRect: nil erase: false

This is just shortcutting the code your supersend executes but also tells
Windows not to erase the screen first. However, as you say that you are
redrawing the whole visible bitmap I'm not 100% if it will work. It's a
simple experiment so worth a try though <g>

Ian


Reply | Threaded
Open this post in threaded view
|

Re: Graphics drawing / flicker question

Bill Schwab-2
In reply to this post by Ole Martin Halck
Ole,

In addition to Ian's suggestion of telling Windows not to erase first, you
might want to specify an rectangle to invalidate.  It takes work both at the
time that you detect a need to redraw (deciding on the rectangle to
invalidate based on what has changed), and when handling the resulting paint
messages.  Look at the "paint struct" which you'll find available through
PaintEvent.  In #onPaintRequired:, you can find the invalid rectangle using
an expression like this:

  aPaintEvent paintStruct rcPaint asRectangle

Note that some of the WM_PAINT messages (which cause Dolphin to call your
#onPaintRequired:) that your app will receive will result from a portion of
the app's view being uncovered by other windows, and some will result from
your explicit invalidate/update calls.  In short, your paint method needs to
look at the invalid rect and draw only what is necessary, but, you should
expect to have to draw the whole thing at times.

Perhaps the best reference to help you quickly understand Windows
programming is Petzold's book from the Windows 3.1 era.  The newer editions
contain so much information that they risk overwhelming the reader.  The
older book holds up conceptually, though the details of how parameters are
packed into messages have changed.  Fortunately, Dolphin insulates you from
much of the detail.

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]


Reply | Threaded
Open this post in threaded view
|

Re: Graphics drawing / flicker question

Ole Martin Halck
"Bill Schwab" <[hidden email]> wrote in message
news:9l0bif$6s4vf$[hidden email]...
> Ole,
>
> In addition to Ian's suggestion ...

Thanks to both of you for swift replies. I suspect I will find this
newsgroup extremely useful in the future. :-)

> ...of telling Windows not to erase first, you
> might want to specify an rectangle to invalidate.
> [snip]

Yes, this was what I meant with my approach #1. I'll look further into both
suggestions.

> Perhaps the best reference to help you quickly understand Windows
> programming is Petzold's book from the Windows 3.1 era.  The newer
editions
> contain so much information that they risk overwhelming the reader.  The
> older book holds up conceptually, though the details of how parameters are
> packed into messages have changed.  Fortunately, Dolphin insulates you
from
> much of the detail.

Actually, I did a search for Windows programming stuff, and found what seems
to be this book in Win95/98/NT version (bar some images etc which seem to
have fallen out) on http://angelfire.com/al2/allf18/index.htm. Looks very
useful.

--
Ole Martin Halck


Reply | Threaded
Open this post in threaded view
|

Re: Graphics drawing / flicker question

Dave Harris-3
In reply to this post by Ole Martin Halck
[hidden email] (Ole Martin Halck) wrote (abridged):
> 2) Tricking Dolphin -- or, most probably, Windows -- into not erasing
> the view before the new one is copied from the bitmap.

The erase is actually requested with a separate Windows message, namely
WM_ERASEBKGND. I have found this apparently simple message to be one of
the darker areas of Windows. It sometimes seemed to be send unexpectedly
and not as part of a general WM_PAINT, eg when moving menus around. I hate
it. I'd much rather have all painting routed through a single message.
Little or nothing is gained by separating out erasure, in my experience.

That's based on my Windows C++ experience, where I usually define
WM_ERASEBKGND to return without erasing anything. I don't know Dolphin UI
stuff well, but I see there is message #wmEraseBkGnd:wParam:lParam: which
forwards to #onEraseRequired:.

I suggest you override #onEraseRequired: to do nothing. I suspect you need
to return true (or perhaps 1) to prevent the erasure being done by
Windows. This is your simple solution.


> 1) Calculate which parts of the view actually need updating, and
> performing some #invalidateRect: magic, or something.

That won't help the flicker. It'll just confine it to a smaller area.

If you invalidate explicitly you can also tell Windows that the background
doesn't need to be erased for that particular invalidation, but in general
there may be invalidation requests sent from outside your control so it is
not a complete solution. Also, in truth, you do want the background to be
erased - it's just that you can combine erasure with drawing. I have found
it best not to lie to my computer.

  Dave Harris, Nottingham, UK | "Weave a circle round him thrice,
      [hidden email]      |   And close your eyes with holy dread,
                              |  For he on honey dew hath fed
 http://www.bhresearch.co.uk/ |   And drunk the milk of Paradise."


Reply | Threaded
Open this post in threaded view
|

Re: Graphics drawing / flicker question

Andy Bower
In reply to this post by Ole Martin Halck
Ole,

I haven't had time to fully read through your post (I'm moving house today
so am in a bit of a rush) but you might be interested in this
DoubleBufferedView class which we've used successfully to represent animated
views without flicker.

In particular, implementing #onEraseRequired: to answer true (without doing
any actual erasing) is the way we avoided the unpleasant flickering due to
Windows automatically erasing the view by default. You may like to think
about using the class itself since it is likely that this will appear in a
future version of Dolphin.

Best Regards,

Andy Bower
Dolphin Support
http://www.object-arts.com
---
Are you trying too hard?
http://www.object-arts.com/Relax.htm
---

---------------------------------------------------------------------

"Filed out from Dolphin Smalltalk 2000 release 4.0"!

View subclass: #DoubleBufferedView
 instanceVariableNames: 'backSurface requiresRender'
 classVariableNames: ''
 poolDictionaries: ''
 classInstanceVariableNames: ''!
DoubleBufferedView comment: ''!

DoubleBufferedView guid: (GUID fromString:
'{F0757E5D-E398-4EDE-9E0F-8C6CCB3699FC}')!

!DoubleBufferedView categoriesForClass!Unclassified! !
!DoubleBufferedView methodsFor!

canvas
 "Answer a <Canvas> onto the back surface"

 ^backSurface canvas
  setBkColor: self backcolor;
  yourself
  !

flip
 "Private - Flip the current back surface to the front and paint it"

 backSurface drawOn: super canvas at: 0@0 extent: backSurface extent. !

initialize
 "Private - Initialise the receiver."

 super initialize.
 backcolor := Color white.
 requiresRender := false.
!

initializeSurfacesFor: aPointExtent
 "Private - Initialize the front and back surfaces for a view size of
aPointExtent"

 | canvas |

 backSurface notNil ifTrue: [ backSurface free ].
 canvas := super canvas.
 backSurface := Bitmap compatible: canvas extent: aPointExtent.
 self invalidate.
!

invalidate
 "Flag the current rendition as being invalid. A repaint will cause a
 render to occur"

 requiresRender := true.
 super invalidate!

onCreated: anEvent
 "Private - Handler for view created "

 super onCreated: anEvent.
 self initializeSurfacesFor: self extent.
!

onEraseRequired: aColorEvent
 "Private - Handler for erase background"

 ^true!

onPaintRequired: aPaintEvent
 "Private - Handler for paint event"

 requiresRender ifTrue: [ self render ].
 self flip.
!

onPositionChanged: aPositionEvent
 "Private - Handle a window position change event (move or resize)."

 aPositionEvent isResize ifTrue: [
  self initializeSurfacesFor: aPositionEvent extent.
  self repaint ].
 ^super onPositionChanged: aPositionEvent!

refreshContents
 "The model held by the receiver has been changed so repaint"

 self repaint
!

render
 "Private - Render the background image"

 requiresRender := false
!

repaint
 "Repaints the receiver"

 self render flip
! !
!DoubleBufferedView categoriesFor: #canvas!accessing!public! !
!DoubleBufferedView categoriesFor: #flip!operations!private! !
!DoubleBufferedView categoriesFor: #initialize!initializing!private! !
!DoubleBufferedView categoriesFor:
#initializeSurfacesFor:!initializing!private! !
!DoubleBufferedView categoriesFor: #invalidate!operations!public! !
!DoubleBufferedView categoriesFor: #onCreated:!event handling!private! !
!DoubleBufferedView categoriesFor: #onEraseRequired:!event handling!private!
!
!DoubleBufferedView categoriesFor: #onPaintRequired:!event handling!private!
!
!DoubleBufferedView categoriesFor: #onPositionChanged:!event
handling!private! !
!DoubleBufferedView categoriesFor: #refreshContents!public!updating! !
!DoubleBufferedView categoriesFor: #render!operations!private! !
!DoubleBufferedView categoriesFor: #repaint!operations!public! !

---------------------------------------------------------------------


"Ole Martin Halck" <[hidden email]> wrote in message
news:9l077r$i1l$[hidden email]...
> Hello all,
>
> As someone relatively new to Dolphin -- and a _total_ newbie to digging
into
> Windows -- I have a question for you. I haven't found an answer to exactly
> this problem in the news archive, Wiki etc, but if it's there, a pointer
is

> as good as a full answer for me.
>
> I have a view that requires redrawing following certain user input events.
> The view is put together mainly by a number of gif/jpeg pictures, which
> together cover the whole view. To reduce unwanted flicker, the contents of
> the view are first written to a bitmap through its canvas, before being
> copied onto the view. This, BTW, is done by overriding #refreshContents to
>
> self updateCachedBitmap
> ^super refreshContents
>
> -- and simply letting #onPaintRequired copy the cached bitmap onto the
view.
>
> This works mostly as expected (and the slight delay from the user input to
> the update is no problem). The only small cosmetic problem left is that
> Dolphin -- or, most probably, Windows -- whites out the view before
copying
> the bitmap onto it, causing a short "blink". I would very much like to
> eliminate this as well.
>
> Off the top of my head, I can think of two approaches for achieving this:
>
> 1) Calculate which parts of the view actually need updating, and
performing
> some #invalidateRect: magic, or something.
> 2) Tricking Dolphin -- or, most probably, Windows -- into not erasing the
> view before the new one is copied from the bitmap.
>
> The first one should not be all that difficult, but requires a lot of
work,
> especially if the look of the view is to be changed in the future. Thus,
my

> question is: Is there a simple way to implement the second approach?
>
> Finally, I would like to congratulate OA on their product. The Value
> Edition, which I've purchased, is simply incredible VFM.
>
> --
> Best regards,
> Ole Martin Halck
>
>


Reply | Threaded
Open this post in threaded view
|

Re: Graphics drawing / flicker question

Bill Schwab-2
Andy,

Interesting!  One question/caution would be that without attention to doing
the minimal drawing required, this might lead to a system that consumes a
lot of CPU time, or put another way, something that "is slow but doesn't
look it".  It all depends on what the app does.  If it's something in which
all changes occur in a particular region, then optimized painting makes
sense and is probably preferred.  If it's something that can change
anywhere/everywhere, then hiding the drawing process and tossing up a
finished frame when its ready is the way to go.

All that aside, I'll be interested to see what can be done with this class!

Have a good one,

Bill

--
Wilhelm K. Schwab, Ph.D.
[hidden email]