XyText-UTF8

From Second Life Wiki
Jump to navigation Jump to search

Scripting tools to allow display of text on a prim: XyText 1.5 , XyzzyText, XyyyyzText, XyText-UTF8, XyzzyText-UTF8, ZZText

Introduction

After some years of using XyzzyText I eventually got convinced that Xyzzy is really slow compared to xytext solutions. Probably a bit less lag, but when used in lessons people clearly noticed the filling up of lines terribly slow. So I backported my utf8 experience to XyText.

Also I noticed that whenever I needed to adapt xyXXXX to a new character set or encoding or if wanting to change the parameters for slicing, gridding, offsetting and finding the UTF8 counterpart in the internal lists was really difficult.

This is why here I'm proposing new parametrized CELL using 5 chars able to be driven by external main script.

A primer on UTF-8 encoding (for our needs with lsl and xytext handling)

Just a quick view of the UTF-8 encoding used by SecondLife. It is a very complete and smart way of representing special characters.

With normal characters such as 'A', UTF-8 is perfectly equivalent to ASCII encoding and both will use 1 byte (hexadecimal 41). For special or International characters, then UTF-8 is offering a unique translation which can be more than one byte.

For instance if you take the char 'ç', this will translate (according to http://www.isthisthingon.org/unicode/index.php) in utf8 to: C3A7 (two bytes).

You can also know this writing the following simple lsl script:

<lsl> default {

   touch_start(integer total_number)
   {
       llSay(0, llEscapeURL("ç"));
   }

}

</lsl> which is giving in chat

[15:20]  Object: %C3%A7

The super parametrizable cell

This cell has the following interesting characteristics:

  • It names itself after the object name number ("1000" for instance) this can be a bit unconvenient, but is a compromise among the linking order of standard xytext and the xyzzytext-m-n. You can find a way to rename all the linked object automagically ;)

Setting parameters and texture

  • It can receive in one shot the configuration of the texture and all parameters:

<lsl>

llMessageLinked(LINK_SET, 204005, 
               llList2CSV( [  
                   10, // knum number of characters per row
                   <-0.445,0.1,0>, // offset multiplier for cols
                   <0.422,-0.05,0>, // offset multiplier for rows
                   
                   <0.15, 0.05, 0>, // kmul1
                   <0.06, 0.05, 0>, // kmul2
                   <-0.86, 0.05, 0>, // kmul3
                   <0.06, 0.05, 0>, // kmul4
                   <0.15, 0.05, 0>, // kmul5
                   
                   //<0.045, 0, 0>, // koff1
                   <0.035, 0, 0>,
                   <-0.012,0,0>, // koff2
                   //<-0.284, 0, 0>, // koff3
                   <-0.298, 0, 0>,
                   <-0.012,0,0>, // koff4
                   //<-0.046, 0, 0> // koff5
                   <-0.055, 0, 0>
                  ]), "7120dab1-744c-692c-15f0-948fda775561");
                  

</lsl>

Setting the UTF8 decode table

  • It can be instructed on the listing of decode table to understand with a simple message like this:

<lsl> decode = [ "%C3%A8", "%C2%A1", ..... ]; llMessageLinked(LINK_SET, 204006, llList2CSV(decode),NULL_KEY); </lsl> for instance a complete settings for portuguese can be:

<lsl>

            // special UTF-8 chars for European languages
            // these 80 chars correspond to the following chars in CP850 codepage: (some are not viewable in editor)
           
            //           Ç          ü         é         â         ä         à        å         ç          ê        ë
            decode= [ "%C3%87", "%C3%BC", "%C3%A9", "%C3%A2", "%C3%A4", "%C3%A0", "%C3%A5", "%C3%A7", "%C3%AA", "%C3%AB",
            //           è         ï          î         ì         Ä         Å         É         æ         Æ    BLACK RIGHT-POINTING TRIANGLE
                      "%C3%A8", "%C3%AF", "%C3%AE", "%C3%AC", "%C3%84", "%C3%85", "%C3%89", "%C3%A6", "%C3%AE", "%E2%96%B6",
            //           ö         ò          û         ù         ÿ         Ö         Ü         ¢         £         ¥
                      "%C3%B6", "%C3%B2", "%C3%BB", "%C3%B9", "%C3%BF", "%C3%96", "%C3%9C", "%C2%A2", "%C2%A3", "%C2%A5",
            //           A^    copyright     á         í         ó         ú         ñ         Ñ         ª          º"
                      "%C3%82", "%C2%A9", "%C3%A1", "%C3%AD", "%C3%B3", "%C3%BA", "%C3%B1", "%C3%91", "%C2%AA", "%C2%BA",
            //            ¿        O^         ¬        ½         ¼          ¡         «        »       alfa          ß"
                      "%C2%BF", "%C3%94", "%C2%AC", "%C2%BD", "%C2%BC", "%C2%A1", "%C2%AB", "%C2%BB", "%CE%B1", "%C3%9F",
            //           gamma      pi      bigsigma  smsigma    mu  
                      "%CE%93", "%CF%80", "%CE%A3", "%CF%83", "%C2%B5" ];
                     
            //                              tau       BIGfi      theta       omega   delta  
            decode=(decode=[])+decode+ [ "%CF%84", "%CE%A6", "%CE%98", "%CE%A9", "%CE%B4",
            //         Uu          uu       EPS         INTERS        3bars        +-         <=           >=        INTEGRUP   INTEGRDOWN
                      "%C5%AC", "%C5%AD", "%CE%B5", "%E2%88%A9", "%E2%89%A1", "%C2%B1", "%E2%89%A5", "%E2%89%A4", "%E2%8C%A0", "%E2%8C%A1",
            //           A/       A\        a~         A~       E^         I/        O/        o~       O~        o^
                      "%C3%81", "%C3%80", "%C3%A3", "%C3%83", "%C3%8A", "%C3%8D", "%C3%93", "%C3%B5", "%C3%95", "%C3%B4" ];

</lsl>

The cell code

<lsl> //////////////////////////////////////////// // XyText v1.2 Script (5 Face, Single Texture) // Simplified Esperanto version // // Written by Xylor Baysklef // // Modified by Kermitt Quirk 19/01/2006 // To add support for 5 face prim instead of 3 // // Modified by Salahzar Stenvaag to show International UTF8 chars // May 2009 // With easily personalization for each language // ////////////////////////////////////////////

/////////////// CONSTANTS /////////////////// // XyText Message Map. integer SET_PARAMS = 204005; // set params is a CSV value including the following: // # is 1..5 knum, kcol<v>, krow<v>, kmul#<v*5>, koff#<v*5>, and in id=gFontTexture integer SET_DECODE = 204006; integer SET_COLOR = 204007;

// This is an extended character escape sequence. string ESCAPE_SEQUENCE = "\\e";

// This is used to get an index for the extended character. string EXTENDED_INDEX = "12345";

// Face numbers. integer FACE_1 = 3; integer FACE_2 = 7; integer FACE_3 = 4; integer FACE_4 = 6; integer FACE_5 = 1;


// number of characters for each "line" in texture integer knum=10;

// adjusting offset + multipliers for columns and rows vector kcol=<-0.445,0.1,0>; // offset + multiplier for cols vector krow=<0.422,-0.05,0>; // offset + multiplier for rows


// texture resizing for each face vector kmul1=<0.15, 0.05, 0>; // multiplicator for 1st char vector kmul2=<0.06, 0.05, 0>; // multiplicator for 2nd char vector kmul3=<-0.86, 0.05, 0>; // central char vector kmul4=<0.06, 0.05, 0>; vector kmul5=<0.15, 0.05, 0>;

// offset for each face vector koff1=<0.045, 0, 0>; vector koff2=<0,0,0>; vector koff3=<-0.284, 0, 0>; vector koff4=<0,0,0>; vector koff5=<-0.046, 0, 0>;


list decode; integer ME; // Used to hide the text after a fade-out. key TRANSPARENT = "701917a8-d614-471f-13dd-5f4644e36e3c"; ///////////// END CONSTANTS ////////////////

///////////// GLOBAL VARIABLES /////////////// // This is the key of the font we are displaying. key gFontTexture = "ce614b28-e80e-5731-3aca-c23dca1b3b70"; // All displayable characters. Default to ASCII order. string gCharIndex; // This is the channel to listen on while acting // as a cell in a larger display. integer gCellChannel = -1; // This is the starting character position in the cell channel message // to render. integer gCellCharPosition = 0; // This is whether or not to use the fade in/out special effect. integer gCellUseFading = FALSE; // This is how long to display the text before fading out (if using // fading special effect). // Note: < 0 means don't fade out. float gCellHoldDelay = 1.0; /////////// END GLOBAL VARIABLES ////////////

ResetCharIndex() { ’

    gCharIndex  = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`";
    gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~\n\n\n\n\n";
    decode=[];
    

}

vector GetGridOffset(integer index) {

  // Calculate the offset needed to display this character.
  integer Row = index / knum - 1;
  integer Col = index % knum;
  // Return the offset in the texture.
  return < kcol.x + kcol.y * Col, krow.x + krow.y * Row, 0.0>;

} ShowChars(vector grid_offset1, vector grid_offset2, vector grid_offset3, vector grid_offset4, vector grid_offset5) {

  // Set the primitive textures directly.
  
  llSetPrimitiveParams( [
       PRIM_TEXTURE, FACE_1, (string)gFontTexture, kmul1, grid_offset1 + koff1, 0.0,
       PRIM_TEXTURE, FACE_2, (string)gFontTexture, kmul2, grid_offset2 + koff2, 0.0,
       PRIM_TEXTURE, FACE_3, (string)gFontTexture, kmul3, grid_offset3 + koff3, 0.0,
       PRIM_TEXTURE, FACE_4, (string)gFontTexture, kmul4, grid_offset4 + koff4, 0.0,
       PRIM_TEXTURE, FACE_5, (string)gFontTexture, kmul5, grid_offset5 + koff5, 0.0
       ]);

}

// SALAHZAR intelligent procedure to extract UTF-8 codes and convert to index in our "cp850"-like table integer GetIndex(string char) {

   integer  ret=llSubStringIndex(gCharIndex, char);
   //llSay(0,"pos: "+(string)ret);
   if(ret>=0) return ret;

   // special char do nice trick :)
   string escaped=llEscapeURL(char);
   //llSay(0,"char: "+escaped);
   integer found=llListFindList(decode, [escaped]);

   // Return blank if not found
   if(found<0) return 0;

   // return correct index
   return 100+found;

} // END SALAHZAR


RenderString(string str) {

  // Get the grid positions for each pair of characters. 
  vector GridOffset1 = GetGridOffset( GetIndex(llGetSubString(str, 0, 0)) ); // SALAHZAR intermediate function
  vector GridOffset2 = GetGridOffset( GetIndex(llGetSubString(str, 1, 1)) ); // SALAHZAR
  vector GridOffset3 = GetGridOffset( GetIndex(llGetSubString(str, 2, 2)) ); // SALAHZAR
  vector GridOffset4 = GetGridOffset( GetIndex(llGetSubString(str, 3, 3)) ); // SALAHZAR
  vector GridOffset5 = GetGridOffset( GetIndex(llGetSubString(str, 4, 4)) ); // SALAHZAR

  // Use these grid positions to display the correct textures/offsets. 
  ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5); 

}

integer ConvertIndex(integer index) {

  // This converts from an ASCII based index to our indexing scheme.
  if (index >= 32) // ' ' or higher
      index -= 32;
  else { // index < 32
      // Quick bounds check.
      if (index > 15)
          index = 15;
      index += 94; // extended characters
  }
  return index;

}

default {

  state_entry() {
      // Initialize the character index.
      ResetCharIndex(); ME=(integer)llGetObjectName();
      RenderString(llGetObjectName());
      
  }
  link_message(integer sender, integer channel, string data, key id) {
      if (channel == ME) {
          RenderString(data);
          return;
      }
      // set_params will return in key the texture id, and in data
      // knum, kcol<v>, krow<v>, kmul#<v*5>, koff#<v*5>, and in id=gFontTexture
      if (channel == SET_PARAMS) {
          llSetText("*",<1,1,1>,1); // show we are working
          list l=llCSV2List(data);
          // Use the new texture instead of the current one.
          gFontTexture = id;
          // Change the currently shown texture.
          llSetTexture(gFontTexture, FACE_1);
          llSetTexture(gFontTexture, FACE_2);
          llSetTexture(gFontTexture, FACE_3);
          llSetTexture(gFontTexture, FACE_4);
          llSetTexture(gFontTexture, FACE_5);
          integer i=0;
          knum=(integer)llList2String(l,i++);
          kcol=(vector)llList2String(l,i++);
          krow=(vector)llList2String(l,i++);
          // kmul#
          kmul1=(vector)llList2String(l,i++);
          kmul2=(vector)llList2String(l,i++);
          kmul3=(vector)llList2String(l,i++);
          kmul4=(vector)llList2String(l,i++);
          kmul5=(vector)llList2String(l,i++);
          // koff#
          koff1=(vector)llList2String(l,i++);
          koff2=(vector)llList2String(l,i++);
          koff3=(vector)llList2String(l,i++);
          koff4=(vector)llList2String(l,i++);
          koff5=(vector)llList2String(l,i++);
          
          
          llSetText("",<1,1,1>,1); // remove working mark
          //RenderString("mmmmm");
          
          return;
      }
      // change the decode array to be able to easily change font
      if(channel == SET_DECODE) {
          
          // we are lucky since decode does NOT contain normal characters like ","
          decode=llCSV2List(data);
          return;
      }
      if (channel == SET_COLOR) {
          vector newColor = (vector)data;
          llSetColor(newColor, ALL_SIDES);
      }
  }

} </lsl>