c++direct2d

How to draw a image with effects that rescales with it's window in direct2d


I created a Direct2D application following this example: https://github.com/microsoft/Windows-classic-samples/tree/master/Samples/Win7Samples/multimedia/Direct2D/SimpleDirect2DApplication

I managed to show a bitmap in the applications window and the bitmap also rescales when rescaling the window. But now I wanted to apply effects on the bitmap and here comes my problem. The effect is applied like this

hr = m_pRenderTarget->QueryInterface( __uuidof(ID2D1DeviceContext), (void**)&m_pDeviceContext );
m_pDeviceContext->CreateEffect( CLSID_D2D1GammaTransfer, &gammaTransferEffect );
gammaTransferEffect->SetInput( 0, m_pBitmap );
gammaTransferEffect->SetValue( D2D1_GAMMATRANSFER_PROP_RED_AMPLITUDE, 4.0f );

The problem is that after applying the effect, the image data is now in the format of ID2D1Effect. This can be drawn with DrawImage like this:

m_pDeviceContext->DrawImage(gammaTransferEffect);

But I did the rescaling with destinationRectangle in the function DrawBitmap and there is no equivalent to destinationRectangle in DrawImage.

m_pDeviceContext->DrawBitmap(
            m_pBitmap,
            D2D1::RectF(
                0,
                0,
                renderTargetSize.width,
                renderTargetSize.height),
            1.0f,
            D2D1_BITMAP_INTERPOLATION_MODE_NEAREST_NEIGHBOR
        );

So how can I rescale the bitmap after applying the effect when rescaling the render target? I had some ideas about this, but none led me to a solution.

  1. Rescale the device context. I didn't find a method like Resize for the rendert target.
  2. Make a bitmap from the effects output to use DrawBitmap again. I found no possibility to do this.
  3. Rescaling the bitmap before applying effects on it. I found no way to do this.

Somebody an idea what could be a solution here?


Solution

  • One solution to my problem is to rescale the render target:

    // Retrieve the size of the render target.
    D2D1_SIZE_F renderTargetSize = m_pRenderTarget->GetSize();
    // calculate scale factors
    float scale_x = renderTargetSize.width / _bitmapSource.width;
    float scale_y = renderTargetSize.height / _bitmapSource.height;
    // scale render target
    m_pRenderTarget->SetTransform(
        D2D1::Matrix3x2F::Scale(
            D2D1::Size( scale_x, scale_y ),
            D2D1::Point2F( 0.0f, 0.0f ))
    );
    hr = m_pRenderTarget->QueryInterface( __uuidof(ID2D1DeviceContext), (void**)&m_pDeviceContext );
    m_pDeviceContext->CreateEffect( CLSID_D2D1GammaTransfer, &gammaTransferEffect );
    gammaTransferEffect->SetInput( 0, m_pBitmap );
    gammaTransferEffect->SetValue( D2D1_GAMMATRANSFER_PROP_RED_AMPLITUDE, 4.0f );
    m_pDeviceContext->DrawImage(gammaTransferEffect);
    

    Additionally I had to remove my resize function from the WM_SIZE message, otherwise my painted bitmap didn't rescale with its window. That was a bit counter intuitive to me, but yay it works.