# Cinder-SdfText: Initial Release (WIP)

**URL:** <https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171>\
**Category:** CinderBlocks\
**Created:** [July 22, 2016, 7:26pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171 "2016-07-22T19:26:05Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 27, 2016, 9:02am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/21 "2016-07-27T09:02:21Z")

</div>

Next challenge: laying out text that runs from right to left (Arabic) with all kinds of ligatures and what not. But that is not for the faint of heart. 😓

Edit: by the way, are you sure you render the text using pre-multiplied alpha, Hai? If not, you may want to change the shader to: `Color.rgb = uFgColor.rgb;`.

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/72c9ce6a8601b455a78eed9f91248881b57b76e1.png)

Left: wrong blend mode. … Right: correct blend mode.

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 27, 2016, 2:59pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/22 "2016-07-27T14:59:31Z")

</div>

Ola Hai,

I’ve taken a bunch of snapshots of SDF text, you can find the album [here](https://goo.gl/photos/sLrFA6LRZGETBDaCA):

[[41 new photos · Album by Paul Houx] Cinder-SDF ![](https://lh3.googleusercontent.com/cpro4tH-rnrxJ-h--te-Upj8SOUw44YdFZ2jCirbe_K1Gnb2JP9ar72Dl7rRiIcW9aN61FuwK7LHaXGw6GkdoWHfwvXhIL9UM88zLug6MNP09UilkfEzEIrDZR3eRrtLY3p6dVtm=w600-h315-p-k "Cinder-SDF") ](https://photos.google.com/share/AF1QipO8xUZwnNNG5AqyPBQwzjOf921ofkeAaF8zeAFOQFGD6AO00xY3cZXChMCxJxZ98w?key=X2dxU2V6QlhuNjI3alhTMEV3dXpWRGplbU1KeHhB)

Most of the images are from text that looks great, even at smaller sizes. Some of them exhibit flaws, though, and I’ve indicated them here or there. Have fun looking at your great work.

-Paul

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [July 27, 2016, 8:25pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/23 "2016-07-27T20:25:14Z")

</div>

@paul.houx This thing wouldn’t be where it is without your efforts! Thanks for jumping in! Also thanks for making the album, I went through it - some useful stuff in there to track down more of the formatting issues.

I updated the shader to handle a premultiply toggle. I’m not sure if my formulation is 100% correct. If you have some time, would you mind taking a look?

Thanks,  
Hai

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [July 27, 2016, 8:46pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/24 "2016-07-27T20:46:16Z")

</div>

Tweaked it a little. [There](https://github.com/chaoticbob/Cinder-SdfText/pull/6) ya go!

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [September 3, 2016, 10:05pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/25 "2016-09-03T22:05:22Z")

</div>

Cinder-SdfText has come a long way since the initial release! Much of this is thanks to the might hands of @paul.houx and contributions from @ryanbartley and @num3ric.

Recnt New Features:

- Save/Load - allows you to cache the generated SDF texture atlases so you don’t have to generate them every time. The same cache can be used for multiple font sizes.
- Alignment - horizontal alignment for left, right, center, and justify.
- New Samples - several new samples to demonstrate new features.

**Obligatory Screenshot**

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/4743384cafd790e1bbcbf102288a2623b78c376c.png)

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [September 3, 2016, 11:13pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/26 "2016-09-03T23:13:52Z")

</div>

All 400 fonts on my system, loaded, rendered and recorded in real time.

---

<div class="post-metadata">

**Author:** ![felixfaire](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/felixfaire/32/168_2.png) [@felixfaire](https://discourse.libcinder.org/u/felixfaire)\
**Post date:** [September 4, 2016, 3:55pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/27 "2016-09-04T15:55:42Z")

</div>

This looks fantastic, awesome work guys.

Is this the kind of thing that could go into the core Cinder library for rendering text in the future? And if not what are its limitations / advantages over TextureFont apart from the obvious quality / resolution benefits etc. Is it more / less computationally expensive to initialise / render text on the fly for example?

Excited to get to grips with this, if theres anything I might be able to help with to bring this to OSX too let me know 🙂

[http://felixfaire.com/](http://felixfaire.com/)

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [September 4, 2016, 10:12pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/28 "2016-09-04T22:12:28Z")

</div>

Hi,

Hai’s (and a bit of my) work was based on the `TextureFont` classes, so in general they are similar. Here are the differences:

- Instead of rendering the glyph as a bitmap, we use [MSDFGEN](https://github.com/Chlumsky/msdfgen) to generate a special 3-channel signed distance field per glyph. This takes considerably more time, meaning that creating the texture on-the-fly (dynamically) would cause a drop in frame rate if done on the main thread. The code is not multi-threaded yet (but could be made that way, it’s 100% CPU-only). In the meantime, consider creating the font texture during development, then saving it as a binary file for ultra-fast loading. Methods to load and save the file are provided.
- To render text, a mesh needs to be constructed that takes the texture and draws the glyphs in the right location. The code for this is almost identical to `TextureFont`, but we also added left, centered, right and justified alignment. The code is only slightly slower because of this, but the difference is hardly noticeable in most cases. More layout options are not provided at this time, since that should really be handled more generically in Cinder. This solution was designed to render high quality text efficiently in OpenGL. It wasn’t our goal to replace Adobe Indesign. Lastly, if you intent to use static text, consider creating the mesh once and reuse it. It’s on our TODO list to provide an out-of-the-box solution for this in the form of a `SdfTextMesh` class.
- The text must be rendered using a shader that is a little [bit more complex](https://github.com/chaoticbob/Cinder-SdfText/blob/master/src/cinder/gl/SdfText.cpp#L100-L121) than just a simple texture lookup. The shader calculates several derivatives in order to properly determine the distance from each fragment to the actual glyph outline, then using this distance as a threshold to render the anti-aliased glyph at any possible size. Calculating the derivatives requires [internal synchronization](http://stackoverflow.com/a/16368768/858219) in the GPU that makes this a _relatively_ slow process, but any desktop GPU should have absolutely no problem rendering a large amount of SDF text. There is no OpenGL ES shader support at this time (although this can be added - the shader code does not require exotic functionality), so we haven’t tested on iOS to measure performance, but I am pretty sure it will be viable to use SDF text on a mobile platform.

-Paul

P.S.: as for integration into the Cinder code: I would love to see that. It should completely replace `TextureFont` in my opinion, but that would require support for dynamic texture creation (adding missing glyphs on-the-fly), preferably on a separate thread. I would also break out most of the layout code and use it not only for `TextureFont`, but also for `TextBox` and basically anywhere text is used. As you can understand, this takes quite some engineering to do it properly. I know proper text handling is high on the wish list, so hopefully we’ll see some of this in the core soon. It’s just a matter of time.

By the way, here’s an example of an SDF texture that is generated by this solution:

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/35fbf4c9f11bcf10c787c458b856459092f8fcdd.png)

---

<div class="post-metadata">

**Author:** ![hurpyderpy](https://avatars.discourse-cdn.com/v4/letter/h/919ad9/32.png) [@hurpyderpy](https://discourse.libcinder.org/u/hurpyderpy)\
**Post date:** [September 6, 2016, 9:47pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/29 "2016-09-06T21:47:16Z")

</div>

This is wonderful stuff. You guys are amazing. 🎆

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [September 7, 2016, 8:57pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/30 "2016-09-07T20:57:36Z")

</div>

Added a SdfTextMesh class to cache the geometry for text.

It’s relatively straight forward to use. A ‘run’ is created for each section of text. You can have multiple runs in a single SdfTextMesh object. Each run supports **most** of the features from SdfText::DrawOptions. Internally, SdfTextMesh caches gl::BatchRef objects on an as needed basis corresponding to textures and glyphs.

Example looks something like this:  
mSdfTextMesh = gl::SdfTextMesh::create();

```
	std::string blockText( "Some realyy long text." );
	Rectf blockBoundsRect( 40, mSdfText->getAscent() + 40, getWindowWidth() - 40, getWindowHeight() - 40 );
	gl::SdfTextMesh::Run::Options blockOptions = gl::SdfTextMesh::Run::Options().setAlignment( mAlignment ).setJustify( mJustify );
	mBlockRun = mSdfTextMesh->appendTextWrapped( blockText, mSdfText, blockBoundsRect, blockOptions );

	vec2 baseline = vec2( 10, 30 );
	mAlignmentRun = gl::SdfTextMesh::Run::create( "LEFT", mSdfText, baseline );
	mSdfTextMesh->appendText( mAlignmentRun );

	baseline = vec2( 10, getWindowHeight() - mSdfText->getDescent() );
	mFpsRun = gl::SdfTextMesh::Run::create( "fps", mSdfText, baseline );
	mSdfTextMesh->appendText( mFpsRun );

	float fontNameWidth = mSdfText->measureString( mSdfText->getName() ).x;
	baseline = vec2( getWindowWidth() - fontNameWidth - 10, getWindowHeight() - mSdfText->getDescent() );
	mSdfTextMesh->appendText( mFont.getName(), mSdfText, baseline );

```

**Obligatory Screenshot**

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/e411bb26f85e2f82d361c187d183cc11c97b04b3.png)

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [September 8, 2016, 4:22am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/31 "2016-09-08T04:22:59Z")

</div>

Initial version of OS X has been added. There are still some issues:

1. SDF is reversed for some fonts.
2. System fonts are not being loaded as expected, e.g. Helvetica. Probably needs an update to tell FreeType to pull the specific style if requested and Regular if nothing is requested.
3. Some of the sample projects do not have Xcode projects yet.

If anyone wants to brave an iOS version, please feel free!

**Obligatory Screenshots**

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/ed2ab3f22af458cc22df8a1a0e18aec37d5602b9.png)

---

<div class="post-metadata">

**Author:** ![gabor\_papp](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/gabor_papp/32/769_2.png) [@gabor\_papp](https://discourse.libcinder.org/u/gabor_papp)\
**Post date:** [September 8, 2016, 6:28am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/32 "2016-09-08T06:28:30Z")

</div>

I tried to build this with XCode 6.2, but the project file is incompatible. Probably a newer version. Then I tried with cmake, but I had to make some modifications similar to Petros’s [pull request](https://github.com/chaoticbob/Cinder-SdfText/pull/17/commits/3a3d637d5e2c0b456ebae73969c5708dd6b1ce0e) to `readLittle`, `writeLittle` calls. And probably for similar reasons `boost::algorithm::trim_right_copy` ([here](https://github.com/chaoticbob/Cinder-SdfText/blob/master/src/cinder/gl/SdfText.cpp#L1106) and [here](https://github.com/chaoticbob/Cinder-SdfText/blob/master/src/cinder/gl/SdfText.cpp#L1113)) gives errors for `char32_t`. Errors [here](https://gist.github.com/gaborpapp/64d49677d468bba0d4c7a4b21f9fad82)

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [September 8, 2016, 6:42am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/33 "2016-09-08T06:42:38Z")

</div>

Are you using the latest version? Both of those issues should be resolved.

---

<div class="post-metadata">

**Author:** ![gabor\_papp](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/gabor_papp/32/769_2.png) [@gabor\_papp](https://discourse.libcinder.org/u/gabor_papp)\
**Post date:** [September 8, 2016, 6:53am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/34 "2016-09-08T06:53:04Z")

</div>

Thanks. The newer version builds fine. I tried this two days ago, and didn’t notice these changes in the OS X commits.

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [September 9, 2016, 5:50am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/35 "2016-09-09T05:50:26Z")

</div>

Added build files for iOS for Cinder-SdfText. The following samples also have build projects updates:

- Basic
- BasicMesh
- MeshPages
- StarWars

I don’t currently have an iOS device that’s provisioned to run apps - if anyone wants to run test it and report back, that would be helpful!

**Obligatory Screenshot**

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/fe3847ea996e890334f109de30780a8fcd30ff51.png)

---

<div class="post-metadata">

**Author:** ![felixfaire](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/felixfaire/32/168_2.png) [@felixfaire](https://discourse.libcinder.org/u/felixfaire)\
**Post date:** [September 9, 2016, 8:25am UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/36 "2016-09-09T08:25:13Z")

</div>

Hey.

Had mixed results building on iOS (iPhone 6S)

**Basic - Success**  
**MeshPages - Success**

**BasicMesh - Fail**  
**StarWars - Fail**  
I get a runtime error for both of these:  
|error | void cinder::app::AppBase::executeLaunch()[137] Uncaught exception, type: cinder::Exception, what: Invalid out stream  
libc++abi.dylib: terminating with uncaught exception of type cinder::Exception: Invalid out stream

---

<div class="post-metadata">

**Author:** ![chaoticbob](https://avatars.discourse-cdn.com/v4/letter/c/ecc23a/32.png) [@chaoticbob](https://discourse.libcinder.org/u/chaoticbob)\
**Post date:** [September 9, 2016, 4:33pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/37 "2016-09-09T16:33:28Z")

</div>

Would you mind double checking these? A stack trace from the line that’s throwing the exception would be helpful.

The provisioning stuff finally came through for me and I was able to run all 4 samples on my 6S+ without issue.Here’s a screenshot of Star Wars:

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/711158392bda42d7e02ec69eeda4a59001e3a87f.PNG)

---

<div class="post-metadata">

**Author:** ![gabor\_papp](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/gabor_papp/32/769_2.png) [@gabor\_papp](https://discourse.libcinder.org/u/gabor_papp)\
**Post date:** [September 20, 2016, 2:56pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/38 "2016-09-20T14:56:35Z")

</div>

I have encountered a strange issue with `measureString`. It does not seem to return the correct size if I change the font size. With size 24 it seems to be ok, but otherwise it differs from the drawn string.

![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/22223a6a2256443ef6c70e0d8148b17fcd2227fa.gif)

This is drawn with Helvetica on OSX with the BasicApp sample.

I draw the string and the rect like this:

```auto
gl::translate( vec2( 100 ) );
vec2 strSize = mSdfText->measureString( str );
Rectf rect( vec2( 0, -strSize.y ), vec2( strSize.x, 0 ) );
gl::drawStrokedRect( rect );
mSdfText->drawString( str, vec2( 0 ) );

```

Am I missing something? Should I use the size in different way instead of assuming that the size and the drawn string match?

---

<div class="post-metadata">

**Author:** ![paul.houx](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/paul.houx/32/31_2.png) [@paul.houx](https://discourse.libcinder.org/u/paul.houx)\
**Post date:** [September 20, 2016, 3:11pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/39 "2016-09-20T15:11:42Z")

</div>

Hi Gabor,

can you try to make the following change?

 ![](https://canada1.discourse-cdn.com/flex030/uploads/libcinder/original/1X/a13052b7102d7079c54a1c2bf08a27c972116d96.png)

(To avoid confusion: on the left side is the current version, the right side is what I think it should be.)

I am using this block in a large project at the moment and had to make a few changes when I ran into some issues. I’ll probably create a PR when I’ve finished working on the project, but you can try this now if you want to.

-Paul

---

<div class="post-metadata">

**Author:** ![gabor\_papp](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.libcinder.org/gabor_papp/32/769_2.png) [@gabor\_papp](https://discourse.libcinder.org/u/gabor_papp)\
**Post date:** [September 20, 2016, 8:38pm UTC](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171/40 "2016-09-20T20:38:50Z")

</div>

Hi Paul,

Thanks. I made the change, but the bounding box size still doesn’t match the text size.

-Gabor

[Previous page](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171.md?page=1)

[Next page](https://discourse.libcinder.org/t/cinder-sdftext-initial-release-wip/171.md?page=3)
