Articles Archive
Articles Search
Director Wiki

Pointer Operations in Lingo

October 14, 1998
by Brennan Young

One of the things that makes a programming language really powerful is pointers. Pointers are a very efficient way of processing data. Instead of shuffling it about from place to place, you just manipulate a reference to its actual location in RAM. This is especially useful for large volumes of data because they may be too unwieldy to move without significant performance problems. If you are working with a bunch of heavy data (such as all the plays of Shakespeare, each stored in seperate strings), you are going to benefit from a little understanding of pointers. Your movies will probably run better too.

If you use Director, you are already using pointers. All the high level datatypes are stored as pointers. The most obvious one is the cast member. Haven't you ever thought it remarkable that you can drag a multi-megabyte bitmap around in the cast and drop it into a new cast member location with the same ease that you would with, say, a 64 byte quickdraw shape? How does the score update itself when you move a cast member around which is in use by a sprite. What magic is this?

A cast member is a pretty fancy object, but most of the time you are barely touching it. A castlib does not really contain all those media objects, though the Director engineers have done a good job of convincing you that it does. A castlib is just a list of pointers. It takes care of showing the right icon, according to the media type of the data pointed to, and in most cases, displays a little thumbnail for each member which reminds us visually what it is pointed to. When you drag a member onto the score, a sprite object stores a pointer to that member in its "member" property.

OK, maybe this is rather useless information, even obvious perhaps, but I think it's important to have a more than skin-deep understanding of the tools you are using. Director is not just a "Black Box", we do need to poke around inside from time to time, if only to get our projects running smoothly.

Learning about pointers has certainly affected my Lingo. I recently wrote an article about sharing data between objects without using globals. To me that was a mini-revolution. The secret was pointers, but their use does not stop there.

Try this simple example in a moviescript

on test
  set referencedData to []
  fill referencedData
  put referencedData
on fill thelist
  repeat with n = 1 to 100
    add thelist, n
  end repeat

If you type...

test the message window, the result you get will be a list of integers from 1 to 100. Nothing unusual about that, but have a close look at the script. The first handler creates an empty list, then sends the list as a parameter to the second handler. The second handler takes the list parameter and fills it up.

There is no return statement.

When the first handler outputs the list (which it created) to the message window, the list is full up with integers. This might seem a little strange, but to a C programmer it's the normal state of affairs. This really blurs the boundaries between a procedure and a function because a return statement is not necessary, but you get a result back anyway. This is yet another reason why no-one can agree whether a procedure is a special kind of function or vice versa.

Lists are the lowest level Lingo datatypes to be passed as pointers. Fortunately it is in the nature of lists that they are container objects, so if there are any other types of data that you want to point to (instead of move around and duplicate in bulk), you need only pop them in a list. Other datatypes you could use are property lists and instances created from parent scripts or behaviors, each of these are 'passed by reference' (the traditional computer jargon for "stored as a pointer").

Let's take another example. A score script this time.

property myPath, mypos, stagerect 
on beginsprite me
  set mypos to 1
  set myPath to [the loc of sprite the ¬
    spritenum of me]  
  set sw to the width of the rect of the stage
  set sh to the height of the rect of the stage
  set stagerect to rect(0,0,sw,sh)
on exitFrame me
  set mpos to point(the mouseH, the mousev)
  set pointCount to count(myPath)
  set mypos to mypos + 1
  if mypos > pointCount then set mypos to 1
  set the loc of sprite the spritenum of me to ¬
    getat(myPath, mypos)
  if inside(mpos, stagerect) and the mousedown then
    if getat(myPath, pointCount) = mpos then return
    add myPath, mpos
  end if
on getPath me
  return mypath

Drag a bitmap sprite onto the stage, sprite channel 1, and attach this script. Make sure your movie is set to looped playback with an appropriate framescript or in the control panel.

It's a fairly simple behavior which will record drag movements of the mouse on the stage, and the sprite will follow the path continuously. I don't want to go into detail with this script, but the point is that the sprite stores a list of positions - a path - as a property which can be retrieved with the getPath function.

Now here's a handler for a moviescript.

on offset pathlist, pOff
  set pos to 1
  repeat with n in pathlist
    setat pathlist, pos, n+pOff
    set pos to pos + 1
  end repeat

Run your movie, drag around on the stage for a while and then type...

offset getPath(Sprite 1), point(0,50) the message window. You should see the path immediately offset by 50 pixels.

Having urged everybody to go in for serious encapsulation in my previous article, some of you may think I am being "messy" with this example; going over the boundaries of an object in this way is maybe not very polite. Nonetheless, this example shows that an object can export a pointer to one of its fundamental properties. What an external object does with that pointer may affect the object significantly.

If we really want an object to guard its data, it should only export pointers to duplicates of its data.

on getPath me
  return duplicate(mypath)

This prevents any messing around from outside, but don't you think the first example suggests some interesting possibilities? Sometimes, there are software designs which require an object to "bare all" to the outside world in this way. Those are objects which invite the outside world to modify them. A selection in an image-editing program (for example) is just an exported pointer to parts of a bitmap which is passed to whatever filters the user chooses. This is also what makes Photoshop's plug-in architecture possible.

There are no really rigid rules in OO, and having a clear understanding about object boundaries includes knowing the implications when an object has a function which returns a pointer to one of its properties. There's a strong case for clear boundaries, but there's an equally strong case for an object to open itself up from time to time.

Brennan Young is an English freelance multimedia designer / programmer living and working in Copenhagen, Denmark. He started making interactive presentations on Commodore and Acorn computers as a teenager in the early 1980s, but went on to study Fine Art and Art history at Goldsmith's College, London where he discovered Director. He teaches and lectures on multimedia at various institutions around Denmark. When he is not fiddling with interesting authoring software, he composes and performs music, writes theoretical and practical articles, and 'makes art' for exhibitions or private consumption.

Copyright 1997-2019, Director Online. Article content copyright by respective authors.