Last week I fixed some longstanding issues with the Director engine’s implementation of the ‘go’ command!
‘go’ is one of the most commonly used Lingo commands, used to change which frame a movie is on or to load an entirely different movie. While it seems straightforward on the surface, it has some subtle quirks that can affect movie execution in major ways.
Most of the time, ‘go’ is used in a script that looks like this:
on exitFrame go to frame 5 end
It’s pretty clear what we need to do here. When we exit the current frame, we just need go to frame 5. Previously, we did that something like this:
- When a ‘go’ command is executed, queue the requested frame or movie.
- When script execution has finished, the Lingo interpreter returns control to the score.
- If a frame has been queued, the score loads the requested frame. If a movie has been queued, the score does nothing and returns control to the window.
- If a movie has been queued, the window loads the requested movie.
Now what if we make the script a bit more complicated?
on exitFrame go to frame 5 doSomethingElse() end
With our previous implementation, the entire script, including
doSomethingElse() would execute before the frame/movie switched. This isn’t how the original does it, though. It should actually work like this:
- When a ‘go’ command is executed, pause execution of the current script.
- Immediately load the new movie/frame.
- Process any startMovie/enterFrame events for the new movie/frame.
- Unpause execution of the script containing the ‘go’ command.
With this execution order,
doSomethingElse() shouldn’t execute until after the new frame/movie is loaded. I implemented the correct implementation order, and then I immediately ran into another longstanding problem.
A movie’s scripts can sometimes outlast the movie that originally contained them, as in the example I gave above. But scripts could also contain pointers to data owned by the movies, most notably the name table. Once the movie was destroyed, these would become dangling pointers, and dereferencing them would cause the engine to segfault. I solved this by copying any data which a script needs, including any names, over to the script itself, eliminating all references from the script to the movie.
An additional, new problem popped up. Previously, after a script was executed, the call stack would be entirely empty, and we could safely share one stack among several movies running in parallel in different windows. They would just take turns executing their scripts, leaving the stack nice and tidy for the next movie. Now, though, a movie’s script execution could be temporarily paused, leaving data on the stack. We can no longer share one call stack among multiple windows, so I gave each each window its own call stack.
Also, I’ve debugged one of Meet MediaBand’s interactive music videos, House Jam, and it’s now running quite well! There are some rendering issues that need to be sorted out, but that doesn’t make it any less fun. Here’s a small sample of it, but it’s much better to interact with the music video yourself. 😉