Skip to content
This repository has been archived by the owner on Mar 28, 2024. It is now read-only.

[BUG-231731] Script text quality and performance #9138

Open
sl-service-account opened this issue Feb 1, 2022 · 0 comments
Open

[BUG-231731] Script text quality and performance #9138

sl-service-account opened this issue Feb 1, 2022 · 0 comments

Comments

@sl-service-account
Copy link

How would you like the feature to work?

Please read fully and consider before cancelling the submission. I've considered solutions for solving performance issues and preventing abuse of this feature. This solution increases text quality, performance and portability to other platforms, e.g. mobile.

The feature requested is a high performing set of functions that can draw text onto surfaces so we don't have to awkwardly hack in text via bitmaps and offsets in-world.

The feature includes:

  • Multi-line support via \n

  • Measured font sizes

  • Batched draws

  • Baked font styles compiled into the viewer engine

    Restrict this feature to face 0 of the LINK_ROOT prim in an object. Attempts to draw onto any other link or face would silently fail. This prevents the feature from being spammed in a single object for abuse purposes.

    Additionally, a maximum arbitrary number of "screens" could be allowed per region. This limit could be raised in the future if necessary. But, a finite limit will help limit potential abuse. For example, the maximum limit of llInitDrawString calls per region could be set to for example 256. This would mean that 256 objects in a region are emitting text to a screen. Attachments on the HUD would not contribute towards this limit. Until the feature has been fully tested, use in attachments anywhere but the HUD or rezzed in a region could be automatically prevented.

    Example font styles, these styles lookup into the internal list of styles baked into the viewer from files 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 function prototypes:

    llInitDrawString(integer fontstyle)

    Initializes the text context for this object. If this is called again with the same style it should silently return without doing anything. If called with a different style then the new style is chosen. (Note: In the C++ call another call to initialize the opengltext will delete the previous glyphInfo automatically. And, if the GLSL program is already linked it is reused. There is no performance or memory hit in calling this method again.)

    parameters:
    style: Uses an integer of FONT_* constants that reference previously
    compiled baked fonts made originally from supplied TTF at the Linden
    Labs when the viewer was compiled.

    llBeginDrawString()

    Begins drawing the string with the selected style from init draw string.

    float llMeasureString(string text)

    Measures the size of the string to draw.

    parameters:
    text: The text to draw

    return value: The measured size.

    llDrawString(x, y, text, color)

    Draws the string at the position specified with the color.

    parameters:
    x: x position
    y: y position
    text: the text string
    color: the color of the text

    llEndDrawString()

    Swaps the buffer onto face 0 of the root prim.

    Note: llBeginDrawString just sets an integer in the C++ code to 0. Which means that there is no disadvantage to calling it again and no disadvantage to missing the end call. Other than your text not being drawn. This means it is low overhead and safe.

    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);
      // This begins drawing on face 0 on the LINK_ROOT using Arial.
      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);
      // This swaps the text onto face 0 on LINK_ROOT using Arial.
      llEndDrawString();
    }
    
    default
    {
      state_entry()
      {
        // This establishes the text context for drawing on face 0 on the LINK_ROOT using Arial.
        llInitDrawString(FONT_STYLE_DEFAULT);
        drawMyStrings();
      }
    } 

    The OpenGL C++ implementation (written by Nvidia, but it will work on AMD as well) to place in the viewer code to support this functionality is here. The code is under a very permissive open source license to be used as a sample. A patch is provided for gltext to support baking.

    Internally in the viewer these fonts could be looked up with the FONT_* constants.

    Note: The initialization of the ogl context per font for the text should instanced once per object using llInitDrawString in for example the state_entry so it can be used for multiple scripts and prims without reinitialization. This would get destroyed when the viewer releases the object.

    https://github.com/tlorach/OpenGLText

    There are provided a bakeFonts.exe for turning ttf fonts into texture atlases that could be shipped with the viewer for baking a variety of fonts. The baked fonts can be produced as .bin and .tga files with offset information. Or, it can be baked into font_xx.h and font_xx_bitmap.h files that can be included for compilation.

    This solution does not require the freetype library, e.g. Android or iOS.

    Why is this feature important to you? How would it benefit the community?

    Increased performance and visual quality for text.

Original Jira Fields
Field Value
Issue BUG-231731
Summary Script text quality and performance
Type New Feature Request
Priority Unset
Status Accepted
Resolution Unresolved
Created at 2022-02-01T04:45:32Z
Updated at 2022-02-03T02:47:26Z
{
  'Build Id': 'unset',
  'Business Unit': ['Platform'],
  'How would you like the feature to work?': 'Please read fully and consider before cancelling the submission. I\'ve considered solutions for solving performance issues and preventing abuse of this feature. This solution increases text quality, performance and portability to other platforms, e.g. mobile.\r\n\r\nThe feature requested is a high performing set of functions that can draw text onto surfaces so we don\'t have to awkwardly hack in text via bitmaps and offsets in-world.\r\n\r\nThe feature includes:\r\n* Multi-line support via \\n\r\n* Measured font sizes\r\n* Batched draws\r\n* Baked font styles compiled into the viewer engine\r\n\r\nRestrict this feature to face 0 of the LINK_ROOT prim in an object. Attempts to draw onto any other link or face would silently fail. This prevents the feature from being spammed in a single object for abuse purposes.\r\n\r\nExample font styles, these styles lookup into the internal list of styles baked into the viewer from files originating from ttf:\r\n\r\ninteger FONT_STYLE_DEFAULT = 0; // e.g. arial\r\ninteger FONT_STYLE_ARIAL = 0;\r\ninteger FONT_STYLE_CANDYSCRIPT = 1;\r\ninteger FONT_STYLE_SHELLEYALLEGRO = 2;\r\ninteger FONT_STYLE_BAUB = 3;\r\n\r\nLSL function prototypes:\r\n\r\nllBeginDrawString(integer style)\r\n\r\nBegins drawing the string with the selected style.\r\n\r\nparameters:\r\n  style: Uses an integer of FONT_* constants that reference previously \r\n  compiled baked fonts made originally from supplied TTF at the Linden \r\n  Labs when the viewer was compiled.\r\n\r\nfloat llMeasureString(string text)\r\n\r\nMeasures the size of the string to draw.\r\n\r\nparameters:\r\n  text: The text to draw\r\n\r\nreturn value: The measured size.\r\n\r\nllDrawString(x, y, text, color)\r\n\r\nDraws the string at the position specified with the color.\r\n\r\nparameters:\r\n  x: x position\r\n  y: y position\r\n  text: the text string\r\n  color: the color of the text\r\n\r\nllEndDrawSwing()\r\n\r\nSwaps the buffer onto face 0 of the root prim.\r\n\r\nNote: llBeginDrawString just sets an integer in the C++ code to 0. Which means that there is no disadvantage to calling it again and no disadvantage to missing the end call. Other than your text not being drawn. This means it is low overhead and safe.\r\n\r\nExample SL script:\r\n\r\nvector pos1 = <0, 0, 0>;\r\nvector pos2 = <0, 30, 0>;\r\nvector pos3 = <0, 60, 0>;\r\nvector color1 = <1,0,0>;\r\nvector color2 = <1,1,0>;\r\nvector color3 = <0,1,0>;\r\nstring text1 = "Hello World!";\r\nstring text2 = "It worked.";\r\nstring text3 = "This is a\\nmultiline string.";\r\nvector sz1 = llMeasureString(text1);\r\nvector sz2 = llMeasureString(text2);\r\nvector sz3 = llMeasureString(text3);\r\n\r\n// This begins drawing on face 0 on the LINK_ROOT using Arial.\r\nllBeginDrawString(FONT_STYLE_DEFAULT);\r\n\r\n// This draws "Hello World!" on the first line.\r\nllDrawString(pos1.x - sz1.x * 0.5, pos1.y - sz1.y, text1, color1);\r\n\r\n// This draws "It worked." on the next line.\r\nllDrawString(pos2.x - sz2.x * 0.5, pos2.y - sz2.y, text2, color2);\r\n\r\n// This draws "This is a" on the third line\r\n// and "multiline string." on the fourth.\r\nllDrawString(pos3.x - sz3.x * 0.5, pos3.y - sz3.y, text3, color3);\r\n\r\n// This swaps the text onto face 0 on LINK_ROOT using Arial.\r\nllEndDrawSwing();\r\n\r\nThe OpenGL C++ implementation (written by Nvidia, but it will work on AMD as well) to place in the viewer code to support this functionality is here. The code is under a very permissive open source license to be used as a sample. A patch is provided for gltext to support baking.\r\n\r\nInternally in the viewer these fonts could be looked up with the FONT_* constants.\r\n\r\nNote: The initialization of the ogl context per font for the text should instanced once per scene so it can be used for multiple scripts and prims without reinitialization. This would get destroyed when the viewer releases the scene entirely. It should not be reinitialized each time a script performs a begin.\r\n\r\nhttps://github.com/tlorach/OpenGLText\r\n\r\nThere are provided a bakeFonts.exe for turning ttf fonts into texture atlases that could be shipped with the viewer for baking a variety of fonts. The baked fonts can be produced as .bin and .tga files with offset information. Or, it can be baked into font_xx.h and font_xx_bitmap.h files that can be included for compilation.\r\n\r\nThis solution does not require the freetype library, e.g. Android or iOS.\r\n',
  'ReOpened Count': 0.0,
  'Severity': 'Unset',
  'Target Viewer Version': 'viewer-development',
  'Why is this feature important to you? How would it benefit the community?': 'Increased performance and visual quality for text.\r\n',
}
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

1 participant