Storing data on a prim
|
|
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
|
03-23-2007 23:23
I've been playing with this bit of code for a few hours, and I thought it might be of some interest to others. //Store text in side coloring //Keknehv Psaltery, 2003.02.24 // integer <-> float functions by Strife Onizuka
//Just a hack based on another hack-- not intended for production code
string chars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~\n";
vector zv = <0.0,0.0,0.0>; float zf = 0.0;
list stoi( string in ) { //Fits 28 bits in each integer -- 7 bits per character integer l = llCeil( llStringLength( in ) / 4.0 ) * 4; list outList; integer w; integer x; for ( x = 0 ; x < l ; ) { w = (w << 7) | ( llSubStringIndex( chars, llGetSubString( in, x, x ) ) & 0x7F ); if ( ++x % 4 == 0 ) { outList += [ w ]; w = 0; } } if ( x % 4 != 0 ) outList += [ w ]; return outList; }
string itos( list in ) { integer l = llGetListLength( in ) * 4; string outString; integer x = 0; integer w = (integer)llList2String( in, x / 4 ); for ( x = 0 ; x < l ; ) { outString += llGetSubString( chars, (w >> 21) & 0x7F, (w >> 21) & 0x7F ); w = w << 7; if ( ++x % 4 == 0 ) w = (integer)llList2String( in, x / 4 ); } return outString; }
storeData( string data ) { data = llGetSubString( data, 0, llGetNumberOfSides() * 16 - 2 ) + "\n"; llSetPrimitiveParams( [PRIM_COLOR,ALL_SIDES,zv,zf] ); list ints = stoi( data ); list params; integer x; integer l = llGetListLength(ints); for ( x = 0 ; x < l ; x += 4 ) { params += [ PRIM_COLOR, x >> 2, < iuf( llList2Integer( ints, x ) ), iuf( llList2Integer( ints, x + 1 ) ), iuf( llList2Integer( ints, x + 2 ) ) >, iuf( llList2Integer( ints, x + 3 ) ) ]; } ints = []; while ( (llGetListLength( params ) / 4) < llGetNumberOfSides() ) params += [ PRIM_COLOR, (x+=4)>>2, zv, zf ]; llOwnerSay((string)llGetListLength(params)); llSetPrimitiveParams( params ); }
string getData() { list params = llGetPrimitiveParams( [ PRIM_COLOR, ALL_SIDES ] ); list ints; vector c; integer x; integer l = llGetListLength(params); for ( x = 0 ; x < l ; x += 2 ) { c = llList2Vector( params, x ); if ( c != zv ) ints += [ fui(c.x), fui(c.y), fui(c.z), fui( llList2Float( params, x + 1 ) ) ]; } params = []; string data = itos( ints ); ints = []; while ( llGetSubString( data, -1, -1 ) == " " ) data = llDeleteSubString( data, -1, -1 ); return llDeleteSubString( data, -1, -1 ); }
//The next two functions are copyright Strife Onizuka //I lifted them off his wiki.secondlife.com user page integer fui(float a){//union float to integer if(a){//is it non zero? integer b = (a < 0) << 31;//the sign, but later this variable is reused to store the shift if((a = llFabs(a)) < 2.3509887016445750159374730744445e-38)//Denormalized range check & last stirde of normalized range return b | (integer)(a / 1.4012984643248170709237295832899e-45);//this works because the math overlaps; saves cpu time. integer c = llFloor(llLog(a) / 0.69314718055994530941723212145818);//extremes will error towards extreme. following yuch corrects it. return (0x7FFFFF & (integer)(a * (0x1000000 >> b))) | (((c + 126 + (b = ((integer)a - (3 <= (a /= (float)("0x1p"+(string)(c -= (c == 128)))))))) << 23 ) | b); }//for grins, detect the sign on zero. it's not pretty but it works. the previous requires alot of unwinding to understand it. return ((string)a == (string)(-0.0)) << 31; }
float iuf(integer a) {//union integer to float return ((float)("0x1p"+(string)((a | !a) - 150))) * ((!!(a = (0xff & (a >> 23))) << 23) | ((a & 0x7fffff))) * (1 | (a >> 31)); }//will crash if the raw exponent == 0xff; reason for crash deviates from float standard; though a crash is warented.
default { state_entry() { string msg = "Some miscellaneous amount of information"; llOwnerSay("storing data"); storeData(msg); llOwnerSay("Okay, done storing"); llOwnerSay("getData = \"" + getData() + "\""); } }
I got the idea after I saw Strife Onizuka's integer/float union functions, and wondered whether it could be used to store a useful number of bits from a string in a float in an object's color. It can. Using Strife's function, I put four 7 bit characters into each float. For some reason, I believe because the exponent is zero, these 28 bit floats all appear to be 0.0000 when typecasted. A cube that's been hollowed and cut has 9 sides, so using the floats in the color and transparency on each side, you can store 4 characters * ( 3 floats per color + 1 float per alpha ) * 9 sides = 144 characters. The code isn't commented, is slower than it could be, and is definitely ugly-- I blame this on lack of sleep combined with laziness. Comments would be appreciated.
|
|
Geuis Dassin
Filming Path creator
Join date: 3 May 2006
Posts: 565
|
03-24-2007 00:18
might this idea be adapted to passing small amounts of string data to newly rezzed objects via the passed integer? that would be immensely useful
|
|
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
|
03-24-2007 00:28
From: Geuis Dassin might this idea be adapted to passing small amounts of string data to newly rezzed objects via the passed integer? that would be immensely useful The on_rez integer is 32 bits so you can encode 4 characters into it without problem but its hardly worth it (IMHO). If the initialisation data is mainly bit fields then it becomes much more useable.
|
|
Keknehv Psaltery
Hacker
Join date: 11 Apr 2005
Posts: 1,185
|
03-24-2007 09:05
You could probably fit 12 characters in the initial rotation as well.
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
03-24-2007 12:06
From: Keknehv Psaltery You could probably fit 12 characters in the initial rotation as well. The data that can be encoded into a quat in this manner is limited by the fact that quats representing rotation must be normalized, that is, x^2 + y^2 + z^2 + s^2 == 1. llGetRot() will only return normalized quats (or perhaps more precisely, llSetRot will normalize any non-normal quat passed to it), as the following test script demonstrates: default { state_entry() { llSetRot( <0,0,2,0> ); llOwnerSay( (string)llGetRot() ); } }
Output: Object: <0.000000, 0.000000, 1.000000, 0.000000>
So unless the data you want to store happens to encode to a normalized quat, the data will be corrupted.
|
|
Brain Curry
Registered User
Join date: 15 Jun 2006
Posts: 9
|
03-28-2007 19:19
From: Keknehv Psaltery I've been playing with this bit of code for a few hours, and I thought it might be of some interest to others.
Am I wrong in thinking that prims store information in their scripts until reset? I'm honestly curious here. I have some rezzers that rely on positioning information being saved across rezzes, but I have no clue how this actually works. Particularly under what conditions the contents of global variables are reset. Anyway, it occurs to me that saving a value is as easy as loading it into a global and not calling llResetScript(). Retrieving is at least as easy. So, given that there appears to be a call for encoding data as colors, what is it? Cuz, seriously, that's some whacked out code. Does LSL not support the "?" ternary operator or something? Geez.
|
|
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
|
03-28-2007 23:46
The problem is that script variables are volatile and subject to the whims of LL. I agree that 99% of the time they should be fine but sometimes it is neccessary to reset a script but still retain the configuration data.
|
|
Ace Albion
Registered User
Join date: 21 Oct 2005
Posts: 866
|
03-29-2007 01:55
I think it's a pretty nifty idea, particularly for objects where you maybe don't need or care about prim limits or decoration, such as HUDs. Having an array of datacubes would be a fun way of holding data.
_____________________
Ace's Spaces! at Deco (147, 148, 24) ace.5pointstudio.com
|
|
Darien Caldwell
Registered User
Join date: 12 Oct 2006
Posts: 3,127
|
03-29-2007 12:34
Nice, I'll have to see if this will help me eliminate linked messages.
|
|
Valradica Vanek
Registered User
Join date: 1 Aug 2006
Posts: 78
|
String data
03-29-2007 13:44
'course we all know that there are 255 string characters available in the description field of a prim. Thats a lot of numbers if you leave off the preceding zeros and limit the number of decimal places. You can also store lists in string form and convert them as necessary. I Use the description field to store offset and rotation data for all my pose balls that require it. You can also store a lot of data in the prim size etc. OK, so the field is visible to the user. Well if the user messes with stuff they don't understand, what should they expect? You can always tell them not to and many things I make, they don't have access to it anyway cuz of permissions.
If the prim is invisible an the size don't matter an you're depending on the size of the numbers, you can make very small prims and use multipliers to get values more like you need such as storing a prim size as <.035, 1, .012> and getting numbers like 35.0, 100.0 and 1.2 by just multiplying by an order of maginitude or whatever. There is a lot of flexibility here.
Booleans can be stored almost anywhere and simply typecast into TRUEs and FALSEs
A couple small prims using the size, color, twist, hollow, dimple, description and even the name (which I think is 64 characters) and you have maybe 700 bytes of non-volatile memory.
Nice thing about this is that numbers hidden in this way are non-volatile and don;t disappear when the script is reset like numbers stored in variables. This is particularly useful in development where you have to recompile and test all the time. Try it you will like it
Valradica
|
|
Newgate Ludd
Out of Chesse Error
Join date: 8 Apr 2005
Posts: 2,103
|
03-30-2007 04:50
I think you will find that description is only reliably 128 characters. You can store more, up to 8K has been reported, but its prone to disappear.
|
|
Quantum Hax
Registered User
Join date: 8 Feb 2007
Posts: 39
|
03-30-2007 05:34
What are advantages to store data on prims compared to store the data in textures?
|
|
Darien Caldwell
Registered User
Join date: 12 Oct 2006
Posts: 3,127
|
03-30-2007 12:57
From: Quantum Hax What are advantages to store data on prims compared to store the data in textures? How do you store data in a texture? The first time I heard of this I thought it was meant you set the texture name with data, however I could never get that to work. Is there an example showing how this is done?
|
|
Quantum Hax
Registered User
Join date: 8 Feb 2007
Posts: 39
|
03-30-2007 14:41
From: Darien Caldwell How do you store data in a texture? The first time I heard of this I thought it was meant you set the texture name with data, however I could never get that to work. Is there an example showing how this is done? Some real life examples: http://en.wikipedia.org/wiki/QR_Codehttp://www.semapedia.org/http://semacodeshop.com/
|
|
Darien Caldwell
Registered User
Join date: 12 Oct 2006
Posts: 3,127
|
03-30-2007 14:53
Ok, thats like making a complex barcode. But I don't understand how you would to that with LSL. LSL doesn't have the ability to create bitmaps on the fly, does it?
|
|
Sys Slade
Registered User
Join date: 15 Feb 2007
Posts: 626
|
03-30-2007 15:39
Presumably though you could set the texture to a key value, and use that key value as the storage. I don't know how it would react if the texture doesn't actually exist though.
|
|
Deanna Trollop
BZ Enterprises
Join date: 30 Jan 2006
Posts: 671
|
03-30-2007 15:44
From: Darien Caldwell LSL doesn't have the ability to create bitmaps on the fly, does it? Nor, for that matter, to read any data from them (other than the fact of their existence, if part of a prim's inventory.)
|
|
Quantum Hax
Registered User
Join date: 8 Feb 2007
Posts: 39
|
03-30-2007 18:35
From: Darien Caldwell Ok, thats like making a complex barcode. But I don't understand how you would to that with LSL. LSL doesn't have the ability to create bitmaps on the fly, does it? Perl and PHP source code for generation QR code are mentioned in Wikipedia. You can port it to LSL, but the problem is how to decode those 2D codes inside SL?
|