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
Nexii Malthus
Another alternative, which could co-exist with llRenderText, is to be able to extend llSetText behaviour.
The benefit is that you would have a fallback to floating text on older viewers and that hover text is also widely implemented across LSL and can even be retrieved from other objects via llGetObjectDetails OBJECT_TEXT.
I would like a llSetTextParams with similar possible parameters as above (maybe with TEXT_* prefix?). But additionally:
* TEXT_POSITION, vector pos, integer relative -- relative can be constants 1, 2, or 3: TEXT_POSITION_SCREEN for default hover position above prim, TEXT_POSITION_LOCAL where it follows relative to local coordinates of the prim (and scales with distance), TEXT_POSITION_ABSOLUTE where it can be positioned in region coordinates probably limited to max linkset distance rules to limit abuse
* TEXT_ROTATION, rotation rot, integer facing -- facing can be constants 1, 2 or 3: TEXT_FACING_SCREEN for default hover text behaviour where it rotates to face screen -- ignore rot maybe, TEXT_FACING_LOCAL to make text rotate relative to prim / local coordinates, TEXT_FACING_GLOBAL to rotate in region coordinates
* TEXT_SCALE, integer scaling -- scaling can be constants 1 or 2: TEXT_SCALE_SCREEN for default hover text scaling behaviour where it is same size regardless of distance, TEXT_SCALE_WORLD for behaviour where it scales down based on distance as if it were placed in-world like a prim
* TEXT_BOX_WIDTH, vector size -- Turn into a textbox that wraps and clips within the <width, height, 0> -- if TEXT_SCALE_SCREEN then width/height are HUD sizes, if TEXT_SCALE_WORLD then it is in meters like a prim size
Nelson Jenkins
Nexii Malthus What's the use case for this on older viewers with a fallback to legacy llSetText? I'm not sure this really does anything that the proposed llRenderText wouldn't accomplish in a more sensible way, and the only time you'd use these flags is if you specifically do not want legacy llSetText behavior.
Also, how do you detect where the text comes from? With llRenderText, you have a prim right there. llSetText rendering at arbitrary positions would be a nightmare to diagnose.
I'm open to tweaking llSetText but making it do everything feels like master-of-none situation if llRenderText also exists.
Nexii Malthus
Nelson Jenkins I mean I can throw that back at you with llRenderText as well -- how do you know if a face has rendered text? llRenderText is hard to diagnose, whats the texture size it is rendering at? Is text wrap in pixels or in meters? How do I know I positioned the text correctly? Do I just guess and check constantly? Is there a way to determine if something is positioned precisely, what if I need to mix in custom icons, how do I make a gap in rendered text and figure out how to position my icon? What about the aspect ratio of the texture? Some usecases might be better with a high aspect ratio for, say, a wide billboard sign, compared to a tall blackboard. This can affect things like font size you want to use, how much room for characters in that texture.
An extended llSetText could have a high amount of precise positioning control since it could be changed to have a physical world size measured in meters that SL uses (text scale world) and/or be defined by the amount of physical space available (text box).
llRenderText is going about it the other way -- the size will be in pixels on an arbitrarily defined texture size, limited to the size of that texture to wrap with as a hardcoded max.
Nelson Jenkins
I'd certainly be interested in anything that can avoid me having to embarassingly explain to new scripters that LSL still has no way to render text without ridiculous one-face-per-character solutions or the ever-awkward llSetText.
Few things:
First: this needs custom fonts that don't need to be installed locally by the user. While a curated repository like Google Fonts would be nice, I wouldn't be able to use this to replace most of my XyText-like applications without being able to import custom fonts for things like LED matrix displays. I'm not sure how to do that without a new asset type though. Downloading fonts from a custom URL might be a security risk and introduces a bit of complexity with font management. (Though if all else fails, I'll distribute my own fonts and tell people to install them...)
Second: text needs to be, at least, white on transparent. I'd also suggest a bitfield parameter with flags for a static black background and an inverse flag to make the background white and text black, among maybe some other binary flags. I can't think of any super-pressing applications for the non-transparent options - Z-fighting could be avoided with a background face, not that big of a deal - but it would be a nice touch.
Three: as has been suggested before, I think a way to render multiple pieces of text dynamically at certain positions on a 2D canvas would be comparatively trivial to implement and much more useful than just printing a blob of text into the bounds of the face. That does introduce a little complexity with needing to specify a position (maybe text box bounds?) and foreground and background colors (think subtitles), but I really don't think that's that big of an ask beyond rendering text in the first place. (One drawback to this for HUDs - you can't just put a transparent prim over the entire viewport unless you don't want to click on anything ever. I guess Lua will have some kind of solution for that, maybe...?)
Finally: I've never heard of SVG being used to render individual characters dynamically beyond, y'know, a font. So while useful, I also don't exactly understand how it would be possible to generate an SVG file that could be used as a font without just making a font, and that probably introduces a bit too much complexity to be in scope of the original request.
Gwyneth Llewelyn
I know I have given some feedback already, but let me just remind you that such functionality has already been implemented in OpenSimulator, several years ago, and we know it works on the TPVs which haven't been modified to allow for text rendering :)
Look at their source code and just copy it (and adapt it to whatever programming language LL's own servers are written in). There is no need to reinvent the wheel, when it's already there.
It has limitations...? Sure. It's just that the OpenSimulator crowd has already done all the features listed on Signal Linden's proposal and implemented them on OSSL. You just need to grab them. There might even be some test scripts somewhere. An extra advantage would be having a set of already familiar functions — familiar to those who regularly write scripts both in LSL and OSSL, that is — giving us the possibility of backporting content from OpenSimulator directly into SL, even though I will be the first person to admit that this is highly unlikely!
Anyway, I personally still favour Bleuhazenfurfle Resident's suggestion of just using SVG. SVG is the
perfect
format for that:- It's vector-based. No more problems with resolution, blurring, etc.
- It's well-documented.
- There are already gazillions of tools that export directly to SVG, so it's trivial for content creators to use it (Inkscape and Adobe Illustrator are possibly the best examples, but we shouldn't forget that things like Figma export to SVG as well!)
- You can add whatever fonts you wish. No problem whatsoever. No limitations.
- The full SVG specs already includes several filters and special effects, e.g. the drop shadows mentioned below, or having gradients, etc. All that is done straight out of the box.
- It enables not only textto be rendered on a prim's face, of course. It allows you to renderanything— from logos to full-blown HUDs.
- There must already be a gazillion SVG rendering engines all over the place. Pick the one that is fastest!
- As mentioned, SVG is just text, so it can be copied & pasted into a notecard, and then the notecard becomes a new asset type for all purposes. Simple!
- In the future, you can even go crazy and implement SMIL (https://developer.mozilla.org/en-US/docs/Web/SVG/SVG_animation_with_SMIL) on SVG to animateeverything! (or, alternatively, Lottie animations)
Some reading material (pertaining mostly to WebGL, but I think it could also be used for OpenGL as well): https://css-tricks.com/rendering-svg-paths-in-webgl/
You might also take a peek at how Google does it with Skia or how the Khronos Group implements OpenVG.
Another interesting project that attempts to do SVG rendering on top of OpenGL:
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.
![](https://canny.io/images/f26da9f8ba9bb3e25c8c7b215b6fe311.png)
![](https://canny.io/images/b9ad548936164a3b59258ed3de443af3.png)
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.
Gwyneth Llewelyn
Bleuhazenfurfle Resident yes, YES, YESSSSSSS!!!
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.
Load More
→