NexiiText2

From Second Life Wiki
Revision as of 22:35, 19 September 2011 by Nexii Malthus (talk | contribs)
Jump to navigation Jump to search


Non-License

<lsl> //===================================================// // NexiiText.8 // // "20 September 2011", "06:15:00 GMT-0" // // By Nexii Malthus // // Public Domain // //===================================================// </lsl>

Intro

Second generation of my prim text renderer. It's meant to be easy, compact, efficient and high performance. The new design utilises PRIM_LINK_TARGET and a dynamic prim allocation architecture.

While you do not have the precise control of prim positioning that static text displays have, on the other hand you can very easily scale font size and create text boxes.

This library is excellent for use in the dynamic environment of HUDs. You can allocate a reserve of prims for use of the text library and use them up as you wish. The renderer is extremely efficient in prim usage as empty areas are completely void of prims. Prims are only used where text is visible. This also supports newlines (\n) and tabs (\t).

Note on Colour

It makes more sense for a rotation type to transport colours in a compact format (rotation RGBA), rather than multiple vars (vector RGB + float Alpha).

The compact format is <Red [0,1], Green [0,1], Blue [0,1], Alpha [0,1]>


Text Prim

<lsl> default {

   state_entry() {
       llSetPrimitiveParams([
           PRIM_TYPE,
               PRIM_TYPE_PRISM,
               PRIM_HOLE_SQUARE,
               <0.199, 0.8, 0>,
               0.306,
               <0, 0, 0>,
               <1, 1, 0>,
               <0, 0, 0>,
           PRIM_SIZE,
               <0.01, 0.58, 0.18>,
           PRIM_TEXTURE,
               ALL_SIDES,
               "180d23df-62b6-8608-0535-03413ddf3805",
               <1, 1, 0>,
               <0, 0, 0>,
               0.0
       ]);
       llSetObjectName("Text");
       llRemoveInventory(llGetScriptName());
   }

} </lsl>


Fonts

Some fonts I created. <lsl> key Normal = "0967db80-5132-d6dc-f37c-4f9cc1196983";// Normal Font key Bold = "48de7a07-1641-3d26-2bca-9773a20d2adf";// Be Bold! key Lined = "35399d2f-e35f-5100-179a-f3a119b1cdf7";// URLy Underline! key Italic = "1bb8a1f9-87cb-4946-afc6-b1856bc9b752";// Iffy Italics! key Stroked = "a2d5149e-d018-3ddd-202d-3432605c8084";// Edgy Edge! key Shadowed = "347ff828-9cef-31e5-a792-1bfdd2a1cea0";// Silly Shadow! </lsl>

Colours

Here's an extra snippet for use alongside, instead of writing down the colours all the time. For quick reference and convenience. <lsl> rotation White = <.99,.99,.99, 1.0>; rotation Black = <.00,.00,.00, 1.0>; rotation Red = <.99,.00,.00, 1.0>; rotation Green = <.00,.99,.50, 1.0>; rotation Blue = <.00,.40,.90, 1.0>; rotation Orange = <.99,.50,.00, 1.0>; rotation LSL = <.00,.99,.50, 1.0>; rotation URL = <.20,.40,.70, 1.0>; </lsl>


Core

<lsl> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NexiiText2 list TextLinkset; integer TextPrim; integer TextPrims; integer TextBreadth; list TextRender;

integer TextLength; integer TextPtr; vector TextPos; rotation TextRot; float TextHeight; integer TextLineX; integer TextLineY;

float TextRatio = 3.2222; float TextOffset = 2.85; string TextChars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"; </lsl>

There are five functions:

  • TextInit
    • Initializes the text renderer. This must be run once on script startup in default state on state_entry. It looks for all the prims named "Text".

<lsl> TextInit() {

   integer Hay = 1; integer Stacks = llGetNumberOfPrims();
   for(; Hay <= Stacks; ++Hay ) if(llGetLinkName(Hay) == "Text") TextLinkset += Hay;
   TextPrims = llGetListLength(TextLinkset);
   TextBreadth = TextPrims*5;

} </lsl>


  • TextCursor
    • Sets a location where to push text into.

<lsl> TextCursor(vector Position, vector Direction, float FontHeight, integer MaxCharsPerLine) {

   TextPos = Position;
   TextRot = llRotBetween(<1,0,0>, Direction);
   TextLength = MaxCharsPerLine;
   TextHeight = FontHeight;
   TextLineX = TextLineY = TextPtr = 0;

} </lsl>

  • TextPush
    • Virtually draws string characters with colour and font.

<lsl> TextPush(string Text, rotation Colour, key Font) {

   integer x; integer y = llStringLength(Text);
   for(; x < y && TextPrim < TextPrims; ++TextPrim) {
       while(llGetSubString(Text,x,x) == "\n") { ++x; ++TextLineY; TextLineX = 0; }
       while(llGetSubString(Text,x,x+3) == "\t") {
           ++TextLineX; x += 4;
           if(TextLineX >= llCeil(TextLength/5)) {
               TextLineX = 0; ++TextLineY;
           }
       }
       
       vector Pos;
       Pos.x = 0.0025;
       Pos.y = TextHeight * TextOffset*.5;
       Pos.z = TextHeight*-.5;
       //Pos.y += TextHeight *TextOffset * (TextPrim % llCeil(TextLength/5));
       //Pos.z -= llFloor(x/TextLength)*TextHeight + TextNewLines*TextHeight);
       Pos.y += TextHeight * TextOffset * TextLineX;
       Pos.z -= TextHeight * TextLineY;
       
       TextRender += [
           PRIM_LINK_TARGET, llList2Integer(TextLinkset,TextPrim),
           PRIM_SIZE, <0.01, TextHeight*TextRatio, TextHeight>,
           PRIM_ROT_LOCAL, TextRot,
           PRIM_POS_LOCAL, TextPos + Pos*TextRot
       ];
       
       integer Face;
       @Consume;
       string Char = llGetSubString(Text,x,x);
       if(Char != "\n" && x < y && Face < 5) {
           TextRender += TextFace(Face, Char, Colour, Font);
           ++x; ++Face;
           jump Consume;
       }
       
       ++TextLineX;
       if(TextLineX >= llCeil(TextLength/5)) {
           TextLineX = 0; ++TextLineY;
       }
   }

} </lsl>

  • TextFace
    • Private internal function -- returns a prim parameters list for drawing a character on a prim face.

<lsl> list TextFace(integer Face, string Char, rotation Colour, key Font) {

   integer i = llSubStringIndex(TextChars, Char);
   float W = 0.60; float X = 0.0;
   float H = 0.98;
   if(Face == 0) return [
       PRIM_TEXTURE, 3, Font, <.25*W,.1*H,0>, <((-.45+.1*(i%10)) + (.0745*W)) + (X*W), .45-(.1*(i/10)), 0>, 0,
       PRIM_COLOR, 3, <Colour.x,Colour.y,Colour.z>, Colour.s];
   else if(Face == 1) return [
       PRIM_TEXTURE, 7, Font, <.1*W,.1*H,0>, <((-.45+.1*(i%10))) + (X*W), .45-(.1*(i/10)), 0>, .0,
       PRIM_COLOR, 7, <Colour.x,Colour.y,Colour.z>, Colour.s];
   else if(Face == 2) {
       float x = ((-.45+.1*(i%10)) - (.69*W)) + (X*W); if(x < -1) x = 2 + x;
       return [PRIM_TEXTURE, 4, Font, <-1.635*W,.1*H,0>, <x, .45-(.1*(i/10)), 0>, .0,
               PRIM_COLOR, 4, <Colour.x,Colour.y,Colour.z>, Colour.s];
   } else if(Face == 3) return [
       PRIM_TEXTURE, 6, Font, <.1*W,.1*H,0>, <((-.45+.1*(i%10))) + (X*W), .45-(.1*(i/10)), 0>, .0,
       PRIM_COLOR, 6, <Colour.x,Colour.y,Colour.z>, Colour.s];
   /*/ Face == 4 /*/ return [
       PRIM_TEXTURE, 1, Font, <.25*W,.1*H,0>, <((-.45+.1*(i%10)) - (.0745*W)) + (X*W), .45-(.1*(i/10)), 0>, .0,
       PRIM_COLOR, 1, <Colour.x,Colour.y,Colour.z>, Colour.s];

} </lsl>

  • TextFrameEnd
    • Finishes text input and starts actual rendering.

<lsl> TextFrameEnd() {

   for(; TextPrim < TextPrims; ++TextPrim) TextRender += [
       PRIM_LINK_TARGET, llList2Integer(TextLinkset, TextPrim),
       PRIM_POS_LOCAL, ZERO_VECTOR,
       PRIM_ROT_LOCAL, ZERO_ROTATION,
       PRIM_SIZE, <0.01, 0.01, 0.01>,
       PRIM_COLOR, ALL_SIDES, ZERO_VECTOR, 0.0
   ];
   llSetLinkPrimitiveParamsFast(llList2Integer(TextRender,1), llList2List(TextRender,2,-1));
   TextRender = [];
   TextPrim = 0;

} </lsl> <lsl> // NexiiText2 //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// </lsl>

Complete Script

<lsl> //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Linkset Indexing list LinkedList(string Needle) {

   list Needles;
   integer Hay = 1;
   integer Stacks = llGetNumberOfPrims();
   for(; Hay <= Stacks; ++Hay ) if(llGetLinkName(Hay) == Needle) Needles += Hay;
   return Needles;

} integer Linked(string Needle) {

   integer Prims = llGetNumberOfPrims()+1;
   while(--Prims) if(llGetLinkName(Prims) == Needle) return Prims;
   return 0;

} // Linkset Indexing ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // NexiiText2 list TextLinkset; integer TextPrim; integer TextPrims; integer TextBreadth; list TextRender;

integer TextLength; integer TextPtr; vector TextPos; rotation TextRot; float TextHeight; integer TextLineX; integer TextLineY;

float TextRatio = 3.2222; float TextOffset = 2.85; string TextChars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";


TextInit() {

   integer Hay = 1; integer Stacks = llGetNumberOfPrims();
   for(; Hay <= Stacks; ++Hay ) if(llGetLinkName(Hay) == "Text") TextLinkset += Hay;
   TextPrims = llGetListLength(TextLinkset);
   TextBreadth = TextPrims*5;

}

TextCursor(vector Position, vector Direction, float FontHeight, integer MaxCharsPerLine) {

   TextPos = Position;
   TextRot = llRotBetween(<1,0,0>, Direction);
   TextLength = MaxCharsPerLine;
   TextHeight = FontHeight;
   TextLineX = TextLineY = TextPtr = 0;

}

TextPush(string Text, rotation Colour, key Font) {

   integer x; integer y = llStringLength(Text);
   for(; x < y && TextPrim < TextPrims; ++TextPrim) {
       while(llGetSubString(Text,x,x) == "\n") { ++x; ++TextLineY; TextLineX = 0; }
       while(llGetSubString(Text,x,x+3) == "\t") {
           ++TextLineX; x += 4;
           if(TextLineX >= llCeil(TextLength/5)) {
               TextLineX = 0; ++TextLineY;
           }
       }
       
       vector Pos;
       Pos.x = 0.0025;
       Pos.y = TextHeight * TextOffset*.5;
       Pos.z = TextHeight*-.5;
       //Pos.y += TextHeight *TextOffset * (TextPrim % llCeil(TextLength/5));
       //Pos.z -= llFloor(x/TextLength)*TextHeight + TextNewLines*TextHeight);
       Pos.y += TextHeight * TextOffset * TextLineX;
       Pos.z -= TextHeight * TextLineY;
       
       TextRender += [
           PRIM_LINK_TARGET, llList2Integer(TextLinkset,TextPrim),
           PRIM_SIZE, <0.01, TextHeight*TextRatio, TextHeight>,
           PRIM_ROT_LOCAL, TextRot,
           PRIM_POS_LOCAL, TextPos + Pos*TextRot
       ];
       
       integer Face;
       @Consume;
       string Char = llGetSubString(Text,x,x);
       if(Char != "\n" && x < y && Face < 5) {
           TextRender += TextFace(Face, Char, Colour, Font);
           ++x; ++Face;
           jump Consume;
       }
       
       ++TextLineX;
       if(TextLineX >= llCeil(TextLength/5)) {
           TextLineX = 0; ++TextLineY;
       }
   }

}

list TextFace(integer Face, string Char, rotation Colour, key Font) {

   integer i = llSubStringIndex(TextChars, Char);
   float W = 0.60; float X = 0.0;
   float H = 0.98;
   if(Face == 0) return [
       PRIM_TEXTURE, 3, Font, <.25*W,.1*H,0>, <((-.45+.1*(i%10)) + (.0745*W)) + (X*W), .45-(.1*(i/10)), 0>, 0,
       PRIM_COLOR, 3, <Colour.x,Colour.y,Colour.z>, Colour.s];
   else if(Face == 1) return [
       PRIM_TEXTURE, 7, Font, <.1*W,.1*H,0>, <((-.45+.1*(i%10))) + (X*W), .45-(.1*(i/10)), 0>, .0,
       PRIM_COLOR, 7, <Colour.x,Colour.y,Colour.z>, Colour.s];
   else if(Face == 2) {
       float x = ((-.45+.1*(i%10)) - (.69*W)) + (X*W); if(x < -1) x = 2 + x;
       return [PRIM_TEXTURE, 4, Font, <-1.635*W,.1*H,0>, <x, .45-(.1*(i/10)), 0>, .0,
               PRIM_COLOR, 4, <Colour.x,Colour.y,Colour.z>, Colour.s];
   } else if(Face == 3) return [
       PRIM_TEXTURE, 6, Font, <.1*W,.1*H,0>, <((-.45+.1*(i%10))) + (X*W), .45-(.1*(i/10)), 0>, .0,
       PRIM_COLOR, 6, <Colour.x,Colour.y,Colour.z>, Colour.s];
   /*/ Face == 4 /*/ return [
       PRIM_TEXTURE, 1, Font, <.25*W,.1*H,0>, <((-.45+.1*(i%10)) - (.0745*W)) + (X*W), .45-(.1*(i/10)), 0>, .0,
       PRIM_COLOR, 1, <Colour.x,Colour.y,Colour.z>, Colour.s];

}

TextFrameEnd() {

   for(; TextPrim < TextPrims; ++TextPrim) TextRender += [
       PRIM_LINK_TARGET, llList2Integer(TextLinkset, TextPrim),
       PRIM_POS_LOCAL, ZERO_VECTOR,
       PRIM_ROT_LOCAL, ZERO_ROTATION,
       PRIM_SIZE, <0.01, 0.01, 0.01>,
       PRIM_COLOR, ALL_SIDES, ZERO_VECTOR, 0.0
   ];
   llSetLinkPrimitiveParamsFast(llList2Integer(TextRender,1), llList2List(TextRender,2,-1));
   TextRender = [];
   TextPrim = 0;

} // NexiiText2 ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Styles key Normal = "0967db80-5132-d6dc-f37c-4f9cc1196983";// Normal Font key Bold = "48de7a07-1641-3d26-2bca-9773a20d2adf";// Be Bold! key Lined = "35399d2f-e35f-5100-179a-f3a119b1cdf7";// URLy Underline! key Italic = "1bb8a1f9-87cb-4946-afc6-b1856bc9b752";// Iffy Italics! key Stroked = "a2d5149e-d018-3ddd-202d-3432605c8084";// Edgy Edge! key Shadowed = "347ff828-9cef-31e5-a792-1bfdd2a1cea0";// Silly Shadow!

rotation White = <.99,.99,.99, 1.0>; rotation Black = <.00,.00,.00, 1.0>; rotation Red = <.99,.00,.00, 1.0>; rotation Green = <.00,.99,.50, 1.0>; rotation Blue = <.00,.40,.90, 1.0>; rotation Orange = <.99,.50,.00, 1.0>; rotation LSL = <.00,.99,.50, 1.0>; rotation URL = <.20,.40,.70, 1.0>; // Styles ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // Application default {

   state_entry() {
       TextInit();
       TextFrameEnd();
       
       integer primA = Linked("A");
       vector vA = llList2Vector(llGetLinkPrimitiveParams(primA, [PRIM_POS_LOCAL]),0);
       integer primB = Linked("B");
       vector vB = llList2Vector(llGetLinkPrimitiveParams(primB, [PRIM_POS_LOCAL]),0);
       
       
       TextCursor(vA, <1,0,0>, 0.01, 30);
       TextPush("Awesome!", White, Italic);
       TextPush("\n\nNexiiText", Orange, Lined);
       TextPush("\n\tA Prim Text Renderer", White, Normal);
       TextPush("\n\n...with dynamic\n\t\tprim allocation", White, Normal);
       TextFrameEnd();
   }

} </lsl>