Add a Text Rendering Method
under review
Signal Linden
Add a new function LSL function named
llRenderText
or similar, which allows users to dynamically render text, with limited but flexible formatting, onto the face of their choosing.Concept:
// Signature
llRenderText(integer face, string text, list params);
// Basic example
llRenderText(ALL_FACES, "Lorem ipsum...", [
FONT_ALIGN, "right",
FONT_WEIGHT, "bold",
FONT_FAMILY, "sans serif"
]);
Rationale
Text is ubiquitous, yet Second Life has no way for users to display text other than uploading a texture, setting floating text using
llSetText
, or using relatively resource intensive solution such as XyText/Furware/et al. This absence precludes interesting features, such as being able to create a responsive interactive terminal in Second Life, HUDs with dynamic text, etc.A scripted and efficient text solution that displays on the face of a prim/mesh would give Second Life the biggest bang for the buck:
- Limited in scope (easier to implement than grand UI-creation ideas)
- Easy to kitbash into existing and new creations
For inspiration, you can look to how the Text Display widget is implemented in the Playstation game Dreams. It has limited options: a finite number of fonts and formatting options, but the fact that it can be combined with other content makes it rather powerful.
Other details
- Font color, opacity, glow, etc are controlled by prim properties (Example: setting face color to red sets font color to red)
Questions
- Should the background always be transparent? Creators could put another prim behind the text display face to give it a background, or it could be a property of the render params.
Possible Parameters
FONT_WEIGHT
FONT_STYLE
FONT_FAMILY
FONT_VERTICAL_ALIGN
FONT_HORIZONTAL_ALIGN
FONT_TEXT_WRAP
FONT_LINE_HEIGHT
FONT_SIZE
Possible Features
- Markdown / rich text
Log In
Kythyria Resident
Markdown is a bit of a thumbs down for me--IMO it's easy to hand-write at the cost of being horrible to generate or parse, and doesn't include features like colour that are inevitably going to be requested. It won't be fun to jam into LSL, but a common API for rich text is a list of (string,format) pairs, that might be a good bet.
Re transparent background: the concern I have there is z-fighting with a backdrop, which is never pretty, and the workaround of moving the text away has its own odd look if you zoom in real close.
The extra-deluxe version of this feature would probably be some kind of API for doing all sorts of 2D graphics into a texture that can be referred to in the normal ways. That has different tradeoffs to text being a whole new pass, though: potentially less sharp, but using it like a regular texture has its own advantages (eg, one canvas to drive multiple panels or be repeated throughout an area). I'm not sure what that wold look like, though.
Regardless, even basic text will be a good addition!
EDIT: Re the suggestions for custom fonts: neither raw texture atlases nor SVG are really great suggestions IMO: Raw texture atlases omit
all
shaping, positioning, and encoding data, requiring that information be supplied in some form anyway. Meanwhile SVG is neither space-efficient nor capable of representing complex text shaping.Space-inefficient, so good luck fitting it into a notecard, and bad at shaping, so handling languages other than english will be... awkward.
Honey Puddles
An optional way to have the background of the text be transparent, would seem to be a must.
I would suggest also the addition of a Blur setting. I'll try to illustrate a use-case.
Using multiple layers of text (3 panels in this example), one white, one grey, and one transparent black, you can simulate the appearance of a 3D letter, with a dropshadow. (Figure A) (Figure B)
If the shadow layer were blurred, the effect could be considerably more convincing.
Bleuhazenfurfle Resident
I still believe basic SVG support would be the best option. Doesn't even need to be full SVG (like drop the external stylesheet stuff, just inline styling, etc.) — as long as it's an internal renderer that doesn't involve the browser, because all that click to load nonsense, and people not trusting the browser. If you can't find a pre-made SVG renderer, then pretty much every language has a path based graphics library that'll do the bulk of it for you.
I also think it'd be great to hijack MoaP with a special url scheme or media type that bypasses the browser and invokes the internal renderer instead, with the SVG content passed through the space presently allocated for the MoaP whitelist or something (though also allowing script http urls would make a good bonus option, for scripters willing to jump through those hoops).
People have been wanting to be able to render simple graphics to a face too, since forever, graphs and stuff especially, and they'll want to be able to include text on their graphs. SVG support would cover that, this, and the whole darned UI (add support for receiving touch events later on).
Toss an appropriate delay on it so it's not being spammed, let the viewer queue renders rather than trying to cram them all in every frame, etc.
Rathgrith027 Resident
Might I suggest adding eventual support for Google Fonts? The service's font delivery API could broaden the horizons of what SL users could use creatively for their UI. Otherwise, including a broad spectrum of fonts for things like electronics, UI/UX, handwriting, printed text (from a printer/typewriter and the sort would be imperative.
observeur Resident
I was writing the same suggestion when i saw this post. This is MUST HAVE option in SL. Any easy way to write some text would be very very welcomed and avoid using the tricks we are currently using, that are slow, heavy on servers and not flexible.
dantia Gothly
I would add a linkset flag to this function so we can control text across a linkset given that sometimes the text we will want to edit would be on one of the other object surfaces in the linkset.
Gwyneth Llewelyn
YES
!Thanks Signal Linden for reviving this ancient feature request from not only Jira, but even from more remote tools that existed before to register customer feedback! This is likely one of the Most Requested Features Ever and I'm definitely enthusiastic about seeing it already
Under Review
!That said, aye, please add Markdown too 😂
Now, the tricky issue here is dealing with all the suggestions on the comments and do something which considerably improves the existing half-solutions (hovertext, XYText and the like).
I loved the idea of uploading a font using a simple, transparent texture, having all characters in a certain grid (there would be a template for those) in order to "get the weights right". The problem, of course, is that this works well for ASCII — but hardly so for Unicode (assuming a "reasonable" 1024x1024 texture, that is). And while one may argue that Unicode support is "not a thing" — who misses those accented characters from the non-English European languages, anyway? — and it would be "good enough" to at least support ASCII, well...
Not really.
To do something
useful
— as opposed to a not-quite-so-limited version of hover text — you'd have to go much further than that. Luckily, there is no need to dig in very deeply into LL's SL Viewer code to find a solution!The SL Viewer (at least the desktop version!) is written from scratch on top of OpenGL. And, naturally enough, LL uses the FreeType library to render the Deja Vu Sans font for all things UI.
Therefore, anything that FreeType does, the SL Viewer
can
also do. And, as expected, hard-core OpenGL programmers have put it to good use — essentially doing everything possible to render TTF or OTF fonts using FreeType on top of any surface/model manipulated by OpenGL in the most effective and performant way.This article actually illustrates some of the issues about rendering text using OpenGL and provides
lots
of suggestions to libraries that do the heavy work — https://stackoverflow.com/a/36065835/1035977But since LL
already
includes FreeType in the viewer, it makes a lot of sense to simply build upon what is already in there as opposed to add Yet Another Font Rendering Engine.Now... FreeType requires fonts, of course, and we most certainly have millions to pick from. The only issue is — which ones to select, and how? Having a limited pre-selected choice is, for the reasons given by other commenters, a very poor strategy.
One possible solution would be to use the "texture atlas" approach; as can be seen on the link to Stack Overflow, a "simple" texture (752x752 I think) is able to provide an ASCII font in several point sizes. Of course, the texture is just half the issue here; you'd need to provide the "atlas" itself, i.e. a file describing how exactly the desired character should be extracted from the texture. Once
both
are fed into the OpenGL pipeline, the texture can just be pushed to the GPU as a "normal" texture, and the actual font rendering happens via the "atlas" lookup.The
only
problem with this approach is that it's essentially CPU-bound (the GPU does little but apply the texture — or bits of it — to the right place, which is the job that the CPU has). It's also true that people would have to generate their own texture atlas for their
fonts (but I can imagine that this, even though not trivial, might be accomplished with some sort of tool, such as, say, https://fonts.varg.dev/ — a cute example using WebGL, not OpenGL, but it shows how it can be automated). Fortunately, such texture atlas can be plain simple text, copied & pasted on a notecard, and that would be it — anyone could then sell their font texture + atlas notecard on the Marketplace to allow others to "use" their font (of course, there are legal implications with non-free fonts used for this purpose, but, alas, this is always a problem that needs to be deal with...).While this works — to a degree — I imagine that actually having bold, italic, etc. might complicate things further, unless all the hard work is already done by FreeType. In that case, I'd suggest this as
Possible Solution #1
.But wait, there is more 😉
The above approach, of course, is limited to actual font size(s) and/or how many characters (ASCII, ISO Latin 1, EBCDIC...) are supplied with it. I can imagine that
some
mappings might even include italics and bold variants as well — until adding more and more data essentially exhausts the one-million pixel limit we have on a 1024x1024 texture.And, of course, you would be unable to mix and match fonts (surely
someone
will want to have that
!) or change colours or anything like that.Enter
Possible Solution #2
: SVG fonts!Not TTF or OTF (or WOFF2) — mostly because most of these would be overkill, and there would be the question of how to upload them (although I would assume they'd become regular assets like all the others).
FreeType, however, also fully supports SVG fonts as well. The advantage? You can very easily pick just the glyphs you need and nothing else.
And, of course, an SVG is just another text file — plain old XML — which can simply be placed in a notecard and that's it. So, you wouldn't need anything else except a library function to load the notecard and interpret it as an SVG; no need to upload any "special" assets. And there are a gazillion (free) tools out there to convert OTF/TTF files to SVG fonts.
Honey Puddles
This has been something I've struggled with recently, and I can explain a clear use-case where this is needed.
Allow me to set the stage: The user created mini-game "GTFO" creates a lot of interesting opportunities for scripting and playing
with
SL, as well as within SL. One of the features of the game, is that each time a cargo load is picked up, or delivered, there is some detectable game data that says "Joe Smith delivered 6 cases of Prim Cola" or whatever. This data can easily be heard by a script, it can be formatted, cataloged, analyzed and stored by that script. You can easily keep a running log of who are your most frequent drivers, which cargo items are being moved around, add up the totals, and have fun with that.But the one thing that's shockingly clumsy to do in SL, is to display that information, inworld.
Hovertext is inelegant, as it's 'floating' mid air above the object(s) generating it, and it doesn't scale with camera movement, meaning those with low-vision can not zoom in to increase readability.
Using a mesh-based solution for this, even using the most expansive "Xyzzy10" style approach, would only allows 16 characters per mesh object. While that expansive 'two letter per face' approach exists, it's hardly simple to implement, and requires more than a few high density, low-letter-resolution textures to pull off.
The more common, easier to implement approach is 1-letter-per-face, by sliding a single texture with a modest compliment of ASCII characters. This concept is used all across the grid, whenever dynamic text is needed; but this method comes at a cost.. land impact.
A simple implementation of a 64 character wide line of text, uses 8 mesh objects. 5 rows.. just FIVE rows.. makes that 40 objects... for 320 characters. Add a little formatting and a frame, and your simple text display, with the last 5 cargo entries, now uses 45 objects in a linkset... and thanks to clever reliance on the 0.5Li nature of simple meshes.. you can get that land impact down to 25.. with just 700 triangles.
The attached image (Example A) is of just such a sign made by another creator, but this is merely an example. Aside from the title and column headings.. the text is all one single texture with different offsets.
This isn't a highly complicated scripted device. Having built something very similar to interpret the same data, I can say with confidence, that even with extensive commenting and unnecessary line feeds for formatting.. the meat of that script is probably less than 100 lines long. The text display is probably half the script.
Another great example can be found at Builder's Brewery sandbox (See Example B)
This sign relies on the higher-effort "Xyzzy10" 2-letter-per-face approach, requiring many more textures to work, yet due to the implementation making use of the 5-sided-prim approach, they only get 10 characters per object (prim) (instead of the potential 16.
Getting just 50 characters (25 faces) per row, with 14 rows, they're able to display a whopping 700 characters of text.. but at the cost of 75 objects (prims at that!), and even with careful use of bounding box settings, it's still 40Li, with over 19,000 triangles and 33 textures.
This is obviously a method of displaying and sharing information that users and creators within SL desire to make use of.. I feel like after 20 years, there has to be a more elegant and efficient way to go about it.
Journey Bunny
To Extrude Ragu's point: Would be useful to permit custom fonts via a standard texture layout. That is to say, supply a texture UUID as a font face, and the viewer would internally subdivide the texture into a virtual grid and draw the portion of the texture located at the relevant coordinate space. In other words, load a texture and draw parts of that texture for each character.
Leading, kerning, tracking settings could be interesting to ponder, but even just allowing custom monospaced fonts would be a massive improvement. The present solution is to add tons of little rectangles with separate faces, linked to a prim just to get settable text, causing unreasonable Li use.
Vincent Nacon
I kinda figured maybe the background should be prim's normal face and you just render text on top of that, but will need a color vector and alpha float input. It would make it a lot easier for HUD stuff. That way we can use llSetTextureAnim to do marquee scrolling and Texture UV offset for scrolling through large wall of text.
Load More
→