Here's why: in a Script node, you get to specify the methods, in a programming language like Java or ECMAScript. In our examples we'll be using ECMAScript exclusively, but any programming language that the browser supports will do.
So let's write a script. Here's one:
DEF Pointless Script { eventIn SFColor colorIn eventOut SFColor colorOut url "javascript: function colorIn(value, timestamp) { colorOut = value; } " }
Here's some routes that will plug this script into the scene and make it execute:
ROUTE Material_1.diffuseColor_changed TO Pointless.colorIn ROUTE Pointless.colorOut TO Material_2.set_diffuseColor
This is, of course, a totally useless script. It merely copies the input to the output. So we could just as easily have forgotten about the script and written the following route:
ROUTE Material_1.diffuseColor_changed TO Material_2.set_diffuseColor
But right now we aren't worried about writing a killer script. We're interested in finding out how scripts work.
The first thing you should notice is that Pointless has an eventIn called "colorIn" and it has a function of the same name. Any event arriving on that eventIn will execute the function of the same name. We said earlier that eventIns were methods. Now that you've written one, you know why. What would happen if you forgot (or misspelled) the function name? Nothing. There's no method corresponding to the eventIn, so nothing happens.
The second thing you should notice is that the function (method) colorIn has two arguments: value and timestamp. Remember when we said that an event consisted of a dataflow, a timestamp and a run request? Now you know why: the "value" is the dataflow. Whatever data gets routed to the colorIn eventIn will show up in the "value" argument. And the timestamp will show up in the "timestamp" argument.
There's nothing magic about the names "value" and "timestamp". You can call your function arguments "foo" and "bar" or anything else that strikes your fancy. The first argument will be the value of the dataflow, and the second, whatever you call it, will be the timestamp. If you don't use the timestamp (as most of the time you won't) you can simply declare the function without it:
function colorIn(value) {
and the VRML browser (and its ECMAScript interpreter) will simply pretend there's only one argument.
The final thing you should notice about the Pointless script is that your script methods (in this case, we only have one: colorIn) are responsible for writing any eventOuts.
Once again, what happens if you forget to write to an eventOut (or misspell it)? Nothing. If you misspell an eventOut name, the ECMAScript interpreter will simply assume that you meant to declare a local variable of that name and will obediently create that variable and write to it.
In all our examples we will explicitly declare variables. So if you see an example where we write to a misspelled eventOut name, you can assume the same thing as you'd assume about your own code: we made a mistake.
Now let's write a useful script:
DEF Diode Script { eventIn SFBool boolIn eventOut SFBool boolOut url "javascript: function boolIn(value) { if (value) boolOut = value; } " }
Why is this a useful script when it seems to do little more than Pointless did? Because this little guy only passes a true value. That's useful for all sorts of things we'll talk about later, but there's one important thing it illustrates about scripts: if a FALSE event comes into boolIn, then the boolIn method won't write anything to boolOut. And if it doesn't write anything to boolOut, then that event won't get generated this time. In general:
a script function (method) may generate an eventOut, but it doesn't have to, and if you don't specifically write to the eventOut (spelled correctly) no event will be generated.
One more thing along the lines of dusting and cleaning. In all the other nodes except the Script node, the value of an internal state variable has to change for the event to be generated on the corresponding eventOut. In a Script node, it doesn't matter whether the value you write to an eventOut is different from the value you wrote last time. The act of writing to the eventOut is what matters, not that the value has changed.
You can think of the people who implemented the methods for all the other 53 nodes as following a design rule in their (invisible) methods: don't write to an eventOut unless the value has changed from last time. Since those people were plenty smart, it's probably a good idea to keep in mind for the script methods you write.
There are three other things you can do in Script nodes:
We'll introduce the former when we absolutely can't avoid it, the middle one some time soon, but we'll save the latter for the very end. For now, we want you to have the main script paradigm firmly in your mind: you route to a script's eventIn methods, and you route from the script's eventOuts. Data comes in the form of events, and, apart from one exception we'll mention very soon, there are no variables. Only after this paradigm is thoroughly pounded into your head, so that there's no possibility of your being confused by these shortcuts, will we suggest you let your guard down a little.