|
©1996 Andy Wilson.
Download the Technical Guide and all of the Tips and Tricks articles as a Acrobat file
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.
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
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
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
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.
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.
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.
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.
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.
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.
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
|