Search code examples
c++effectsdirect2d

Applying effects to output instead of bitmaps?


Let's say I have a gaussian blur effect ID2D1Effect *blur; and I want to apply a bitmap to the effect to get a blured image. I can pass the bitmap to the effect using blur->SetInput(0, bitmap); and get the output with blur->Get(). Now I don't want to blur an image stored on disk, I want to blur the output that I created between renderTarget->BeginDraw() and renderTarget->EndDraw(). My first idea was to get a bitmap of the output, but I could find neither a function for retrieving the already rendered output nor find a way to apply an effect to the renderTarget instead of a loaded bitmap.

Little example:

ID2D1SolidColorBrush *brush;
ID2D1HwndRenderTarget *renderTarget; // Instantiated somewhere else in code

renderTarget->CreateSolidColorBrush(D2D1::ColorF(0.0f, 0.6f, 1.0f), &bush);

renderTarget->BeginDraw();
renderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f));
renderTarget->FillRectangle(D2D1::RectF(50.0f, 50.0f, 100.0f, 100.0f), brush);
// Apply gaussian blur?
renderTarget->EndDraw();

brush->Release();
// renderTarget gets released somewhere else

How can I blur the rectangle in this example?


EDIT (Thanks to enhzflep):

I can obtain the already rendered output as a bitmap with following snippet:

ID2D1BitmapRenderTarget *bitmapRenderTarget;
hwndRenderTarget->CreateCompatibleRenderTarget(&bitmapRenderTarget);

ID2D1Bitmap *bitmap;
bitmapRenderTarget->GetBitmap(&bitmap);

In my code I already tested it by obtaining a bitmap, drawing on it and finally draw this bitmap onto the hwndRenderTarget and it worked. Before drawing the bitmap back to the hwndRenderTarget I want to apply an effect to it (e.g. gaussian blur). But this leads to the next problem (I don't know if I should open a new topic, so I post it here): An ID2D1Effect interface can only be instantiated from an instance of ID2D1DeviceContext which is only available for Windows 8. I cannot imagine that Microsoft restricts ID2D1Effect to Windows 8, so there have to be another way. Does anyone know another way of instatiating an ID2D1Effect interface?


EDIT 2:

I also posted this question on MSDN and finally got an answer. I had to install the Platform Update for Win7 SP1 (KB2670838) and the Win8 SDK (also works on Win7) in order to use Win8 headers on Win7.

(Final solution below as answer)


Solution

  • Here is my final solution. It's simpler than I though it's gonna be:

    // Obtain already initialized ID2D1HwndRenderTarget
    ID2D1HwndRenderTarget *hwndRenderTarget = Game::GetInstance()->gfx->hwndRenderTarget;
    
    // COMs
    ID2D1Bitmap *bitmap;
    ID2D1BitmapRenderTarget *bitmapRenderTarget;
    ID2D1DeviceContext *deviceContext;
    ID2D1Effect *gaussianBlur;
    ID2D1SolidColorBrush *solidColorBrush;
    
    // Create bitmapRenderTarget
    hwndRenderTarget->CreateCompatibleRenderTarget(&bitmapRenderTarget);
    
    // Create solidColorBrush
    bitmapRenderTarget->CreateSolidColorBrush(D2D1::ColorF(0.0f, 0.6f, 1.0f), &solidColorBrush);
    
    // Draw onto bitmapRenderTarget
    bitmapRenderTarget->BeginDraw();
    bitmapRenderTarget->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f));
    bitmapRenderTarget->FillEllipse(D2D1::Ellipse(D2D1::Point2F(400.0f, 300.0f), 100.0f, 100.0f), solidColorBrush);
    bitmapRenderTarget->EndDraw();
    
    // Obtain hwndRenderTarget's deviceContext
    hwndRenderTarget->QueryInterface(&deviceContext);
    
    // Create and apply gaussian blur
    deviceContext->CreateEffect(CLSID_D2D1GaussianBlur, &gaussianBlur);
    
    bitmapRenderTarget->GetBitmap(&bitmap);
    gaussianBlur->SetInput(0, bitmap);
    gaussianBlur->SetValue(D2D1_GAUSSIANBLUR_PROP_BORDER_MODE, D2D1_BORDER_MODE_SOFT);
    gaussianBlur->SetValue(D2D1_GAUSSIANBLUR_PROP_STANDARD_DEVIATION, 5.0f);
    
    // Draw resulting bitmap
    deviceContext->DrawImage(
        gaussianBlur,
        D2D1_INTERPOLATION_MODE_LINEAR);
    
    // Release
    bitmap->Release();
    bitmapRenderTarget->Release();
    deviceContext->Release();
    gaussianBlur->Release();
    solidColorBrush->Release();