
Discuss text printing
Posted Saturday, 6 June, 2009 - 16:01 by objarni| Project: | The Open Toolkit library |
| Version: | all versions |
| Component: | Code |
| Category: | task |
| Priority: | normal |
| Assigned: | Unassigned |
| Status: | won't fix |
Jump to:
Description
The text printing (TextPrinter) APIs has been discussed from time to time in the forums. Users expect quite different things from text printing in a 3d API, so we need to come to an agreement which balances ease-of-use, speed, quality & features and last but not least, scope.


Comments
#1
Ok, let me propose a design based on the latest discussion.
Both Measure and Print operate on text runs. A text run is defined as a continuous part of the text that uses the same TextOptions. Text may consist of one text run (which can be measured or drawn in a single call) or multiple runs (which must be drawn or measured in multiple calls).
Conceptually, it is:
It is the user's responsibility to split text into text runs.
Parameters
"text" is the string for the current text run. If text is null, an ArgumentNullException shall be thrown. If text.Length is 0, Measure shall return an empty TextExtents instance. If text.Length is 0, Print shall return without rendering. In both cases, the advance position shall remain unchanged.
"options" is the TextOptions instance for the current text run. If options is null, an ArgumentNullException shall be thrown.
"boundingBox" is an optional parameter that specifies the maximum width and height of the text. It is used to perform word wrapping and clipping. If this parameter is omitted, the text shall not be wrapped or clipped. If
Vector2.XorVector2.Yis negative or zero, no wrapping or clipping will take place in the relevant direction."advance" is an optional parameter that specifies the advance position of the text run inside the bounding box. If TextDirection is left-to-right, advance defines the top-left corner of the first visible glyph. If TextDirection is right-to-left, advance defines the top-right corner of the first visible glyph. When the method returns, advance shall contain the advance position of the next text run.
"modelview" is an optional parameter that can be used to translate, rotate or shear the text run. It is applied after text layout, during text rendering. If modelview is omitted, text shall be transformed by the identity matrix. If modelview is specified, text shall be transformed by the specified matrix. If modelview is specified and the deprecated OpenGL matrix stack is in use, the resulting transformation is undefined. For compatibility reasons, the deprecated OpenGL matrix stack shall be used, if available, when modelview is omitted. In all cases, the state of the OpenGL matrix stack shall be retained.
"projection" is an optional parameter that can be used to specify a custom text projection. It is applied after text layout, during text rendering. For compatibility reasons, the deprecated OpenGL matrix stack shall be used, if available, when projection is omitted. If projection is omitted and the OpenGL matrix stack is not available, the following orthographic projection shall be used: (top, left, right, bottom, zNear, zFar) = (0, 0, viewport width, viewport height, -256, 256). If projection is not omitted, text will be projected by the specified matrix. In all cases, the state of the OpenGL matrix stack shall be retained.
Questions
#2
I think this is good start.
How do you define word wrapping and clipping?
I don't know a good answer to your question; I would guess the guys that have done extensive GUIs using TextPrinter / other APIs have ideas here.
But I am still hesitant on the approach of "bottom up"; by that I mean we are still discussing APIs instead of discussing use cases. What functionality should the TextPrinter of OpenTK support? I have found it fruitful to divide "wish list items" into "must have", "could come later" and "nice to have". If the ppl most interested in the TextPrinter functionality could step forward and divide their wishes into such categories, we could then move on to how to build a nice and natural API for the "must have" cases first.
#3
How do you define word wrapping and clipping?
Good catch.
The above design is a slightly more flexible version of
System.Drawing.Graphics.[Draw|Measure]StringAPI. While low-level, it should allow you to render formatted text (with colors, fonts, styles, etc) with relatively little work. That's the idea, at least.How do you use the API?
#4
That's the thing, I've never come around to using the text functionality more than to write FPS-text or simple labels above planes, or similar simple cases. For that it has worked quite alright, albeit with some visual artefacts (but this was like beginning 2008 so it is probably much better now).
Could we maybe collect use cases so far from the forums?
#5
I wonder if just taking a texture to print on and returning the bounding box for the text positioning on that texture would be a good addition to the text printer function.
I'm thinking something like:
This would allow the user to then draw the text as a quad anywhere they wished, in any manner they wished, applying blending and matrix translations however they desired.
Obviously boundingBox would have to be <= the size of the texture, which would expect some common sense from the user.
The returned TextExtents should allow the user to easily create any texture coordinates, and indeed taken to an extreme the TextPrinter class could be used to create a sheet of characters for the user to create their own text printing techniques from, using the returned GlyphExtents (unless I'm reading the TextExtents class wrong).
Good/bad idea?
#6
Objarni already started a list here http://www.opentk.com/node/418
* Debugging (headsup, smallish, easy-to-read)
* In-game consoles (headsup, smallish, easy-to-read)
* GUI-widget text (headsup, eyecandy)
* Credits / high score (headsup, eyecandy)
* Decals/info on walls in 3d environments (FPS-games etc.)
* Demo-effects (Star Wars scrolling..)
* In-game entitity info (ontop of NPC's heads etc.)
* In-game message-boxes/chat (RPG games etc.)
#7
@Inertia: great memory!
Other than decals, the new API covers everything else. Decals can be done in two steps: render to texture and use the texture as a decal.
@Mincus: Just use a regular FBO:
Trying to add render-to-texture support to the TextPrinter would introduce a host of new problems that have nothing to do with text printing itself:
Nope, won't work. If you need render-to-texture, just redirect the TextPrinter to a FBO. :)
#8
If all those cases in my old list will be covered, we have come far. Actually, writing a tutorial (or several) on how to do those things i OpenTK, would be a good way to document it (maybe we could even write the tutorial collaboratively, to "explore" what API to have..?)
#9
@Fiddler: Ok, that's all good then. :o)
I just thought if the text was rendered to a texture internally anyway then that was placed on the screen, in which case providing the user with that texture directly would be an easy solution, I see now that's not the case and the FBO idea makes more sense.
That means that objarni's list (as it currently stands) all seem to be covered. Once you have the text in a format like that you can do anything you want with it from what I can see.
#10
The current also API fails with text markup , due to the lack of an "advance" parameter. The issue is that different styles belong to different text runs and there's no way to start a new text run at the exact location where the previous one ended.
The new, Pango-based engine works great here (understatement: it actually blows GDI+ out of the water API- and quality-wise). I'm now searching whether you can specify the text advance in GDI+.
#11
What dependencies would Pango bring in..? A native .dll/.so for each operating system? Or is it .NET based? Maybe even open source so it could be compiled into OpenTK.Utilities.dll?
#12
Pango is native C code LGPL licenced. So linking statically against it would require to change OpenTK licence. Distributing DLL for windows also will be not easy - it has a lot of dependencies (glib/cairo/...) which doesn't allow linking statically so easy.
#13
Regarding tutorials we have a FBO example in OpenTK and the book contains a rather verbose description of the FBO extension. If this is not sufficient to get you to print some text - instead of the random triangles - into the texture it would help if you tell where you got stuck, so either the example or the tutorial can be enhanced.
Just for the record, I totally agree that TextPrinter should not deal with FBOs or PBOs. Binding a framebuffer is a rather expensive operation (which does not mean it should not be done, but rather it should be done as seldom as possible) and the application programmer can usually chose a logic that suits his application alot better than a generic solution could. Afaik the best course of action is to bind multiple (target) textures to the FBO color attachments at the same time and use GL.DrawBuffers() to select them one after the other to write text into them.
#14
The tutorial idea was for the TextPrinter itself, not FBOs.
#15
Hmm, it seems Pango and .Net itemize strings differently (the measured TextExtents contain a different number of clusters than the string they originated from). Nice.
We could go down to the character level where the counts match, but this only works for simple latin scripts. The other solution is to refactor the data structures and move glyph/cluster information to the TextExtents - which means a lot of duplication. Even nicer.
#16
Alright, fixed this issue. Now implementing the new public API for testing.
#17
The TextPrinter project will be spun off from the main OpenTK distribution. Maintainers wanted.