aku-aku: v.. To move a tall, flat bottomed object (such as a bookshelf) by swiveling it alternatively on its corners in a "walking" fashion. [After the book by Thor Heyerdahl theorising the statues of Easter Island were moved in this fashion.] source: LangMaker.com. Aku Aku also has another meaning to the islanders: a spiritual guide.
« familiar sight | Main Page | what's in my bag? »
a day in the second life
Posted by dav at 2005 March 6 04:45 PM
File under: Geek

Before I left for Brazil, Mie and I set up accounts on Second Life (SL) so that we could have an online experience with each other while we're apart that would be richer than just moblogging, skype and video chats. Unfortunately her laptop died before I got back on the Internet here and she had't had time to install the SL client again yet.

Sunday, while she was in Portland I decided to spend some time getting my avatar in better shape. The in-world avatar editing tools are good but I wanted my avatar to look more like me so using a provided head/face template I stretched and smeared a photo of me into place and managed to get something that was an improvement. It's mostly just my lips and nose that came out ok, since they got stretched the least. Apparently you can't map your own eyes onto the avatar, which is a shame since they are probably the best bang for the buck in terms of making it really look like someone. I think I'll go back and try to do the stretched parts a little better but it's not too bad for now.

Encouraged by this small success, I next tackled a custom animation. Using an excellent tutorial for Poser 5, I managed to manipulate an actor to bring his palms together at his heart with a slight bow. I recorded myself saying "namaste" and combined the animation and sound into a cheesy hindi gesture that I can have my avatar perform in-world.

Now I was on a roll! There's only one way to top off design and animation work, and that's with a little coding. I remembered reading that the Second Life scripting language (LSL) had XML-RPC capabilites so I figured a fun thing to do would be to write a script that would call out to the Flickr API occasionally and download my latest photos for display in-world.

[Note, since the gory details of the ensuing hackfest are rather long, I've added them in the Extended Entry section, click the "MORE" link below to take you to the full posting which involves praise for Ruby, disdain for LSL and moments of joy and anguish]

I hit a snag pretty quickly though. The SL API only supports in-bound XML-RPC calls because they are worried about the game servers being used to abuse the outside world, so there's no way to call out to external servers (like Flickr). I decided to route around this by writing some Ruby XML-RPC code that I could run on my server which would get the data from Flickr and then post it to Second Life.

I was able to quickly get simple Ruby->SL XML-RPC client-server action going thanks to an example LSL script and the fact that it's just ridiculously easy to do things in Ruby. Then I hit the next obstacle: the LSL API doesn't provide a way to download an image from the Internet! That seemed like such a given to me that I hadn't bothered to look for that functionality earlier. I thought perhaps I could pass the image data as a String of hex digits encoded through XML-RPC and then re-assemble it in SL, but there also isn't a way to dynamically create an image via LSL either!

"No," I cried defiantly, "I will not be defeated by this crappy scripting language," and came up with a new plan. The new plan was to assemble an array of small in-world objects ("prims"), one for each pixel I wanted to display, and simply color the prim for each according to the associated pixel color. Haiyaaa!

However, Second Life countered this deft jab with an inability to generate objects using scripts. Which means that I would have to use the in-world tools to create each pixel-object by hand, which is a painstaking process of mouse-clicking to shape, position and add a coloring script to each one. For the smallest thumbnail size Flickr image that would be 75 x 75 pixels, or 5625 objects. At the rate of one object every 30 seconds or so (an optimistic estimate) that would be 46 hours of mouse clicking. OK then.

I decided to work on a different problem for a bit while I let the in-world display issue work itself out in my subconcious (this really works, by the way, old hacker technique) and focused on getting the data into SL. I installed ImageMagick and its Ruby interface RMagick and then wrote some code to read a JPG and turn it's pixel/color information into a hex value string suitable for passing via XML-RPC. Or so I thought. It turns out that SL's XML-RPC interface is fairly limited. You can only make calls that pass exactly two parameters: a String and an integer value. A three color (Red, Green Blue) 75x75 jpeg with 16-bit depth would thus produce 3*4*75*75 characters in the hex string, or 67500 characters. I had my suspicions that this would prove too lengthy for the XML-RPC transfer and it turned out to be so as attempting to send the data failed. It's not an issue with XML-RPC as I've transferred much larger strings in java projects before. After digging around a bit I found that an LSL script in Second Life is limited to 16kb of memory usage, including heap and stack.

I could break it up into several XML-RPC calls, but that seemed inelegant. I decided to instead convert the image to grey scale and lower the depth to 8 bits per pixel (or two characters) bringing the string length down. This is a fairly drastic step in terms of image quality reduction, but I was anxious to get something working. It's important when working on useless hacking projects to keep things moving.

It turned out that this was still 11250 characters, and half that was also too much, as was 2813. I started experimenting and noticed that although I could successfully send strings up to 512+ characters in length, the XML-RPC server in SL was truncating them to 254 without warning. Agh! How incredibly useless is that!?!

254 hexadecimal characters is 127 bytes or 1016 bits. I could also get 32 bits out of the integer parameter allowed, but still means I could only conceivably send a two color (black and white) image of roughly 32x32 pixels in one XML-RPC call. Pathetic. At this point though, there was no looking back. I changed the ruby code to convert the image from 75x75 color to a 32x32 black and white and voila: the beat up image was arriving in Second Life as a string of hex digits.

Now back to the question on how to display it. SL allows you to create a bunch of prims and link them together into one object, so I created 32 cubes scattered around to represent the 32 pixels per row and linked them together. Next I wrote some code that would take the 254 character hex string and convert it back into a series of 1's and 0's (representing black and white pixels). Finally I added code that went through the image row by row and changed the color of the 32 blocks to represent the black and white pixels of the row. This worked (yay for small successes) but it didn't really look like much since the boxes were spread all over the place.

I needed to get the boxes in a horizontal row and I wanted to shrink them down from the default size they start as when you create them. Unfortunately moving each box around and editing it is extremely tedious in SL (especially with the lag time from Brazil). I hunted around some more in the LSL library functions and discoverd that there was a method for re-positioning a prim. This obviously was the key, but unfortunately each prim can only reposition itself. Of the 32 prims, one was considered the parent and the rest were all children. The script I was writing runs only in the parent prim, and although it could change the color of a child it was unable to position the other 31 boxes.

Undaunted, I decided to write another script that would run only on the child prims and allow them to reposition themselves. The script would query the link number (which is the number assigned to a child prim when it is linked into a group) and then position itself next to the parent prim according to that number. I unlinked the group and then dropped this child script onto each of the 31 child prims and then relinked them back together. After re-rezzing the set they magically self-organized into a perfect row! w00t!

I ran the ruby script again to upload the image and watched as each row of the image was slowly displayed on the row of boxes. It took about a second per row. I was hoping it would flash by fast enough so that the viewer could still make out the image but it just wasn't happening. In a last ditch effort to make it clear I altered to code to physically move the row up and then have it descend as it displayed each row of pixels. It was still way too slow to make out the image though.

So I guess in the end Second Life's crippled pathetic scripting language and slow-ass runtime won, but I like to think I went down swinging. I didn't exactly succeed in my efforts to display photos from flickr in second life, but I can display a savagely stripped down version of the image in a manner that is technically an achievement but wholly worthless. Yay?

Using the successive XML-RPC calls I could send more data, improving the image quality (size, color or both), and then using the same technique I could just as well do the original 75x75 image. I could also create more rows in theory, but SL allows you to create a maximum number of prims based on how much in-game land you own. I don't own enough land to create 32x32 (1024) prims, much less 75x75 (5625).

Not too mention coding this system is difficult in a physical way. If I want to change something in the client script for the 31 prims, I need to edit each prim, delete the old script and drop in the new one. This takes a lot of clicking around with the mouse and moving things around to different positions so I can keep track of them. It is a very error prone process and I had to start over a number of times. It's like Second Life has managed to take the difficulty of dealing with multiple objects in the real world and combined it with the frustration of dealing with a crappy API.

Comments:

// rez a row of prims, passing them their "address" in the grid
rez_row(string object, integer row, integer columns, vector offset)
{
integer i;

for(i = 0; i {
llRezObject(object, offset*i, ZERO_VECTOR, ZERO_ROTATION, i+row*count);
}
}

// rez a grid of prims, passing each their "address" in the grid
rez_grid(string object, integer rows, integer columns, vector row_offset, vector column_offset)
{
integer i;
vector start = llGetPos();

for(i = 0; i {
rez_row(object, i, columns, column_offset);
llSetPos(llGetPos() + row_offset);
}
llSetPos(start);
}

integer countdown;

default()
{
state_entry()
{
}

on_rez()
{
state builder;
}
}

state builder
{
state_entry()
{
rez_grid("Pixel", 16, 16, , );
countdown = 16*16;
}

// When I rez an object, bring it in to my link set
object_rezzed(key id)
{
llCreateLink(id, TRUE);
countdown -= 1;
if(countdown state built;
}
}

state built
{
}

Posted by: Leechman on October 5, 2005 02:31 PM

That's the problem with being a super-villain, you get thwarted by stupid software. Those for() loops both got trashed because of the "less than" symbol in them.

they should both be something like "for(i = 0; i less-than rows/columns; i++)"

Eh, you're a smart cookie, you can figure out what I'm getting at. The script in the prims should have an "on_rez" that does something smart with the parameter they're passed, like sending it and their UUID back to the root prim in a link message.

Posted by: Leechman on October 5, 2005 02:37 PM

So where is the Ruby code for the "server" side? I would love to see such an example in Ruby!

Have you done any other LSL coding?

Thanks!

Posted by: Robert J Berger on December 18, 2005 04:30 PM

Hello, I'm led to believe that one can have dynamic photo serving in SL if you set the photo(s) up through the parcel video media URL. Reference lslwiki.com/lslwiki/wakka.php?wakka=llParcelMediaCommandList It makes for a bit of a hackjob, but it can be done.

Posted by: KageSeraph on September 30, 2006 06:17 PM

Huzzah! Second Life now supports HTTP calls. All is well. In fact, here is a very cool example, made last year, of exactly what you are trying to do:

http://www.hackdiary.com/archives/000085.html

Posted by: slant on February 20, 2008 10:26 AM

Post a new comment:

Thanks for signing in, . Now you can comment. (sign out)

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)


Remember me?