About

The SL Developer’s Corner is my place in the virtual world “Second Life”, where i experiment and tinker with the features of this platform. I try to publish my experiences and often also include the source code of the scripts on this site. Other posting related to Second life can be also found on Happy Coding 2nd-life section.

Wednesday, 14 March 2007

Display external XML-Resources on objects in Second Life

If have played a little bit with Second Life and its ability to access external resources. Inspired by Matt Biddulph’s “flickr screen”, now i wanted to load xml data from an external source into the SL-world and display it on a nice looking screen. Because it is not possible — from my point of view — to display text directly on a SL-primitive, it was necessary to render the text in a first step to an image. I did this using a little RubyOnRails application which also loads and parses the xml-resource. Ok, now i show how i did this.
I used the REXML processor to work with the xml-data and RMagick to create the image. The xml-source is used is a little xml-file provided by LindenLabs which shows the land sales by resident for the last three month (http://secondlife.com/reports/marketplace_stats/2007-03-01/land_sales_by_residents.xml). The whole parsing is specific to this source.

# get the xml via http and read it into a variable and create a XML-Document after that
@content = Net::HTTP.get(URI.parse("
http://secondlife.com/reports/marketplace_stats/2007-03-01/land_sales_by_residents.xml"))
xmlDoc = REXML::Document.new(@content)

# get some attributes and select them with xpath
elRecords = REXML::XPath.first(xmlDoc, "records")
reportTitle = elRecords.attributes['report']
reportDate = elRecords.attributes['date']

# create a new image in the size you need. in my case it was 400 width and 200 height
f = Image.new(400,200) { self.background_color = "white" }# make some settings for the font
drawable = Magick::Draw.new
drawable.pointsize = 15.0
drawable.font_family = 'Helvetica'
drawable.fill = 'gray'
drawable.gravity = Magick::NorthWestGravity
drawable.font_weight = Magick::BoldWeight
drawable.annotate(f, 0, 0, 5, 4, "Second Life #{reportTitle} (#{reportDate})")
drawable.pointsize = 13.0
drawable.fill = 'black'
drawable.font_weight = Magick::NormalWeight

# set some position for the text i want to print
@startTopPos = 24

# go the records in the xml-document and print the values into the new image
REXML::XPath.each( xmlDoc, "records/record") do |element|
element.elements.each("field") do |field|
name = field.attributes['name']
value = field.attributes['value']
drawable.annotate(f, 0, 0, 5, @startTopPos, name)
drawable.annotate(f, 0, 0, 250, @startTopPos, value)
@startTopPos = @startTopPos + 15
end
@startTopPos = @startTopPos + 15
end

# write the image to the disk. i wasnt able to return it directly without saving. :(
f.write("result.png")
# return the image
createdImg = Magick::Image.read("result.png").first
@response.headers["Content-Type"] = "image/png"
@response.headers['Content-Disposition'] = %q{inline; filename="thepicture.png"}
render :text => createdImg.to_blob

This script returns the following image:

Second Life land sales

To put this image on an primitive i used the following linden script code:

touch_start(integer num_detected) {
llSay(0, "trying...");

if(llGetLandOwnerAt(llGetPos()) != llGetOwner()) {
llSay(0,"Error: Cannot modify parcel media settings.");
}

key video_texture = llList2Key(llParcelMediaQuery( [PARCEL_MEDIA_COMMAND_TEXTURE]), 0);

if(video_texture == NULL_KEY)
{
video_texture = VIDEO_DEFAULT;
llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_TEXTURE, VIDEO_DEFAULT]);
}
llSetTexture(video_texture,ALL_SIDES);
llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_URL,"http://###URL###"]);
llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_PLAY]);
llParcelMediaCommandList([PARCEL_MEDIA_COMMAND_AUTO_ALIGN,TRUE]);
}

###URL### has to be replaced with the URL of the Ruby-Script.

Note: To use this ParcelMedia-feature you have to allow streaming media i think in SL.

No comments: