ravi.joshi53's picture

Modification in TextRendering

Hi,

Somehow I need to migrate from QuickFont for printing text. So I though of modifying an existing TextRendering code provided with OpenTK.

I have following queries-

  1. The above code has public void Clear(Color color) method, which is changing background color. Instead of this, I want to use the existing background color of my application. (Un-commenting this is causing black background)
  2. In the above code renderer.DrawString is being called inside OnLoad function. What if i have a dynamic text? May I call renderer.DrawString from OnRenderFrame? (Any performance degradation?)
  3. The above code has dirty region Rectangle dirty_region. Will this create any rendering issue, after integrating it with my existing OpenTK application?

Please suggest me the required changes.

-
Thanks
Ravi


Comments

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
the Fiddler's picture
Quote:

The above code has public void Clear(Color color) method, which is changing background color. Instead of this, I want to use the existing background color of my application. (Un-commenting this is causing black background)

You can clear to a translucent color, such as Color.FromArgb(128, Color.Blue) and enable alpha blending, or you can clear to Color.Black and enable color blending.

You can find more about blending modes here: http://www.andersriggelsen.dk/glblendfunc.php

Quote:

In the above code renderer.DrawString is being called inside OnLoad function. What if i have a dynamic text? May I call renderer.DrawString from OnRenderFrame? (Any performance degradation?)

Yes, this works. There is a performance penalty, but it should be ok for a typical application.

Quote:

The above code has dirty region Rectangle dirty_region. Will this create any rendering issue, after integrating it with my existing OpenTK application?

This is simply an optimization to avoid updating the whole texture if you have modified only a small part of it. You don't have to use it, but it does improve fps, especially on higher resolutions.

ravi.joshi53's picture

Hi Fiddler,

I am facing some issues with it.

  1. font.measure is not working as per my dimension i.e. 800x600 (You can see printing the text in 0,100 is printing in middle of the window)
  2. I want to have single print method inside font class, which should generate the texture and also map it to the desired rectangle as per given location (Currently, I am not able to place it in font class. So i have placed in game window class )

See my code-

Font class:

class MyFont : IDisposable
{
    Font font;
    Bitmap bmp;
    Graphics graphics;
    Rectangle dirtyRegion;
 
    int texture;
    bool disposed;
 
    public int getLineSpacing()
    {
        return font.Height;
    }
 
    public MyFont(int width, int height)
    {
        if (width <= 0)
            throw new ArgumentOutOfRangeException("width");
        if (height <= 0)
            throw new ArgumentOutOfRangeException("height ");
        if (GraphicsContext.CurrentContext == null)
            throw new InvalidOperationException("No GraphicsContext is current on the calling thread.");
 
        font = new Font(FontFamily.GenericSerif, 20);
 
        bmp = new Bitmap(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
        graphics = Graphics.FromImage(bmp);
        graphics.TextRenderingHint = System.Drawing.Text.TextRenderingHint.AntiAlias;
 
        texture = GL.GenTexture();
        GL.BindTexture(TextureTarget.Texture2D, texture);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMinFilter, (int)TextureMinFilter.Linear);
        GL.TexParameter(TextureTarget.Texture2D, TextureParameterName.TextureMagFilter, (int)TextureMagFilter.Linear);
        GL.TexImage2D(TextureTarget.Texture2D, 0, PixelInternalFormat.Rgba, width, height, 0, PixelFormat.Rgba, PixelType.UnsignedByte, IntPtr.Zero);
    }
 
    public void Clear(Color color)
    {
        graphics.Clear(color);
        dirtyRegion = new Rectangle(0, 0, bmp.Width, bmp.Height);
    }
 
    public SizeF measure(string text)
    {
        return graphics.MeasureString(text, font); ;
    }
 
    public void setText(string text, Brush brush, PointF location)
    {
        graphics.DrawString(text, font, brush, location, StringFormat.GenericTypographic);
        SizeF size = measure(text);
        dirtyRegion = Rectangle.Round(RectangleF.Union(dirtyRegion, new RectangleF(location, size)));
        dirtyRegion = Rectangle.Intersect(dirtyRegion, new Rectangle(0, 0, bmp.Width, bmp.Height));
    }
 
    public int Texture
    {
        get
        {
            UploadBitmap();
            return texture;
        }
    }
 
    void UploadBitmap()
    {
        if (dirtyRegion != RectangleF.Empty)
        {
            System.Drawing.Imaging.BitmapData data = bmp.LockBits(dirtyRegion, System.Drawing.Imaging.ImageLockMode.ReadOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb);
 
            GL.BindTexture(TextureTarget.Texture2D, texture);
            GL.TexSubImage2D(TextureTarget.Texture2D, 0, dirtyRegion.X, dirtyRegion.Y, dirtyRegion.Width, dirtyRegion.Height, PixelFormat.Bgra, PixelType.UnsignedByte, data.Scan0);
 
            bmp.UnlockBits(data);
 
            dirtyRegion = Rectangle.Empty;
        }
    }
 
    void Dispose(bool manual)
    {
        if (!disposed)
        {
            if (manual)
            {
                bmp.Dispose();
                font.Dispose();
                graphics.Dispose();
                if (GraphicsContext.CurrentContext != null)
                    GL.DeleteTexture(texture);
            }
 
            disposed = true;
        }
    }
 
    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}

Game Class:

class TextRendering : GameWindow
{
    const int farZ = 1;
    const int topY = 0;
    const int leftX = 0;
    const int nearZ = -1;
    const int rightX = 800;
    const int bottomY = 600;
 
    MyFont font;
    string text = "\"अभिव्यक्ति\" व्यक्तिगत अभिरुचि की अव्यवसायिक साहित्यिक पत्रिका है";
 
    public TextRendering() : base(rightX, bottomY) {}
 
    protected override void OnLoad(EventArgs e)
    {
        GL.ClearColor(Color.Blue);
        font = new MyFont(Width, Height, FontFamily.GenericSerif, 20);
        GL.Enable(EnableCap.Blend);
        GL.BlendFunc(BlendingFactorSrc.SrcAlpha, BlendingFactorDest.OneMinusSrcAlpha);
    }
 
    protected override void OnUnload(EventArgs e)
    {
        font.Dispose();
    }
 
    protected override void OnResize(EventArgs e)
    {
        GL.Viewport(ClientRectangle);
        GL.MatrixMode(MatrixMode.Projection);
        GL.LoadIdentity();
        GL.Ortho(leftX, rightX, bottomY, topY, farZ, nearZ);
    }
 
    protected override void OnUpdateFrame(FrameEventArgs e)
    {
        if (Keyboard[OpenTK.Input.Key.Escape])
        {
            this.Exit();
        }
    }
 
    protected override void OnRenderFrame(FrameEventArgs e)
    {
        GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);
        GL.MatrixMode(MatrixMode.Modelview);
        GL.LoadIdentity();
 
		PointF position = new PointF(0, 100);
        font.Clear(Color.FromArgb(0, Color.White));
 
        font.setText("अव्यवसायिक है", Brushes.White, position);
        position.Y += font.measure("अव्यवसायिक है").Height;
 
        PointF position2 = position;
        font.setText("साहित्यिक पत्रिका", Brushes.White, position2);
 
        print(font.Texture, position2.X, position2.Y);
        print(font.Texture, position.X, position.Y);
 
        SwapBuffers();
    }
 
    void print(int texture, float leftX, float topY)
    {
        drawTexture(texture, leftX, topY, Width, Height);
    }
 
    void drawTexture(int texture, float leftX, float topY, float width, float height)
    {
        GL.PushMatrix();
        GL.Enable(EnableCap.Texture2D);
        GL.BindTexture(TextureTarget.Texture2D, texture);
        GL.Begin(PrimitiveType.Quads);
 
        GL.TexCoord2(0.0f, 0.0f);
        GL.Vertex2(leftX, topY);
 
        GL.TexCoord2(1.0f, 0.0f);
        GL.Vertex2(leftX + width, topY);
 
        GL.TexCoord2(1.0f, 1.0f);
        GL.Vertex2(leftX + width, topY + height);
 
        GL.TexCoord2(0.0f, 1.0f);
        GL.Vertex2(leftX, topY + height);
 
        GL.End();
        GL.Disable(EnableCap.Texture2D);
        GL.PopMatrix();
    }
 
    public static void Main()
    {
        using (TextRendering example = new TextRendering())
        {
            example.Run(30.0);
        }
    }
}