Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

XyText v1.0 - It it normal to get slow rendering time?

Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
01-15-2006 19:29
Hi,

I'm getting 5-20second rendering times for 20-30 characters using XyText v1.0 (2 char per prim face). Is this normal? (i.,e. not a problem with my PC)

Is yes I guess I should try v1.1 (1 char per prim face) - I assume the only negative is that more prims are required?

Tks
Introvert Petunia
over 2 billion posts
Join date: 11 Sep 2004
Posts: 2,065
01-15-2006 20:10
XyText is one of those ultra-clever hacks that should almost not work at all. Even with in-game 1/10th the load in prior years, XyText was never what one would call zippy. Given the current delays in texture changing and loading, I'm kind of amazed that it is still working at all.

HTML on a prim is the "promised land" that will supposedly bring live text to SL. Until then there is XyText.
_____________________
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
01-15-2006 21:07
got any ideas of response time improvements going from XyText v1.0 to v1.1?
Aaron Levy
Medicated Lately?
Join date: 3 Jun 2004
Posts: 2,147
01-15-2006 21:20
Well, like Introvert said, it's likely not a XyText problem. Texture loading in general is borked.
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
01-15-2006 23:15
ok - I think you're saying there won't be much of a difference/improvement then - thanks
Christopher Omega
Oxymoron
Join date: 28 Mar 2003
Posts: 1,828
01-15-2006 23:49
From: Greg Hauptmann
ok - I think you're saying there won't be much of a difference/improvement then - thanks

Actually, there will be. The original Xytext used a special, very large texture to get more then one character on a face (basically, it had every combination of two printable letters). Due to the texture's size, SL takes long to load it. As it seems the newest version uses only one character per face, the textures will be *much* smaller, and will load quicker.
==Chris
_____________________
October 3rd is the Day Against DRM (Digital Restrictions Management), learn more at http://www.defectivebydesign.org/what_is_drm
Easy Wheeling
Registered User
Join date: 18 Jun 2004
Posts: 28
01-16-2006 18:01
Not too long ago, I made a hud that uses 8, nine sided prims and face swapping to force refresh of XyText's 67 total textures(one for the 1 char per face texture, and 66 for all the 2 character per face textures...)

It seems to work, and not impact others in your area, but carrying around all those textures does seem to pretty much fill my cache to where other texture loading seems impacted.
_____________________
- Life is precious. Live it well.
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
01-16-2006 19:03
actually there a 2 things I don't understand here - this is noting that actual display of new text is based around an "llSetPrimitiveParams([PRIM_TEXTURE,..." type call:

[1] Re "carrying around all those textures...": I'm assuming the XyText textures were developed once, and stored only once in SL? (i.e. in Xylor's inventory I guess they must be) - mulitple people in the same prim shouldn't impact performance from a texture caching point of view no?

[2] Noting it is acknowledged that 1 char per face renders faster: I'm just wonder why this would be. I would have guessed that the response time for rendering a texture would be kind of independant of what the content of the texture was? That is, to display a string of 18 characters:
- 2 char/face = 3 prims * 3 faces/prim * 2 char/face = 18

- 1 char/face = 6 prims * 3 faces/prim * 1 char/face = 18
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
01-16-2006 19:05
actually there a 2 things I don't understand here - this is noting that actual display of new text is based around an "llSetPrimitiveParams([PRIM_TEXTURE,..." type call:

[1] Re "carrying around all those textures...": I'm assuming the XyText textures were developed once, and stored only once in SL? (i.e. in Xylor's inventory I guess they must be) - mulitple people in the same prim shouldn't impact performance from a texture caching point of view no?

[2] Noting it is acknowledged that 1 char per face renders faster: I'm just wonder why this would be. I would have guessed that the response time for rendering a texture would be kind of independant of what the content of the texture was? That is, to display a string of 18 characters:
- 2 char/face = 3 prims * 3 faces/prim * 2 char/face = 18
=> 9 textures to render
- 1 char/face = 6 prims * 3 faces/prim * 1 char/face = 18
=> 18 textures to render

So wouldn't the 2 char/face be faster (i.e. more textures to render)?
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-16-2006 19:32
The reason for the different load times is more to do with how you use xytext (or which implementation of it you use). The basic way xytext works its that you flatten a prim so that 3 faces are showing toward the front. This way u can display a separate texture on each face (or different offsets of the same texture).

The simple implementation of xytext uses just one texture which contains all the available letters, symbols etc. So you display that same texture on all 3 faces, then offset it to display the desired letter. Using this method (my personal preference) you are only using one texture, so once it's loaded all the characters will display quickly. This is also the method I used on Tringo simply for the better speed and the fact it only requires the single texture (hence less to download to the client).

The more complicated version uses exactly the same principal, except it displays 2 characters on each face (giving you a total of 6 characters possible to display on a single prim). The problem you get with trying to display 2 letters per face is that you then have to have textures with all the possible combinations of 2 characters. I haven't actually looked at those textures myself, but I expect the first texture would contain AA to AZ, then next would have BA to BZ, next CA to CZ etc (not counting numbers and symbols which would increase the combinations even more). So when you're looking at something that uses this 2 char per face version, and it displays a 2 letter combination you haven't seen yet, that texture has to be downloaded into the local client cache.

The guts of it is that the 3 letter version only uses one texture, and the 6 letter version uses heaps of textures (or one very big texture. Seems to be some discrepancy on that part in the posts above). So, it's not the rendering of the textures that's the problem, it's the fact you've gotta download them all. Personally I think the 6 letter version is far too resource hungry and you can't actually read much of it unless you hang around near something using it for quite some time (till you've got the majority of the necessary textures), so I think I'd go for the 3 letter version every time.

So I think the "carrying around all those textures" comment is referring to the fact that Easy is forcing the textures to stay in the cache (because they're being used by the attachment) and therefore leaving less room for other textures.
Greg Hauptmann
Registered User
Join date: 30 Oct 2005
Posts: 283
01-16-2006 19:43
thanks Kermitt - that helped a lot - I'd misunderstood part of the XyText operation - I'll head to the 1 char/face version straight away

BTW - There isn't a prebuilt set of xyText cells available someone could seen me in-world? or available to purchase? Just to save time manually building up a set of these cells (e.g. for say 80 lines x 10 rows display or something like this)
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
01-17-2006 09:00
You can also use the 5-face hack someone recently came up with, using a cut hollow box, to get 5 characters per prim.

I don't recall the exact prim, but it looks like the top size of a U-shaped prim is set close to zero and then it's flattened, so you see (in sequence) an outside face, a cut face, part of the inside face, a cut face, and an outside face.
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-17-2006 14:40
From: Argent Stonecutter
You can also use the 5-face hack someone recently came up with, using a cut hollow box, to get 5 characters per prim.

I don't recall the exact prim, but it looks like the top size of a U-shaped prim is set close to zero and then it's flattened, so you see (in sequence) an outside face, a cut face, part of the inside face, a cut face, and an outside face.


That's interesting. Never heard of shaping it like that before. I'll have a go at making one of these tonight, but if anyone has a pre-shaped prim they could send me a copy of I'd really appreciate it.
Patch Lamington
Blumfield SLuburban
Join date: 2 Nov 2005
Posts: 188
01-17-2006 15:42
From: Argent Stonecutter
You can also use the 5-face hack someone recently came up with, using a cut hollow box, to get 5 characters per prim.

I don't recall the exact prim, but it looks like the top size of a U-shaped prim is set close to zero and then it's flattened, so you see (in sequence) an outside face, a cut face, part of the inside face, a cut face, and an outside face.


Seeing as the inside only uses one texture for all faces, this will be a major hack that will still require a texture with every possible pair of chars...

I can imagine using this to get one extra char without bumping the texture requirement right back up again - not two.
_____________________
Blumfield - a regular everyday kind of 'burb in an irregular world.
This notice brought to you by the Blumfield Visitors and Residents Bureau.
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-17-2006 18:58
From: Patch Lamington
Seeing as the inside only uses one texture for all faces, this will be a major hack that will still require a texture with every possible pair of chars...


Good point, although it'd still be nice to even get one more character out of it. I was wondering when I wrote the last post if there might be other side effects from doing this too. I think I've tried something similar before, and found that because you couldn't flatten it totally, you also ended up with tiny little pieces of texture showing on the sides of the inside face. Whether that's a problem with xytext or not I don't know. Probably depends how close together the characters are on the actual texture.

I'll definately dig into this whole area more deeply when I can get into SL after work tonight. Of course the bummer about only using the 3 char version of xytext is that it uses double the prims of the 6 char version (to get the same total number of characters), so if the number of prims can be reduced in any way I'm very keen to find out how.
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-18-2006 04:29
From: Argent Stonecutter
You can also use the 5-face hack someone recently came up with, using a cut hollow box, to get 5 characters per prim.

I don't recall the exact prim, but it looks like the top size of a U-shaped prim is set close to zero and then it's flattened, so you see (in sequence) an outside face, a cut face, part of the inside face, a cut face, and an outside face.


OK... you got me stumped. With the way that Hollow and Top Size work I can't see how the configuration you've described is possible.
Ben Bacon
Registered User
Join date: 14 Jul 2005
Posts: 809
01-18-2006 05:16
From: Kermitt Quirk
OK... you got me stumped. With the way that Hollow and Top Size work I can't see how the configuration you've described is possible.
explanation here
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-18-2006 05:30
From: Ben Bacon


Excellent. Thanx for the link.
Patch Lamington
Blumfield SLuburban
Join date: 2 Nov 2005
Posts: 188
01-18-2006 09:40
wow... (*sound of brain melting and dripping out of ears*)
I missed that.

will have to check that out a.s.a.p.
cool stuff.
_____________________
Blumfield - a regular everyday kind of 'burb in an irregular world.
This notice brought to you by the Blumfield Visitors and Residents Bureau.
Tiger Crossing
The Prim Maker
Join date: 18 Aug 2003
Posts: 1,560
01-18-2006 10:37
I've always used the letter-pairs version of XyText to get 6 characters per prim. (I'll have to look into the 10 character version... Anyone have the modified XyText script for that? If not, I'll release the change if I make it.)

To speed up the loading of the text, I'll sometimes burry a pair of cubes painted with the XyText textures (6 or 8 or so, I forget) in the ground or inside some other solid prim. It won't be seen, but since SL doesn't have surface culling the textures WILL get loaded. Then when the text changes to use letter combinations on the textures you weren't already using, they will be pre-loaded and come up quickly.

Of course, that technique isn't very usefull for HUDs and attachments, just for displays set in a particular location and that change often.
_____________________
~ Tiger Crossing
~ (Nonsanity)
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-18-2006 14:54
From: Tiger Crossing
I've always used the letter-pairs version of XyText to get 6 characters per prim. (I'll have to look into the 10 character version... Anyone have the modified XyText script for that? If not, I'll release the change if I make it.)


I shoulda mentioned in my post last night that I'm gonna have a go at updating xytext for the 5 face version too. Just didn't have time to get into it when I first saw the link Ben posted. I'll be updating xytext 1.1.1 though, so it'll be a 5 char/1 prim version. So, if anyone else has done that already please let me know. Otherwise I'll post my results when it's done.
Sordal Saramago
Registered User
Join date: 19 Dec 2005
Posts: 1
01-19-2006 02:19
The center character / characters are going to give you problems if you use a character set that has transparency. To help a little bit, the face order of the five faces that you see are as follows:


3 7 4 6 1


And

CODE

ShowChars(vector grid_offset1, vector grid_offset2, vector grid_offset3,vector grid_offset4,vector grid_offset5) {
// Set the primitive textures directly.
llSetPrimitiveParams( [
PRIM_TEXTURE, LEFT_FACE1, (string) gFontTexture, <0.2, 0.1, 0>, grid_offset1, 0.0,
PRIM_TEXTURE, LEFT_FACE, (string) gFontTexture, <0.1, 0.1, 0>, grid_offset2, 0.0,
PRIM_TEXTURE, MIDDLE_FACE, (string) gFontTexture, <-1.3, 0.1, 0>, grid_offset3, 0.0,
PRIM_TEXTURE, RIGHT_FACE, (string) gFontTexture, <0.1, 0.1, 0>, grid_offset4, 0.0,
PRIM_TEXTURE, RIGHT_FACE1, (string) gFontTexture, <0.2, 0.1, 0>, grid_offset5, 0.0
]);
}


Have fun calculating the grid_offsets... I've got most working except grid_offset5....


NOTE: This is for the ver 1.1.1 of XYText
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
01-19-2006 02:46
From: Sordal Saramago
The center character / characters are going to give you problems if you use a character set that has transparency. To help a little bit, the face order of the five faces that you see are as follows:


I've already finished the script... just doing a bit of testing. Middle char was a little of a pain, but I've got it working fine. Will post the code shortly.
Kermitt Quirk
Registered User
Join date: 4 Sep 2004
Posts: 267
XyText v1.2 (5 Face, Single Texture)
01-19-2006 03:28
I've posted my script to the original XyText thread but it looks like that forum is moderated so it isn't showing up yet... so I'll post it here too...

CODE
////////////////////////////////////////////
// XyText v1.2 Script (5 Face, Single Texture)
//
// Written by Xylor Baysklef
//
// Modified by Kermitt Quirk 19/01/2006
// To add support for 5 face prim instead of 3
//
////////////////////////////////////////////

/////////////// CONSTANTS ///////////////////
// XyText Message Map.
integer DISPLAY_STRING = 204000;
integer DISPLAY_EXTENDED = 204001;
integer REMAP_INDICES = 204002;
integer RESET_INDICES = 204003;
integer SET_CELL_INFO = 204004;
integer SET_FONT_TEXTURE = 204005;
integer SET_THICKNESS = 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;

// 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 = "b2e7394f-5e54-aa12-6e1c-ef327b6bed9e";
// 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[\\]^_`";
// \" <-- Fixes LSL syntax highlighting bug.
gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~";
gCharIndex += "\n\n\n\n\n";
}

vector GetGridOffset(integer index) {
// Calculate the offset needed to display this character.
integer Row = index / 10;
integer Col = index % 10;

// Return the offset in the texture.
return <-0.45 + 0.1 * Col, 0.45 - 0.1 * Row, 0.0>;
}

ShowChars(vector grid_offset1, vector grid_offset2, vector grid_offset3, vector grid_offset4, vector grid_offset5) {
// Set the primitive textures directly.

// <-0.256, 0, 0>
// <0, 0, 0>
// <0.130, 0, 0>
// <0, 0, 0>
// <-0.74, 0, 0>

llSetPrimitiveParams( [
PRIM_TEXTURE, FACE_1, (string)gFontTexture, <0.12, 0.1, 0>, grid_offset1 + <0.037, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_2, (string)gFontTexture, <0.05, 0.1, 0>, grid_offset2, 0.0,
PRIM_TEXTURE, FACE_3, (string)gFontTexture, <-0.74, 0.1, 0>, grid_offset3 - <0.244, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_4, (string)gFontTexture, <0.05, 0.1, 0>, grid_offset4, 0.0,
PRIM_TEXTURE, FACE_5, (string)gFontTexture, <0.12, 0.1, 0>, grid_offset5 - <0.037, 0, 0>, 0.0
]);
}

RenderString(string str) {
// Get the grid positions for each pair of characters.
vector GridOffset1 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)) );
vector GridOffset2 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridOffset3 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)) );
vector GridOffset4 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridOffset5 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)) );

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

RenderWithEffects(string str) {
// Get the grid positions for each pair of characters.
vector GridOffset1 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)) );
vector GridOffset2 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridOffset3 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)) );
vector GridOffset4 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridOffset5 = GetGridOffset( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)) );

// First set the alpha to the lowest possible.
llSetAlpha(0.05, ALL_SIDES);

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridOffset1, GridOffset2, GridOffset3, GridOffset4, GridOffset5); // Now turn up the alpha until it is at full strength.
float Alpha;
for (Alpha = 0.10; Alpha <= 1.0; Alpha += 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// See if we want to fade out as well.
if (gCellHoldDelay < 0.0)
// No, bail out. (Just keep showing the string at full strength).
return;
// Hold the text for a while.
llSleep(gCellHoldDelay);
// Now fade out.
for (Alpha = 0.95; Alpha >= 0.05; Alpha -= 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// Make the text transparent to fully hide it.
llSetTexture(TRANSPARENT, ALL_SIDES);
}

RenderExtended(string str) {
// Look for escape sequences.
list Parsed = llParseString2List(str, [], [ESCAPE_SEQUENCE]);
integer ParsedLen = llGetListLength(Parsed);

// Create a list of index values to work with.
list Indices;
// We start with room for 5 indices.
integer IndicesLeft = 5;

integer i;
string Token;
integer Clipped;
integer LastWasEscapeSequence = FALSE;
// Work from left to right.
for (i = 0; i < ParsedLen && IndicesLeft > 0; i++) {
Token = llList2String(Parsed, i);

// If this is an escape sequence, just set the flag and move on.
if (Token == ESCAPE_SEQUENCE) {
LastWasEscapeSequence = TRUE;
}
else { // Token != ESCAPE_SEQUENCE
// Otherwise this is a normal token. Check its length.
Clipped = FALSE;
integer TokenLength = llStringLength(Token);
// Clip if necessary.
if (TokenLength > IndicesLeft) {
Token = llGetSubString(Token, 0, IndicesLeft - 1);
TokenLength = llStringLength(Token);
IndicesLeft = 0;
Clipped = TRUE;
}
else
IndicesLeft -= TokenLength;

// Was the previous token an escape sequence?
if (LastWasEscapeSequence) {
// Yes, the first character is an escape character, the rest are normal.

// This is the extended character.
Indices += [llSubStringIndex(EXTENDED_INDEX, llGetSubString(Token, 0, 0)) + 95];

// These are the normal characters.
integer j;
for (j = 1; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}
else { // Normal string.
// Just add the characters normally.
integer j;
for (j = 0; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}

// Unset this flag, since this was not an escape sequence.
LastWasEscapeSequence = FALSE;
}
}

// Use the indices to create grid positions.
vector GridOffset1 = GetGridOffset( llList2Integer(Indices, 0));
vector GridOffset2 = GetGridOffset( llList2Integer(Indices, 1) );
vector GridOffset3 = GetGridOffset( llList2Integer(Indices, 2) );
vector GridOffset4 = GetGridOffset( llList2Integer(Indices, 3) );
vector GridOffset5 = GetGridOffset( llList2Integer(Indices, 4) );

// 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();
}

link_message(integer sender, integer channel, string data, key id) {
if (channel == DISPLAY_STRING) {
RenderString(data);
return;
}
if (channel == DISPLAY_EXTENDED) {
RenderExtended(data);
return;
}
if (channel == gCellChannel) {
// Extract the characters we are interested in, and use those to render.
string TextToRender = llGetSubString(data, gCellCharPosition, gCellCharPosition + 4);
// See if we need to show special effects.
if (gCellUseFading)
RenderWithEffects( TextToRender );
else // !gCellUseFading
RenderString( TextToRender );
return;
}
if (channel == REMAP_INDICES) {
// Parse the message, splitting it up into index values.
list Parsed = llCSV2List(data);
integer i;
// Go through the list and swap each pair of indices.
for (i = 0; i < llGetListLength(Parsed); i += 2) {
integer Index1 = ConvertIndex( llList2Integer(Parsed, i) );
integer Index2 = ConvertIndex( llList2Integer(Parsed, i + 1) );

// Swap these index values.
string Value1 = llGetSubString(gCharIndex, Index1, Index1);
string Value2 = llGetSubString(gCharIndex, Index2, Index2);

gCharIndex = llDeleteSubString(gCharIndex, Index1, Index1);
gCharIndex = llInsertString(gCharIndex, Index1, Value2);

gCharIndex = llDeleteSubString(gCharIndex, Index2, Index2);
gCharIndex = llInsertString(gCharIndex, Index2, Value1);
}
return;
}
if (channel == RESET_INDICES) {
// Restore the character index back to default settings.
ResetCharIndex();
return;
}
if (channel == SET_CELL_INFO) {
// Change the channel we listen to for cell commands, the
// starting character position to extract from, and
// special effect attributes.
list Parsed = llCSV2List(data);
gCellChannel = (integer) llList2String(Parsed, 0);
gCellCharPosition = (integer) llList2String(Parsed, 1);
gCellUseFading = (integer) llList2String(Parsed, 2);
gCellHoldDelay = (float) llList2String(Parsed, 3);
return;
}
if (channel == SET_FONT_TEXTURE) {
// 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);
return;
}
if (channel == SET_THICKNESS) {
// Set our z scale to thickness, while staying fixed
// in position relative the prim below us.
vector Scale = llGetScale();
float Thickness = (float) data;
// Reposition only if this isn't the root prim.
integer ThisLink = llGetLinkNumber();
if (ThisLink != 0 || ThisLink != 1) {
// This is not the root prim.
vector Up = llRot2Up(llGetLocalRot());
float DistanceToMove = Thickness / 2.0 - Scale.z / 2.0;
vector Pos = llGetLocalPos();
llSetPos(Pos + DistanceToMove * Up);
}
// Apply the new thickness.
Scale.z = Thickness;
llSetScale(Scale);
return;
}
if (channel == SET_COLOR) {
vector newColor = (vector)data;
llSetColor(newColor, ALL_SIDES);
}
}
}
Thraxis Epsilon
Registered User
Join date: 31 Aug 2005
Posts: 211
01-19-2006 08:36
And based off that, here is the code for the 10 characters version.

(Second note) The post above by Sordal Saramago was me, forgot to log in as myself on that PC

UPDATED: This now works with transparent textures. The prim setup script is different then the one used for the XyText 1.2 modification and is included below.


[edit] January 20, 2006: New Script Fixes

Prim Setup Script
CODE

////////////////////////////////////////////
// XyText v1.0.3 Prim Setup Script (5 Face, Multi Texture)
//
// Modified by Thraxis Epsilon January 20, 2006
//
////////////////////////////////////////////

default
{
state_entry()
{
llSetPrimitiveParams([PRIM_TYPE, 2, 32, <0.199, 0.8, 0.0>, 0.30, <0.0, 0.0, 0.0>, <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, PRIM_SIZE, <0.03, 2.89, 0.5>, PRIM_TEXTURE, 1, "09b04244-9569-d21f-6de0-4bbcf5552222", <2.48, 1.0, 0.0>, <-0.740013, 0.0, 0.0>, 0.0, PRIM_TEXTURE, 6, "09b04244-9569-d21f-6de0-4bbcf5552222", <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, 0.0, PRIM_TEXTURE, 4, "09b04244-9569-d21f-6de0-4bbcf5552222", <-14.75, 1.0, 0.0>, <0.130009, 0.0, 0.0>, 0.0, PRIM_TEXTURE, 7, "09b04244-9569-d21f-6de0-4bbcf5552222", <1.0, 1.0, 0.0>, <0.0, 0.0, 0.0>, 0.0, PRIM_TEXTURE, 3, "09b04244-9569-d21f-6de0-4bbcf5552222", <2.48, 1.0, 0.0>, <-0.255989, 0.0, 0.0>, 0.0]);
llRemoveInventory(llGetScriptName());
}
}



XyText 1.03 Script
CODE

////////////////////////////////////////////
// XyText v1.0.3 Script (5 Face, Multi Texture)
//
// Written by Xylor Baysklef
//
// Modified by Thraxis Epsilon January 20, 2006
// Added Support for 5 Face Prim, based on modification
// of XyText v1.1.1 by Kermitt Quick for Single Texture.
//
////////////////////////////////////////////

/////////////// CONSTANTS ///////////////////
// XyText Message Map.
integer DISPLAY_STRING = 204000;
integer DISPLAY_EXTENDED = 204001;
integer REMAP_INDICES = 204002;
integer RESET_INDICES = 204003;
integer SET_CELL_INFO = 204004;
integer SET_THICKNESS = 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 = "123456789abcdef";

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

// Used to hide the text after a fade-out.
key TRANSPARENT = "701917a8-d614-471f-13dd-5f4644e36e3c";
// This is a list of textures for all 2-character combinations.
list CHARACTER_GRID = [
"00e9f9f7-0669-181c-c192-7f8e67678c8d",
"347a5cb6-0031-7ec0-2fcf-f298eebf3c0e",
"4e7e689e-37f1-9eca-8596-a958bbd23963",
"19ea9c21-67ba-8f6f-99db-573b1b877eb1",
"dde7b412-cda1-652f-6fc2-73f4641f96e1",
"af6fa3bb-3a6c-9c4f-4bf5-d1c126c830da",
"a201d3a2-364b-43b6-8686-5881c0f82a94",
"b674dec8-fead-99e5-c28d-2db8e4c51540",
"366e05f3-be6b-e5cf-c33b-731dff649caa",
"75c4925c-0427-dc0c-c71c-e28674ff4d27",
"dcbe166b-6a97-efb2-fc8e-e5bc6a8b1be6",
"0dca2feb-fc66-a762-db85-89026a4ecd68",
"a0fca76f-503a-946b-9336-0a918e886f7a",
"67fb375d-89a1-5a4f-8c7a-0cd1c066ffc4",
"300470b2-da34-5470-074c-1b8464ca050c",
"d1f8e91c-ce2b-d85e-2120-930d3b630946",
"2a190e44-7b29-dadb-0bff-c31adaf5a170",
"75d55e71-f6f8-9835-e746-a45f189f30a1",
"300fac33-2b30-3da3-26bc-e2d70428ec19",
"0747c776-011a-53ce-13ee-8b5bb9e87c1e",
"85a855c3-a94f-01ca-33e0-7dde92e727e2",
"cbc1dab2-2d61-2986-1949-7a5235c954e1",
"f7aef047-f266-9596-16df-641010edd8e1",
"4c34ebf7-e5e1-2e1a-579f-e224d9d5e71b",
"4a69e98c-26a5-ad05-e92e-b5b906ad9ef9",
"462a9226-2a97-91ac-2d89-57ab33334b78",
"20b24b3a-8c57-82ee-c6ed-555003f5dbcd",
"9b481daa-9ea8-a9fa-1ee4-ab9a0d38e217",
"c231dbdc-c842-15b0-7aa6-6da14745cfdc",
"c97e3cbb-c9a3-45df-a0ae-955c1f4bf9cf",
"f1e7d030-ff80-a242-cb69-f6951d4eae3b",
"ed32d6c4-d733-c0f1-f242-6df1d222220d",
"88f96a30-dccf-9b20-31ef-da0dfeb23c72",
"252f2595-58b8-4bcc-6515-fa274d0cfb65",
"f2838c4f-de80-cced-dff8-195dfdf36b2c",
"cc2594fe-add2-a3df-cdb3-a61711badf53",
"e0ce2972-da00-955c-129e-3289b3676776",
"3e0d336d-321f-ddfa-5c1b-e26131766f6a",
"d43b1dc4-6b51-76a7-8b90-38865b82bf06",
"06d16cbb-1868-fd1d-5c93-eae42164a37d",
"dd5d98cf-273e-3fd0-f030-48be58ee3a0b",
"0e47c89e-de4a-6233-a2da-cb852aad1b00",
"fb9c4a55-0e13-495b-25c4-f0b459dc06de",
"e3ce8def-312c-735b-0e48-018b6799c883",
"2f713216-4e71-d123-03ed-9c8554710c6b",
"4a417d8a-1f4f-404b-9783-6672f8527911",
"ca5e21ec-5b20-5909-4c31-3f90d7316b33",
"06a4fcc3-e1c4-296d-8817-01f88fbd7367",
"130ac084-6f3c-95de-b5b6-d25c80703474",
"59d540a0-ae9d-3606-5ae0-4f2842b64cfa",
"8612ae9a-f53c-5bf4-2899-8174d7abc4fd",
"12467401-e979-2c49-34e0-6ac761542797",
"d53c3eaa-0404-3860-0675-3e375596c3e3",
"9f5b26bd-81d3-b25e-62fe-5b671d1e3e79",
"f57f0b64-a050-d617-ee00-c8e9e3adc9cb",
"beff166a-f5f3-f05e-e020-98f2b00e27ed",
"02278a65-94ba-6d5e-0d2b-93f2e4f4bf70",
"a707197d-449e-5b58-846c-0c850c61f9d6",
"021d4b1a-9503-a44f-ee2b-976eb5d80e68",
"0ae2ffae-7265-524d-cb76-c2b691992706",
"f6e41cf2-1104-bd0b-0190-dffad1bac813",
"2b4bb15e-956d-56ae-69f5-d26a20de0ce7",
"f816da2c-51f1-612a-2029-a542db7db882",
"345fea05-c7be-465c-409f-9dcb3bd2aa07",
"b3017e02-c063-5185-acd5-1ef5f9d79b89",
"4dcff365-1971-3c2b-d73c-77e1dc54242a"
];

///////////// END CONSTANTS ////////////////

///////////// GLOBAL VARIABLES ///////////////
// 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[\\]^_`";
// \" <-- Fixes LSL syntax highlighting bug.
gCharIndex += "abcdefghijklmnopqrstuvwxyz{|}~";
gCharIndex += "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n";
}

vector GetGridPos(integer index1, integer index2) {
// There are two ways to use the lookup table...
integer Col;
integer Row;
if (index1 >= index2) {
// In this case, the row is the index of the first character:
Row = index1;
// And the col is the index of the second character (x2)
Col = index2 * 2;
}
else { // Index1 < Index2
// In this case, the row is the index of the second character:
Row = index2;
// And the col is the index of the first character, x2, offset by 1.
Col = index1 * 2 + 1;
}
return <Col, Row, 0>;
}

string GetGridTexture(vector grid_pos) {
// Calculate the texture in the grid to use.
integer GridCol = llRound(grid_pos.x) / 20;
integer GridRow = llRound(grid_pos.y) / 10;

// Lookup the texture.
key Texture = llList2Key(CHARACTER_GRID, GridRow * (GridRow + 1) / 2 + GridCol);
return Texture;
}

vector GetGridOffset(vector grid_pos) {
// Zoom in on the texture showing our character pair.
integer Col = llRound(grid_pos.x) % 20;
integer Row = llRound(grid_pos.y) % 10;

// Return the offset in the texture.
return <-0.45 + 0.05 * Col, 0.45 - 0.1 * Row, 0.0>;
}

ShowChars(vector grid_pos1, vector grid_pos2, vector grid_pos3, vector grid_pos4, vector grid_pos5) {
// Set the primitive textures directly.


llSetPrimitiveParams( [
PRIM_TEXTURE, FACE_1, GetGridTexture(grid_pos1), <0.25, 0.1, 0>, GetGridOffset(grid_pos1) + <0.075, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_2, GetGridTexture(grid_pos2), <0.1, 0.1, 0>, GetGridOffset(grid_pos2), 0.0,
PRIM_TEXTURE, FACE_3, GetGridTexture(grid_pos3), <-1.48, 0.1, 0>, GetGridOffset(grid_pos3)+ <0.37, 0, 0>, 0.0,
PRIM_TEXTURE, FACE_4, GetGridTexture(grid_pos4), <0.1, 0.1, 0>, GetGridOffset(grid_pos4), 0.0,
PRIM_TEXTURE, FACE_5, GetGridTexture(grid_pos5), <0.25, 0.1, 0>, GetGridOffset(grid_pos5) - <0.075, 0, 0>, 0.0
]);
}

RenderString(string str) {
// Get the grid positions for each pair of characters.
vector GridPos1 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)),
llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridPos2 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)),
llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridPos3 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)),
llSubStringIndex(gCharIndex, llGetSubString(str, 5, 5)) );
vector GridPos4 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 6, 6)),
llSubStringIndex(gCharIndex, llGetSubString(str, 7, 7)) );
vector GridPos5 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 8, 8)),
llSubStringIndex(gCharIndex, llGetSubString(str, 9, 9)) );

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridPos1, GridPos2, GridPos3, GridPos4, GridPos5);
}

RenderWithEffects(string str) {
// Get the grid positions for each pair of characters.
vector GridPos1 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 0, 0)),
llSubStringIndex(gCharIndex, llGetSubString(str, 1, 1)) );
vector GridPos2 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 2, 2)),
llSubStringIndex(gCharIndex, llGetSubString(str, 3, 3)) );
vector GridPos3 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 4, 4)),
llSubStringIndex(gCharIndex, llGetSubString(str, 5, 5)) );
vector GridPos4 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 6, 6)),
llSubStringIndex(gCharIndex, llGetSubString(str, 7, 7)) );
vector GridPos5 = GetGridPos( llSubStringIndex(gCharIndex, llGetSubString(str, 8, 8)),
llSubStringIndex(gCharIndex, llGetSubString(str, 9, 9)) );

// First set the alpha to the lowest possible.
llSetAlpha(0.05, ALL_SIDES);

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridPos1, GridPos2, GridPos3, GridPos4, GridPos5);

float Alpha;
for (Alpha = 0.10; Alpha <= 1.0; Alpha += 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// See if we want to fade out as well.
if (gCellHoldDelay < 0.0)
// No, bail out. (Just keep showing the string at full strength).
return;
// Hold the text for a while.
llSleep(gCellHoldDelay);
// Now fade out.
for (Alpha = 0.95; Alpha >= 0.05; Alpha -= 0.05)
llSetAlpha(Alpha, ALL_SIDES);
// Make the text transparent to fully hide it.
llSetTexture(TRANSPARENT, ALL_SIDES);
}

RenderExtended(string str) {
// Look for escape sequences.
list Parsed = llParseString2List(str, [], [ESCAPE_SEQUENCE]);
integer ParsedLen = llGetListLength(Parsed);

// Create a list of index values to work with.
list Indices;
// We start with room for 6 indices.
integer IndicesLeft = 10;

integer i;
string Token;
integer Clipped;
integer LastWasEscapeSequence = FALSE;
// Work from left to right.
for (i = 0; i < ParsedLen && IndicesLeft > 0; i++) {
Token = llList2String(Parsed, i);

// If this is an escape sequence, just set the flag and move on.
if (Token == ESCAPE_SEQUENCE) {
LastWasEscapeSequence = TRUE;
}
else { // Token != ESCAPE_SEQUENCE
// Otherwise this is a normal token. Check its length.
Clipped = FALSE;
integer TokenLength = llStringLength(Token);
// Clip if necessary.
if (TokenLength > IndicesLeft) {
Token = llGetSubString(Token, 0, IndicesLeft - 1);
TokenLength = llStringLength(Token);
IndicesLeft = 0;
Clipped = TRUE;
}
else
IndicesLeft -= TokenLength;

// Was the previous token an escape sequence?
if (LastWasEscapeSequence) {
// Yes, the first character is an escape character, the rest are normal.

// This is the extended character.
Indices += [llSubStringIndex(EXTENDED_INDEX, llGetSubString(Token, 0, 0)) + 95];

// These are the normal characters.
integer j;
for (j = 1; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}
else { // Normal string.
// Just add the characters normally.
integer j;
for (j = 0; j < TokenLength; j++)
Indices += [llSubStringIndex(gCharIndex, llGetSubString(Token, j, j))];
}

// Unset this flag, since this was not an escape sequence.
LastWasEscapeSequence = FALSE;
}
}

// Use the indices to create grid positions.
vector GridPos1 = GetGridPos( llList2Integer(Indices, 0), llList2Integer(Indices, 1) );
vector GridPos2 = GetGridPos( llList2Integer(Indices, 2), llList2Integer(Indices, 3) );
vector GridPos3 = GetGridPos( llList2Integer(Indices, 4), llList2Integer(Indices, 5) );
vector GridPos4 = GetGridPos( llList2Integer(Indices, 6), llList2Integer(Indices, 7) );
vector GridPos5 = GetGridPos( llList2Integer(Indices, 8), llList2Integer(Indices, 9) );

// Use these grid positions to display the correct textures/offsets.
ShowChars(GridPos1, GridPos2, GridPos3, GridPos4, GridPos5);
}

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();

//llSay(0, "Free Memory: " + (string) llGetFreeMemory());
}

link_message(integer sender, integer channel, string data, key id) {
if (channel == DISPLAY_STRING) {
RenderString(data);
return;
}
if (channel == DISPLAY_EXTENDED) {
RenderExtended(data);
return;
}
if (channel == gCellChannel) {
// Extract the characters we are interested in, and use those to render.
String TextToRender = llGetSubString(data, gCellCharPosition, gCellCharPosition + 9);
if (gCellUseFading)
RenderWithEffects( TextToRender );
else // !gCellUseFading
RenderString( TextToRender );
return;
}
if (channel == REMAP_INDICES) {
// Parse the message, splitting it up into index values.
list Parsed = llCSV2List(data);
integer i;
// Go through the list and swap each pair of indices.
for (i = 0; i < llGetListLength(Parsed); i += 2) {
integer Index1 = ConvertIndex( llList2Integer(Parsed, i) );
integer Index2 = ConvertIndex( llList2Integer(Parsed, i + 1) );

// Swap these index values.
string Value1 = llGetSubString(gCharIndex, Index1, Index1);
string Value2 = llGetSubString(gCharIndex, Index2, Index2);

gCharIndex = llDeleteSubString(gCharIndex, Index1, Index1);
gCharIndex = llInsertString(gCharIndex, Index1, Value2);

gCharIndex = llDeleteSubString(gCharIndex, Index2, Index2);
gCharIndex = llInsertString(gCharIndex, Index2, Value1);
}
return;
}
if (channel == RESET_INDICES) {
// Restore the character index back to default settings.
ResetCharIndex();
return;
}
if (channel == SET_CELL_INFO) {
// Change the channel we listen to for cell commands, and the
// starting character position to extract from.
list Parsed = llCSV2List(data);
gCellChannel = (integer) llList2String(Parsed, 0);
gCellCharPosition = (integer) llList2String(Parsed, 1);
gCellUseFading = (integer) llList2String(Parsed, 2);
gCellHoldDelay = (float) llList2String(Parsed, 3);
return;
}
if (channel == SET_THICKNESS) {
// Set our z scale to thickness, while staying fixed
// in position relative the prim below us.
vector Scale = llGetScale();
float Thickness = (float) data;
// Reposition only if this isn't the root prim.
integer ThisLink = llGetLinkNumber();
if (ThisLink != 0 || ThisLink != 1) {
// This is not the root prim.
vector Up = llRot2Up(llGetLocalRot());
float DistanceToMove = Thickness / 2.0 - Scale.z / 2.0;
vector Pos = llGetLocalPos();
llSetPos(Pos + DistanceToMove * Up);
}
// Apply the new thickness.
Scale.z = Thickness;
llSetScale(Scale);
return;
}
if (channel == SET_COLOR) {
vector newColor = (vector)data;
llSetColor(newColor, ALL_SIDES);
}
}
}

1 2