Note: This issue was previously accepted on the JIRA as BUG-231731 in 2022. Resubmitting it to the Canny because I think the idea has been lost in the move.
The feature requested is a high performing set of functions that can draw text onto prim surfaces. With multi-line support via \n, measured font sizes, batched draws, and baked font styles compiled into the viewer engine. Restrict this feature to face 0 of the LINK_ROOT prim in an object. A maximum arbitrary number of "screens" could be allowed per region. The maximum limit of llInitDrawString calls per region could be set to for example 256. Attachments would not contribute towards this limit.
Styles baked into the viewer originating from ttf:
integer FONT_STYLE_DEFAULT = 0; // e.g. arial
integer FONT_STYLE_ARIAL = 0;
integer FONT_STYLE_CANDYSCRIPT = 1;
integer FONT_STYLE_SHELLEYALLEGRO = 2;
integer FONT_STYLE_BAUB = 3;
LSL prototypes:
llInitDrawString(integer fontstyle)
Initializes the text context. If this is called again with the same style it should silently return. If called with a different style then change the style. In C++ call initialize the opengltext to delete the previous glyphInfo. If the GLSL program is already linked it is reused.
parameters:
fontstyle: Uses an integer of FONT_* constants that reference baked fonts
llBeginDrawString()
Begins drawing.
float llMeasureString(string text)
Measures the size of the string.
parameters:
text: The text to draw
return value: The measured size.
llDrawString(x, y, text, color)
Draws the string at the position and color.
parameters:
x: x position
y: y position
text: the text string
color: the color
llEndDrawString()
Swaps the buffer onto the face of the prim.
Note: llBeginDrawString just sets an integer in the C++ code to 0.
Example SL script:
drawMyStrings()
{
vector pos1 = <0, 0, 0>;
vector pos2 = <0, 30, 0>;
vector pos3 = <0, 60, 0>;
vector color1 = <1,0,0>;
vector color2 = <1,1,0>;
vector color3 = <0,1,0>;
string text1 = "Hello World!";
string text2 = "It worked.";
string text3 = "This is a\nmultiline string.";
vector sz1 = llMeasureString(text1);
vector sz2 = llMeasureString(text2);
vector sz3 = llMeasureString(text3);
llBeginDrawString();
// This draws "Hello World!" on the first line.
llDrawString(pos1.x - sz1.x * 0.5, pos1.y - sz1.y, text1, color1);
// This draws "It worked." on the next line.
llDrawString(pos2.x - sz2.x * 0.5, pos2.y - sz2.y, text2, color2);
// This draws "This is a" on the third line and "multiline string." on the fourth.
llDrawString(pos3.x - sz3.x * 0.5, pos3.y - sz3.y, text3, color3);
llEndDrawString();
}
default
{
state_entry()
{
llInitDrawString(FONT_STYLE_DEFAULT);
drawMyStrings();
}
}
The OpenGL C++ implementation to place in the viewer code to support this functionality is on github. A patch exists for gltext to for baking. In the viewer these can be looked up with FONT_* constants. The init of the ogl context per font for the text should be instanced once per object using llInitDrawString to be used for multiple scripts and prims without reinitialization. This is destroyed when the viewer releases the object.
There is a bakeFonts.exe for turning ttf fonts into texture atlases to ship with the viewer to bake the fonts and can be produced as .bin and .tga files with offset info. Or, baked into font_xx.h and font_xx_bitmap.h files that can be compiled. This solution does not require the freetype library.