Creating a Slideshow Viewer, Part 2: Reading the Inventory

October 16th, 2011

This is the second installment in my small series about creating a slideshow viewer (based on my new texture vendors). In this one, I’ll be showing you how to add images to the viewer.

In my original texture vendors, the prim which displayed the images was responsible for creating a list of the images available, and then of moving through the images when it received a message from one of the buttons.

In the new version, all of this is handled by the Frame prim, which looks for touch events and determines which button was ‘clicked’, and which then updates the texture on the Display prim. This is made possible by another relatively new script function, llSetLinkTexture(), which allows the texture of a prim to be assigned by another (linked) prim.

There are two elements to handling the images. The simplest is assigning a specified texture to the Display prim. However, in order to do this the Frame needs to have the textures stored in it, and needs to be able to make a list of the available textures.

Let’s start by creating this list. First, edit the Frame prim. As the Frame prim and the Display prim are linked, click the ‘Edit linked’ check box on the build dialog, then click on the Frame. Now switch to the contents tab, and drop your images (textures or snapshots) into it.

Now we need to write a script that will create a list of those images. If you have been following along, you will already have a script in the Frame prim, to handle the buttons. Update this to the following code:

    // A list to hold the image keys
    list images = [];
    readImages()
    {
        // Count the number of textures
        integer count = llGetInventoryNumber(INVENTORY_TEXTURE);
        integer i;
        string name;
        images = [];
        // Look through all the texture
        for (i = 0; i < count; i++)
        {
            name = llGetInventoryName(INVENTORY_TEXTURE, i);
            // Get the key, and add it it to the list
            images += [llGetInventoryKey(name)];
        }
        // If we have at least one image, display the first one.
        if (llGetListLength(images) > 0)
        {
            llSetLinkTexture(LINK_ROOT, llList2Key(images, 0), 0);
        }
    }
    float btn_Cols = 8.0;
    float btn_Rows = 8.0;
    integer btn_Id(vector pos)
    {
        integer button = (btn_Row(pos) * (integer)btn_Cols) + btn_Col(pos);
        return button;
    }
    integer btn_Row(vector pos)
    {
        // Flip the y-axis, so that it runs from top to bottom.
        float y = 1.0 - pos.y;
        integer row = (llFloor((y * 10) * btn_Rows) / 10);
        return row;
    }
    integer btn_Col(vector pos)
    {
        integer col = (llFloor((pos.x * 10) * btn_Cols) / 10);
        return col;
    }
    default
    {
        state_entry()
        {
            readImages();
        }

        touch_end(integer count)
        {
            vector mousePos = llDetectedTouchST(0);
            integer id = btn_Id(mousePos);
            llOwnerSay("Button " + (string)id + " pressed");
        }
    }
    

This finds all the texture items in the prim’s contents, and stores their names in the Image list. Once that is done, it gets the first image from the list, and assigns it on the Display prim.

The llSetLinkTexture() function is used to display the image. The allows us to set the texture of another prim, in this case the display prim, by specifying the prim number, the UUID of the texture (which we read from our list), and the face, which is here assumed to be face 0.

One thing to be careful about here is that it assumes that the Display prim is prim 0, that is, the root prim. If you don’t already know how to do this, the trick is that when you select the prims that you want to link, the root prim should be the last prim that you select before linking. In this case there are only two prims, so select the Frame prim first, then Shift+Click the Display prim to add it to the selection. Finally link the prims (the option to link is on the Build menu in Viewer 2, and in most third-party viewers).

Creating a Slideshow Viewer, Part 1: Buttons

October 11th, 2011

Recently I decided to update my Texture Vendors. If you have seen my stores inworld, you will know that the Texture Vendors display one texture at a time, with buttons to let you cycle through the different textures in the set.

The current version of the vendors was created quite a while ago, and uses techniques that are now out-dated and inefficient. Each vendor uses three scripts — one for each button, and a script in the central prim to actually display the texture. Messages are sent from the script to the central prim to tell it to change textures.

With some of the new features that have appeared over the last couple of years it should now be possible to reduce those three scripts into one much more efficient script, and that’s what I am planning on doing.

While I am doing it, I am also going to write it up in this blog, because the basic idea of a gadget which lets you move forwards and backwards through a set of images obviously has more uses than just as a texture vendor.

The slideshow needs at least two buttons, to move forwards and backwards through the slides. It might need ‘first’ and ‘last’ buttons as well.

Until a couple of years ago the only reasonable way to implement buttons was to create a prim for each button, with a script in each prim to detect a touch event, and probably then to send a message to some kind of controller. This is the way my existing vendors work, and you can see that this is hardly efficient for either prims or scripts.

In Viewer 1.21, however, the llDetectedTouchST() function was introduced (along with some other related and useful functions). This allows you to detect which point on a prim face was touched. This makes it possible to have several buttons as a single texture, and then determine which button was actually clicked on.

Second Life Wiki: “Detected” functions

To test this out, and create a starting point for the viewer, I’m going to create two prims. One will be the surface on which the images will be displayed, and the other will be the surrounding frame, which will include any buttons.

Create two prims, one with a size of 1.0 x 1.0 x 0.1, which will be the frame, and the other with a size of 0.75, 0.75, x 0.1, which will be the display face. For the frame, set it to hollow, at a value of 80, and rotate both prims so that they are facing the right way. Centre the display prim inside the frame prim. Given those values, you should find that the prims fit together exactly. Set the textures to blank.

If you want a larger version, try setting the frame to 2.0 x 2.0 x 0.1, hollowed to 75, and the display frame to 1.5 x 1.5 x 0.1.

To test the buttons, I’m going to use a grid texture. I’ll assign it by UUID using a temporary script, so that you can use the same texture. In the Frame prim, create the following script. You might need to change the ‘face’ parameter to get the image onto the correct side of the prim. Once the texture has been applied, you can delete the script again:

    default
    {
        state_entry()
        {
            integer face = 0;
            llSetTexture("53e5f19a-70a0-ae65-831f-da5f4ec69fdb", face);
        }
    }
    

You should end up with something like this (I’ve coloured the display prim for clarity, but actually you should leave it white):

Blog tutmisc 0002a

We now have an 8×8 grid, of which the outermost cells are visible. Now we can test the button-handling. To work out which cell was clicked on requires a little bit of calculation, based on the size of the grid. The code I’m using is relatively generic, so you can modify it for different button layouts simply by changing the ‘btn_Rows’ and ‘btn_Cols’ values.

Create a new script in the Frame prim, and copy in the following code:

    float btn_Cols = 8.0;
    float btn_Rows = 8.0;
    integer btn_Id(vector pos)
    {
        integer button = (btn_Row(pos) * (integer)btn_Cols) + btn_Col(pos);
        return button;
    }
    integer btn_Row(vector pos)
    {
        // Flip the y-axis, so that it runs from top to bottom.
        float y = 1.0 - pos.y;
        integer row = (llFloor((y * 10) * btn_Rows) / 10);
        return row;
    }
    integer btn_Col(vector pos)
    {
        integer col = (llFloor((pos.x * 10) * btn_Cols) / 10);
        return col;
    }
    default
    {
        touch_end(integer count)
        {
            vector mousePos = llDetectedTouchST(0);
            integer id = btn_Id(mousePos);
            llOwnerSay("Button " + (string)id + " pressed");
        }
    }

Now try clicking on the grid. As you do so, it should display (in local chat) the number of the cell that you clicked. The top-left cell should be 0, and the bottom-right cell should be 63. You might need to rotate the prim if this is not the case, although as long as you know which cell is where, you don’t necessarily need to do that. It’s just more convenient.

Aside: Why am I using touch_end() instead of touch_start()? This is because if you use touch_start() to trigger a state change, the touch_end gets ‘lost’ (it’s expecting the wrong script state), which can cause problems, and result in touches not being detected. Using touch_end() is safer. If you know that you are not going to change state, you can use touch_start().

LSL Scripts: Scrolling floating text

August 24th, 2011

This is one of an occasional series of small but (I hope) useful pieces of code.

Floating text above a prim has a lot of uses in Second Life, and here is a script which might add even more possibilities. This takes advantage of the fact that you can display multiple lines of text and uses this to create a scrolling text display, like so:

It works very simply. We have a list which stores the lines to be displayed. To add a new line to the text, and to scroll the text up, we remove the first entry in the list, and add the new entry at the end. To display the text, we just string the entries in the list together, separating them with a new-line, and set the result as the floating-text for the prim.

In this little example program, a line of text is added whenever the prim is touched.

list lines = ["", "", "", "", ""];
addLine(string line)
{
    // Add the new message to the end of the list, losing the first entry
    // from the list at the same time.
    lines = llList2List(lines, 1, llGetListLength(lines) - 1) + [line];
    // Concatenate the lines together, separated by a new-line.
    string output = llDumpList2String(lines, "\n");
    // Set the result as the floating text.
    llSetText(output, , 1.0);
}
default
{
    touch_start(integer count)
    {
        addLine("Touched at " + llGetTimestamp());
    }
}

Templar Creations Inworldz Store

July 31st, 2011

The Templar Creations store in Inworldz has moved to a new location amongst the Magellan Sea sims. You will now find it at Eole (100, 245, 1201).

Support SLUniverse

June 4th, 2011

What is SLUniverse?

SLUniverse is a web-forum dedicated to Second Life and to other virtual worlds, and is one of the most successful and popular of the unofficial Second Life forums. It is also the home of the Snapzilla photo-site for sharing Second Life snapshots.

You’ll find it here: http://www.sluniverse.com

Why does it need support?

SLUniverse is run by Cristiano Midnight, a long-time resident of Second Life, and is funded out of his own pocket, offset by advertising. Until recently there was significant income from Google’s AdSense service, but this has recently ended (click here for details).

As a result, the site has now become more expensive to run, and a group of merchants who are also members of SL Universe decided to do their bit to help out. Each merchant has assigned one item whose earnings will be passed to Cristiano as a contribution to support the forum.

Here is the forum thread with the full list of merchants and items.

For Templar Creations contribution, I am releasing the Japanese House Texture Collection, which brings together all 60 textures from the Japanese House texture sets 1 – 3. You will find it inworld at the main store. It won’t be available from the Second Life marketplace, because the marketplace takes 10% commission, and I would prefer that the whole amount went to SLUniverse.

Templar Creations Main Store

 

Japanese House Textures, Set 3

June 2nd, 2011

This is a new set of textures based on my previous Japanese House textures, this time with a painted red wood theme. There are 20 textures in this mostly, mostly at 512 x 512, but with a few at 256 x 512 for narrow panels such as doors.

You can see the whole set on the Gallery page but here is a preview of some of the textures:

As usual, you will find it on the SL Marketplace at  or inworld at the main store:

Second Life Marketplace page

Main Templar Creations Store

 

Industrial Wall Textures – Set 1

May 21st, 2011

This is a collection of general-purpose red-brick and concrete wall textures for industrial builds. There are 31 textures in all, most at 512×512 in size. Here’s a couple of quick previews:


As usual, you will find the set in-world at the Templar Creations main store, both in Second Life (see the link below), and in Inworldz at at Tulare 134/220/22, as well as on the Second Life Marketplace website:

Second Life Marketplace page

Main Store

Industrial Metal Textures, Set 1

April 30th, 2011

At last, a new texture set!

This is a collection of general-purpose rusty and weathered metal textures for industrial builds. There are 30 textures in all, most at 512×512 in size.

You can see the whole set on the Gallery page but here is a preview of some of the textures:

As usual, you will find the set in-world at the Templar Creations main store, both in Second Life (see the link below), and in Inworldz at at Tulare 134/220/22, as well as on the Second Life Marketplace website:

SecondLife Marketplace page

Main Store

 

 

Old Wood Textures, Set 1

March 20th, 2011

This a collection of general-purpose old and weathered wood textures, with floorboards, planking, and plain fill textures, along with a few tree bark textures. All the textures are 512×512 in size.

You can see the whole set on the Gallery page but here is a preview of some of the textures:

Floorboards

Old Woods, Floorboard sample

Planking

Old Woods, Planking sample

Tree barks

Old Woods, Tree Barks sample

As usual, you will find the set in-world at the Templar Creations main store, both in Second Life (see the link below), and in Inworldz at at Tulare 134/220/22, as well as on the Second Life Marketplace website:

Second Life Marketplace

Templar Creations Main Store

 

Steampunk Textures, Set 14

March 6th, 2011

This is an extension to sets 9-13, and contains a mixture of wall and girder textures. There are 30 distinct textures, plus transparent versions of the window textures, and most of them are 512 x 512 in size.

Here’s a preview. Check the gallery to see all the textures.

Steampunk Textures, Set 14, Sample 1

Steampunk Textures, Set 14, Sample 2

Steampunk Textures, Set 14, Sample 3

As usual, you will find it in-world at the Templar Creations main store, and on the Second Life Marketplace website.

Second Life Marketplace Page

Templar Creations Main Store in Second Life