Add a Text Rendering Method
tracked
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
Cain Maven
Yes! This would be a great -- and I think we can all agree, long overdue -- addition.
I like the idea of keeping it relatively simple; even in its most basic version this would be a big step forward.
I'm not convinced that the font color should be controlled by face color. This would mean that the face color changes meaning depending on whether or not text is rendered on the face. I think it's better to leave existing properties alone and handle added capabilities separately, e.g. in the form of parameters such as FONT_COLOR. Transparent background should definitely be a supported feature, but I think that too should be a parameter rather than implicitly tied to the face texture/transparency.
Rich text would of course be nice, but it may be worth considering if that's a candidate for llRenderRichText() to avoid complicating matters too much.
Jenna Felton
I hope the "under review" status allows me to add a suggestion or two :)
I am designing a HUD currently which would allow the user to browse through a list of options. I not wanted to use a XyText-like solution because that are quite many faces for a little text and you only can use a limited number of characters while I'd like to display every character a note card can use.
I also not like to use MoaP because not everyone wants to use media. The only solution remains is using hover text but it has its own limitations.
So, I wanted to write a canny request for writing text over a prim face and was happy to find this one. But I'd like to make a suggestion. I would define the function like this:
llLinkRenderText(integer link, integer face,
integer width, integer height, string text,
list params);
The link number allows to control an other prim in link-set, while using
LINK_THIS
controls the same prim.The function should work so: The viewer creates a buffered transparent texture with the size (width, height) and renders the text into it. Then it applies the texture to the given face of the given prim. This allows to control the size of the text.
The actual text is rendered only within the area on the UV map the given face uses. When, for example the face uses the left upper corner of the UV map, then only in these boundaries the text is rendered. This allows to render different text upon different faces of the same prim.
The text lines are broken regularly but only at the outer right edge of the text area. When the face uses multiple areas in the UV map, the text line continues in the next area but a word is never broken in two except when both areas are connected then a word can be written over the edge connecting both areas.
The function can be called multiple times for every prim, but when two calls set text for the same face, the second call replaces the text set by the previous one.
I would also add one more option:
[TEXT_BACKGROUND, key texture]
When you want the text to be solid you provide a texture to render the text upon it. The texture itself will retain the color and transparency when the face color and transparency changes because these parameters control the rendered text.
Nexii Malthus
Something that may be of interest is this c++ library: https://sluglibrary.com/
This is a modern library specifically designed for drawing text/typography on the GPU and so can be added to 3D environments easily.
This could even be used to replace the current text renderer used in the viewer if it proves to be performant enough which would increase FPS.
animats Resident
I'd suggest going with SVG. Probably the small mobile subset - no animation. That's enough for signs, notice boards, and such. Open source implementations of SVG are available.
It should be possible to change SVG text from scripts, so signs can be changed.
Kyle Linden
tracked
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.
Load More
→