You are currently browsing the monthly archive for January 2008.

Sooner or later, if you are creating gadgets that do useful things, you will find the need to have some communication between scripts in different prims.

There are two basic methods of doing this. One is to use the llMessageLinked() function, the other is to use a chat channel. In this article I am going to look at using llMessageLinked, but it is important to understand when to use which option.

Let me start, then, by briefly looking at the chat channel option.

The main advantage of this option is that the prims which contain the communicating scripts do not have to be linked. This allows prims to communicate across an entire sim (note that there is no easy way to communicate across different sims short of using an external web-service of some kind).

The main disadvantage, and this is a biggie, is that using a chat channel normally requires the scripts to set up Listeners which are constantly active. This adds to simulator lag, and is something that therefore should be minimised.

If your scripts absolutely need to be run in unlinked prims, or in prims which are in separate objects, however, the chat channel option is probably the only way to go.

However, if your scripts are part of a set of linked prims, the llMessageLinked function is a better option, and it is this option that I am going to cover.

llMessageLinked takes a number of parameters, although you rarely need to make use of all of them. The first parameter is crucial, though, as it is the number of the prim that you are sending the message to. It can also be one of a set of special values, the most useful of which are probably the following:

LINK_ALL_OTHERS – this sends the message to all other prims except the current one.

LINK_ALL_CHILDREN – this sends the message to all prims which are children of the root prim.

LINK_ALL – this sends the message to all the prims in set, including the one that the message is sent from.

The second parameter is an integer. This can be used as an identifier of the type of message. For example, you could set up the following constants in each script:

integer CMD_INIT = 1;
integer CMD_MOVE = 2;	// I'll use this in my examples below

You would then pass the appropriate value to llMessageLinked.

The third parameter is a string. This can be used to pass parameters to the receiving scripts. If you only need one parameter, this is simple. Remember that you can use LSL’s type-casting to let you put (for example) numbers into this parameter. I’ll show an example of this later.

The final parameter is a key.

At the receiving end, the message() function will be called when a message is received from an llMessageLinked() call. It is passed five values, the first of which is the number of the sending prim, and the other four are the four parameters from llMessageLinked().

As an example, lets create a system whereby touching the root prim will move the linked prim. In itself, this isn’t exactly useful, but it could be used as the basis of (for example) some kind of ‘sliding door’ system.

Create two prims, and link them together.

Create a new script in the root prim (note that if you create a script while a link set is selected, the script will automatically be created in the root prim).

In our script, we will have a setting which tells us if the other prim is in its original position. If it is, when the owner touches the root prim, we move the other prim a short distance away. If it is not, we will move it back.

Here is the basic script:

integer hasMoved = FALSE;
float moveBy = 1.25;
// Commands
integer CMD_MOVE = 1;
integer CMD_RESTORE = 2;
default
{
    touch_start(integer count)
    {
        // Only respond to our owner.
        if (llDetectedKey(0) == llGetOwner())
        {
            if (hasMoved)
            {
                // Tell the other prim to restore its original position.
                llMessageLinked(2, CMD_RESTORE, "", NULL_KEY);
                hasMoved = FALSE;
            }
            else
            {
                // Tell the other prim to move by a specified distance. Note
                // that we are type-casting the distance to a string.
                llMessageLinked(2, CMD_MOVE, (string)moveBy, NULL_KEY);
                hasMoved = TRUE;
            }
        }
    }
}

Save the script.

Now, tick the ‘Edit individual prims’ checkbox, and select the other prim. Create a script in this prim. In this script, we will detect the message from the root prim, and respond accordingly:

vector originalPos;
// Commands
integer CMD_MOVE = 1;
integer CMD_RESTORE = 2;
default
{
    state_entry()
    {
        originalPos = llGetLocalPos();
    }
    on_rez(integer param)
    {
        originalPos = llGetLocalPos();
    }
    link_message(integer sender, integer num, string params, key id)
    {
        // Check that this came from the main script.
        if (sender == 1)
        {
            // Find out which command was received
            if (num == CMD_MOVE)
            {
                // Read our local position (i.e. relative
                // to the link-set object)
                vector pos = llGetLocalPos();
                // Adjust it -- note that we can typecast
                // the string parameter to a float.
                pos.x += (float)params;
                // Set the new position
                llSetPos(pos);
            }
            else if (num == CMD_RESTORE)
            {
                // Restore our original position
                llSetPos(originalPos);
            }
        }
    }
}

Save the script, close the Build dialog, and test the object.

You should find that this works, and touching the object will move the second prim. Touching it again will move it back to its original position.

However, there are some problems with this system. For example, we need to know the link number of the prim that we want to send a message to. When there are only two prims (as in our example) this is simple, but if there are a number of prims, it can get difficult to keep track of this (especially if you
unlink and relink the prims while you are building your object, as is quite likely).

Also, the string that we are using to pass a parameter to the linked prim seems a little restrictive.

In the next article I’ll look at both of these issues, and some possible solutions (though as a hint for the parameters, remember that you can typecast a list).

A few months ago I decided it was finally time to ditch Microsoft, and I purchased a MacBook Pro. It’s excellent, and I can’t say that I’ve regretted it in any way.

Except…

There is one application which has caused me some problems, and that is Second Life. What a surprise.

For the benefit of anyone else who is using a MacBook Pro, here are a few notes of things that I have learnt that are of use when running Second Life (these notes apply to Mac OS 10.4 (Tiger) – I don’t intend to update to Leopard until the various issues with it have been fixed. Never buy the first release of anything!).

Nvidia Graphics Card Driver

Recent MacBook Pros use an Nvidia GeForce 8600M GT graphics card. On the Mac, the driver for this graphics card is bugged. Seriously, seriously bugged. Using it will bring your Mac grinding to a halt within minutes, to the extent that only a forced reset (see Emergency Shutdown below) will get you out.

The problem appears to lie with Apple, although there are some question-marks over this. For example, although World Of Warcraft users have reported similar problems, it does not seem to be universal (personally, WOW runs impeccably on my own machine).

There are two possible work-arounds. One is to use a virtual machine with Windows (via BootCamp seems the best option). I have no personal experience with this, but I understand that it works well. I am tempted to try it at some point.

The other work-around is not straight-forward, but it is what I am doing at the moment. The key lies in using an alternative driver, actually for another video card (this seems a somewhat scary option, but I have been doing it for several months without problems).

Being able to specify an alternative driver, however, is not something that comes with the standard Mac OS X install, and is not straight-forward to set up. If you want to go down this route, the following link will take you to instructions on how to do this (it will also give some more inforation about the problem):

MacBook Pro Graphics Freeze Work-around

The downside to this is that some graphic options which should be available will be disabled, because they are not available for this particular driver.

The other downside is that this work-around does not really work under the Windlight version. If Windlight goes live without this graphics problem being fixed, it might meant the end of Second Life for MacBook Pro users.

Keyboard shortcuts

For the MacBook Pro, assuming that you are using the laptop’s own keyboard, here are the key translations you need:

Right-click: Click + Command (Apple) key
Fly up: e or FN + UP
Fly down: c or FN + DOWN
Delete
: FN + Backspace
Debug menus: CTRL+Option+D

Note that even if you have a mouse with a right-click available, this doesn’t seem to work in Second Life on the Mac.

Emergency Shutdown

I’ve never seen this documented by Apple (maybe they don’t like to admit that it would ever be necessary), but my experience with PCs prompted me to try it out, and it does indeed work.

If you ever get into the situation where the Mac completely hangs — the cursor stops moving, there is no response to any key-presses — there is a way to force the Mac to shutdown (being a laptop, of course, just pulling the plug out won’t help — it will switch to battery instead).

Hold down the power button. If the ‘shut-down’ dialog appears, you can breathe a sigh of relief, and shut down normally. If not, keep the button held down. After about 4 seconds the Mac should shut down (with a rather disturbing ‘clink’ on my machine!). You may well find that when you boot up again it takes longer than usual — I suspect that this is because it has noticed the forcible shutdown, and is performing various hardware checks (especially hard-drive checks) to make sure everything is still functioning correctly.

This is not something you want to make a habit of.

Second Life is the only application I have come across which has ever forced me into this situation. No comment!

This is a simple but effective way to create a ‘draped cloth’ effect that can be used as the base texture of (for example) capes or curtains. I’m afraid that this one is specific to the Gimp graphics program, although possibly other programs will have similar features.

Start with an empty picture, at a large size such as 512 x 512, or even 1024 x 1024. I do this with all my textures. Starting large and scaling down usually works well, and sometimes actually improves things by removing or hiding small glitches, whereas it is well-nigh impossible to get good results by starting small and scaling up.

Find the Solid Noise option, under the Filters/Render/Clouds menu.

Set the options so that the X size is set to the maximum, or somewhere near it, and the Y size is set to the minimum, 0.0. You can try experimenting with different values, but you need to be aware that setting the Y size to anything other than the minimum can make it more difficult to create a seamless texture.

You should already see the drape effect.

If you want to increase or decrease the ‘depth’ of the effect, use the Brightness and Contrast — lowering the Contrast will make the effect shallower, increasing the depth (especially in conjunction with decreasing the Brightness) will make the effect deeper.

I would now colorise the texture. Select the Colorise option. Adjust the Hue slider to get the colour you want. Play with the other two sliders to tweak the result.

At this point, the drape will tile horizontally, but probably not vertically. There is a fairly easy way to fix this.

Start by selecting the top half of the image (you don’t have to be exact, but make sure that the top edge is at 0). Feather this fairly drastically, possibly to something like 50 pixels, then copy it. Paste it back in, flip it vertically, then move it down to the bottom, being careful not to move it horizontally.

If you find that the texture does not tile horizontally, you can apply a similar technique to the left and right sides of the texture.

The end result should be tileable. This technique of copying and pasting the top/bottom (and equally the left/right) halves of an image can often be used to make an image tileable if it has right/left or top/bottom symmetry.

Here is an example of the final result:

Drape texture

Sometimes it is useful to be able to change or apply textures through a script. Imagine, for example, a button or switch where you want to change the appearance when the user clicks on it.

There are a number of functions in the LSL library for dealing with textures. In this post I will cover the most basic of them. I’ll go into more details in subsequent posts.

Applying a Texture

Applying a texture to a prim is probably the simplest thing that can be done when scripting textures. You can use the llSetTexture function to do this, which simply needs the texture, and the side to apply the texture to. I’ll discuss prim sides a bit later, but for the example I’ll use the ALL_SIDES constant, which will apply the texture to all sides of the prim.

There are two different ways of specifying the texture. You can either use the name of the texture, or you can use the asset UUID of the texture.

To use the name, the texture must be included in the prim’s contents (just drag the texture from your inventory into the contents list of the prim).

Assume we have a texture called “test”. This script will apply the texture to all sides of the prim when the prim is touched:

default
{
    touch_start(int number)
    {
        llSetTexture("test", ALL_SIDES);
    }
}

Alternatively, we can specify the asset UUID. To find the UUID, right-click on the texture in your inventory, and select the Copy Asset UUID option. You can then paste the result into the script, like so:

default
{
    touch_start(int number)
    {
        llSetTexture("3c8f1c70-671a-4cb6-9f06-58b95c77e6a6", ALL_SIDES);
    }
}

The advantage with using the UUID is that the texture does not need to be in the prim’s inventory, it only needs to exist somewhere in SL’s asset server.

Note that the asset UUID in the above code is a real one, and will get you a “test card” pattern that you can use for testing offsets (see below).

Aside: What happens if you upload a texture into your inventory, get the UUID for it, then delete the texture? Will the texture vanish from Second Life altogether? No, it won’t. Once a texture is uploaded, it is permanently added to the asset server, and deleting it from your inventory has no effect on it — you simply won’t be able to refer to it by name any longer. It will still exist on the server, and you can still use the UUID to refer to it in a script.

Sides

Suppose you want to apply a texture to just one side of a prim. To do this you simply specify the side number:

llSetTexture(“test”, 1);

Ah, but how do you know which side has which number? That’s the tricky bit. Assume that you have just rezzed a cube, and haven’t rotated it in any way. The sides will be numbered as follows:

top: 0
side with lowest y: 1
side with highest x: 2
side with highest y: 3
side with lowest x: 4
bottom: 5

If you hollow the cube, side 5 is the inside (yes, all four interior sides count as a single side), and the bottom becomes side 6.

Working out the side numbers for a rotated cube, or for a more complex prim, gets rather more difficult, and can involve a lot of trial and error. A better way is to use the debug menu. If you don’t have the debug menu displayed, press CTRL+ALT+D to reveal it.

To get information about one side of a prim, tick the ‘Select Texture’ option in the build dialog, select the prim side that you want to know about, then press CTRL+SHIFT+ALT+T. Information about the prim side will be displayed, including the side number.

Scaling and Offsetting

Once a texture is applied, you can scale and offset it using the llScaleTexture and llOffsetTexture functions.

llScaleTexture(0.5, 2.0, ALL_SIDES);

llOffsetTexture(0.5, 0.0, ALL_SIDES);

The horizontal and vertical parameters taken by these functions are exactly the same as those on the texture tab of the build dialog, so you can use the build dialog to help find the appropriate values.

If you have already worked with textures you will know that a scaling of 1.0 x 1.0 will fit the texture to the size of the prim, whereas higher values will tile the texture, and lower values will only display part of the texture.

For example, a value of 0.25 will display one quarter of the texture, stretching it to fit the prim. Which quarter of the texture is actually displayed depends on the offset, and the way in which the offset works is not immediately obvious.

Basically, the offset is from the centre of the texture. An offset of 0.0 x 0.0 will therefore centre the texture. How other offset values affect the texture is easier to explain using an actual example.

Here is the testcard texture which I mentioned above, applied initially with an offset of 0.0 x 0.0:

Test Card example 1

If you change the horizontal offset to 0.25 you get this:

Test Card example 2

Try changing the horizontal scaling to 0.25, and the horizontal offset to 0.0. This produces the following, which is actually displaying the centre of the scaled texture, showing half of one band of colour, and half of the other.

Test Card example 3

To offset it so that we are centred in a band of colour, we need to use an offset of 1/8, or 0.125. Set the horizontal offset to this value, and we get a single band.

Test Card example 4

To centre each band in turn, use the following offsets:

-0.375
-0.125
0.125
0.375

Obviously, this only works when the horizontal scale is 0.25.

Using scaling and offsetting to select just one portion of a texture can help to make more efficient use of textures, especially if you have a prim which needs to sometimes change appearance — you can pack the different images into a single texture, and select the appropriate part of the texture using the scale and offset. The alternative method is to have multiple textures, but this means that when the texture is changed, there is a delay while the new texture is loaded. Using the scale and offset method, the texture is already fully loaded, and the prim changes appearance almost instantly.

I’ll cover this more in a later post.

Links

You will find a lot of useful information about the texture-handling functions on the LSL Wiki:

LSL Wiki

Arcana Nuevo

I thought I’d start the new year with an introduction to a place that I’ve been intending to blog about for a while, but haven’t got round to, at least until now. I was introduced to it by Saffia Widdershins of PrimPerfect magazine (thanks, Saffia!).

I’ve never played any of the Myst series of computer games, but I’ve seen plenty of screen-shots from it, and once played through part of a demo, so I’m quite familiar with famously attractive look of it.

Unsurprisingly, there have been attempts to recreate that look in Second Life (the creators of Myst themselves did, but only temporarily). This site, Arcana Nuevo, owned and created by Angelica Zuma, is one of the most successful that I’ve seen.

When you teleport in, you land at the telehub beside the shop (where you can buy furniture in the same style as the main building). Walking through the shop and out the other side, you come to the steps that lead up to the imposing entrance:

From here you walk through a corridor beneath a waterfall, leading into the main bulk of the castle. There is plenty to see and explore, and I’ve put together a Snapzilla photo album of some of the scenic views (see the links at the bottom of the post).

One notable highlight, at least for me, is the small ‘office’ that you find at one end of a corridor near the entrance. Apparently this is based directly on one of the locations in Myst:

The castle is definitely one of the places in Second Life that deserves to be visited.

Links

Photo Album

SLURL for Arcana Nuevo