Question

Is there a way to draw a text with multiple colored horizontal areas? As an example I want to draw the text "Hello" with the lower half in red and the upper in green. The text to use has to be dynamic. With a normal Texture I would just use the Draw method and pass a subrectangle to draw parts of the texture in different color but for text?

Was it helpful?

Solution

The best method would probably involve custom shaders. But, you should be able to do it with scissor rectangles too.

  1. Draw the text normally in your upper color (green)
  2. Set up a ScissorRectangle that allows drawing only on the bottom half of the text
  3. Draw the text normally, using your bottom color (red). The top half should be clipped so the green text should remain there.

To clarify, your text should be drawn in the same place both times.

OTHER TIPS

I would do this with a custom effect as suggested by 'Crappy Coding Guy', it requires a bit of data sent to the effect, the code below is the HLSL that you need to pixel by pixel fade the color of the string between Color1 and Color2. You could make it a solid colour change by subtracting .5 from it and saturating the value used for lerp multiplied by 10.

float4x4 Projection;
float4 Color1, Color2;
float FontHeight;
float2 Location;

Texture2D FontTexture;
sampler TextureSampler = sampler_state { texture = <FontTexture> ; magfilter = LINEAR; minfilter = LINEAR; mipfilter=LINEAR; AddressU = clamp; AddressV = clamp;};

struct VertexShaderInput
{
    float4 Position : POSITION0;
    float2 Texture : TEXCOORD0;
};

struct VertexShaderOutput
{
    float4 Position : POSITION0;
    float2 Texture : TEXCOORD0;
    float2 OriginalPosition : TEXCOORD1;
};

VertexShaderOutput VertexShaderFunction(VertexShaderInput input)
{
    VertexShaderOutput output;

    output.OriginalPosition = input.Position;
    output.Texture = input.Texture;
    output.Position = mul(input.Position, Projection);

    return output;
}

float4 PixelShaderFunction(VertexShaderOutput input) : COLOR0
{
    float4 fontColor = lerp (Color1, Color2,  (1.0 / FontHeight) * (input.OriginalPosition.y - Location.y));
    return tex2D(TextureSampler, input.Texture)*  fontColor;
}

technique Technique1
{
    pass Pass1
    {
        VertexShader = compile vs_2_0 VertexShaderFunction();
        PixelShader = compile ps_2_0 PixelShaderFunction();
    }
}

and the C# to use it. (obviously you don't have to set all the parameters of the effect every frame, I just didn't want to post too many methods, if you need the complete example I'll be happy to email it to you)

protected override void Draw(GameTime gameTime)
{
   GraphicsDevice.Clear(Color.CornflowerBlue);
   fontEffect.Parameters["Projection"].SetValue(Matrix.CreateOrthographicOffCenter(0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height, 0, 0, 1));
   fontEffect.Parameters["Color1"].SetValue(Color.Red.ToVector4());
   fontEffect.Parameters["Color2"].SetValue(Color.Blue.ToVector4());
   fontEffect.Parameters["FontHeight"].SetValue(font.LineSpacing);
   FieldInfo fontTexture = typeof(SpriteFont).GetField("textureValue", BindingFlags.NonPublic | BindingFlags.Instance);
   fontEffect.Parameters["FontTexture"].SetValue((Texture2D)fontTexture.GetValue(font));            
   fontEffect.CurrentTechnique.Passes[0].Apply(); 

   spriteBatch.Begin( SpriteSortMode.Immediate, BlendState.AlphaBlend, SamplerState.PointClamp, DepthStencilState.Default, RasterizerState.CullNone, fontEffect);            
   spriteBatch.DrawString(font, "abcdefghijklmnopqrstuvxyz", new Vector2(10, 100), Color.White);
   spriteBatch.End();

   base.Draw(gameTime);
}

Edit: You'll probably notice that I've had to get the texture out of the sprite font, it's a private field which is quite annoying! If anyone knows a better way to get this please do tell!

I know this is an old question, but this tool will allow you to create custom Bit Map Fonts with all kinds of effects, like shadows, embossing, glow. It will generate a font texture for you that you can then edit and add multiple colors or other post-processing efftcs. Using it in XNA is then just a matter of adding to your Content project, and setting the ContentProcessor to "Sprite Font Texture". You can then load it in your game the same way you would load a normal sprite font.

If you want more control, you could use two different spritefont textures. Use the bitmap font maker to get your initial spritefont: http://create.msdn.com/en-US/education/catalog/utility/bitmap_font_maker. If desired, modify your texture to make it look nice (drop shadow etc). Make a copy of the font texture and overwrite the top half of the text with the transparent magenta colour. Then you draw your text twice, the second time with the modifed fonts and a different colour. The advantage of this method is that your top and bottom half don't need to be delineated by a straight line, ie perhaps the top half could be goo dripping over the top etc.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top