Home 0 SoundRaider 0 Director 0 Faust 0 Nectarine 9 0 Personal 0
 
 XObjects
 Shockwave Gallery
 Technical Guide for Director Developers
 Director Tips and Tricks
 
 Director Users Group
 DUG Members List
©1996 Andy Wilson.

Download the Technical Guide and all of the Tips and Tricks articles as a Acrobat file

Section One : Aim of the Technical Guide

Section Two : Organising the Project

Section Three : Project Conventions

Section Four : Preparing Media Assets

Section Five : Assembling the Project

Section Six : Optimising Performance


Back to the top

Section One : Aim of the Technical Guide

Why we use a Technical Guide

Whether it takes the form of a screensaver, kiosk, web site or straightforward presentation, a multimedia project involves the organisation of various media types - bitmaps, digital video, text, audio, MIDI - into a single interactive environment. This often means preparing and optimising hundreds of megabytes of different media types to integrate them into the project. In the majority of cases we are using Macromedia Director as our authoring environment.

The fact that a project can be delivered by many different means (such as floppy disk, CD ROM, an intranet or internet, and so on) and to many different delivery platforms and operating systems, means the technical problems in designing and implementing a project can become very complex. Add to this the fact that the technology itself - the software, protocols, specifications, hardware, bandwidth, standards, techniques - changes from day to day, and you begin to sense the scale of the technical issues involved in managing a project successfully.

We must also take into account the fact that members of the production team often have very specialised skills, without an in depth knowledge of other aspects of the total production process yet their work impacts the whole project. Therefore we need to establish a general awareness of these issues across all members of the production team and create working practices to maximise the effectiveness of our work.

The aim of the technical guide is ;

  • To make all members of the team aware of the general technical issues involved in preparing a multimedia project using Director as the authoring environment. This should help everyone to better understand the context in which they are working when they are involved in any particular project.

  • To establish guidelines governing how we organise and control assets within Macromedia Director. Basically this means establishing good general methods when working with multimedia in general and Director in particular.

  • To lay down certain conventions which should be adhered to by all members of the production team at all times.

Aims of Good Project Design and Implementation

Inasmuch as we are talking about technical design, the aims of good design are ; economy, concision, consistency, speed, clarity, scalability, reusability.
  • Economy : we should minimise the effort required to create the assets, avoiding unnecessary repetition (economy of effort). We should minimise the use of resources (disk space and memory, for example) to the extent that is compatible with good interface design (economy of resources).

  • Concision : the conceptual equivalent of economy, the aim is to optimise the structural relations between assets, creating clear relations which allow the project to be easily modified, maintained and understood.

  • Consistency : similar methods, techniques, palettes, layouts, fonts, colour depths, etc., should be used throughout a project where compatible with the design goals and client needs as a whole. A consistent approach to technical issues makes maintenance easier and enhances the design integrity ("look and feel") of the product.

  • Speed : much multimedia work is undermined by a failure to take into account that end users often have lower specification machine than those used by developers. Because the project has not been properly optimised, performance on the users" machine is poor. With a properly managed project there is no reason why it should not be optimised for the best possible performance on the lowest spec machine we can reasonably expect to be authoring for.

  • Clarity : our programming conventions, the way we organise assets, how we archive resources, etc., should all make it as clear as possible what the purpose of a particular file, handler or line of code is within the project as a whole. This makes it easier to maintain and develop a project.

  • Scalability : all aspects of project development should take place with an eye on the possibility of the future expansion of the project to include new assets, updated data, extra modules, etc. If scalability is built into our programming and data management assumptions it is easier to expand the project in the future.

  • Reusability : Where it is compatible with the nature of a particular project, all code written and all assets created should be designed to take into account the possibility that they may be reused in future projects. Why reinvent the wheel or, indeed, the database engine? Obviously, this is an important issue for programmers.

Status of the Technical Guide

All members of the production team should read this guide, make themselves aware of the general issues raised, and attempt to follow the methods described. All members of the team will be required to follow the specific rules and conventions detailed here.

A Note on CD Performance

The advent of CD technology massively increased the amount of data that could be delivered economically to end users, allowing developers to include audio, animation and video files as an integral part of work targeted at a general audience.

However, as Obi Wan Kenobi said, there is a dark side to the force. Because as well as allowing developers to deliver huge amounts of data to the user"s machine, the low bandwidth and slow access time of the CD also limits the rate at which this data can be delivered from that machine to the actual user.

Even with the advent of new four- and eight-speed CD players, the rate at which data can be read from most user"s CD"s is still slow enough for it to form the major bottleneck in most of our work (only the internet is slower, which means that the problem is even greater when authoring for Shockwave).

Many users have a two-speed CD drive, which limits the data access rate to something in the region of 300 Kbs (300 kilobytes per second). A multimedia application which tried to load a 16 bit 640 * 480 image as a background while also trying to start a 16 bit, 22 kHz stereo audio file would run into problems immediately. The audio file would need to be reading in about 88 Kb per second just to keep playing while Director also tried to load up an image around 100 Kb in size, and all the time the CD read head would be skipping back between trying to stream the audio off the disk and trying to read in the bitmap in order to draw the next frame, slowing things down yet further. The likely outcome is that the audio would "stutter" while the program dragged it"s feet trying to load the image.

In this example we haven"t even started talking about playing a QuickTime or MPEG file, which have much higher data rates, and we simply assume that the user isn"t running other programs at the same time, which would degrade performance even further. This is why many multimedia productions delivered on CD perform like a man trying to suck a marble through a straw.

For an application to stand a chance of playing even reasonably well on such a (not at all unusual) machine, we would have to make every effort to see that all the resources used by our program, and the manner of its presentation, had been optimised so they used as little of the machines" time as possible. Only then could we hope to get the user to take our CD seriously as a piece of interactive multimedia, as opposed to an electronic beer mat.

That is why we have a style guide : to make sure that at every stage of a project, from design and specification, through assembling the assets to pressing the gold disk, we understand how our decisions and working practices will affect the performance of our product on a user"s machine. 
Back to the top


Section Two : Organising the Project

Choice of Delivery Platform

Whether we deliver a project for Mac or PC or both is not in itself a technical question. Wherever possible we should create a cross platform version of the project.

Exceptions to the rule occur when we know that the end users have a particular machine. This happens when we create work for kiosks, in which case we can specify the kiosk machine and so determine what the delivery hardware and operating system will be.

Another exception occurs when we need to use a specialised technology which can only be delivered on one platform or where porting it would take a disproportionate amount of effort. For example, we may decide to use an Xtra or Xobject (Director extension) which is only available for Windows. In that case, if Mac users do not make up too significant a proportion of the target audience we will deliver the project as a Windows-only application.

16 bit Windows vs. 32 bit Windows

With Director 5 we are able to target both 16 and 32 bit versions of Windows. In fact it is very simple for us to target both platforms at the same time. We can do this by preparing the bulk of the project as linked Director movies (where each section of the project is a standalone director movie and can therefore be played on either platform without modification - and, indeed, could even be used by the Mac projector if we deliver a hybrid CD ROM). A stub director movie is then created which calls the first section of the main project. This stub can then be compiled twice - once for Windows 3.x and once for Windows 95 and Windows NT. Director 5 ships with a "launcher" utility which automatically detects which version of the operating system is running on the users" machine and automatically launches the appropriate stub. All subsequent movies in the chain are identical for both 16 and 32 bit Windows users.

In this way we can create software which can run on either version of the Windows operating system. Since this method is easy to implement, uses up very little extra disk space (relative to the size of a CD ROM) and is just as easy for the end user to use (they start the same "launcher" application in both cases) there should rarely be any excuse not to give the client the advantage of catering to both flavours of Windows.

We should always use this method unless space dictates otherwise, in which case we should develop for the 16 bit platform.

Cross-Platform Issues

Use of Palettes

When developing a cross platform project in 8 bit depth, the graphics should be prepared using the Windows 8 bit palette (where we are not using custom palettes, of course). Switching between the Windows and Mac system palettes when changing movies causes flashing on many systems. When developing for Shockwave we should always use the 8 bit palette optimised for Netscape. Both of these choices represent de facto industry standards.

Control of Monitor Colour Depth

On the Mac it is possible to reset the color depth of the users" monitor whereas on Windows it is only possible to detect the existing colour depth and issue a warning if it is not appropriate.

This is a significant issue since most graphics will perform relatively slowly if they are being displayed on a monitor with a different colour depth. It is recommended that in the Mac version of a project we reset the monitor depth as appropriate while on the windows side we issue an alert informing the user that the application looks and performs better in the appropriate colour depth.

Audio Issues

Due to it"s origins on the Mac platform, Director seems happiest using AIFF files rather than the Windows-based WAVE format. It is recommended that we use AIFF format files in both Windows and Mac projects.

Another complication with delivering sound under Windows concerns the audio channels. Since the audio capabilities of Wintel machines were never standardised, some older machines can only play one channel of audio. Therefore, although Director has two sound channels in the score, when targeting Windows machines it is worth bearing this limitation in mind. Nevertheless, there will be many cases in which the advantages of being able to use two channels outweighs this consideration, especially since more and more Windows users have newer sound cards capable of playing both channels.

Note also that Windows cannot play either of its sound channels while QuickTime is playing - the system will not mix regular and digital video sound.

Flattening QuickTime

QuickTime movies should always be flattened. That is, they should be saved in Movie Player as "Self-Contained" and "Playable on non-Apple Computers". Only flattened movies will play under Windows (technically, the process involves collapsing the file"s resource fork into it"s data fork, making it compatible with the Windows file system) and, while there is a theoretical degradation of performance on the Mac, in practice this is insignificant.

Because QuickTime is not part of a standard Windows installation and even on Macintoshes the user may have removed QuickTime from their system to save memory, we should always test for the presence of QuickTime (using lingo"s "the QuickTimePresent" command) when an application that uses QuickTime is launched and tell the user to install it if isn"t already present.

Coding Across Platforms

Lingo, the coding language used by Director, is almost completely cross platform compatible. Nevertheless there are some platform specific effects which a cross platform project will have to address.

For example, file paths are described differently across the two platforms. To play a movie under Windows in the relative path ìmyProj\movs\myMovî I might issue the command

go to movie "@\myProj\movs\myMov"

while on the Mac I would say

go to movie "@:myProj\movs\myMov"

In this and similar cases the solution is for the stub movie of the project to detect the platform and set up a global variable called, let"s say gPathSep, appropriately. For example

on startMovie
  -- note that "the machineType" returns
  -- 256 for any wintel machine
  global gPathSep
  set gPathSep = ":"
  if the machineType = 256 then set gPathSep = "\"
end

Whenever a file has to be called you can use this global to make the code cross platform compatible:

global gPathSep
go to movie "@" & gPathSep &
"myProj" & gPathSep & "movs" & gPathSep &
"myMov"

In all cross platform projects there should be a handler in the calling projector which initialises the values of all platform dependent variables, initialises the appropriate Xobjects and carries out any platform specific tasks. In the case above, the only alternative would be to either redetect the machineType value every time a path had to be called - inefficient and slow - or create two versions of the project and hard code in the path values for each platform.This abandons the power of Director as a cross-platform authoring environment and commits the rest of the development team to having to do twice the work to maintain two otherwise identical files.

Choice of Colour Depth

The temptation in many cases is to assume that the greater colour depth used in a project, the better the project will be, with all graphics in "millions of colours" (32 bit colour - that is, 32 bits of colour information for every pixel in the picture) as the best possible option. In fact, in most cases using a lower colour depth will have little impact on the look of the project and will give a significant boost to the speed and responsiveness of the application.

Because of the amount of data that has to be transfered for 32 bit graphics (twice as much as for 16 bit, four times as much as 8 bit, and so on) this colour depth is always going to perform slowly. The same is true to a lesser extent of "thousands of colours" (16 bit colour) but with the added complication that, for technical reasons, this format adds an extra processing overhead when drawing screens (although it is still faster than 32 bit colour). Another consideration is that neither 16 bit nor 32 bit colour images allow their palettes to be controlled from within Director.

In many cases, 256 colours (8 bit colour) is perfectly adequate from a design point of view. Certainly it is far easier to control and manipulate from within Director, performs much faster during screen redraws, and a file saved in this colour depth will be much smaller than the same image stored at a higher colour depth.

Using palette cycling and palette transitions it is possible to achieve some very sophisticated effects in 8 bit colour depth. Also, we can prepare dedicated 256 colour palettes to match our images, giving us very good colour quality even with 8 bits. Put all this together and it becomes clear that we should have a strong bias towards using 8 bit colour, especially when the application is aimed at a general audience and we do not control the specification of the target machine.

For Shockwave we should always use a dedicated 8 bit Netscape palette since performance is unstable at any greater bit depth, and for the moment we can assume that Netscape is the de facto standard for web browsers.

Designing Interface Components

In designing an application"s interface and program flow, after all artistic and interactive design decisions have been made but before actual preparation of the screens begins, we need to make a further analysis of how best to break up the elements of the inteface into logical components.

Pressure of deadlines, etc., has sometimes meant that in the past we have designed the screens for a project and then simply imported each of them into Director, so in moving from one screen to another we are unloading the whole of the old screen and then loading up an entirely new screen to replace it. This is hugely wasteful of system resources and is unacceptable practice.

Instead we should break down each screen into its component parts - background, buttons, icons, logos, etc. - and import these elements rather than importing whole screens. Alternatively we can import a whole screen, copy it and then delete all but the relevant element - useful since it means the element then has the correct registration point relative to the screen.

In the example above this would mean that between the two screens we might use the same background, buttons and icons but simply change some text or a picture. This would mean that the size of the whole project would be reduced since we do not have to store multiple copies of the same background in the cast. Also the program would change screens much more quickly since, for example, it wouldn"t have to load a whole new background but use instead the background already loaded.

This must become standard practice on every project we do.

Building in Time to Optimise

In our project planning we should set aside time at the end of a project, after all assets have been assembled and incorporated into working movies, to optimise the application"s performance, overcoming bottlenecks by unloading and preloading cast members as appropriate.

Building in Time to Debug

We should also set aside time, after optimisation is complete, to thoroughly test and debug the project. Since new code is being added to projects right up to the last moment of the production phase, we cannot just hope that an application will behave as specified or even that it will not crash if we have not had time to test it and fix the bugs that will, inevitably, emerge. We should build in a distinct "Optimisation and Debugging" phase at the end of the project schedule during which no more modifications or additions to the program can be made.

God is in the Details : Finishing the Project

  • All projects should include the "Made with Macromedia" and, where appropriate, the QuickTime logos as required by our user licences.

  • With the agreement of the client, all projects should include a Red Kite New Media logo with contact information and details of the production team on the exit screen.

  • Every project should have an appropriate icon designed for the main projector.

  • Every CD project we prepare targeted at Windows 95 should include an autorun.inf file which loads an icon for the CD and, where appropriate, launches an installer or other application.

  • If a project uses QuickTime, we should include QT installers for the appropriate versions of QT for all targeted platforms (Note : if the project uses the QTVR XObject we will need to ensure that the QT version supplied is compatible with it. Hopefuly this problem will be resolved when Macromedia release their QTVR Xtra).

  • Where possible (depending on the CD authoring software used) the project files should be optimised so that the most used files are moved to the "top" of the CD. Streamed files should also be moved to the top to improve performance.

  • ScanDisk (or Norton DiskDoctor, etc.) should be run over the drive containing the project to ensure there are no file system errors. A file system error in any of the project"s files can create a system crash in the final product.

  • A virus check must be run over all project files immediately before pressing the gold disk.


Back to the top

Section Three : Project Conventions

Filenaming Conventions

If the project is targeted at Windows or is to be delivered on an ISO 9660 format CD, all files in the project itself (as opposed to preparatory work), including all linked files, QuickTime movies, external sound files, etc., should follow the 8.3 naming convention. That is, files should be named using only alphanumeric characters without spaces (ie. you can"t use ¬`"!î£$%^&*()_+-={}[];:@"~#<>,./? TAB or SPACE) should have a maximum eight characters in the first part of the name and should have a three letter extension. Similarly, all directories in the project should be named with a maximum of 8 alphanumeric characters.

Note : our network currently truncates longer filenames to 8.3 format when transfering them between Mac"s and PC"s. When it does this it adds an exclamation to the front of the name. Since Director will happily link to such a renamed file on either platform it is easy to forget that you will need to rename the file again if it is to be put on an ISO 9660 CD. We can end up having to rename the file and then open, relink and save every movie that uses it five minutes before going to pressing. In the worst case the file will be renamed automatically by the CD authoring software. Then the movies that use it will fail to find it when run on the user"s machine, causing error messages.

List of Standard Extensions

When naming files, use the conventional extensions for that file's format. Extensions for files commonly included in our work are :

	DIR - Director movie
	DXR - protected DIR
	MOV - QuickTime / QTVR
	MPG - MPEG format
	FLI / FLC - flic animation
	AVI - avi animation
	JPG - jpeg graphic
	GIF - gif graphic
	PIC - PICT graphic
	PSD - Photoshop graphic
	AIF - aiff sound file
	WAV - wave sound file
	TXT - plain text file
	INI - initialisation file
	RTF - rich text format file
	DOC - word file
	MID - midi file
	HLP - windows help file
	HTM - html file
	HQX - Stuffit compressed file
	SEA - Mac self extracting archive
	ZIP - zip compressed file
	ARJ - arj compressed file
	

Directory Structures During Development

Directory Structures During Development

With several people working on the same project at the same time we often end up with development files scattered across different machines on the network in folders which are difficult to identify. Similarly, files we need often turn out to have been deleted or we end up with large amounts of useless data sitting on drives because no one knows whether they are still needed for a project.

We should use a directory structure during development which makes it easy to identify all files connected with the project and we should build it in one central location, namely the main server on the multimedia group network. The basic directory structure should be built right at the outset of the project before we even begin collecting and building assets and resources. The correct method of working would be to move (as opposed to copy) a file onto a local hard drive then move it back up to the server when finished. This way we avoid the possibility that two people will be working on different versions of a file.

Although the exact directory structure of any project will be peculiar to it, the figure below shows what should be a typical structure for a large project.

Directory Structures in the Project

The directory structure of the project, as it is to be delivered, should reflect the basic organisation of the program and data.

  • The main projector should sit in the root directory of the CD. Linked movies should sit in their own subdirectories, grouped by section where necessary.

  • External cast libraries should be placed in a directory in the root of the CD.

  • Linked files should be grouped into directories by data type (sounds, digital video, graphics, etc.). These directories should be in the root of the CD.

  • Tools and similar resources should be placed in their own directories in the CD root.



Back to the top

Section Four : Preparing Media Assets

Graphics

At the moment graphics tend to be prepared in Photoshop in thousands or millions of colours then dithered down to the appropriate colour depth when they are imported into Director. This is not an efficient way of preparing graphics. Instead, graphics should be prepared in millions of colours and then either dithered down to a prepared or custom palette in Photoshop or dithered using Debabeliser when we want to create graphics with a shared custom palette.

Audio

Audio files can be very resource intensive, taking up disk space and hogging memory. As discussed earlier, it is important that we use audio with the lowest sampling rate and resolution compatible with the delivery medium and the nature of the audio.

To give an example, the size of any sound file can be calculated by the formula

size (Kb) = length (sec) * (resolution / 8) *
  sample rate (Khz) * channels

So ten seconds of 44 Khz 16 bit stereo audio should be about 1760 Kb, while the same audio sampled in mono at 22 Khz with a resolution of 8 bits would be only 220 Kb, and so would take up an eighth of the disk space, load in an eighth of the time (or less) and would be processed eight times more quickly.

It is difficult to imagine any circumstances in which we would use 44kHz sampled audio. We should use 8 or 16 bit audio sampled at 22kHz or, where sound quality is not crucial, 11kHz.

In certain circumstances it may be worth preparing audio as IMA 4 compressed, audio-only QuickTime, as this gives both very high quality and very efficient compression. One project I worked on used 2000 audio files and was to be delivered on four CD"s in a caddy. Using IMA 4 QuickTime files we were able to put the whole project onto a single CD without a noticeable drop in quality.

Digital Video

QuickTime video is extremely resource hungry and we should do everything possible to drop down the data rate of QT files as far as possible. For QuickTime on a CD we should prepare the movie at a maximum of 15 f.p.s, and a maximum data rate of 200 Kbs (though it is better to aim for around 150 Kb), with keyframes every 5 frames. For a CD based project the maximum window size for the movie should be 320 * 240.

Which compression codec we use depends on the nature of the material to be compressed, whether the user will be playing the video from a hard drive or CD-ROM, and the processing power of the user"s machine. Basically, the Animation Codec gives the best quality video, but produces very large files. We should use Animation compression when we are preparing video for a kiosk, since the video will be played from the hard drive and we can therefore handle the high data rates that Animation compression requires. For CD-ROM based work we will almost always use Cinepak compression which produces fairly good quality results in a file about half the size of an Animation compressed file.

QuickTime VR

Most of the above applies also to QTVR with the addition that object movies can have a window size of up to 400 * 300, and panoramic movies of up to 450 * 320, though we should usually aim for something between 320 * 240 and 400 * 300. 
Back to the top


Section Five : Assembling the Project

Introduction to Director

Director is the premier authoring tool for the kind of multimedia work we are engaged in. Approximately half of all multimedia CD"s in the world today were built using it. Director is cross platform, supports an extremely wide range of formats and data types, is based on a metaphor which is intuitively easy to understand, embodies a scripting language which gives the user incredible control of the environment and has a programming interface which allows it to be extended almost indefinitely. Also, even though the metaphor it is based on (of stage and casts) is essentially linear, Director not only allows you to build totally object orientated projects but is itself fundamentally object orientated. All this makes it an extremely powerful production tool.

From a production point of view, however, Director has one major flaw - it is far too forgiving of bad design and bad programming. Almost anybody can throw huge amounts of bloated data into Director, not bother to organise it properly and still the compiled application will run. Of course, it will run like a dog with it"s back legs tied together, but hey, ìit worksî.

While this situation is excellent from one point of view - it means that learners can build their first multimedia project very quickly using Director, without any deep knowledge of either multimedia in general or Director itself - for a professional multimedia team it is a real problem. Comparing Director to many other authoring tools is like comparing a hawk to a chicken - a hawk can soar much higher than any chicken can fly. Unfortunately, a hawk can also flap along quite happily with the rest of the chickens. Ultimately, Director is only as good as the people who use it and we must learn to overcome the generosity of the Director environment to make sure our work flies more often than it flaps.

Design of a Director Project - Scalability and Encapsulation

We have already discussed the need to build scalability into the project design. What we are discussing now is the way we apply the same principles when implementing the project. In the first place it means building it in such a way that it is possible to plug in new modules fairly painlessly. The key to this is to organise the functionality of a project so that it"s elements remain logically and operationally discrete, so that it can then be called not only from existing parts of the work but from new sections that may be added later.

Imagine we have a project whose opening screen consists of a menu which then points to two large, distinct subsections. The obvious way to implement would be to make the movie holding the main menu initialise the whole project, launch any child objects as necessary. Then each subsection should be made self-contained so that the main menu can call either of them with a single line of lingo, eg.

initSection "Section1"

where "initSection" is a handler which performs the appropriate initialisation to launch one of the project"s subsections. Doing this, it would be possible to add further sections in the furture which are self-contained and simply "plug in" to the existing project.

The same logic should be followed at every level of the project - so each section of the project is divided into subsections. Of course, the real art here lies not in announcing to the world that we should do this but in deciding in the context of a particular project which parts need to be separated out as self-contained elements and which do not. It would be easy to make every bit of a project a stand-alone unit even where it was not strictly necessary but that would create extra work to no purpose and make the structure of the project too confusing.

The key to making these decisions lies in the idea of "encapsulation". This requires that each project module encapsulates a piece of the program"s functionality which can then be shared between different parts of the program. The limit to the endless proliferation of project elements is that, wherever possible, a discrete part of the program"s functionality be embodied in a single object (which may mean a single Child object, a single handler, a single movie, or a single resource). Encapsulation will be discussed further below.

Organisation of a Director Project

linked vs. imported graphics

In the past we have assumed that externally linked assets make it easier to build a project. For example, in the case of graphics we have built projects which contain hundreds of externally linked PICT files. The argument for this is that it enables the files to be more easily edited. The external file can be opened up in Photoshop and edited from there, and the edits will be reflected within the Director movie without us ever having to open Director itself.

In practice, however, we very rarely rely on this ability. Instead, graphics are prepared in Photoshop and then brought over into Director. Any subsequent modifications tend to consist in trimming the file and adjusting its registration points, etc., all of which can be done more easily in Director"s paint window, in which case we may as well bring the graphics into a Director cast library rather than linking to them.

There are other reasons for preferring to import graphics rather than link to them.

  • It is useful to think of Director"s cast libraries as being a way of organising resources as if in a database. It is less confusing if all the graphics at a particular stage of development of a project are kept in one cast library which can then be archived either as part of a Director movie or as a stand-alone external cast library. In practice, using linked graphics in large projects tends to get very confusing.

  • Modifications made to an imported graphic are made to the graphic only and not to the original file. This means that any mistakes in editing can be got around by reverting to the original file, which will remain on the server in a development folder even if it is not linked into the project.

  • In general, external link files tend to load more slowly than internal casts so we should get better performance results by importing the files.

For these reasons we should use imported rather than linked graphics.

multiple movies, multiple cast libraries

We use multiple movies (rather than stuffing a whole project into one fat projector) in order to ensure scalability, clarity and reusability. The danger is that we then needlessly proliferate our assets by making more and more copies of them for each new movie.

The idea of encapsulation can be extended to cover a project"s assets. If a particular asset is used across different modules it should be kept separate from each and linked into them ("encapsulating" the resource in one place). For example, if the same buttons are used across a whole project they should be kept in an external "Button" cast library which is then used by the movies that need those buttons. An obvious advantage of this is that we only have to edit this resource once to make changes throughout the whole project.Thissaves time and enforces consistency across a project.

cast scripts vs. sprite scripts

Director is a strongly object orientated system which means it is capable of being used to enforce encapsulation, scalability and many other aspects of good design. It is up to us to use this functionality. One aspect of this is that we should attatch scripts to cast members as member scripts only when we want the functionality of that cast member to be the same wherever it is used. If the functionality is to change depending on context we should not attach the script to the cast member but assign it to a sprite in the score. More accurately, any functionality that is context independant should be in the cast member script. Any that is context dependant should be in a sprite script. In this way, eg., a mouse up event is processed by the sprite script first to carry out context dependant tasks and then passed down to the cast member script to carry out general tasks.

For example, if we have an "up" button which takes the user to different places depending on the context, we should not have multiple copies of the button cast member each with different cast member scripts. Instead, encapsulation requires that we use the same bitmap in every place where we want the buttons to look identical but we attach different sprite scripts depending on context.

Programming Conventions

naming conventions

It is useful if everyone writing code in a project follow some elementary naming conventions to help keep the code as comprehensible as possible.

  • Loop variables (within a "repeat with .. in .." or "repeat with .. = .. to ..") can be given a single letter name (usually "x", "y", "z")

  • Variables used to hold a value temporarily (within the scope of one handler) should be named to indicate this, eg., "stringTemp".

  • Apart from these cases, all variables should be given a name which describes their function. I once worked with someone who liked to call variables "bobo" or "dodo", which made his code almost incomprehensible. Variables should be called, eg., tmpString, numberOfItems, and so on

  • Global variable names should be prefixed with a "g" so that it is immediately clear anywhere in the program whether a variable is a global or a constant. Eg., gCastMember, gStartTime, etc.

functional organisation of code

It is important to organise code in a logical way. So all handlers relating to controlling a database should be kept together in their own script text and not mixed in with other handlers. This makes it easier to follow the execution of code and also, by breaking the code down into smaller sections, makes lingo execute more quickly.

commenting code

Code should be commented to make it comprehensible to anyone who is likely to have to support that code in the future. There is no need to comment and explain every line of code written but at least the purpose of handlers should be explained as should any unusual techniques used, or assumptions made by the programmer.

documenting code

Where we are producing Xobjects or objects that are to be used across a project, these should be clearly documented and an API specification produced so that others can easily call on the object in their own code.

Programming Methodologies

code encapsulation

Wherever practical, code functionality should be encapsulated. On the largest scale this means that when we write a handler that performs a specific function the same copy of the handler should be called right across the project.

For example, if we use a handler to control the display of QuickTime, rather than cut and paste this handler into every movie where we would like to use it we should either put the handler into a cast library that is shared by all the movies that need it or create a global object which encapsulates that code.

To see why this is important, imagine that we want to change the way we control QuickTime, perhaps some amazing new QuickTime Xtra is released which we want to use, or perhaps we want to simply alter one line of code to make the QuickTime movie display better. If we have organised our code properly we can simply open one script text and edited it to incorporate the new functionality into our code. The changes made will be reflected consistently right across the project. The alternative is that we have to open up every movie and repaste all the changes or even modify the code by hand.

object orientation (parent-child scripting)

Object Orientated programming techniques are much talked about but hardly ever implemented. They are, however, very powerful and we should use them wherever appropriate. Basically, parent-child scripting allows us to create objects as global variables which embody a common functionality. This functionality is then available immediately to all the movies in a project.

redundant and verbose code

As a project progresses all redundant code should be stripped from it. This includes multiple copies of handlers, any code which has been commented out and any debugging code. At the same time, we should make sure code is as concise as possible. To give an example, I reproduce below some code which I found in a project we did for a major client:

...
global showMe
global hx
global vx
put vx & "embeded mouseV"
put "started embed"
put the mouseV && "the mouseV"
puppetSprite 2,1
global l	
global t
global r
global b
set h = (hx + the stageLeft) - l
-- put the mouseH
-- put "h" && h
set v = (vx + the stageTop) - t
-- put the mouseV
-- put "v" && v
if not h or not v or h > r or v > b then exit
set h = integer (h * 2)
set v = integer (v * 2)
set the drawRect of window "win1" = ¬
  (rect (0,0,752,502) - rect (h,v,h,v))
put the mouseH
if showMe = 2 then
    set the castNum of sprite 2 to 9
else
    set the castNum of sprite 2 to 8
end if
go to the frame
put "ended embed"
...

Here is what it should look like with all redundancies removed:

...
global showMe,hx,vx,l,t,r,b
puppetSprite 2, TRUE
set h = (hx + the stageLeft) - l
set v = (vx the stageTop) - t
if not h or not v or h > r or v > b then exit
set h = integer (h * 2)
set v = integer (v * 2)
set the drawRect of window "win1" = ¬
  (rect (0,0,752,502) - rect (h,v,h,v))
set the castNum of sprite 2 = 8 + (showMe = 2)
go to the frame
...

The code below is easier to understand and will execute much more quickly.

calling external movies

During development we are invariably using *.DIR movies but before delivering the project all of these should have been turned into protected, *.DXR movies. Therefore, when calling in a movie we should not specify the extension, for example, by writing

play movie "myMovie.dir"

but instead should say

play movie "myMovie"

The program will then call in either the DIR or DXR, as appropriate, so that during development it calls in the DIR

while in the final version it launches the protected movie. This saves us having to rewrite any code and means we can test protected movies at any time during development without having to consider the code.

relative addressing

When calling other movies or external files we should always use relative addressing. Absolute addressing means that we use the full path name to the external file, for example:

go to movie¬
  "c:\worktop\newProj\section1\sMovie1"

Using this method of addressing means that when the project is installed on the user"s machine the file ìsmovie1î will have to be in precisely the place specified in this line of code, otherwise the user will receive an error message. There is no reason why we should not allow the user to place our project anywhere they like (as long as they maintain the relative relations between files). For example, why shouldn"t the user be able to move the whole project into a directory called ìmultimediaî ? In my own case, my home machine has three drives and I like to keep drive C: for system files. Why should we force people to install to a particular drive?

As a matter of course we should always use relative addressing. For example, if the calling file in this case was in the directory "c:\worktop\newProj" and was called orgMovie, we could call the same file using

go to movie "@\section1\sMovie1"

and then return to the calling movie using

go to movie "@\\orgMovie"

(assuming we don"t use the "play movie ..." / "play done" method). As long as we maintain the original directory structure, the root of the structure can now be moved to another drive or directory at any time.

formal efficiency vs. real efficiency

While we should make every attempt to make code as concise as possible, it is important not to confuse formal efficiency with real efficiency. For example, if we have some code:

...
set numLoops = count (myList)
repeat with x = 1 to numLoops
  put getAt (myList, x)
end repeat
...

It may seem more efficient to use

...
repeat with x = 1 to count (myList)
  put getAt (myList, x)
end repeat
...

since this is logically more elegant. However, this is only apparently more efficient since it means that Director has to recount the list every time it goes around the loop (and if there were thousands of items in the list this would be very inefficient indeed). This brings out the difference between formal (logical) efficiency and real efficiency, which takes into account how the Lingo interpreter actually works. The original method, which counted the list only once and held the result in a local variable is the more efficient.

I used this example to illustrate a general principle about how to optimise code so I should point out that there is an easier way of rewriting this example in Lingo, namely

...
repeat with x in myList
  put x
end repeat
...
Back to the top

Section Six : Optimising Performance

      "Speed provides the one genuinely modern pleasure"

      Aldous Huxley

Introduction

The following points simply indicate techniques and methods we can apply throughout the production process to really wring the last ounce of performance out of an application.

Optimising during design

These are specific points to be borne in mind in addition to the more general questions dealt with earlier.

animation and digital video

Keep on-screen animation to an absolute minimum whenever digital video is playing as the combination of the two can really exhaust a system.

streamed media

Wherever possible, keep the number of open, streamed files to a minimum as they too can really stretch system resources. This doesn"t mean that we never have several such files running together, just that we should be aware of the extent that we are pushing the system at any time.

Optimising during development

These techniques should be applied throughout the course of a project.

reducing colour depths

Although we may have decided that a project should work in a certain colour depth, often it is possible to reduce the colour depth of particular graphics much further. For example, we may have a coloured line drawing or cartoon in 8 bit colour but which actually uses only one of the palette"s colours. In that case we can use the "Transform Bitmap" option in Director"s "Modify" menu to dither the colour down to 1 bit (if the graphic is not black, convert it to black before doing this then, after converting it, select the graphic in the score and use the Tool Palette to change back to the original colour). The graphic will then be one eighth the size and will load eight times faster.

In some cases it may even be worth turning an 8 bit or higher image into several 1 bit images. For example, if the original image is 8 bit but only uses two colours, then it is still worth turning this into two overlaid 1 bit images, with the saving in bit depth more than making up for the doubling in the total size of the images.

editing cast members

All graphic cast members should be edited down to the size of the minimum bounding box of the significant area of the graphic. That is, if a graphic shows a logo cropped from against a background image and is going to be placed over the raw background itself, then as much of the background as possible should be cropped from the logo.

Similarly, an irregularly shaped graphic can often be split into several much smaller rectangles whose total area is far less than that of the original image. This can be done very easily. Say that we want to split an irregularly shaped graphic into three to save space. Simply make two more copies of the original graphic in the cast (hilight the cast member and press CTRL-D twice) then cut and paste the sprite corresponding to the image on top of itself twice in the score. Next, edit each of the three cast members to split the image into three component parts, then select each member along with each of the three sprites in turn and press CTRL-E to perform a cast member substitution. Each of the three parts of the image will now be perfectly aligned on the stage.

A good example of when this technique comes in useful is when we use a rectangular frame around some part of the stage. This can very easily be split into four parts (top, bottom, left and right frames) which together are far smaller than the original graphic.

removing redundant asts

It is imperative that all redundant cast members should be removed from a project when they are no longer needed. If this is not done at the time they become redundant the cast libraries end up peppered with members which no longer need to be there. At the end of the project it is often too late to remember which members are no longer needed (even using CTRL-; and asking for a list of members not used in the score will not tell you which of these are puppeted onto the stage).

using tiles

Patterned backgrounds can often be replaced with tiles, saving a great deal of space. Although we do not use such simple patterns very often, this is actually a very effective way of producing backgrounds. It is especially recommended in Shockwave movies where size is at an even greater premium.

using inks

When Director is redrawing a frame (every time it goes to the frame, or when an updateStage command is issued), the use of certain inks makes the whole redraw process much slower. Copy ink is fastest, with Matte and Background Transparent being slower, and Blend is extremely slow. Obviously there are some trade-offs to be made here.

A good example of where we can increase performance is when we have a large graphic which we have made Matte because we trimmed part of the background away leaving it as an irregular shape (and so if it was Copy there would be unwanted white space on stage). It is much better to leave the graphic as a rectangle and use the Copy ink, since the graphic is stored as a rectangular image anyway, so trimming irregular shapes from it doesn"t decrease the size (only cutting down the area of the bounding box reduces the actual size). The combination of a rectangular shaped graphic and Copy ink is the same size on the disk and is much quicker to draw than an irregularly shaped graphic with Matte ink.

stretched sprites

Stretched sprites also take far more time to process than sprites set to the actual size of the cast member. Depending on circumstances, we may get better performance by using the "Auto Distort" tools in the Xtras menu to create a series of intermediate sized bitmaps which can be preloaded and then used to create the same effect as stretching. To make a sprite the same size as its cast member select the sprite properties and click "Revert".

digital video

QuickTime (which is generally what we are talking about in a project when we say "digital video") is always played "direct to stage" in Director for Windows. On the Mac, however, it can have sprites placed on top of it. Because QuickTime plays much faster when it is projected direct to the screen, unless we need to have sprites above the QuickTime sprite we should make sure that the QuickTime member is set to display "Direct to Stage". This can be done by changing the properties of the member (either right click on the cast member - oh, I forgot, you are using a Mac mouse - OK, try highlighting the member and then either clicking on the Information icon at the top of the cast window or pressing CTRL-I and selecting "Direct to Stage").

Digital video plays much slower when stretched. Make sure that all digital video sprites are set to the actual size of the videos or, if this really isn"t possible, select the properties of the member again and set it to crop the picture rather than stretch it.

importing audio

Where the playing of audio is causing a performance problem it is worth remembering that linked audio loads more slowly than imported audio. Therefore, it is worth considering importing the sound into a cast library. If the sound is used by several movies then you can import it into an external library and use it in all movies that need it (despite being in an external library, the sound will still load better than if it is played as a linked file).

using variables

It is not unknown for people to write data into a text field then read it back later down the line rather than use a global variable or pass the value as a parameter to another handler. This is an absurdly slow way of handling data (Lingo handles text more slowly than any other data type anyway, and when it has to read and write to a field as well the performance drops right down). Always use variables in memory (global or local, as appropriate) rather than writing to fields.

cast reference by index and by name

If you are going to repeatedly refer to a particular cast member, refer to it by number (called "reference by index") rather than by name. If you refer to a member by name Director has to trawl through all it"s casts looking for it. It is much more efficient to set up a global variable which you can then refer to in your handlers. For example:

...
on startMovie
  global gMPEGMem
  set gMPEGMem = member "My MPEG Movie" of ¬
    castLib "MPEGFiles"
...

and then later you can say, eg.

...
global gMPEGMem
set the file of gMPEGMem = ¬
  "@\mpeg\newScene.mpg"
...

(this code relies on functions made available by the MPEG Xtra). Whether it is worth doing this depends on how often a particular cast member is going to be referred to in the course of running a program. If it is only referred to once, then the method I have outlined actually wastes a little (though practically negligible) bit of time since the movie is looked up by name once in this method anyway, plus you have the slight overhead of reading the global when you finally come to address the member. However, if a cast member is going to be referred to repeatedly in the course of a program it is worth initialising it"s address in this way.

If you need to refer to a large number of cast members like this it may be worth setting up a property list global instead with the name of the members you want to index used as property names, and the index references of the members as the values.

clearing global variables

To free up memory resources it is good practice to clear any global variables by resetting them to 0 or EMPTY when you have finished using them. For debugging reasons, it is also a good idea to include the command clearGlobals in the stopmovie handler to make sure that your globals are being initialised properly when you run the movie.

opening and closing objects

Leaving a movie does not kill any global objects created by that movie - that is part of the power of parent-child scripting ; you can create an object in one movie which is available to any other movie when it is opened. Make sure, then, that if you have finished with an object you kill it by setting the global that refers to it to 0 or EMPTY. Eg.

...
set gMyObject = 0
-- kills the objecty by removing
-- the reference to it
...

This releases the system resources used by the object (which can be quite considerable with some objects).

using updateStage

It is usual during development to end up with redundant updateStage messages littering the code. This is because it is easy to keep inserting the command into the code just to make sure that all the changes you have programmed are reflected on stage. However, updateStage is an extremely resource-hungry command, since it forces Director to redraw the whole of the stage whether it needs to do so or not.

Therefore it is important that every single updateStage command is justified and that any superfluous calls to it are removed.

Optimising before delivery

compacting movies

Every movie in a project should be protected, turning it from a *.DIR into a *.DXR.
  • Protecting automatically compacts the movie file, making it smaller and quicker to load.

  • Protecting then saves yet more space by stripping out cast member icons and Lingo scripts.

  • An unprotected movie can be opened by anyone with a copy of Director who can then use any of the assets (some of which may be sensitive) or any of the code we have developed.

To protect a movie select "Xtras", then "Update Movies", then select "Protect" and "Backup Into Folder".

remove debugging statements

Debugging statements slow down performance of your code, especially those which put a value into the watch window. Remove all debugging statements before final shipping.

memory management strategies

It is possible to carefully manage the way Director loads and unloads cast members from memory using the Lingo commands idleLoad, preLoad, unLoad, preLoadMember, unLoadMember, preLoadMovie and unLoadMovie, and or by setting the properties of cast libraries or individual cast members either via menus or dynamically, setting the properties the preLoadMember using Lingo.

During the Optimisation phase of a project we should run every movie in a project and work out how we can use memory management to overcome any performance bottlenecks. For example, if a particular frame is very slow to load, we may be able to preload it while the user is looking at the previous screen, using

preLoad "nextFrame"

where "nextFrame" is the marker of the slow frame. This will load the cast members in all the frames between the current frame and the target frame. To load just the target frame, use

preLoad "nextFrame", "nextFrame"

You could preload an animated scene by putting markers on the first and last frame of the sequence and preloading them using this command

Individual cast members can be preloaded using, eg.

preLoad "firstFrame", "lastFrame"
Individual cast members can be preloaded using, eg.,
preLoadMember member "slowMember" of ¬
  castLib "Internal"

Even if we cannot optimise the whole project completely we can at least get rid of the worst bottlenecks using these techniques. 
Back to the top


Section Seven : Conclusions

As is inevitable in an exercise of this kind conventions and methods which seem straightforward on paper turn out to be harder to apply in the real world. Real world applications often require that, for good reasons, some of the usual rules should be ignored. Once again, in concrete situations some of these guidelines will conflict.

George Orwell once wrote an essay on good grammar and writing style but finished by telling the reader to "break any of these rules sooner than do anything barbarous". The same applies with multimedia - the guide lays down some conventions which we should always use but the general methods and heuristics it describes can help us address our production problems only if they are used creatively. In other words, ignore any of the rules laid down here rather than do something barbarous.

Still, the main reason many of the techniques here will sometimes be ignored will inevitably be because of the pressure of deadlines. Of course we always want to keep the client happy, which can mean making all sorts of last minute modifications to a project, and sometimes we are still building core elements of the program at the last minute because we miscalculated how long the project would take. However, we should remember;

  • First, although it is always difficult to predict just how long a project will take to implement (often it takes half as long or twice as long as planned) our only weapon against this is better project planning.

  • Second, every time we cobble together part of a project without building it properly we are not really doing the client any favours - the new work will not be optimised properly, it may not work as specified, it may interfere with the behaviour of the rest of the program, the program will be harder to maintain in the future, future expansion will take longer than if it had been built properly and so on. These are all excellent reasons to resist the temptation to build sloppily in the first place.

Finally, I"d like to point out in advance that the following excuses will not be accepted under any circumstances;

  • I"ve always done it this way
  • It doesn"t really matter
  • I didn"t have time to do it properly
  • This way is easier
  • What Design Guide ?
  • God told me to do it

Andy Wilson
1996

 
There are currently users connected. You have viewed 1 pages. Unless otherwise stated, all content is ©1996-2003 Andy Wilson. If you have any questions or suggestions you can mail me: andyw at dircon dot co dot uk. This site is hosted by LShift Ltd.