Soft shadows

  • iwbnwif

    I have been playing with creating soft shadows under shapes and got some reasonably good results. The following code can go into an overload for wxSFRectShape::DrawShadow(wxDC& dc)

    // get the shadow offset
    double offset = GetParentCanvas()->GetShadowOffset().x;
    wxSize bmpSize = Conv2Size(m_nRectSize);
    bmpSize.IncBy(offset); // the maximum size 'allowed' for a shape and its shadow
    #ifdef NON_GC
      // draw the shadow on a bitmap in memory via a memory DC
      wxBitmap drawBmp(bmpSize);
      wxMemoryDC drawDc(drawBmp);
      drawDc.DrawRectangle(offset / 4.0, offset / 4.0, bmpSize.x - offset, bmpSize.y - offset);
      // convert the bitmap to an image
      wxImage blurImage = drawBmp.ConvertToImage();
      // blur and write to a second bitmap
      wxBitmap outBmp (blurImage.Blur(offset / 2.0));
      wxImage image(bmpSize);
      unsigned char *alpha=image.GetAlpha();
      memset(alpha, wxIMAGE_ALPHA_TRANSPARENT, image.GetWidth()*image.GetHeight());
      wxGraphicsContext *gc=wxGraphicsContext::Create(image);
      gc->SetPen( *wxTRANSPARENT_PEN );
      gc->DrawRectangle(offset / 4.0, offset / 4.0, bmpSize.x - offset, bmpSize.y - offset);
      delete gc;
      wxBitmap outBmp (image.Blur(offset / 2.0));
      dc.DrawBitmap(outBmp, Conv2Point(GetAbsolutePosition()));

    The GC version includes transparency, but of course the non-gc version can't do that.

    Performance is not too bad as the wxImage::Blur method uses a simple box blur algorithm.

    An improvement I would like to make is to cache the shadow bitmap and only re-generate it if the shape changes size / aspect.

    One area where performance does get hit is zooming a drawing using the mouse wheel with a large number of shapes. Redrawing all the shadows does slow things, and I ponder changing the way wxSF performs mouse wheel zooms to be more like Google or Office 2013. i.e. grab the image as a bitmap and zoom the bitmap (temporarily sacrificing resolution for speed). When the user releases the CTRL key, do a proper draw.

    Last edit: iwbnwif 2013-10-29