3

My goal is to draw text in a single layout with certain ranges different sizes and opacities. The ID2D1RenderTarget::DrawTextLayout method seems to be the way to go.

The documentation for the defaultForegroundBrush parameter:

The brush used to paint any text in textLayout that does not already have a brush associated with it as a drawing effect (specified by the IDWriteTextLayout::SetDrawingEffect method).

According to the Remarks section of the IDWriteTextLayout::SetDrawingEffect method,

An ID2D1Brush, such as a color or gradient brush, can be set as a drawing effect if you are using the ID2D1RenderTarget::DrawTextLayout to draw text and that brush will be used to draw the specified range of text.

This drawing effect is associated with the specified range and will be passed back to the application by way of the callback when the range is drawn at drawing time.

It sounds like ID2D1RenderTarget::DrawTextLayout will definitely use any brush set by IDWriteTextLayout::SetDrawingEffect. This unmanaged C++ answer seems to corroborate this idea.

However, in practice, DrawTextLayout ignores any SolidColorBrush I set using SetDrawingEffect. I get styles and sizes in the appropriate ranges, but everything is painted using the default brush.

I worked around this by implementing a custom text renderer (gist) which is dead simple and drew exactly what I expected from ID2D1RenderTarget::DrawTextLayout as per the documentation. I would have been satisfied but the performance of a TextRendererBase and DrawGlyphRun are more than 25% slower than ID2D1RenderTarget::DrawTextLayout.

What might be causing this issue? Can I use color as the documentation suggests and still use ID2D1RenderTarget::DrawTextLayout?

Community
  • 1
  • 1
jnm2
  • 7,960
  • 5
  • 61
  • 99
  • Found and fixed a memory leak ([see new link](https://gist.github.com/jnm2/a067c444fac9d5b34298)). – jnm2 Nov 20 '15 at 21:53
  • I'm trying to do something similar and am very interested in your answer jnm2, would you be able to give an example usage of your CustomBrushTextRenderer class? I don't have a C++ background so have been struggling with the native DirectX docs on this. – millejos May 18 '16 at 22:22
  • 1
    @millejos usage is replacing `renderTarget.DrawTextLayout(params);` with `CustomBrushTextRenderer.DrawTextLayout(renderTarget, params);`- does that answer your question? – jnm2 May 19 '16 at 12:05
  • Yes it does, thank you. One more really quick question? Is it possible to pass a custom class to TextLayout.SetDrawingEffect()? (instead of a color) I basically want to pass two colors, and use them to render a shadow for the text. [more here if you're interested](http://stackoverflow.com/questions/37311969/sharpdx-advanced-text-rendering-multibrush), otherwise thanks again for the help! – millejos May 19 '16 at 16:12
  • Sorry, that's beyond me. I believe you can use any class and it's up to the renderer to decide what to do with the custom class as you can see [I did](https://gist.github.com/jnm2/a067c444fac9d5b34298#file-custombrushtextrenderer-cs-L16) with the not-supposed-to-be-custom effect (brush). In other words, I'd expect a custom effect only to be recognized by a custom renderer that was checking for it. I don't know DirectX but it looks like only one effect is possible at a time, so you'd have to combine the shadow and forecolor effects into one effect class. – jnm2 May 19 '16 at 16:40

1 Answers1

1

instead of:

layout.SetDrawingEffect(myBrush, new TextRange(1, 5));

call it like this:

layout.SetDrawingEffect(myBrush.NativePointer, new TextRange(1, 5));
Jenny
  • 572
  • 4
  • 16