// Begins drawing, allowing updates to content in the specified area. void Scenario1ImageSource::BeginDraw(Windows::Foundation::Rect updateRect) { POINT offset; ComPtr<IDXGISurface> surface; // Express target area as a native RECT type. RECT updateRectNative; updateRectNative.left = static_cast<LONG>(updateRect.Left); updateRectNative.top = static_cast<LONG>(updateRect.Top); updateRectNative.right = static_cast<LONG>(updateRect.Right); updateRectNative.bottom = static_cast<LONG>(updateRect.Bottom); // Query for ISurfaceImageSourceNative interface. Microsoft::WRL::ComPtr<ISurfaceImageSourceNative> sisNative; DX::ThrowIfFailed( reinterpret_cast<IUnknown*>(this)->QueryInterface(IID_PPV_ARGS(&sisNative)) ); // Begin drawing - returns a target surface and an offset to use as the top left origin when drawing. HRESULT beginDrawHR = sisNative->BeginDraw(updateRectNative, &surface, &offset); if (SUCCEEDED(beginDrawHR)) { // Create render target. ComPtr<ID2D1Bitmap1> bitmap; DX::ThrowIfFailed( m_d2dContext->CreateBitmapFromDxgiSurface( surface.Get(), nullptr, &bitmap ) ); // Set context's render target. m_d2dContext->SetTarget(bitmap.Get()); // Begin drawing using D2D context. m_d2dContext->BeginDraw(); // Apply a clip and transform to constrain updates to the target update area. // This is required to ensure coordinates within the target surface remain // consistent by taking into account the offset returned by BeginDraw, and // can also improve performance by optimizing the area that is drawn by D2D. // Apps should always account for the offset output parameter returned by // BeginDraw, since it may not match the passed updateRect input parameter's location. m_d2dContext->PushAxisAlignedClip( D2D1::RectF( static_cast<float>(offset.x), static_cast<float>(offset.y), static_cast<float>(offset.x + updateRect.Width), static_cast<float>(offset.y + updateRect.Height) ), D2D1_ANTIALIAS_MODE_ALIASED ); m_d2dContext->SetTransform( D2D1::Matrix3x2F::Translation( static_cast<float>(offset.x), static_cast<float>(offset.y) ) ); } else if (beginDrawHR == DXGI_ERROR_DEVICE_REMOVED || beginDrawHR == DXGI_ERROR_DEVICE_RESET) { // If the device has been removed or reset, attempt to recreate it and continue drawing. CreateDeviceResources(); BeginDraw(updateRect); } else { // Notify the caller by throwing an exception if any other error was encountered. DX::ThrowIfFailed(beginDrawHR); } }
void TextInlineFormat_Shadow::ApplyInlineFormat(ID2D1RenderTarget* target, IDWriteTextLayout* layout, ID2D1SolidColorBrush* solidBrush, const UINT32& strLen, const D2D1_POINT_2F& drawPosition) { if (!target || !layout) return; // In order to make a shadow effect using the built-in D2D effect, we first need to make // certain parts of the string transparent. We then draw only the parts of the string we // we want a shadow for onto a memory bitmap. From this bitmap we can create the shadow // effect and draw it. D2D1_COLOR_F color = D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f); Microsoft::WRL::ComPtr<ID2D1SolidColorBrush> transparent; HRESULT hr = target->CreateSolidColorBrush(color, transparent.GetAddressOf()); if (FAILED(hr)) return; // Only change characters outside of the range(s) transparent for (UINT32 i = 0; i < strLen; ++i) { bool found = false; for (const auto& range : GetRanges()) { if (range.length <= 0) continue; if (i >= range.startPosition && i < (range.startPosition + range.length)) { found = true; break; } } if (!found) { DWRITE_TEXT_RANGE temp = { i, 1 }; layout->SetDrawingEffect(transparent.Get(), temp); } } Microsoft::WRL::ComPtr<ID2D1Bitmap> bitmap; Microsoft::WRL::ComPtr<ID2D1BitmapRenderTarget> bTarget; hr = target->CreateCompatibleRenderTarget(bTarget.GetAddressOf()); if (FAILED(hr)) return; // Draw onto memory bitmap target bTarget->BeginDraw(); bTarget->DrawTextLayout(drawPosition, layout, solidBrush); bTarget->EndDraw(); hr = bTarget->GetBitmap(bitmap.GetAddressOf()); if (FAILED(hr)) return; // Shadow effects can only be drawn with a D2D device context Microsoft::WRL::ComPtr<ID2D1DeviceContext> dc; hr = target->QueryInterface(__uuidof(ID2D1DeviceContext), reinterpret_cast<void**>(dc.GetAddressOf())); if (FAILED(hr)) return; // Create shadow effect Microsoft::WRL::ComPtr<ID2D1Effect> shadow; hr = dc->CreateEffect(CLSID_D2D1Shadow, &shadow); if (FAILED(hr)) return; // Load shadow options to effect shadow->SetInput(0, bitmap.Get()); shadow->SetValue(D2D1_SHADOW_PROP_BLUR_STANDARD_DEVIATION, m_Blur); shadow->SetValue(D2D1_SHADOW_PROP_COLOR, ToVector4F(m_Color)); shadow->SetValue(D2D1_SHADOW_PROP_OPTIMIZATION, D2D1_SHADOW_OPTIMIZATION_SPEED); // Draw effect dc->DrawImage(shadow.Get(), m_Offset); }