|
[OpenLayer] TextRenderer::getHeight() |
tobing
Member #5,213
November 2004
|
Currently I'm trying to make an OpenLayer-guichan addons that displays TTF fonts in guichan. To do this correctly, I need to find the height of the font, so I'm currently using TextRenderer::GetHeight(text) for this, which unfortunately does only give me the ascending height, not including what is below the baseline (I hope the wording is correct, I'm not a specialist in fonts). So if the TTF has characters which are drawn below the baseline, the given height is too small, resulting in clipped text output and widgets that are not high enough to hold the complete text. How should this be done correctly? |
Kirr
Member #5,060
September 2004
|
I don't know how OpenLayer is doing it. But just in case it is relevant, Glyph Keeper's height functions return complete height, which includes both ascender and descender. (Assuming the TTF font has correct data there). The functions are: gk_char_height(), gk_text_height_utf8(), gk_text_height_utf16() and gk_text_height_utf32(). -- |
tobing
Member #5,213
November 2004
|
I'm using OpenLayer with its own native handling of TTF, because the last time I tried with GlyphKeeper 0.29a or so, it didn't work properly. Essentially, OL uses the freetype functions directly, but as I said, I'm not an expert with fonts. Maybe I'll try to find out, or peek into GK to see how you do it (you're also using freetype, right?)... Edit: Got it. I've added a function to ol::Glyph that returns the total height, ascending + descending, that I can later call from my program. Here's the code, in case the developers are interested in adding it: In Glyph.cpp: int Glyph::GetTotalHeight() { return size.height * (face->height)/(double)(face->units_per_EM) + 1; } to ba called like this in client code: return text_rend_.GetFace()->glyphFace->GetTotalHeight(); Well, the prototype of that function has to be added to Glyph.hpp as well. With that function added to OpenLayer, the following class provides TTF support for guichan, and I would really like to submit it as an addon there:
|
juvinious
Member #5,145
October 2004
|
I suppose I can just add that to getHeight as that would be needed regardless for measuring height accurately. Then there would be no need to access the glyphFace directly, because that would be incompatible if somebody was using glyphkeeper instead of the internal renderer. [edit] __________________________________________ |
Matthew Dalrymple
Member #7,922
October 2006
|
OL Manual said:
TextRenderer( You have to know the height you want when loading a font so can't you just use the variable in the parameter pass for knowing the height? And if you didn't use a variable in the parameter pass then the default would be 12. It's not as convenient as a Height() method but storing that value should work for now, shouldn't it? Edit: Wait TextRenderer has a Height() method... I'm confused so disregard this post. =-----===-----===-----= |
tobing
Member #5,213
November 2004
|
You need both functions, the TextRenderer::Height() which usually returns the height parameter given in the Load function, and the additional function, that returns the total height, which can be slightly larger, depending on the particular font loaded. Of course, if the glyph face doesn't have the data, the total height would be the same as Height(), you can't do better than, or need not, because the font does not descend below the baseline. |
juvinious
Member #5,145
October 2004
|
Regardless, the problem like I said before is that if a person were to be using OpenLayer with GlyphKeeper then it would be incompatible. The textRenderer class relies on the glyphkeeper api. I made a wrapper for the glyph class so that it's compatible with textrenderer. Thus in the event that the user has openlayer compiled with glyphkeeper, your text_rend_.GetFace()->glyphFace->GetTotalHeight() would be undefined as GLYPH_FACE in glyphkeeper doesn't have a glyphFace. __________________________________________ |
tobing
Member #5,213
November 2004
|
That's of course correct. So if OL uses GlyphKeeper (I guess I'll try that again with the current version of GK) then the required function has to be implemented in a different way. So it would be good to add the new function to the TextRenderer, and implement it accordingly. Edit: I have not tried to get OL (SVN) to work with GK (0.32), but it simply does not render fonts correctly. Nevertheless I made some changes to get my OpenLayerTTFont class to work (with OL-GK) and compile (with OL+GK).
of course, the prototypes of the added functions have to added to the corresponding classes TextRenderer and Glyph. I would send this, or a patch to the OpenLayer devs mailing list, but my mails are not accepted and waiting for approval by an administrator, so I can't send changes or proposals that way, sorry. Edit 2: Finished AllegroTTFont class, using GK this time. Really neat, and gave me some insights I'd like to mention here. First, using GK functions for rendering without using a GLYPH_KEEP object is really slow. So it's a very good idea to use a GLYPH_KEEP object for a font in use. Second, comparing the speed of drawing text to the display, I found that OL (using its own rendering functions) is comparingly slow, about the speed I had with GK without GLYPH_KEEP. Debugging into the TextRenderer::Print function shows that there's quite a lot of potential for optimization, so that's what I'll do next. |
juvinious
Member #5,145
October 2004
|
Ok, I'll need to test this with both GK and without, do you have something to test whether they work properly perhaps the guichan font class? In the meantime, I'll go ahead and implement this in my working copy and play around with it. [edit] __________________________________________ |
Kirr
Member #5,060
September 2004
|
tobing said: First, using GK functions for rendering without using a GLYPH_KEEP object is really slow. So it's a very good idea to use a GLYPH_KEEP object for a font in use. Right. Glyph cache is there for reason. With cache the speed of Glyph Keeper's text rendering is comparable to Allegro's built-in fonts (often even faster for me actually). That, with antialiasing, transparency, bold, italics, angles, etc.. Glyph Keeper comes with bunch of benchmark programs, please use them to measure the speed in the rendering mode you are going to use. One comment. Since 0.32 Glyph Keeper supports creation of Allegro's native FONT objects (with Allegro vtable). Can they be used more easily with AllegroGL / OpenLayer? Theoretically this would not need any direct interaction between OpenLayer and Glyph Keeper. I would appreciate any testing and particularly if someone could write a simple examlpe program. -- |
tobing
Member #5,213
November 2004
|
juvinious: Thanks for your kind words, hopefully you can resolve this mailing list issue. I had written a mail to fladimir directly about this, but didn't receive any answer. Well, I'm wondering if I happened to offend anybody, but I have no idea and certainly didn't mean to. If my suggestions, comments or improvements are not welcome, just let me know and I'll keep quiet about OpenLayer. For the optimization, I think it's not a very small change, somehow the TextRenderer::Print has to be re-worked completely. The problem is, this function is quite general and can do many things, so specialized functions that can do less faster will probably help very much in increasing speed. Currently, there are many instances of string which are copied, substr'd, converted to char* and back again, so I think much of the performance loss is due to frequent copying and allocating string memory. I'll try to make a small example to play around with, probably I'll just take the openlayerwidget example of guichan and copy the new font class into that, I'll post this here when I get it complete (weekend has priority...). Kirr: How do you make this FONT conversion? Is there an example? I guess I might try to create a FONT-wrapper class for use with guichan, so this way would be very nice to test that. |
Kirr
Member #5,060
September 2004
|
tobing said: Kirr: How do you make this FONT conversion? Is there an example? I guess I might try to create a FONT-wrapper class for use with guichan, so this way would be very nice to test that. Function gk_create_allegro_bitmap_font_for_range() does this conversion. It is used in "examples/test_alleg.c" and "benchmark/bench_gk_convert_2_alleg.c" example programs. (In Glyph Keeper 0.32 source distribution). All testing reports are very much welcome, because I did not test it very much. Mostly I tested it in the benchmark program. -- |
juvinious
Member #5,145
October 2004
|
Well I'll figure out what's going on in regards to the mailinglist, I don't have full admin access to the openlayer project, only svn and shell. I'll need to get in touch with flad about it, however I think the dev mailinglist is only accepting on invite only which could be the problem. __________________________________________ |
tobing
Member #5,213
November 2004
|
Kirr: Thanks for the hint, maybe I'll test my AllegroFont guichan wrapper class with that, depends on if I have the time to do that. Anyway, using GK with allegro is really neat. juvinious: I'll attach my current versions of the Glyph.* and TextRenderer.* files, with the additions I would need to make the OpenLayerTTF guichan wrapper class work. Thanks for all your help so far, and for this in advance. In general, I must admit that I'm a little tired of trying to get suggestions and improvements to the OL library to the dev team, as I feel that my input is not really welcome. My hobby programming time is quite limited, so I have to decide on what to spend it, and it will be my own game of course. So I'll stop trying to submit my changes, as my mails to the ol-dev mailing list are rejected, and direct mails are ignored. If anyone is interested in my corrected and anhanced version of OL, just contact me directly, I'll happily share my sources. This holds especially for people who are interested in getting guichan + OL to work, I have been through setting up all required stuff (on Windows, using MSVC), and it's not easy. Thanks again for all help so far! |
juvinious
Member #5,145
October 2004
|
Well it is due to the fact that the person who set up the mailinglist last year just upped and dissapeared. I don't have access to manage the mailinglist nor most of the rest of the project on berlios else I would correct these issues. As far as it goes with devs for openlayer, it is mostly Fladimir but he only works on it when he has time himself. I've been assisting partly for some time now trying to help get more community support and involvement, which in turn your work and suggestions are greatly appreciated. As soon as I can get a fix on the mailinglists I'll let you know. [edit] __________________________________________ |
tobing
Member #5,213
November 2004
|
Thank you very much, juvinious, I'll check it out as soon as I come home later. Edit: Got everything from the depot, works fine, and thanks again. Now I started to look deeper into the TextRenderer.Print method, replaced some const std::string& by const char*, then I implemented a new function Glyph::renderFixed(double x, double y, const Rgba& col, Bitmap bmp, int alignment, const char text) consisting of the second half of the original render function and finally ended up in Glyph::drawCharacter. Before going into detail, the summary is: Drawing is faster, but not fast enough. First observation. Look at the code of renderFixed, which is just the second half of the original render function:
I have commented the part involving previous and next, because both being always zero, the code is never executed. Maybe this is obsolete stuff that should be removed? Second observation. Below the code of drawCharacter with comments. Some consts have been added, but that's of course not relevant to performance.
I'm not sure about how to get rid of the color conversion in the innermost loop, I don't understand what this really is supposed to do. Anyway, for the last observation, look at the code of colorConvert. The origianl version of this function was using the rgba(int,int,int,int) constructor, which in turn converted the arguments to float, so I replaced the code by the equivalent, using the correct constructor directly: Rgba colorConvert(const unsigned char *c,short ext) { const float component = *c / (float)(ext-1); return Rgba(component, component, component, component); } All these changes have been made to Glyph.hpp and Glyph.cpp, so should I attach the current files? The most relevant things are already contained in this post. In summary, while there's definitely some improvement, there will be more performance gain if the glyphs are somehow cached, but I guess that this depends on the current colors? Here, OL works a little different from GK (as far as I understand it), but it may be possible to use caching of already (pixelwise) drawn characters to blit the character when it's drawn the second time. |
juvinious
Member #5,145
October 2004
|
Quote: I have commented the part involving previous and next, because both being always zero, the code is never executed. Maybe this is obsolete stuff that should be removed?
Oops you know what that's a typo, they should be set to 1. If the face has kerning capabilities you want to add those details when drawing the characters so that their spacing is proportional and nice. [edit] __________________________________________ |
tobing
Member #5,213
November 2004
|
That's what I was thinking after reading and stepping through that code. Not easy to apply any caching, so maybe we just leave it so for the moment. Quote: I read it wrong, why use a const char * ... use c++ strings. I use const char* to avoid copying std::string objects, or implicitely creating such, as it happenend on the way from TextRenderer.Print to Glyph.render for example. Finally, only a const char* is needed, and most of the time, the string is not changed in any way, so passing around const char* is the fastest you can do. Having a mix of const char* and const std::string& makes the compiler generate implicit conversions, and that means creation of temporary objects. Ah, the formula Quote: (red * 0.30 + green * 0.59 + blue * 0.11) simplifies a little, because in that situation, r,g,b are all equal. So this would become red * (0.30+0.59+0.11) which is red * 1.0. |
|