Trouble with drawing, I need some ideas :)

Hello wxpythoneers,

I’m drawing an image on multiple layers.
The first layer is the background and is the image of a thorax.
The subsequent layers are all groups of lines and circles.

Depending on some selected conditions, one of these layers is animated (the line moves or some circle expands and contracts).

My problem is… how do I draw this multilayer image without having to recompute each layer for every frame of the animation. I want to recompute only the layer that’s animating and reuse the previously computed (and still the same) layers from the previous frame of the animation.

The drawing is done using a wx.GCDC and for certain layers it is rather expensive.
What I need is something like a Blit for each layer but I have no idea how to implement this with GCDC (how do I handle transparency)

Any idea is welcomed.

Thank you in advance.
Peter.

P.S.
The way in works now is almost ok (the software reacts a little bit slower than what I want but is usable)
The processor is really put to work… the python process is constantly
using 50% of processing capability of the system. I can hear my
software start because after I start it the computer’s coolers start to
scream. :slight_smile:

···


There is NO FATE, we are the creators.

I’ve created a small play file to better explain…

How do I buffer somehow the drawing from
render_layer_two
so that I don’t have to redo it every time.

Thank you again.
Peter

test_gcdc.py (1.63 KB)

···

On 9/27/07, Peter Damoc pdamoc@gmail.com wrote:

Hello wxpythoneers,

I’m drawing an image on multiple layers.
The first layer is the background and is the image of a thorax.
The subsequent layers are all groups of lines and circles.

Depending on some selected conditions, one of these layers is animated (the line moves or some circle expands and contracts).

My problem is… how do I draw this multilayer image without having to recompute each layer for every frame of the animation. I want to recompute only the layer that’s animating and reuse the previously computed (and still the same) layers from the previous frame of the animation.

The drawing is done using a wx.GCDC and for certain layers it is rather expensive.
What I need is something like a Blit for each layer but I have no idea how to implement this with GCDC (how do I handle transparency)

Any idea is welcomed.

Thank you in advance.
Peter.

P.S.
The way in works now is almost ok (the software reacts a little bit slower than what I want but is usable)

The processor is really put to work… the python process is constantly
using 50% of processing capability of the system. I can hear my
software start because after I start it the computer’s coolers start to
scream. :slight_smile:


There is NO FATE, we are the creators.


There is NO FATE, we are the creators.

Peter Damoc wrote:

I've created a small play file to better explain...

How do I buffer somehow the drawing from
render_layer_two
so that I don't have to redo it every time.

Thank you again.
Peter

    Hello wxpythoneers,

    I'm drawing an image on multiple layers.
    The first layer is the background and is the image of a thorax.
    The subsequent layers are all groups of lines and circles.

    Depending on some selected conditions, one of these layers is
    animated (the line moves or some circle expands and contracts).

    My problem is... how do I draw this multilayer image without having
    to recompute each layer for every frame of the animation. I want to
    recompute only the layer that's animating and reuse the previously
    computed (and still the same) layers from the previous frame of the
    animation.

    The drawing is done using a wx.GCDC and for certain layers it is
    rather expensive.
    What I need is something like a Blit for each layer but I have no
    idea how to implement this with GCDC (how do I handle transparency)

The key point is to draw the expensive things as few times as possible, and that means drawing them to a bitmap and then just blitting thhe bitmap. It's basically done the same way as you would do it with a DC, you just draw your background and any "layers" above that that you want to cache to a memory dc (or a gc that is targeting a memory dc.) Then in your paint event you first draw the bitmap and then the rest of the stuff on top of that. You don't need to worry too much about transparency as long as you include whatever would be considered the "background" of all your "layers" in he bitmap.

···

On 9/27/07, *Peter Damoc* <pdamoc@gmail.com <mailto:pdamoc@gmail.com>> > wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Well Robin, this is why I tried to create that small sample…
In that sample the “background layer” is the ellipse in the center… the “expensive layer” is the array of ellipses and the “changing layer” is the moving line.

The main problem is that the changing layer is between the background and the expensive. I cannot cache the drawing of the expensive because visually its area changes due to the changing layer beneath it.

I was wondering about a way to cache it in transparent mode. If I tried a naive approach like:

def OnPaint(self, evt):
    w, h = self.GetSize()
    pdc = wx.BufferedPaintDC(self)
    pdc.SetBackground

(wx.Brush(“pink”))
pdc.Clear()
gc = wx.GCDC(pdc)
gc.DrawCircle(w/2, h/2, min(w, h)/4)

    cache = wx.MemoryDC(wx.EmptyBitmap(w,h))
    gc_cache  = wx.GCDC

(cache)

    if self.counter>=10:
        render_layer_one(gc, w, h, 0)
        render_layer_two(gc_cache, w, h)
    else:
        render_layer_one(gc, w, h, self.counter%10

)
render_layer_two(gc_cache, w, h)

    pdc.Blit(0,0, w, h, cache, 0,0)

all I get is black (with the white ellipses from the “expensive” layer) .

Is there a way to create some kind of object that keeps a buffer of the drawing in transparent mode?

Maybe I’m missing something… maybe this could be easily accomplished by a parameter that is already implemented.

Peter.

···

On 9/28/07, Robin Dunn robin@alldunn.com wrote:

The key point is to draw the expensive things as few times as possible,
and that means drawing them to a bitmap and then just blitting thhe
bitmap. It’s basically done the same way as you would do it with a DC,

you just draw your background and any “layers” above that that you want
to cache to a memory dc (or a gc that is targeting a memory dc.) Then
in your paint event you first draw the bitmap and then the rest of the

stuff on top of that. You don’t need to worry too much about
transparency as long as you include whatever would be considered the
“background” of all your “layers” in he bitmap.


There is NO FATE, we are the creators.

Peter Damoc wrote:

    The key point is to draw the expensive things as few times as possible,
    and that means drawing them to a bitmap and then just blitting thhe
    bitmap. It's basically done the same way as you would do it with a DC,
    you just draw your background and any "layers" above that that you want
    to cache to a memory dc (or a gc that is targeting a memory dc.) Then
    in your paint event you first draw the bitmap and then the rest of the
    stuff on top of that. You don't need to worry too much about
    transparency as long as you include whatever would be considered the
    "background" of all your "layers" in he bitmap.

Well Robin, this is why I tried to create that small sample....

Yes, I knew that, but I didn't have the time to really experiment with it. So I just did a quick read and made some assumptions.

In that sample the "background layer" is the ellipse in the center.... the "expensive layer" is the array of ellipses and the "changing layer" is the moving line.

The main problem is that the changing layer is between the background and the expensive. I cannot cache the drawing of the expensive because visually its area changes due to the changing layer beneath it.

Ah, ok, this is the bit I didn't pick up from my quick read.

I was wondering about a way to cache it in transparent mode. If I tried a naive approach like:

    def OnPaint(self, evt):
        w, h = self.GetSize()
        pdc = wx.BufferedPaintDC(self)
        pdc.SetBackground (wx.Brush("pink"))
        pdc.Clear()
        gc = wx.GCDC(pdc)
        gc.DrawCircle(w/2, h/2, min(w, h)/4)
               cache = wx.MemoryDC(wx.EmptyBitmap(w,h))
        gc_cache = wx.GCDC (cache)
               if self.counter>=10:
            render_layer_one(gc, w, h, 0)
            render_layer_two(gc_cache, w, h)
        else:
            render_layer_one(gc, w, h, self.counter%10 )
            render_layer_two(gc_cache, w, h)
               pdc.Blit(0,0, w, h, cache, 0,0)

all I get is black (with the white ellipses from the "expensive" layer) .

Is there a way to create some kind of object that keeps a buffer of the drawing in transparent mode?

First you want to save the bitmap used for the cache, not recreate it every paint event. Just recreate the wx.MemoryDC using the same bitmap when you need to. Second, don't draw to the cache bitmap on every paint event. Paint the bitmap somewhere else and only update it when needed, then just Blit it or use DrawBitmap in the paint event. Third, give the bitmap a mask for the parts you want to be transparent. An easy way to do this is to initialize the bitmap to a known solid color (something close to what your background will be if possible to make blending better) and then use theBitmap.SetMaskColour(theColour). Since you are using the GraphicContext it would probably be better to use an alpha transparency instead, but I don't have the code for doing that at the tip of my fingers...

···

On 9/28/07, *Robin Dunn* <robin@alldunn.com <mailto:robin@alldunn.com>> > wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Hi Robin,
First, let me apologize for not being clear again. :slight_smile:

I appreciate the advice you gave BUT it is not touching the real issue.
The sample created was just some boiler plate for people to play with. It was not “efficient”.

I can do all the buffering that could be done BUT my main issue remains the same:

How do I use alpha in a buffer that need to be blited over some other drawing? Color based transparency won’t do because of the wxGCDC used in the buffer.

Here… take a look at this kind of desperate code:

    cache = wx.MemoryDC(wx.EmptyBitmap(w,h))       
    cache.SetBackground(wx.TRANSPARENT_BRUSH)
    cache.SetBackgroundMode(wx.TRANSPARENT

)
cache.Clear()
gc_cache = wx.GCDC(cache)
gc_cache.SetBackground(wx.TRANSPARENT_BRUSH)
gc_cache.SetBackgroundMode(wx.TRANSPARENT)
gc_cache.Clear()

Maybe it expresses what I’m trying to accomplish.

Peter.

···


There is NO FATE, we are the creators.

Problem solved via:

def SetAlpha(bmp):
w, h = bmp.GetSize()
img = bmp.ConvertToImage()
img.InitAlpha()
for i in range(w):
for j in range(h):
img.SetAlpha(i,j, 0)

return img.ConvertToBitmap()

Ugly hack but… until I find something better… :slight_smile: will have to do…

Peter

···

On 10/1/07, Peter Damoc pdamoc@gmail.com wrote:

Hi Robin,
First, let me apologize for not being clear again. :slight_smile:

I appreciate the advice you gave BUT it is not touching the real issue.
The sample created was just some boiler plate for people to play with. It was not “efficient”.

I can do all the buffering that could be done BUT my main issue remains the same:

How do I use alpha in a buffer that need to be blited over some other drawing? Color based transparency won’t do because of the wxGCDC used in the buffer.

Here… take a look at this kind of desperate code:

    cache = wx.MemoryDC(wx.EmptyBitmap(w,h))       
    cache.SetBackground(wx.TRANSPARENT_BRUSH)
    cache.SetBackgroundMode

(wx.TRANSPARENT
)
cache.Clear()
gc_cache = wx.GCDC(cache)
gc_cache.SetBackground(wx.TRANSPARENT_BRUSH)
gc_cache.SetBackgroundMode(wx.TRANSPARENT)
gc_cache.Clear()

Maybe it expresses what I’m trying to accomplish.

Peter.

There is NO FATE, we are the creators.


There is NO FATE, we are the creators.

Peter Damoc wrote:

Hi Robin,
First, let me apologize for not being clear again. :slight_smile:

I appreciate the advice you gave BUT it is not touching the real issue.
The sample created was just some boiler plate for people to play with. It was not "efficient".
I can do all the buffering that could be done BUT my main issue remains the same:

How do I use alpha in a buffer that need to be blited over some other drawing? Color based transparency won't do because of the wxGCDC used in the buffer.

Here... take a look at this kind of desperate code:

        cache = wx.MemoryDC(wx.EmptyBitmap(w,h)) cache.SetBackground(wx.TRANSPARENT_BRUSH)
        cache.SetBackgroundMode(wx.TRANSPARENT )
        cache.Clear()
        gc_cache = wx.GCDC(cache)
        gc_cache.SetBackground(wx.TRANSPARENT_BRUSH)
        gc_cache.SetBackgroundMode(wx.TRANSPARENT)
        gc_cache.Clear()

Maybe it expresses what I'm trying to accomplish.

I see you found a solution, but to help clarify this for you let me point out that using a transparent brush simply means "don't draw anything", not "change these pixels to transparent".

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Peter Damoc wrote:

Problem solved via:

def SetAlpha(bmp):
    w, h = bmp.GetSize()
    img = bmp.ConvertToImage()
    img.InitAlpha()
    for i in range(w):
        for j in range(h):
            img.SetAlpha(i,j, 0)
    return img.ConvertToBitmap()

Ugly hack but... until I find something better.... :slight_smile: will have to do...

I was just chatting with a coworker at OSAF about a similar problem, and I realized that this is probably equivalent to how you are using the above. It creates a new bitmap with all pixels set to black and with a fully transparent alpha:

  bytes = array.array('B', [0] * width*height*4)
  bmp = wx.BitmapFromBufferRGBA(width, height, bytes)

Then any drawing you do on it with a wx.GCDC or a wx.GraphicsContext will be working on a fully transparent background, and will reset the alpha as as specified in the pen or brush objects when drawing other things on top of it.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Robin Dunn wrote:

It creates a new bitmap with all pixels set to black and with a fully transparent alpha:

    bytes = array.array('B', [0] * width*height*4)
    bmp = wx.BitmapFromBufferRGBA(width, height, bytes)

It looks handy. Maybe it's time for a new wx.Bitmap constructor:

wx.TransparentBitmap(width, height) # (or some other name)

By the way, what is the performance like drawing (blitting) transparent bitmaps with DC (or GC)? It used to be very, very, slow to Draw a masked Bitmap to a DC.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Christopher Barker wrote:

By the way, what is the performance like drawing (blitting) transparent bitmaps with DC (or GC)? It used to be very, very, slow to Draw a masked Bitmap to a DC.

I'm not sure, but I expect that it varies widely by platform.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

Out of curiosity, why does it varies so widely? Is Cairo really that slow?

···

On 10/17/07, Robin Dunn <robin@alldunn.com > wrote:

Christopher Barker wrote:

By the way, what is the performance like drawing (blitting) transparent

bitmaps with DC (or GC)? It used to be very, very, slow to Draw a masked
Bitmap to a DC.

I’m not sure, but I expect that it varies widely by platform.


Robin Dunn
Software Craftsman

http://wxPython.org Java give you jitters? Relax with wxPython!


To unsubscribe, e-mail:
wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org


There is NO FATE, we are the creators.

Robin Dunn wrote:

By the way, what is the performance like drawing (blitting) transparent bitmaps with DC (or GC)? It used to be very, very, slow to Draw a masked Bitmap to a DC.

I'm not sure, but I expect that it varies widely by platform.

Probably so -- I guess it's time for some profiling!

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Peter Damoc wrote:

Out of curiosity, why does it varies so widely? Is Cairo really that slow?

    Christopher Barker wrote:

     > By the way, what is the performance like drawing (blitting)
    transparent
     > bitmaps with DC (or GC)? It used to be very, very, slow to Draw a
    masked
     > Bitmap to a DC.

    I'm not sure, but I expect that it varies widely by platform.

I wasn't really thinking about Cairo here, but more about how the different ports do their optimization of handling bitmap data, transporting it to/from the display buffer, what APIs are available from the platform, what has to be done to make those APIs conform to the wx API, etc.

···

On 10/17/07, *Robin Dunn* <robin@alldunn.com <mailto:robin@alldunn.com>> > wrote:

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

I was thinking that almost all drawing is done off-screen and that the library that does the background drawing is the main reason for certain performances issues.
I didn’t imagine that the final blitting to the pdc could be that costly. :slight_smile:

Peter

···

On 10/19/07, Robin Dunn robin@alldunn.com wrote:

Peter Damoc wrote:

Out of curiosity, why does it varies so widely? Is Cairo really that slow?

On 10/17/07, Robin Dunn <robin@alldunn.com <mailto: > robin@alldunn.com>> > > wrote:

Christopher Barker wrote:

 > By the way, what is the performance like drawing (blitting)
transparent
 > bitmaps with DC (or GC)? It used to be very, very, slow to Draw a
masked
 > Bitmap to a DC.

I'm not sure, but I expect that it varies widely by platform.

I wasn’t really thinking about Cairo here, but more about how the
different ports do their optimization of handling bitmap data,

transporting it to/from the display buffer, what APIs are available from
the platform, what has to be done to make those APIs conform to the wx
API, etc.


Robin Dunn
Software Craftsman

http://wxPython.org
Java give you jitters? Relax with wxPython!


To unsubscribe, e-mail:
wxPython-users-unsubscribe@lists.wxwidgets.org
For additional commands, e-mail: wxPython-users-help@lists.wxwidgets.org


There is NO FATE, we are the creators.

Peter Damoc wrote:

I was thinking that almost all drawing is done off-screen and that the library that does the background drawing is the main reason for certain performances issues.
I didn't imagine that the final blitting to the pdc could be that costly. :slight_smile:

Have you tried anything yet?

All I know is that with the old DC method, a masked bitmap was apparently a non-native concept, so wx had to loop through all the pixels, check the mask, then draw or not draw the given pixel. It was orders of magnitude slower than drawing a non-masked bitmap. As a result, I didn't put multiple transparent layers in FloatCanvas -- you could draw a LOT of vector objects faster than drawing a masked bitmap.

I'm really curious how the performance is with alpha bitmaps with Graphics Context, but I don't know when I'll be able to test.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Christopher Barker wrote:

Peter Damoc wrote:

I was thinking that almost all drawing is done off-screen and that the library that does the background drawing is the main reason for certain performances issues.
I didn't imagine that the final blitting to the pdc could be that costly. :slight_smile:

Have you tried anything yet?

All I know is that with the old DC method, a masked bitmap was apparently a non-native concept, so wx had to loop through all the pixels, check the mask, then draw or not draw the given pixel.

I think you're thinking of blitting a bitmap on OS X with a logical operation other than wx.COPY. I don't recall any pixel iteration code just for masks...

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!

I gave up, :slight_smile:
Performance was rather low… BUT I’ve managed to push a lot of the experimentations inside a project I have in a desperate attempt to force myself to look at that code again. I have lots of good ideas that went rotting in some God forsaken place on one of the hard-drives.

I have frequent dreams of sexing up my applications and maybe cooking up a small demo of what can be accomplished with a few gradients and some alpha bitmaps :slight_smile:

I’ve got a crazy idea of expanding wxPython components, declaring them transparent and rendering them separately. Actually the components are accompanied by a “smart” Panel that detects if they are transparent and renders them off-screen.

I’ve attached what I’ve done so far. Not much… but still…

Peter.

ni.py (5.25 KB)

···

On 10/22/07, Christopher Barker Chris.Barker@noaa.gov wrote:

Have you tried anything yet?


There is NO FATE, we are the creators.

Robin Dunn wrote:

I think you're thinking of blitting a bitmap on OS X with a logical operation other than wx.COPY. I don't recall any pixel iteration code just for masks...

Hmm .. maybe that was it, but not just OS-X -- it was pokey on Windows ans GTK as well.

Anyway, I do hope to check out performance of DrawingBitmaps with Alpha, that would be a really nice feature to have in FloatCanvas.

-Chris

···

--
Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

Christopher Barker wrote:

Robin Dunn wrote:

I think you're thinking of blitting a bitmap on OS X with a logical operation other than wx.COPY. I don't recall any pixel iteration code just for masks...

Hmm .. maybe that was it, but not just OS-X -- it was pokey on Windows ans GTK as well.

Nevermind, I found the code that you were probably thinking of. wx.GraphicsContext.DrawBitmap on MSW does do a pixel by pixel conversion of mask to alpha before drawing. I'm not sure why it was done that way, I would think that there would be a more efficient way to do that. On the other hand, if it does have alpha to begin with then the image goes straight to the graphics context in just a couple steps.

···

--
Robin Dunn
Software Craftsman
http://wxPython.org Java give you jitters? Relax with wxPython!