exspider64's picture

Printer text depth problem

Hi,

I am trying to make a gui system within a GameWindow. I have already made the framework for creating in-game 2D windows with different parts like message boxes and buttons. I tried to base it on Windows forms so that the event triggering and properties are similar.

My problem lies with displaying text at different z-depths. The quads representing the windows themselves are displayed at the correct depth, but when I use a text printer, all the text appears above every window.

In the attached picture, the FPS window is above the Game Information window, but the text for both windows appears above the FPS window.

I tried to find something in the other post about 2D text at 3D positions, but it didn't help.

Here is some sample code that I am using:

Base class:

public virtual void SetUpOrtho()
{
    int w = GameWindow.Width;
    int h = GameWindow.Height;
    GL.MatrixMode(MatrixMode.Projection);
    GL.PushMatrix();
    GL.LoadIdentity();
    GL.Viewport(0, 0, w, h);
    GL.Ortho(0, w, 0, h, -10, 10);
    GL.Scale(1, -1, 1);
    GL.Translate(0, -h, 0);
    GL.MatrixMode(MatrixMode.Modelview);
    GL.PushMatrix();
    GL.LoadIdentity();
}
 
public virtual void CleanUpOrtho()
{
    GL.PopMatrix();
    GL.MatrixMode(MatrixMode.Projection);
    GL.PopMatrix();
}
 
public virtual void InitializePosition() 
{
    if (Parent != null) Parent.InitializePosition();
    GL.Translate(position.X, position.Y, -GUIDepth);
}
 
public virtual void Draw() 
{
    if (!Visible)
        return;
    foreach (var child in Children) child.Draw();
    SetUpOrtho();
    InitializePosition();
    GL.Enable(EnableCap.Blend);
    if (Focus)
        GL.Color4(FocusOnColor.R, FocusOnColor.G, FocusOnColor.B, FocusOnColor.A);
    else
        GL.Color4(FocusOffColor.R, FocusOffColor.G, FocusOffColor.B, FocusOffColor.A);
    GL.Begin(BeginMode.Quads);
    GL.Vertex3(0, 0, 0);
    GL.Vertex3(0, Height, 0);
    GL.Vertex3(Width, Height, 0);
    GL.Vertex3(Width, 0, 0);
    GL.End();
    GL.Disable(EnableCap.Blend);
    CleanUpOrtho();
}

Derived class:

public override void Draw()
{
    if (!Visible)
        return;
    base.Draw();
    SetUpOrtho();
    InitializePosition();
    printer.Print(Message, font, textColor, rect);
    CleanUpOrtho();
}

The base class is a gui node. The derived class in this case is a message box which is being used as a child in another derived class (Window).

Each gui node has a parent and any number of children. It's absolute position is set by using InitializePosition().

The GUIDepth field is set depending on the window's position in a stack that I use to order the windows properly.

I have also tried replacing SetUpOrtho() / CleanUpOrtho() with printer.Begin() / printer.End(), but the result is exactly the same.

I have attached a picture of my problem.

Has anyone tested if text is translated properly in the z-direction? Maybe I shouldn't be assuming that the text printer should be able to translate in the z-direction at all...

AttachmentSize
text problem.PNG443.3 KB

Comments

Comment viewing options

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

The issue is that TextPrinter.Print does not use depth testing at all. I'll modify it to enable depth testing and make a quick bugfix release later today.

Edit: now that I think of it, this is not enough, because the TextPrinter always renders text at z = 0. This means we are going to need an extra parameter in TextPrinter.Print - I'll have to think about this for a while.

In the meanwhile, is it possible to render windows (and text) back-to-front? This will ensure correct appearance in all cases.

objarni's picture

There is a conflict between ease-of-use and flexibility for the TextPrinter.

Are the underlying algorithms available? Then advanced usages, could use those algorithms instead of the "high level" TextPrinter, for increased flexibility.

the Fiddler's picture

The TextPrinter is the minimum abstraction over the platform and OpenGL version. Any lower and you are into platform- or version-specific territory.

The problem discussed on this thread is mainly an API issue: TextPrinter.Print is just not expressive enough. I think the best solution is an API like this:

Point Print(string text, Font font, Color color, Point advance, Size size, TextPrinterOptions options, TextAlignment alignment, TextDirection direction, ref Matrix4 modelview);

Of course, with overloads to simplify the more typical use cases.

The main differences from the current implementation:

  • The layout rectangle is always (0, 0) - (size.Width, size.Height). This is only used for word wrapping and clipping, not positioning (unlike th current API).
  • The "advance" parameter specifies the current location inside the layout rectangle. This allows you to print formatted text, where consecutive text runs have different e.g. colors, fonts etc. The return value is the new advance position after printing the current string.
  • The "modelview" parameter specifies an optional translation and rotation that is applied after text layout.

The current API only allows you to specify a x and y offset in the z = 0 plain. It lacks any notion of text advance or custom translations, rotations, searing etc.

objarni's picture

Good.

I think first we should discuss of how general the text printing is to be in OpenTK. I have brought up this subject before, I know, but since this API still has not matured a year later, I think it is good to re-specify what exactly the text printing facilities provide functionalitywise, and maybe even more important, what it does *not* provide.

[With that said, I do have some ideas on how to improve the proposed new API:

* TextPrinterOptions is vague. Are not all the parameters to this function options? What does Options specify?
* Too many parameters are sign of an object wanting to come out. Maybe a PrintOptions object?
* The "state" that has to be passed in (alignment) and comes out again as return, is another sign of an object wanting to be born.
* Pseudocode to discuss:

PrintOptions options = new PrintOptions(); // defaults to "sane" values
options.Font = ... // I want to override the font used
options.Alignment = ... // I want to override the alignment used
TextPrinter printer = new TextPrinter(options);
printer.PrintLine("some text");
printer.Options.Size = printer.Options.Size*1.5; // we can change the options during printing
printer.PrintLine("Some more text");
printer.Print("one word ");
printer.Print("another word, on the same line");

I'm not sure I think the Matrix has anything in the API to do at all; why not use the current ModelView matrix instead..?]

the Fiddler's picture

This is a very good idea, can you open an issue?

The modelview parameter is necessary for OpenGL 3.0+, where there is no matrix stack. The current API was designed before OpenGL 3.0, so it didn't take this into account.

exspider64's picture

Thank you for your help.

I have fixed the issue by rendering the gui windows and text back to front.