PDA

View Full Version : First impressions about ClanLib 3.0 (and a bunch of questions)



Pap
09-13-2013, 04:56 PM
Hi all,
Being about to start a large project, I decided to switch to ClanLib 3.0 (even though it is still beta.) Better to switch early than having to modify a long code later - not to mention that might help ClanLib developers to eliminate some bugs or whatever. :o
First impressions about version 3.0 are mostly positive - although converting existing code from 2.3.7 to 3.0 is not an easy task, mainly because it seems many things are changed. Documentation is limited, so I had to experiment a lot, guessing why existing code that used to work in 2.3.7 doesn't work on 3.0 and what needs to be modified. For example, the new way of declaring font formats is better compared to the old cl_format, but I needed quite some time to figure out how clan::StringFormat works. The consequences of using a (mostly undocumented) beta version, I guess...

Anyway, I got some questions that I can't figure out without further documentation (beware, more to come as I keep modifying my 2.3.7 codes to work in version 3.0 ;))

(1) When I compile any ClanLib-based code, g++ is complaining, giving 8 warnings concerning ClanLib/core.h, specifically half_float.h:

/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h: In static member function ‘static float clan::HalfFloat::half_to_float_simple(short unsigned int)’:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h:85:48: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
(and 7 more similar warnings.) Of course, I can get rid of the warnings if I add the Cflag -Wno-strict-aliasing after -Wall but I'm not sure it's safe to allow non-strict aliasing. Note that strict aliasing rule used to work in 2.3.7, and I get no warnings at all using g++ -Wall to compile 2.3.7 code.

(2) I'm not sure why Canvas was introduced, and what's the difference comparing to a GraphicContext. Furthermore, I don't get why clan::Font::resource() requires a Canvas as its first argument, while the corresponding method for sprites, namely clan::Sprite::resource(), requires a GraphicContext as its first argument. What's more confusing is the fact clan::Font::resource() gives a compiler error if I provide a GraphicContext as its first argument, while clan::Sprite::resource() is still working with a Canvas object, although documentation mentions only GraphicContext is allowed. Note that Breaking Changes says "fonts, images and sprites now use the Canvas class". :crazy:

(3) I also have another problem concerning fonts. In ClanLib 2.3.7, you can load a font which is not installed in your system (very useful feature for distributing your work to others who don't have to install specific fonts in their system.) For example, I used to load fonts using a resource file, like that:

CL_ResourceManager resources("resources.xml");
CL_Font_Freetype message_font("message",&resources);
where resources.xml is something like

<resources>
<sprite name="rectangle">
<image file="rectangle.png">
</image>
</sprite>
<font name="message">
<freetype file="DejaVuSans.ttf" height="30" average_width="0" anti_alias="true" subpixel="true"/>
</font>
</resources>and the ttf font, in this example DejaVuSans, is in the same directory as resources.xml. This doesn't seem to work anymore; I am able to use fonts installed in my system, but nothing else. The new way to use font descriptions in resource files seems to be (correct me if I am wrong)

const clan::ResourceManager &resources=clan::XMLResourceManager::create(clan::X MLResourceDocument("resources.xml"));
clan::Font message_font;
message_font=clan::Font::resource(canvas,clan::Fon tDescription("message"),resources);but it doesn't let you load specific fonts (the file attribute in resources.xml seems to be ignored; unfortunately, clan::FontDescription() only accepts a typeface name as its argument, so the font description named "message" in my resource.xml file is interpreted as a typeface name. I looked at all the examples shipped with ClanLib 3.0, but none of them uses xml resources to describe fonts (only sprite fonts, which is a different story), and none of them uses font loading. So it seems impossible to load fonts from ttf (or otf) files, and all you can do is to use fonts installed in the system.

Note that the sprite description in the above xml file works as expected, but the font description is ignored as it is; furthermore, even if I change resource.xml so that it describes a font installed in my system, parser seems to ignore the height attribute, and I get a microscopic font of height 1. So I have to give up using font descriptions in resource files and describe fonts in the code itself (much less convenient), and that only for fonts installed in my system. :mad:

It seems fonts in version 3.0 lack the (very useful) feature of font loading, or, most probably, I am missing something important here.
Sorry for wasting your time, but I have no clue what am I doing wrong here, after looking up in the doxygen documentation, and all examples in the ClanLib 3.0 folder. Needless to say any help concerning the above questions is much appreciated :)

Note: using g++ version: 4.7.3 (Debian 4.7.3-4) on a Debian 8 64-bit system (no 32-bit libraries installed at all.)

rombust
09-13-2013, 08:20 PM
I switched to ClanLib 3.0 about 2 months ago. Working with it, is a delight.

First thing to ask, are you using the git version of ClanLib? (git clone https://github.com/sphair/ClanLib.git ). The download version on the web site is missing lots of linux fixes.

Although the web pages classify ClanLib 3.0 as Beta, we all use it. I personally prefer all examples and tests fixed before taking it out of beta.

To port from ClanLib 2.3.7 to ClanLib 3.0.0, I use 6 main steps (in order).
1) Rename CL_String and CL_StringRef to std::string
2) Rename CL_SharedPtr to std::shared_ptr
3) Rename cl_format to clan::string_format
4) Rename CL_* prefix to clan:: prefix
5) Rename cl_ prefix to clan:: prefix
6) For 2D work (without using shaders) - Rename clan::GraphicContext &gc to clan::Canvas &canvas

Then manually fix the remaining parts (see breaking changes)

If I run into difficulties, I compare the 3.0 examples with the 2.3.7 looking at how they change.

Point 1) g++ is complaining, giving 8 warnings
I don't know without looking at the source. (I have not got time today)

Point 2) Why Canvas?
The old GraphicContext had a problem when using it for 3D or 2D using custom shaders. There was an overhead of maintaining clanDisplay 2D implementation (eg modelview and batching) whilst considering the state for 3D. Using ClanLib for 3D games, this overhead was unnecessary.

So GraphicContext was split up. Canvas contains the batchers, modelview matrix and the standard shaders.

Why some functions in Sprite's still contain GraphicContext? Well ... Because it works ;) Another developer said it should be changed to avoid confusion.
The Canvas contains a GraphicContext, and there is an operator to automatically return it.

Point 3) Fonts
Loading custom .ttf fonts via a resource file should be there, but it appears it is missing! I cannot see how to load any font via a resource file.

This needs looking at.

Pap
09-13-2013, 10:53 PM
Thank you for letting me know about those things rombust. :hat:

Actually, I avoided development version so far, because in the GNU C++ on Linux (http://clanlib.org/build-environment-linux-gcc.html) webpage it explicitly says "not recommended at the moment on Linux". However, after your post here, I switched to git version. Unfortunately, everything concerning the g++ warnings and the ttf font loading via xml resources remains the same: works as expected in 2.3.7 but not at all in 3.0 - or version 3.0 needs something more in order to load ttf fonts via xml resources, which I'm not aware of.

Judas
09-14-2013, 01:12 AM
Thanks for trying out 3.0. :)


For example, the new way of declaring font formats is better compared to the old cl_format, but I needed quite some time to figure out how clan::StringFormat works.

clan::string_format (named cl_format previously) is actually just a template wrapper around clan::StringFormat. Only difference here between 2.3 and 3.0 is that it was renamed.



(1) When I compile any ClanLib-based code, g++ is complaining, giving 8 warnings concerning ClanLib/core.h, specifically half_float.h:

/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h: In static member function ‘static float clan::HalfFloat::half_to_float_simple(short unsigned int)’:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h:85:48: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]


Looked into this and discovered it is caused by a direct cast from float* to uint*. Supposedly one has to first cast to void*, which I now added, and hopefully that should silence the warning.


(2) I'm not sure why Canvas was introduced, and what's the difference comparing to a GraphicContext.

The main rationale behind creating a new class for the 2D drawing is to cleanly separate the lower level GPU API (GraphicContext) from our batch-accelerated higher level APIs (Canvas, Sprite, Font, etc). Perhaps the best comparison is Direct2D, which also layers itself on top of Direct3D. One of the biggest problems with the 2.x series of ClanLib compared to 1.0 was that we lost our easy 2D APIs in the process of supporting complex 3D apps, and Canvas is the first step in getting back there.


Furthermore, I don't get why clan::Font::resource() requires a Canvas as its first argument, while the corresponding method for sprites, namely clan::Sprite::resource(), requires a GraphicContext as its first argument

Long term the plan is that all 2D things will always work with Canvas (including those functions you mentioned) and along with that add additional features like shader post processing steps, path stroking and so on. In other words, it will stop being possible at some point to use a Sprite or the general 2D Font objects without a Canvas, and therefore those functions you listed will eventually all require a Canvas argument.

The fonts are currently the biggest problem with executing this plan, as our current font objects can't really make up their mind for what they should be used for. What happened in 2.x was that our fonts weren't sure if they should be bitmap truetype fonts, vector truetype fonts or sprite fonts. And whether they should be usable in 3D context or not. At some points the font classes needs to be adjusted:

1) Merge our different font types at the API level. I don't think there are any good reasons for why we expose so much of the implementation. A few extra constructors just on Font should be enough.
2) Render fonts in vector mode with the path stroking functions.
3) Create a low level font class type which allows you to generate bitmap glyphs and assist in cursor movement.
4) Create a low level font class type which allows you to generate vector glyphs, maybe with 3D shape support.

The current font classes try to be both 1, 2, 3 and 4 at the same time.

Personally I wouldn't mind if we already changed all the font constructors to use a Canvas already now. To my knowledge there's no actual applications using fonts without a Canvas currently, except maybe for one example or two (nuke them from orbit :nuke: ;) ).

I'm sure rombust may have an opinion on this subject. :)


Note that the sprite description in the above xml file works as expected, but the font description is ignored as it is; furthermore, even if I change resource.xml so that it describes a font installed in my system, parser seems to ignore the height attribute, and I get a microscopic font of height 1. So I have to give up using font descriptions in resource files and describe fonts in the code itself (much less convenient), and that only for fonts installed in my system. :mad:

Sounds like a rather nasty bug. Probably should be fixed. :)

- - - Updated - - -

Just noticed you said Sprite::resource() was taking a GraphicContext rather than Canvas (as opposed to Font::resource()). There is no good reason for that and it should be changed. You can't even render a Sprite with a GraphicContext AFAIK.

rombust
09-14-2013, 08:28 AM
I personally really like the 2.3 API for fonts, and the basic 3.0 API is still the same.

clan::Font is the base font. It only draws text. Nice and simple

clan::Font_System is the TTF based font. This contains a couple of extra things to extract the glyphs (for use with custom shaders)

clan::Font_Vector is an outline/triangle based TTF font. You can place custom textures onto the font face.

clan::Font_Sprite is a texture based font.

Font_System, Font_Vector and Font_Sprite all inherit clan::Font.

This works beautifully.

However, in my opinion, something went wrong with the API with respect to resources.

This function should load any font from the resources


static Resource<Font> clan::Font::resource(Canvas &canvas, const FontDescription &desc, const ResourceManager &resources);

But there is no code that I can see where you can define the typeface filename in the resources.

Also the current API does not allow loading of a font from resources to a specific requested type (with the exception of clan::Font_Sprite::load with the obscure API)

Pap
09-14-2013, 10:42 AM
clan::string_format (named cl_format previously) is actually just a template wrapper around clan::StringFormat. Only difference here between 2.3 and 3.0 is that it was renamed.
I actually was not aware that cl_format still exists as clan::string_format, so I guessed it was gone. Luckily, lack of knowledge about that forced me to find another way: I now declare the format string as, say, clan::StringFormat example("Step: %1") and update it in the rendering loop with the set_arg() method, say example.set_arg(1,clan::StringHelp::float_to_text( step,2)). This seems more clear to me.



Looked into this and discovered it is caused by a direct cast from float* to uint*. Supposedly one has to first cast to void*, which I now added, and hopefully that should silence the warning.I just re-downloaded git version and the warnings while compiling code are still there. For clarity, I post all those warnings when compiling with the -Wall flag here:

In file included from /usr/include/ClanLib-3.0/ClanLib/core.h:195:0,
from Application.hpp:3,
from Application.cpp:1:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h: In static member function ‘static float clan::HalfFloat::half_to_float_simple(short unsigned int)’:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h:85:63: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h: In static member function ‘static short unsigned int clan::HalfFloat::float_to_half_simple(float)’:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h:91:80: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h: In static member function ‘static float clan::HalfFloat::half_to_float(short unsigned int)’:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h:98:63: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h: In static member function ‘static short unsigned int clan::HalfFloat::float_to_half(float)’:
/usr/include/ClanLib-3.0/ClanLib/Core/Math/half_float.h:103:80: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]

g++ -O2 -std=c++11 -Wall -pthread ../Game.o ../test.o `pkg-config --cflags --libs clanCore-3.0 clanDisplay-3.0 clanApp-3.0 clanGL-3.0 clanSWRender-3.0` -o ../test
where Application:hpp:3 is just #include <ClanLib/core.h> (of course, warnings are repeated one more time in Application.cpp because it includes Application.hpp.)
I am guessing git version is not a "nighty build", and I should wait for updated git announced here (http://www.rtsoft.com/forums/showthread.php?18476-ClanLib-3-0-Beta&)?



The main rationale behind creating a new class for the 2D drawing is to cleanly separate the lower level GPU API (GraphicContext) from our batch-accelerated higher level APIs (Canvas, Sprite, Font, etc). Perhaps the best comparison is Direct2D, which also layers itself on top of Direct3D. One of the biggest problems with the 2.x series of ClanLib compared to 1.0 was that we lost our easy 2D APIs in the process of supporting complex 3D apps, and Canvas is the first step in getting back there.Fair enough... Thank you for clarifying the topic. :)



Sounds like a rather nasty bug. Probably should be fixed. :)
Actually, as it is now, clan::Font::resource() has no way to know what is the element in the xml file that corresponds to the font description it should read, because its syntax is

clan::Font::resource (Canvas &canvas, const FontDescription &desc, const ResourceManager &resources)
Second argument is a font description, not a resource id; this makes the method useless - unless I am missing something here. Compare to the sprite version of the resource method, which works as expected:

clan::Sprite::resource (Canvas &canvas, const std::string &id, const ResourceManager &resources)
Here, second argument is a resource id string, so the method knows it should read the corresponding element in the xml file. In contrast, resource method for fonts has no way to know that information, and whatever it is included in the xml file seems to be silently ignored; you end up with the default font of height 1.
In 2.3 versions, there used to be a CL_Font_Freetype class, which worked as expected:
CL_Font_Freetype (const CL_StringRef &resource_id, CL_ResourceManager *resources)
I could not find something equivalent to the old CL_Font_Freetype class though, and it's probably not needed, provided clan::Font::resource() is fixed so that its second argument is const std::string &id (and treated as such,) just as in clan::Sprite::resource() (same for clan::Font_Vector::resource(), where the same issue appears.)



Just noticed you said Sprite::resource() was taking a GraphicContext rather than Canvas (as opposed to Font::resource()). There is no good reason for that and it should be changed. You can't even render a Sprite with a GraphicContext AFAIK.
Indeed, both clan::Sprite::resource(canvas,"sprite_description",resources) and clan::Sprite::resource(gc,"sprite_description",resources) are currently accepted by the compiler and both work in runtime. I modified all sprite resource loading instances to the Canvas version. I guess doxygen documentation should be updated, as it still mentions only the GraphicContext version, which is obviously obsolete.

Judas
09-14-2013, 01:36 PM
I just re-downloaded git version and the warnings while compiling code are still there.

Oh well, I am not sure then how to access the bits of a float safely without GCC complaining. A stack overflow link said this should have worked, but apparently not.


Actually, as it is now, clan::Font::resource() has no way to know what is the element in the xml file that corresponds to the font description it should read, because its syntax is

clan::Font::resource (Canvas &canvas, const FontDescription &desc, const ResourceManager &resources)
Second argument is a font description, not a resource id; this makes the method useless - unless I am missing something here.

The biggest differences between 2.3 and 3.0 with regard to resources are that a resource in 2.3 is always: 1) declared in a XML file, 2) all resources are identified with an id, 3) no proper support for caching.

Most resources are identified by a name/id, but fonts deviate from this practice for several reasons. Fonts are different in the sense that a font belongs to a family (normal weight, bold, italic, light, height, etc) and therefore in a typical font system is identified by a range of properties (FontDescription in ClanLib), which a font mapper then uses to find the closest match.

Just like the @fontface rule in CSS fonts, the idea in 3.0 is that the resource system (the DisplayCache implementation) is responsible for acting as the font mapper. The main difference being that the font mapping practice in CSS fonts are governed by @fontface declarations, while the default XML backend in ClanLib uses xml elements.

In case you haven't played much with custom CSS fonts, the way it works there is that you can declare multiple different fonts for the same family. For example, you could make a rule saying it should use font A for normal weighted fonts, and font B to bold fonts. By extending this principle to ClanLib, the intention in 3.0 is that you might have 4 different sprite fonts, i.e. normal, bold, large normal, large bold. Then by making the proper XML declarations you can use the same font family for them all, with the bold flag and height values as the selectors for which of the 4 fonts are actually used.

I have kept this somewhat vague without examples because the truth is the XML font backend hasn't really been updated yet to support this well. Only the frontend part (Font::resource and DisplayCache) look like they are meant to.

Pap
09-14-2013, 02:18 PM
Oh well, I am not sure then how to access the bits of a float safely without GCC complaining. A stack overflow link said this should have worked, but apparently not.
I will try with Intel and Oracle C++ compilers (the latter is built-n with Oracle Studio 12.x,) but, if I were to guess, and judging from past experience, I'd say they will both complain as much g++ does, provided the -Wall compilation flag is used (which I use in every application so far.) More news about that in 1-2 days.



In case you haven't played much with custom CSS fonts, the way it works there is that you can declare multiple different fonts for the same family. For example, you could make a rule saying it should use font A for normal weighted fonts, and font B to bold fonts. By extending this principle to ClanLib, the intention in 3.0 is that you might have 4 different sprite fonts, i.e. normal, bold, large normal, large bold. Then by making the proper XML declarations you can use the same font family for them all, with the bold flag and height values as the selectors for which of the 4 fonts are actually used.I have limited experience with CSS, just as much I needed for simple webpage development with little javascript support, but I get the point and, indeed, sounds better and more flexible than the 2.3 implementation. Looking forward to see it implemented. :)



I have kept this somewhat vague without examples because the truth is the XML font backend hasn't really been updated yet to support this well. Only the frontend part (Font::resource and DisplayCache) look like they are meant to.
I suppose that means I should forget xml resources as a way to describe fonts (for now.) I exclusively used this method in 2.3.x to describe fonts (be it fonts installed in the system or - even better - custom ttf fonts loaded from files,) pretty much like sprites and everything that can be declared there. Of course, as a temporary workaround, I could still use an external xml parser to do that, such as pugixml (http://pugixml.org/) which I liked a lot for its simplicity and convenience in use. But there is no reason to get external parsers involved, since, if I understand well, ClanLib will offer a better solution once the xml resource functionality for fonts is restored (and expanded) in version 3.0.

Judas
09-14-2013, 03:01 PM
clan::Font is the base font. It only draws text. Nice and simple

I agree, no complaints there.


clan::Font_System is the TTF based font. This contains a couple of extra things to extract the glyphs (for use with custom shaders)

Except that the glyphs are offered to you prepackaged in textures, designed and useful only for the purpose of doing what Font is already does / supports. All you are offered is a view into the objects used by Font_System to implement the Font interface.


clan::Font_Vector is an outline/triangle based TTF font. You can place custom textures onto the font face.

Once again the devil is in the detail. While you can use a custom texture, try something slightly more complex like wanting to restart the texture for each glyph and line. Likewise using a vector font to render a font with a black outline and a pink inner filling is not really realistic.


clan::Font_Sprite is a texture based font.

For almost all points and purposes a sprite font and a bitmapped truetype font (aka Font_System) behave identical - the only difference is where they got the glyph data from. If they behave alike, why have different (API level) classes?


Font_System, Font_Vector and Font_Sprite all inherit clan::Font.

This is actually my main complaint about the system. There are actually only two types of fonts: bitmapped and vector. And while they do have a lot in common, they also differ in significant ways.

The differences are bit like TCPConnection vs TCPListen vs UDPSocket. They all have socket options, read/write features and eventually send or consume IP packets. However the semantics and what is allowed and/or useful differ enough in subtle ways that IMO it makes more sense to present them as individual classes tailored for specific use cases. Having a base Socket class is IMO not useful. It obviously isn't as clear cut in the Font case, but in general you use vector fonts for something different than bitmapped fonts.

You can generally split fonts and their glyphs into three categories:

1) Font metrics and ABC widths for glyphs. Since those can be hinted, the metrics actually depends on the actual size you intend to render them, both for bitmapped and vector glyphs. This is why all sizes in the Win32 font API are in logical units, as they are hint-adjusted. This makes moving the cursor common for all font types and probably justifies a base class.

2) Bitmap glyph rendering. Exists in a few different variants: monochrome, anti-aliased, and sprite frames. In an ideal implementation the glyph bitmap generating would take the Canvas scaling into account (as GDI does), but supporting this will probably be a pipedream for the time being.

3) Vector glyph rendering. Usually rendered hinted, used as input for stroke path, fill path or complex clipping regions. Alternatively used in 3D as either a 2D path, or glyphs extended into 3D.

What I ideally want to have is that the System and Sprite font classes are merged at the API level, and their specific implementations sealed off. There are a few use cases where retrieving glyph bitmaps is useful (the original Pacman exploding font effect, for example), but exposing the actual implementation also means we can't change it. This is especially a problem for the System backend if it is ever to generate its glyphs more cleverly.

As for vector glyph rendering, I think this variant should only really be used as input for pathing functions. Uploading the vector data to the GPU as we are doing today is way too limiting. I think it would be better then to have the path functions able to return vertices for an app wanting this.

Not that any of this is actually going to happen. Too lazy to put my coding where my mouth is. :)


This function should load any font from the resources


static Resource<Font> clan::Font::resource(Canvas &canvas, const FontDescription &desc, const ResourceManager &resources);

But there is no code that I can see where you can define the typeface filename in the resources.

Yep, the XML resource backend needs its font xml nodes updated so you can do proper font declarations.


Also the current API does not allow loading of a font from resources to a specific requested type (with the exception of clan::Font_Sprite::load with the obscure API)

This could be fixed easily by adding a resource() function to each of the derived Font classes, casting a loaded font.

rombust
09-14-2013, 08:25 PM
I agree with all that is said.

Just one point to elaborate...



As for vector glyph rendering, I think this variant should only really be used as input for pathing functions. Uploading the vector data to the GPU as we are doing today is way too limiting. I think it would be better then to have the path functions able to return vertices for an app wanting this.


There are clan::Font_Vector functions,


const std::vector<Vec2f> &get_glyph_filled(unsigned int glyph);
const std::vector< std::vector<Vec2f> > &get_glyph_outline(unsigned int glyph);

I have used them via clan::Canvas's



void draw_lines(const Vec2f *positions, int num_vertices, const Colorf &color = Colorf::white);
void draw_lines(const Vec2f *line_positions, const Vec2f *texture_positions, int num_vertices, const Texture2D &texture, const Colorf &line_color = Colorf::white);

void fill_triangles(const Vec2f *triangle_positions, int num_vertices, const Colorf &color = Colorf::white);
void fill_triangles(const Vec2f *positions, const Vec2f *texture_positions, int num_vertices, const Texture2D &texture, const Colorf &color = Colorf::white);


So when I use Font_Vector, I don't use it as a font, I just use it to generate outlines.

I personally don't mind Sprite/System to be merged into Font.

And Vector could be moved into the Shape2D class. Actually, it will fit quite nice in there.

All of this should be easy to do.

Judas
09-14-2013, 09:58 PM
So when I use Font_Vector, I don't use it as a font, I just use it to generate outlines.

Oh, seems my knowledge of the Font_Vector class is somewhat out of date then. I'll take a better look at how the API actually looks like today before making further comments on them. :)

rombust
09-15-2013, 08:59 PM
Looking at Font_Sprite, it only contains a single different function: void draw_text(... with scale)

You can achieve the same using the standard draw_text() and canvas.set_scale() :)

The constructor without using resources is: Font_Sprite( Sprite sprite, const std::string &letters, int spacelen, bool monospace, FontMetrics metrics);

That's a bit more tricky to merge with Font_System cleanly ;)

rombust
09-16-2013, 03:39 PM
In GIT repo:

Font_System and Font_Sprite is now merged into Font
Font_Vector is now called VectorFont, and does not inherit font.

It "should" all work as before. But has not been tested.

Loading ttf's manually and from resources should now work:


<font name="myfont">
<ttf
file='optional filename, if a ttf file'
typeface='typeface name'
height='height value'
average_width='optional value'
anti_alias='optional bool'
subpixel='optional bool'
>/
</font>

(Note, "freetype" also works as an alias to ttf, for backwards compatibility)

One last note, since it may not be obvious. When using Font::resource(), FontDescription's typeface name is searched for in the resource file.

Pap
09-16-2013, 07:06 PM
Loading ttf's manually and from resources should now work:
I can't test it, just downloaded ClanLib from git and, for some reason, it fails linking programs:

Package clanCore-3.0 was not found in the pkg-config search path.
Perhaps you should add the directory containing `clanCore-3.0.pc'
to the PKG_CONFIG_PATH environment variable
No package 'clanCore-3.0' found
(similar messages for clanDisplay-3.0, clanApp-3.0, and basically everything else.)
Note that I didn't touch the Makefile, and it used to work perfectly with the previous git version. Maybe pkg-config paths configuration is somehow missing from the last git? I don't want to change anything before asking, as literally everything used to work until I switched to the last git version, one hour ago.

rombust
09-16-2013, 09:35 PM
Another patch to git "Adjust the ttf resource loader to use original font description as a reference description, when building a new description using the resource (so font height and weight etc don't need to be specified in
the resource)"

Nothing has changed to the pkg config's

That PKG_CONFIG_PATH error usually is because the libraries have been installed onto /usr/local/lib, where the setup expects it to be /usr/lib, depending on the distro.

I adjusted some makefiles, that would have caused ./configure to be rurun. But it 'should' have used the previous prefix. eg ./configure --prefix=/usr or ./configure --prefix=/usr/local (default)

Also ... if it did install into the incorrect place, it would have picked up the "old" version.

echo $PKG_CONFIG_PATH to ensure that it is actually set :)

Pap
09-16-2013, 10:30 PM
Actually, I re-installed ClanLib from git using a script I wrote for that purpose, the exact same script I used to install previous git versions, so installation was done in the exact same way as one day ago, but this time it doesn't work. I really doubt it is something wrong in my part: same installation, same Makefile in the test program... basically, nothing has been changed in my system but the git repo. But this time I get this error while compiling ClanLib:

In file included from Font/font_impl.cpp:50:0:
Font/X11/font_provider_freetype.h:31:55: fatal error: API/Display/TargetProviders/font_provider.h: No such file or directory
compilation terminated.
make[2]: *** [Font/libclan30Display_la-font_impl.lo] Error 1
make[2]: Leaving directory `/usr/share/ClanLib/Sources/Display'
make[1]: *** [all-recursive] Error 1
make[1]: Leaving directory `/usr/share/ClanLib/Sources'
make: *** [all-recursive] Error 1which indicates something is wrong concerning fonts. Note that installation script uses
./configure --prefix=/usr --enable-docs --disable-static
Headers are in /usr/include/ClanLib-3.0, and libraries are installed in /usr/lib, but this time only libclan30App and libclan30Core are there; the rest, such as libclan30Display, are missing, apparently because of the error above.
For completeness, I post the installation script I wrote here (although, I repeat, it is the same script I used to install ClanLib from git yesterday, and worked perfectly):

#!/bin/bash
separator=--------------------------------------------------------------------------------
install_prefix=/usr/share
echo Installing ClanLib \(install prefix: $install_prefix\).

echo $separator
echo \(1\) Downloading git version of ClanLib.
cd $install_prefix
git clone https://github.com/sphair/ClanLib.git

echo $separator
cd ClanLib
source_dir=$(pwd)
echo \(2\) Switching working directory to $source_dir.

echo $separator
echo \(3\) Configuring ClanLib.
echo
read -p "Press any key to start configuring ClanLib." -n1
./autogen.sh
./configure --prefix=/usr --enable-docs --disable-static

echo $separator
echo \(4\) Compiling ClanLib.
echo
read -p "Press any key to start compiling ClanLib." -n1
make

echo $separator
echo \(5\) Installing ClanLib.
echo
read -p "Press any key to install ClanLib." -n1
make install

echo $separator
echo \(6\) Compiling ClanLib documentation.
echo
read -p "Press any key to compile ClanLib documentation." -n1
make html

echo $separator
echo \(7\) Installing ClanLib documentation.
echo
read -p "Press any key to install ClanLib documentation." -n1
make install-html

echo $separator
echo ClanLib installed in $source_dir.

Also, while making html I got this (although that one seems to be another story):

lookup cache used 31674/65536 hits=250664 misses=33325
finished...
make[2]: Leaving directory `/usr/share/ClanLib/Documentation/Reference'
Making html in Overview
make[2]: Entering directory `/usr/share/ClanLib/Documentation/Overview'
make[2]: *** No rule to make target `html'. Stop.
make[2]: Leaving directory `/usr/share/ClanLib/Documentation/Overview'
make[1]: *** [html-recursive] Error 1
make[1]: Leaving directory `/usr/share/ClanLib/Documentation'
make: *** [html-recursive] Error 1

rombust
09-17-2013, 06:23 AM
That's a ClanLib bug, i'll fix it later.

rombust
09-17-2013, 08:47 AM
Should be working now

btw, in your script, use "make -j9" in the "compiling clanlib" stage. Compiling will be a lot quicker

Pap
09-17-2013, 10:33 AM
Should be working nowIndeed, ClanLib compiles perfectly now. Loading custom ttf fonts from xml resource file works as well (I didn't really test Font_System and Font_Sprite yet.)

I noticed that, when using Font::resource(), the typeface attribute must be present, even if it's not used. For example, in the following resource xml definition,

<font name="step font">
<ttf file="cmunrm.ttf" typeface="type whatever tou like here, it is ignored" height="30"
average_width="0" anti_alias="true" subpixel="false"
/>
</font>
the file attribute works as expected (the ttf font is loaded correctly,) provided the typeface attribute is there - otherwise I get an exception caught. You don't really have to give the correct typeface font; in fact, whatever you provide as the font typeface name is ignored once the file attribute is present. I assume this is because in my case the ttf file only contains one typeface (no italics, bold etc versions in the same file.)


btw, in your script, use "make -j9" in the "compiling clanlib" stage. Compiling will be a lot quicker
Indeed, although I use -j9 in my own applications, I forgot to add it in the script that compiles GlanLib, where it is much more effective, given the large amount of files to be compiled. Thank you for reminding me. :)
I wonder when -j9 will finally be the default flag for make... in an era even cheap laptops have multicore processors, make still uses only one by default. :scratch:

Edit: Something else must be changed to the git as well, as g++ doesn't give any warning messages anymore, with the "warn all" flag set (-Wall).
Well done! :)

rombust
09-17-2013, 12:08 PM
Yes you are correct, we do not need to have a typeface attribute. It can be optional.
(updated git accordingly)

Edit, yeah fixed that warning as well ;)

Pap
09-17-2013, 01:36 PM
Confirmed; it is optional now. :yeah:

Now I have some doubts about the InputCode enum. I can't find keycodes for some keys, specifically the minus and equal keys (the ones left to backspace on a querty keyboard, not the NumPad ones,) as well as the PageUp and PageDown keys. I expected something like keycode_equal, keycode_dash, keycode_page_up, and keycode_page_down, but nothing in the enum list seems similar. What am I doing wrong here?

Also, I noticed that, although Canvas has methods fill_rect() and draw_box() to fill a rectangle (or just draw its perimeter) with a specified color, the functionality for circles is not equivalent, as one would expect: There are fill_circle() methods but not draw_circle(). So you can fill a circle but can't draw its circumference. Of course, one can easily write a function to do that, something like

void draw_circle(clan::Canvas &canvas,const clan::Pointf center,const float radius,const clan::Colorf color) {
// A workaround for the lack of canvas.draw_circle() method.
clan::Shape2D shape;
std::vector<clan::Vec2f> circle;
shape.add_circle(center,radius,false);shape.add_ci rcle(center,radius-1.f,true);
shape.get_triangles(circle);
canvas.fill_triangles(circle,color);
}
(or using Shape2D.get_outline(), but the above implementation seems still easier and faster to me.) I wonder why it's not worth prototyping though, given that draw_box() is there.

rombust
09-17-2013, 04:24 PM
Now I have some doubts about the InputCode enum. I can't find keycodes for some keys, specifically the minus and equal keys (the ones left to backspace on a querty keyboard, not the NumPad ones,) as well as the PageUp and PageDown keys. I expected something like keycode_equal, keycode_dash, keycode_page_up, and keycode_page_down, but nothing in the enum list seems similar. What am I doing wrong here?


PageUp == keycode_prior
PageDown == keycode_next

There isn't one for '=' on Microsoft Windows (See Virtual-Key Codes (http://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx) ). So, it cannot be made portable (as far as I know)

In my opinion, there shouldn't be. Else every single glyph on every possible keyboard would require a keycode.
It's better to use the string equivalent for keystrokes that return strings, especially for keyboards that take advantage of modifier keys.



... There are fill_circle() methods but not draw_circle()...
I thought about that myself. But decided against it. Although draw_circle() is a nice convenience function, it is relatively slow. Also, I am not sure it's useful.
I also thought of adding Shape2D::draw_circle() static. But the code to do it is so trivial, it would just add to ClanLib API bloat.

Other developers may have other ideas and thoughts...

Pap
09-18-2013, 04:46 PM
I was not sure I should start a new topic, so I post my question here.
I need to draw text on the canvas, but the problem is, the text size can vary. The only way I could find to do that is to set up a FontDescription, then set up a Font, something like

labelDescription=clan::FontDescription("font name");
labelDescription.set_height(12);
labelFont=clan::Font(canvas,labelDescription);
Now, each time I need to change the text size, it is not enough to just call labelDescription.set_height(), as the font itself will still have the previous description. So I am forced to do the following each time I need to change font height:

labelDescription.set_height(newHeight);
labelFont=clan::Font(canvas,labelDescription);
labelFont.draw_text(canvas,x,y,"blah blah",color);
The problem is that this is very slow, as each time the height is changed, font is essentially recreated. Having something like that in a loop is really not convenient, as it slows down execution a lot. I could easily solve the speed issue if Font had a method to change description, say Font::set_description(). Unfortunately, Font class doesn't have such a method (in fact, Font doesn't provide any "set" method,) so if I understand well, once.a font is set it cannot be changed, unless you do something like the above, which is very slow in runtime. Maybe I am missing something here?

rombust
09-18-2013, 07:53 PM
It's what I personally know as the font size trap :)

Recreating the font every time you use it will be slow.
Each time you create it, it has to extract the system glyphs into a pixelbuffer, and upload it to the GPU. Once it's created, it is cached.

There are 2 ways to solve the problem.
1) Create an array of fonts on initialisation with various sizes.
2) Create a large font (say 100pixels). Use canvas.set_scale() to scale it when drawing

Option 1 is preferable when you have a known limited set of font sizes. Too many, wastes GPU memory, and performance (if using more than 16 fonts.)

If using Option 2, you must turn off sub-pixel rendering in the font description, else the font will look dreadful when scaled. Keep anti-alias option on though.
Also Option 2 looks bad on small font sizes (less than 24 size)

If using very large fonts (>100 pixels), use VectorFont (the Input example uses this) and use canvas.set_scale()

Pap
09-18-2013, 08:21 PM
There are 2 ways to solve the problem.
1) Create an array of fonts on initialisation with various sizes.
2) Create a large font (say 100pixels). Use canvas.set_scale() to scale it when drawing
Actually, I was already implementing first option when I saw this - implementing it very reluctantly I must add, as I think it's too much computational work for just changing font size. Same for second option (plus font sizes are rarely that big to use it.) Best solution would be a Font::set_description() method, so that you could have one Font object, but also the ability to dynamically change its size using FontDescription::set_height() then update the font using Font::set_description()... neat, more convenient, and without wasting resources or doing scaling tricks (with all their disadvantages.) How difficult is to add such a method? Or it makes no sense because it would still be slow?

Judas
09-18-2013, 10:21 PM
Adding a Font::set_height() function is not realistic, at least not the way the Font class is currently coded. On a related note, functions such as the Win32 CreateFont function also does not allow you change the font size after it has been created.

The key issue here is how a font works internally. To maintain a high rendering speed, font glyphs are first converted from vector form to an image. This process involves the font height as it needs to know what size you intend to render the glyph. The process is further complicated by the fact the individual glyph images then needs to be stored in a shared texture image (one texture per glyph would be way too slow).

The Font implementation cheats slightly by assuming that you intend to render the font at the exact pixel size given in the FontDescription. By doing this, it can render the glyphs at this one size once and thereby solving the problem. The catch is that this doesn't work very well with canvas scaling. I think the GDI font renderer internally uses a somewhat more dynamic glyph bitmap cache to support scaling, but its exact behavior is unknown to me (I don't have the source). Personally I virtually never use canvas scaling, so for me an improved glyph bitmap cache is a nice to have feature.

Adding Font::set_height() is not realistic because with the current glyph cache design it would be forced to recreate the entire cache, which effectively will run at exactly the same speed as creating a new Font from scratch.

Therefore the current assumption in ClanLib has always been that you create individual Font objects for the sizes you need, which in most applications actually map to surprisingly few variations (assuming no canvas scaling). For example, rendering a website usually only involves 1-3 fonts with 3-5 different sizes. The only catch here is that you need to share those Font objects created along where you draw the text.

If you're using the resource system, then the caching of Font objects should be automatic - call Font::resource(canvas, desc) with a few different font sizes, and it will only create the font objects once for each of those sizes.

Otherwise you'd have to create your own cache, something like:



class MyFontCache
{
public:
clan::Font get(clan::Canvas &canvas, int size)
{
auto it = cache.find(size);
if (it != cache.end())
return it->second;

clan::Font font(canvas, "Times Ugly Roman", size);
cache[size] = font;
return font;
}
private:
std::map<int, clan::Font> cache;
};


Only catch is for canvas scaling fonts won't look too good. Fixing this would require a lot of work, and so far none have had the need badly enough to try.

Pap
09-19-2013, 05:38 PM
I ended up with a vector of Fonts with different sizes, defined in class construction, and indeed it is fast enough in practice. Maybe not the best way to change font sizes in run time, but it works. Maybe another font class that doesn't store glyphs to the GPU, so it's not that fast but it's also more flexible and configurable in run time is a good idea.
For more wide font size range, I will use a vector font (or a sprite) and rescaling. Thank you both for your support. :)