Kamujin's picture

OpenTK Fonts

I have been looking at the OpenTK Font system and I wanted to make some comments. I hope I don't come across as too pushy. Please feel free to correct / enlighten me if I am just missing the point.

I am very impressed with OpenTK and I am excited about using it for my project. I wanted to start by talking about why I like OpenTK so much as I think it will help provide color for my Font related comments.

OpenTK is a C# binding to the OpenGL API. It provides me with a way to write OpenGL programs in C# without the need to learn the OpenTK "way" of doing things. I can read the OpenGL specs and implement what I read with very little modification in OpenTK. As I get good at writing programs using OpenTK, I am also getting good at writing OpenGL programs. To me, this is a non-trivial factor. It is my long term goal to know OpenGL. It is not my goal to master any particular wrapper library. OpenTK allows you to "think" in OpenGL. This also benefits me in that OpenTK does not attempt to repackage OpenGL in some OO framework that would end up adding complexity and limitations with (in my opinion) little real benefit to the programmer. Sure, I am already making OO wrappers for some OpenGL objects, but these are easy to make and specialized to my needs. My simple FrameBuffer class built to my needs was trivial to construct and will likely outperform something that attempts to be a general purpose FrameBuffer class that EVERYONE can use. I also like OpenTK because of the enumerations for OpenGL functions parameter. This really simplifies things without any perceptible downside.

OpenTK does not stop at being an OpenGL wrapper. Clearly the binding to the window systems, math libraries, and such go beyond just being an OpenGL wrapper. Again, OpenTK does this in a restrained, tasteful, and more efficient way (IE no FreeGLUT / SDL). The GameWindow class does its job of providing a context on which OpenGL can operate without forcing too much onto the engine design.

So now I come to Fonts...
When I think of text drawing in a 3d environment. I think of a textured mesh on a plane. I think of some extents clipping.

Because of this, I think OpenTK should view text drawing in 2 stages. The first stage should be designed around creating an OpenGL friendly list of textured vertexes. The second stage, as a helper, can be provided as an optional means of rendering those textured vertexes to the screen.

There are many use cases for drawing text that my not be suitable to the second stage, that would still benefit greatly from access to the first. For example, I would imagine it would be awkward to try and do "star wars" style scrolling text in the current system.


Comments

Comment viewing options

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

I'm at work now, so I'll have to keep the reply brief - if you want to transform the text in 3d space, you are free to setup any 3d projection and transform you want, after calling TextPrinter.Begin(). It's a little awkward maybe as currently OpenTK changes the projection matrix, but on the other hand, I think OpenTK should cater to the common use cases first (head-up displays, text, subtitles, console etc).

The font system is actually already split in the way you mention, layout as vertices and rendering (I don't say it's well designed, just split). It would be simple to expose the vertices to the user for rendering, but this would start imposing restrictions that I'm not sure I'd like (e.g. how do you communicate which textures to bind when?) The other solution is to have an option to specify "do not change the projection matrix, I'll handle that" - would this be enough for your use cases?

objarni's picture

"do not change the projection matrix, I'll handle that" - would this be enough for your use cases?

I think that is fair. I was greatly surprised the first time I used the fonts that such things were going on "under the hood". It did not feel OpenGL at all.. But I understand the sentiment "things should be easy for the casual user" -- but then again, the font system as it is now, is not that easy to grok ... Many objects interacting, "caching or not caching" etc.

the Fiddler's picture

It's not so much the ease factor, but that 2d text is by far the most common case. In fact, apart from the Star Wars series, I can't remember any game that uses 3d text anywhere...

Edit: The current font system is quite similar to GDI+ (System.Drawing.Graphics): you have a TextPrinter object (Graphics) a TextureFont (Font) - the only difference is caching, which is quite simple actually: don't use any, unless you have (a lot of) static text and perceive a performance issue.

objarni's picture

the only difference is caching, which is quite simple actually: don't use any, unless you have (a lot of) static text and perceive a performance issue.

Is this documented somewhere..?

Kamujin's picture

I guess what I was trying to say is that I don't think you should cater to any use case. I think the base font system should return nothing more then textured vertexes in a model space that matches the Viewport. This makes the helper classes optional.

If simplicity for novice users is that important, then encapsulate (with accessors) the data in a class that can be passed to your helper classes for rendering.

the Fiddler's picture

I think the base font system should return nothing more then textured vertexes in a model space that matches the Viewport.
Doing this will expose an implementation detail to the user and I'm not sure if this is a good idea. What if the implementation changes in the future? This will occur at least once (e.g. right now there's 1 texture for all glyphs, but this is too limiting). Or maybe we discover it's better to store complete text runs instead of individual glyphs - will the user have to change his implementation?

I guess my question is, what does this added complexity gain you that you couldn't do in the current system, provided it leaved the projection matrix alone?

Kamujin's picture

I think if you reverse the argument, you will find part of the answer.

If you give me an array of textured vertexes with a texture handle. I have a very stable, predicable resource to consume with the most freedom on how to consume it. If you change the base format, I should have a compile time error to pull me to the areas that need attention.

If you give me a black box object, each little tweak and twist of the internal nobs creates a real possibility that my code renders differently. This can be quite frustrating.

You don't know how I am consuming the class, so you can only guess whether changes to a black box system will break my code.

Lastly, if a vanilla user wants a black box and immunity to changes, they can use your helper classes which will logically change in sync with any base format changes.

If the previous argument is unconvincing. Ask yourself this. Why don't you use FreeGLUT or SDL for your windowing system? These system were designed to provide suitable windowing system for most use cases. For the record, I am happy that you use native bindings. I am just trying to make the point that I would like the same freedom with text, that you clearly find valuable when coding your window system.

bendada's picture

Hello,
I am using opentk for c# project,
I have a problem in opentk.Fonts, I can write text successfully, but sometimes I have an AccessViolationException to draw text on my viewer.
With this instruction:

GL.PushAttrib(OpenTK.OpenGL.Enums.AttribMask.AllAttribBits);

TextureFont font = new TextureFont(new Font(_font, FontStyle.Italic));

TextHandle handle = null;

m_textPrinter.Prepare(_text[i], font, out handle);

if (handle != null)
{
m_textPrinter.Begin();

using (handle)
{
GL.Color3(_colorText);
if (bText)
GL.Color3(_colorTextSelected);
GL.Translate(Vertex_Initiale.X + _imarge, Vertex_Initiale.Y + i * _iTailleTextY + _imarge,
Vertex_Initiale.Z);
m_textPrinter.Draw(handle);
}
m_textPrinter.End();
handle.Dispose()
}

My exception is :

System. AccessViolationException

OpenTK. OpenGL. GL. Imports. CallList(UInt32 list) à OpenTK. OpenGL. GL. CallList(Int32 list) à OpenTK. Fonts. DisplayListTextPrinter. Draw(TextHandle handle) à OpenTK. Fonts. TextPrinter. Draw(TextHandle handle)

Does someone know why this exception happens ?
Thanks.
Billel