Scripthackery: Improvements On A Theme

When establishing the photo studio in one corner of Don’t Panic!, Danielle set up a backdrop prim with a number of different textures in it for picture backdrops. To switch between them, she came up with this little script:

default
{
  touch_start(integer total_number)
  {
    integer number = llGetInventoryNumber(INVENTORY_TEXTURE);
    float rand = llFrand(number);
    integer choice = (integer)rand;
    string name = llGetInventoryName(INVENTORY_TEXTURE,choice);
    if (name!="")
      llSetTexture(name,ALL_SIDES);
  }
}

When touched, this script finds the number of textures the object contains in inventory, then picks a random number between 0 and that number minus 1. (As in most programming languages, casting from float to integer in LSL truncates everything after the decimal point.) Then it gets the name of the texture with that index and applies it to all sides. Simple enough.

Danielle wanted the script to say which texture was being displayed at touch time, so she asked me to take a look at the code and improve it. At the same time, I felt that random switching was not the way to go here; better yet would be sequential switching, to run through all the textures in order. Herewith my solution:

// Enhanced Texture Switcher
// Erbo Evans - 8/20/2006
///////////////////////////////////

list all_textures = [];
integer count = 0;
integer current = 0;

set_texture(integer ndx)
{
  string s = llList2String(all_textures,ndx);
  llSetTexture(s,ALL_SIDES);
  string p = (string)(ndx + 1);
  llWhisper(0,"Now displaying texture: " + s + " (" + p + "/"
              + (string)count + ")");
}

default
{
  state_entry()
  {
    count = llGetInventoryNumber(INVENTORY_TEXTURE);
    integer i;
    for (i=0; i<count; i++)
    {
      string s = llGetInventoryName(INVENTORY_TEXTURE,i);
      all_textures += [s];
    }
    llWhisper(0,"Texture switcher is ready.");
    set_texture(current);
  }

  on_rez(integer param)
  {
    llResetScript();
  }

  touch_start(integer total_number)
  {
    if (++current==count)
      current = 0;
    set_texture(current);
  }
}

The code now loads the names of all textures into a list at state_entry() time, for faster access. Notice that, after we load the name of a texture into the string variable s, we turn that into a single-element list to concatenate it onto the all_textures list. We also save the number of textures in count, to avoid having to call llGetListLength() unnecessarily later.

Since setting textures now involves a few different operations, I moved the process into its own function, set_texture(), which takes as an argument the 0-based index of the texture to display. Note that, when the texture number is actually displayed via llWhisper(), it is displayed as a 1-based index, which is more “natural” for humans to deal with. (Unless they’re programmers…but let’s not go there.)

The first two lines of the touch_start() handler will be difficult to understand for anyone not already familiar with LSL, or familiar with one of the languages that inspired it (C, C++, Java). The expression adds one to the current variable, then, if that variable is equal to the count, resets it to 0. “++” in this context is used as a pre-increment operator, which increments the value of current before using it in the test for equality with count. If I had written “current++” rather than “++current”, the “++” would have been a post-increment operator, which means the value of current would have been incremented after its use in the comparison with count. This is sometimes useful, too…just not here. (Sometimes it doesn’t matter which you use, as in the third expression of the for loop in the state_entry() handler. In those contexts, I tend to use the post-increment form. Others will use the pre-increment form here. That’s just a stylistic difference.)

The main drawback of this code as compared to Danielle’s is that it won’t automatically adapt to the addition of new textures to the object; you have to reset the script manually. I could get around that by adding a changed() handler to listen for inventory changes, and call llResetScript() when they happen. In actual practice, though, we don’t add new textures to the backdrop often enough to worry about this.

This code also worked well for an automatic picture cycler that displays a number of pictures I took of Danielle. I simply changed the touch_start() handler into a timer() handler, and called llSetTimerEvent() at the end of the state_entry() handler, with an appropriate delay value.

Share and enjoy! 🙂

Advertisements

5 Comments

Filed under Scripthackery

5 responses to “Scripthackery: Improvements On A Theme

  1. Both the photo backdrops and the picture changer work amazingly well. Also with having it display sequentially I don’t have to bounce through the backdrops until I find the one I want anymore. 🙂

  2. That’s because I am a professional programmer, Love. 🙂

    When I do these “Scripthackery” posts with code examples, it’s mostly me trying to explain to the average reader what’s going on, in hopes of better improving everyone’s understanding.

    Oh, and I know that texturing all sides of the prim is a bit sloppy…but for objects which are primarily 2-dimensional and usually up against a wall, it’s a reasonable behavior.

  3. Yeah well I am hardware mostly but I am learning software, slowly but surely. 🙂

  4. Bingo! I was looking for this for a slide show device … except I need to mod it so that only the owner can change the texture. 🙂

  5. Pingback: Behind the Scenes #1. | Sanctuary Online

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s