Undocumented Lingo

From Director Online Wiki
Jump to: navigation, search

Contents

3D

generateOutlines() - font outlines from font members

With the undocumented method generateOutlines() you can create a vertex list from any given string using an imported font. This could be used in a vector member e.g.

  • First we import the desired font into the cast.
  • Now we call the font member method generateOutlines() with a string and get the vertex list:
-- Lingo-Syntax
myVertexList = member("myFont").generateOutlines("Hello World")

Attention! The string provided to generateOutlines() must be a valid string with characters (not just spaces). Otherwise you'll get a script error! Note: vector shapes suffer from a maximum size of 2798.0499px width and height, and using generateOutlines() produces large vector shapes, thus the size of the string passed to it is very limited... however, you can do this:

-- Lingo-Syntax
myVertexList = member("myFont").generateOutlines("Hello World")
myVertexList = myVertexList / 2
-- divide the [#newCurve] item by 2
newCurve = [#newCurve] / 2
-- anywhere a [#newCurve] item is found in the vertexList, which in this case
-- has been converted to [733] because of the division by 2, we change it back
 
repeat while true
newCurveItem = myVertexList.getOne(newCurve)
if newCurveItem = 0 then exit repeat
myVertexList[newCurveItem] = [#newCurve]
end repeat

#extruder property of a vector shape cast member

It is possible to extrude vector shapes with the extrude3d command. But you have to build an extruder resource from a normal textmember, before you are able to apply the vertexList from the vector shape.

- create a text cast member

textMember = new(#text)

- initialize the member with any string

textMember.text = "a"

- extrude the text member's string into a 3D cast member

extruderResource = textMember.extrude3d(member("3D"))

- grab vertex list of vector shape cast member

tList = member("vector shape").vertexList

- update model resource

extruderResource.vertexList = tList

Now use that model resource as desired.

newTexture

newTexture() accepts an additional list like the one for copypixels(). Very useful for creating matte or transparent textures from image objects with no alpha color.

im=the stage.image
wrld=member("3d")
txtr=wrld.newTexture("MyNewTexture", #fromImageObject, im, [#bgcolor:rgb(255,255,255), #ink:36])
-- Note: see the entry on copypixels for the exact syntax/options of the list
-- this example is just from the top of my head

member.userdata

Allows to store a list object with a 3D castmember which is persistent.

property pSprite
property pMember
 
on beginSprite me
  pSprite = sprite(me.spriteNum)
  pMember = pSprite.member
 
  -- create a property list to be stored in userData
  myPropList = [#name:"bla",#data1:1,#data2:2,#data3:3]
  -- create member's userData and add the above property list
  pMember.userData = myPropList
  -- create reference to existing userData property
  ud = pMember.userData
  -- add an item to the userData list
  ud.addProp(#age,22)
  -- change a property's value
  ud.setProp(#name,"blubb")
 
  -- check
  put pMember.userData
end
----------------------------------------------------------------------
-- SAVE the movie, close Director, restart Director, reopen your movie
-- Make sure, you've removed the above sprite behavior before playing the movie!
----------------------------------------------------------------------
put member(my3dWorld).userdata

No script objects, nor image objects can be saved though. Just static data. Can be very helpful nevertheless.

supersample filters for antialiasing in Shockwave3D

You can set the sampling mode for anti-aliasing with Lingo. This only works in #software rendering mode! Here is the list of available modes:

#superSample4x
#superSample4xSoft
#superSample9x
#superSample9xSoft
#superSample16x
#superSample16xSoft
 
Usage:
sprite(1).antialiasingmode=#superSample4x

4, 9, 16 refer to the number of samples per pixel (2x2, 3x3, 4x4). The "soft" modes use a 4x4, 5x5, and 6x6 tent filter to provide a larger sampling area for blending the color samples. The non-soft modes simply average the color samples. This still works apparently as of Director 11. Great for doing hi-res 3D captures.

Interface of a 3D cast member

Usefull for xtras developpers, you may want to access the different interface of a 3D cast member.

For more information, see Director XDK, "Tips, Guidelines and Gotchas", end of page, "Getting the interface of an Xtra Asset for a cast Member".

There is 3 undocumented method:

member("3D").getMoaInterface() -- same as: member("3D").interface
member("3D").getAssetCallback()
member("3D").get3DCastMember()

Reference to a meshDeform modifier

Not an Undocumented method/property, but a little-tip to obtain direct access to "genDeform" modifier.

myModel.addModifier(#meshDeform)
 
-- When you apply meshdeform modifier, you retrieve data like this:
myModel.meshDeform.mesh[i].vertexlist[j]
-- You could, also do it like this:
t_genDeform = (myModel.meshDeform.list)[1]
t_genDeform.mesh[i].vertexlist[j]

Multiple texture coordinates for a newMesh()

When you create a newMesh(), you could apply multiple texture coordinates.

myModelResource = my3DMember.newMesh( sResourceName, nFacesCount, nVerticesCount, nNormalsCount, nColorsCount, nCoordsCount, nLayersCount )
myModelResource.vertexList = myVerticesList
myModelResource.normalList = myNormalsList
myModelResource.colorList  = myColorsList
--
repeat with i = 1 to nLayersCount
  myModelResource.textureLayer[i].textureCoordinates = myCoordsPropList[i]
end repeat
--
repeat with i = 1 to nFacesCount
  myModelResource.face[i].vertices = myVerticesFaceList[i]
  myModelResource.face[i].normals  = myNormalsFaceList[i]
  myModelResource.face[i].colors   = myColorsFaceList[i]
  repeat with j = 1 to nLayersCount
    -- we must pass "j" to the textureCoordinates, (see Director XDK, "AccessPropRef" IMoaMmXValue Interface)
    myModelResource.face[i].textureLayer[j].textureCoordinates[j] = myCoordsFaceList[i]
  end repeat
end repeat

Shader.elasticity

by default to 0.5

According to Intel:

"- This property retrieves/assigns an elasticity value. This is a single floating-point value. It has a range of 0.0f - 1.0f, where 0.0 represents extremely low elasticity and 1.0f represents high elasticity. Elasticity is a physics property that will apply to any object which uses this material. A low elasticity value will cause the object to dissipate energy during collisions with other objects. A high elasticity value will cause to preserve energy during collisions with other objects. a good analogy would be to compare a clay ball (low elasticity) to a billiard ball (high elasticity)." source W3D SDK:"IFXMaterialResource"

Particle Resource

3 undocumented properties for particle resource:

myParticleResource.upVector    = vector(0,1,0) -- vector  expected
myParticleResource.useUpVector = TRUE          -- boolean expected
myParticleRecource.faceCamera  = FALSE         -- boolean expected

Get/Set getRendererServices().pixelAspectRatio

You can distort the image of the 3D viewport. Everything below 1 means a wider aspect ratio, anything bigger means a taller aspect ratio

-- get pixelAspectRatio
put getRendererServices().pixelAspectRatio
-- 1.000
 
-- set pixelAspectRatio
getRendererServices().pixelAspectRatio = .85

Two Other Toon Modifiers

The toon modifier allows non-photorealistic rendering like in a cartoon.  It is used on a per model basis. There are two additional undocumented toon modifiers, #toon1 and #toon2. These combine the normal toon rendering with either an newsprint or engraver shader. This is achieved by chaining multiple shaders together. The toon shader, for instance, is a combination of an inker and a or multiple standard shader. #toon1 and #toon2 just use newsprint or engraver shader instead of the standard one.

member("3d").model("yourModel").addModifier(#toon1)
-- or
member("3d").model("yourModel").addModifier(#toon2)

Credit goes to Ulla Gusenbauer for discovering them independently from Tom Higgins (former Director team member) who revealed their existence in an article on a now-defunct site.

.fileSaveMode

This is an undocumented property of 3D members. Its default value is #saveOriginal, which means that any Lingo changes to the 3D models in a member will not be saved in the member permanently. However, if you use #saveMarked, then any models that are cloned will also be saved in the member. If you use #saveScene setting, then changes to existing models will be saved, but not new models created. If you use #saveAll, then all changes to the models will be saved.

 
sprite(1).member.fileSaveMode = #saveAll


.primitiveOrientation

When you create a primitive in Shockwave3D, the default orientation for the model is #NegZForwardYUp, meaning that the primitive is pointing away from the default cam in a freshly created Shockwave3d world. When you create a Shockwave3D world programmatically, you are looking down the negative Z-axis, and the Y-axis is up.

The default camera is set up at vector (0,0,250), looking at the origin of the world:

mem = new(#shockwave3d)
put mem.camera(1).transform.position
-- vector( 0.0000, 0.0000, 250.0000 )

This actually causes a problem when you create a default plane primitive for instance, as the plane´s surface normals will be pointing away from the camera and thus cannot be seen (remember backface culling). You will have to rotate it around 180 degrees around the Y-axis in order to see it or to create a plane primitive with double sided geometry. In order to change this, several other symbols were implemented:

  • #DefaultOrientation
  • #NegZForwardYUp
  • #ZForwardYUp
  • #PreRelease

These symbols change the default orientation of new models which are created by Lingo. This is not a problem for box, sphere and particle primitives, and just a minor issue for cylinders. It does however apply to plane primitives for reasons explained above.

member("your3DWorld").primitiveOrientation=#ZForwardYUp

Any subsequently created model will now be created pointing down the Z-axis and the Y-axis up. This means that a newly created plane primitive will be facing the camera and thus can be seen right away.

Audio

#rateShift property of sound playback

Change the playback speed of your sound with the undocumented #rateShift property in the queue() method.

-- the value of #rateShift can be a float
-- to change the rateShift you must stop() the sound
-- the sound property sound(1).rateShift is read-only
on shiftRate myValue
  sound(1).stop()
  sound(1).queue([#member: member("mySound"), #rateShift: myValue])
  sound(1).play()
  put sound(1).rateShift
end
-- message window
shiftRate(1.5)
  --1.5000
  • Note: 12 semitones is an octave.

Fonts

fontList() and outlineFontList()

  • The undocumented method fontList() of the Font Xtra returns a list of all installed fonts. Works on PC and Mac.
  • The undocumented method outLineFontList() of the Font Xtra returns a list of all installed fonts that can be embedded (imported) in Director because they contain the necessary "Outlines".
  • These methods require the Font Asset Xtra
-- Lingo-Syntax
on getAllFonts
  myFont = new(#font)
  myFontList = myFont.fontList()
  myFont.erase()
  put myFontList
end
 
on getAllOutlineFonts
  myFont = new(#font)
  myFontList = myFont.outlineFontList()
  myFont.erase()
  put myFontList
end
// JavaScript-Syntax
function getAllFonts() {
  var myFont = _movie.newMember(symbol("font"));
  var myFontList = myFont.fontList();
  myFont.erase();
  trace(myFontList);
}
 
// JavaScript-Syntax
function getAllOutlineFonts() {
  var myFont = _movie.newMember(symbol("font"));
  var myFontList = myFont.outlineFontList();
  myFont.erase();
  trace(myFontList);
}

generateOutlines() - generate font outlines from font members

With the undocumented method generateOutlines() you can create a vertex list from any given string using an imported font. This could be used in a vector member e.g.

  • First we import the desired font into the cast.
  • Now we call the font member method generateOutlines() with a string and get the vertex list:
-- Lingo-Syntax
myVertexList = member("myFont").generateOutlines("Hello World")

Attention! The string provided to generateOutlines() must be a valid string with characters (not just spaces). Otherwise you'll get a script error! Note: vector shapes suffer from a maximum size of 2798.0499px width and height, and using generateOutlines() produces large vector shapes, thus the size of the string passed to it is very limited... however, you can do this:

-- Lingo-Syntax
myVertexList = member("myFont").generateOutlines("Hello World")
myVertexList = myVertexList / 2
-- divide the [#newCurve] item by 2
newCurve = [#newCurve] / 2
-- anywhere a [#newCurve] item is found in the vertexList, which in this case
-- has been converted to [733] because of the division by 2, we change it back
 
repeat while true
  newCurveItem = myVertexList.getOne(newCurve)
  if newCurveItem = 0 then exit repeat
  myVertexList[newCurveItem] = [#newCurve]
end repeat

Undocumented Font Styles

Here's the list of all undocumented font styles for text members:

  1. #Boxed
  2. #DoubleUnderline
  3. #WordUnderline
  4. #DottedUnderline
  5. #HiddenText
  6. #StrikeOut
  7. #SuperScript
  8. #SubScript
  9. #AllCaps
  10. #AllLower
  11. #SmallCaps
  12. #Overline
-- text member named "text"
member("text").fontStyle = [#DottedUnderline, #SmallCaps]
  • Note: in D11+ only #DottedUnderline, #StrikeOut, #SuperScript and #SubScript work.

Imaging Lingo

floodFill()

Use this undocumented method to flood fill an area of a bitmap image with identical color value with a given color. Works a bit like the paint bucket.

-- Lingo-Syntax
myImage.floodFill(xPoint,yPoint,rgb(myRed,myGreen,myBlue))

copyPixels() with undocumented #dither values

The copyPixels() method has two unocumented values for the "#dither" parameter. These additional values for #dither are 1215 and 1969 (see below details).

  • Use [#dither:1215] - This uses a remapping algorithm that searches the palette for the closest color instead of using 5 bits of R, G and B to find a color. Good for very subtle palettes with lots of very similar colors.
  • Use [#dither:1969) - This uses a high-quality dithering algorithm with better results than the regular dither, but a lot slower.

Using these parameters can strongly affect performance. Don't forget to test and reduce usage to a minimum.

-- Lingo-Syntax
targetImage.copyPixels(sourceImage, targetRect, sourceRect, [#dither:1215])

image(x,y,depth,switch) - 4th parameter

The 4th parameter seems to activate/deactivate useAlpha.

-- Lingo-Syntax
myImage = image(myWidth, myHeight, 32, true)

The 4th parameter can also be a symbol representing any of the built-in palettes: #systemWin, #systemMac, #rainbow, #web216, #metallic, #pastels, #vivid, #ntsc. It will only work on 8-bit images (ie. images consisting of 256 colours).

-- Lingo-Syntax
myImage = image(myWidth, myHeight, 8, #metallic)

or you can use a custom palette member like so:

-- Lingo-Syntax
myImage = image(myWidth, myHeight, 8)
myImage.paletteRef = member("custom palette")

paletteRef of images

It is possible to set the palette used by an in-memory image (that may not be associated with any cast member), although the printed material and help file do not mention it.

img = image(640, 480, 8) 
img.paletteRef = member("my custom palette")      
img.copypixels(_movie.stage.image, rect(0, 0, 640, 480), rect(0, 0, 640, 480))

Image Equality Test

A fast method of doing a pixel based image equality test:

imagesEqual = (member(1).image = member(2).image)
-- or directly with image objects
imagesEqual = (image1 = image2)

Bitmap Image of Field Member

For field members you can't use member.image like you can for text members. Instead use member.picture. See below.

member("bitmap").picture = member("field").picture

hexString()

This color object function converts decimal rgb color values to hexadecimal strings.

mycolor = rgb( 51, 0, 204 )
put mycolor.hexString()
-- "#3300CC"


Lists

deleteAll

l=[1,2,3]
l.deleteAll()
put l
-- []

Filling a List With a Value

You can populate a list by setting some index in the list to any value:

myList = []
myList[10] = 5 
put myList
-- [0, 0, 0, 0, 0, 0, 0, 0, 0, 5]

Test If a List is Empty

To see if a list is empty it's up to 4x faster to test the count of the list instead of comparing the list to an empty list:

if count(someList) = 0 then
nothing
end if
-- Not this: 
if someList = [] then
nothing
end if


Maths & Rects

min() and max() in lists

With the list methods min() und max() you can easily get the min or max value for integers, floats, and strings.

-- Lingo-Syntax
myList = [10,5,3,17,52,26]
put myList.min()
-- 3
put myList.max()
-- 52

Some other examples to illustate how min() and max() function on lists:

aList = ["Bob", "was", "here", "2008"]
put aList.max()
-- "was"
put aList.min()
-- "2008"
 
-- mixing up types
p1 = #zz
p2 = #aa
aList = [3, p1, p2, ["z", "aa", 2.91, 1, 3], "bar" ]
put aList.min()
-- ["z", "aa", 2.9100, 1, 3]
put aList.max()
-- #zz

Note: the methods do not perform a 'deep' search of nested lists. The last example demonstrates that symbols are sorted as strings, not by their integer value (the #aa symbol would have a higher integer value since it is made after the #zz symbol).

random() with 2 parameters

The method random() can be used with 2 parameters to draw random numbers from a given range. The following example draws a random number from the range of 3 to 17:

-- Lingo-Syntax
put random(3,17)

Make sure that the second parameter is strictly superior to the first parameter. ... first parameter the lowest value, second parameter the highest value! If the second parameter is inferior or equal, such as random(100, 50) and random(100, 100), it is equivalent to random(100). Random(-12, 12) also work and so does random(-100, -50). Just make sure to put the smallest number first (and not random(-50, -100)!). i.e. -100 < -50

atan method with 2 parameters (atan2)

An undocumented option of the method atan() is to use 2 parameters, which equals the method "atan2" in other programming languages.

-- Lingo-Syntax
myAngle = atan(y,x)

Get the Width and Height of a Rect

Director already has built-in methods for getting the width and height of a rect*:

-- the unnecessarily complicated way to get the width and height 
theRect = the desktopRectList[1].rect
width = theRect.right - theRect.left
height = theRect.bottom - theRect.top
 
-- instead, use .width and .height which are methods of the rect property/data type
the desktopRectList[1].rect.width
the desktopRectList[1].rect.height
window("stage").rect.width
window("stage").rect.height
  • caveat: the width and height values calculated from the rect are updated on a stage update (or Lingo equivalent: updateStage) so be aware of this limitation.

Using the Inflate() command (8.5 to MX2004)

Takes a rectangle and a width and height change, and returns a new rectangle inflated from the centre.

-- add 5 pixels to the height of the sprite 
sprite(1).rect = sprite(1).rect.inflate(0, 5)
 
-- subtract 5 pixels from the width of the sprite
sprite(1).rect = sprite(1).rect.inflate(-5, 0)

Scripts

the scriptExecutionStyle

In Director 10 (Director MX 2004), the syntax used for creating new objects was standardized. A new movie property, the scriptExecutionStyle, was introduced so that movies created in version 9 (MX) and earlier will still function correctly. By default, any movie last saved in a version of Director prior to MX 2004 will be set to use a value of 9.

see information here: http://www.director-online.com/dougwiki/index.php?title=Syntax_changes_in_Director_MX_2004

scriptSyntax property

Members have an undocumented scriptSyntax property, that can be read and set. Possible values are the symbols "#lingo" and "#javascript". New members have the default value "#lingo".

linkAs with filename parameter

linkAs() supports an optional parameter for specifying the target filename of the linked script file. If it's omitted, a save dialog box is presented.

member("main").linkAs("c:\main.ls")


Using prepareFrame and exitFrame in a Parent Script

This method can be used in a Parent script to provide access to the prepareFrame and exitFrame event handlers via a quirk with timeout objects.

-- frameProxy Script
 
-- provides access to the prepareFrame and exitFrame event handlers 
-- using a timeout object quirk
 
property pObjFrameProxy
 
-----------------------------
-- Public Methods
-----------------------------
on new me
  put "new instance of frameProxy script created."
  return me
end
 
on createFrameProxy me
  put "frame proxy initiated."
  pObjFrameProxy = timeout().new("frameProxy" & the milliseconds, the maxInteger, #frameProxyHandler, me)
end
 
on cleanup me
  put "clean up frameProxy timeout object."
  pObjFrameProxy.forget()
end
 
-----------------------------
-- Private Methods
-----------------------------
on prepareFrame me
  put "prepareFrame! " & the milliseconds
end
 
-- the enterFrame handler will not work
-- added for testing purposes only
on enterFrame me
  put "enterFrame! " & the milliseconds
end
 
on exitFrame me
  put "exitFrame! " & the milliseconds
end
 
on frameProxyHandler me
  nothing
end

Strings & Text Members

Delete Text Chunk Using Dot Syntax

Delete a text chunk in a member using dot syntax:

member("text").line[1].delete()
member("text").char[1..4].delete()

Case Sensitive String Comparison

You can use lists to do case sensitive string comparisons.

put "Steve" = "steve"
-- 1
put list("Steve") = list("steve")
-- 0

Range and Ref of Text Member

You can determine the character range of a text chunk expression using the undocumented .range property:

put member(1).word[10].range 
-- [24, 28]

The somewhat obscure .ref property allows you to set a reference to a text chunk so it can be manipulated directly:

txtRef = member("text").line[2..3].ref
put txtRef
-- <Prop Ref 2 249760>
put txtRef.range
-- [74, 236]
put txtRef.font
-- "Arial"
put txtRef.word[1]
-- "The"
txtRef.word[1].font = "Verdana"
put txtRef.word[1].font
-- Verdana

Note that the .ref property value gives you access to the defined chunk of text as if it was a text member in its own right. You can get and set .font, .fontstyle, .fontsize, .text, .word, .line, .char, etc.

Using the .selection and .selectedText Properties of a Text Member

When using member(“text”).selection the value of the start and end position of the insertion character (carat) is returned; the positions are the spaces between characters, starting at position 0. Thus, there are two systems of numbering - the first is base-0 and the second is base-1, ie. the insertion position starts at 0 and the character position starts at 1. There are two text member properties to consider: .selection and selectedText. Let's say I select the first to fourth characters in a text member. The text reads "This is a test". In the message window:

put member("text").selection
-- [0,4]
-- that's the insertion point (carat) position
put member("text").selectedText
-- <Prop Ref 1 3cb8eac>
Instead, you can use:
put member("text").selectedText.text
-- "This"
put member("text").selectedText.range
-- [1,4]
 
-- since the selectedText is a reference to the text chunk
-- various chunk properties can be set:
member("text").selectedText.fontStyle = [#bold]
member("text").selectedText.font = "Tahoma"
member("text").selectedText.fontSize = 18

The "byte" Chunk Expression

From the Director 7.02 release notes:

On double-byte systems such as Japanese, the "byte" chunk expression enables you to access individual bytes in multibyte characters.

For example, to find out the number of bytes in line 3, use this lingo:

put myTextMember.line[3].byte.count
-- 19
 
-- use this Lingo to access the first byte of a multibyte character:
put myTextMember.char[5].byte[1]

On Roman systems "byte" has the same meaning as "char".

System, Sprites, Cast, Members

the commandLine

With the undocumented property "the commandLine" you can get commandline parameters that had been defined when the projector was started (only Windows and OSX). Start Director in Windows with the following line ...

"C:\Program Files\Macromedia\Director MX 2004\Director.exe" myCommand

... you can now get the additional parameter inside Director:

-- Lingo-Syntax
put the commandLine
  -- "myCommand"

If you drag and drop another file on top of a Director projector, you get the file´s name as the command line.

the stageColor

If you need to clear the stage of some anomalous graphical residue that remains from a sprite who's updating is not being handled by Director (ie. an activeX control, video or flash sprite on the stage) then you can try this (commonly called 'repainting'):

the stageColor = the stageColor

stretch property of sprites

If you import a new image into an existing sprite on runtime (e.g. by setting the filename property of the member), the new image will be stretched or squeezed into the sprite dimensions. This can be prevented with the stretch property set to FALSE.

-- Lingo-Syntax
sprite("myImage").stretch = FALSE -- or TRUE

JavaScript Garbage Collection

Even in Director's (from Director MX 2004) JavaScript syntax, there's something undocumented for you guys.

The JavaScript Interpreter (SpiderMonkey) remembers everything, until 8MB of system memory are used. Then it starts to collect garbage. With the method gc() you can force garbage collection anytime.

// JavaScript-Syntax
_system.gc();

blend property for window opacity (Win only)

With the undocumented blend property of the window object you can set the opacity for the whole projector window.

-- Lingo-Syntax
myWindow = new window("Hello")
myWindow.blend = 50

closeRequest

Developers wishing to use the exitLock property can capture a user's attempt to close the projector by using the following code:

on closeRequest 
  -- statement(s)
end

This new handler used with the exitLock setting is a great way to create a "Save dialog" routine if the user has not saved their work before exiting the program. The closeRequest handler was introduced in DMX2004.

the systemDate

the systemDate returns a date object with the current date and time.

put the systemDate
-- date( 2008, 10, 6 )

You can get the various components of the date and time from the returned date object, eg.

sysDate = the systemDate
put sysDate.month
-- 10
put sysDate.day
-- 6
put sysDate.year
-- 2008
put sysDate.seconds
-- 1084
hours = sysDate.seconds / 3600
minutes = (sysDate.seconds mod 3600) / 60
seconds = sysDate.seconds mod 60
 
-- dot syntax
_movie.systemDate()

_system.date() is not the equivalent dot syntax method (but _system.date(stringOrInt) returns the same kind of date object but only the Int eg. 20081006 works across sytems; a string parameter eg. "10/6/2008" is dependent upon the regional settings of the computer it's running on so cannot be relied upon).

the stage.name

Allows a developer to store some piece of information. Not to be confused with the stage.title. It's important to note that one of the dot syntax equivalents is _movie.window("stage"), however, if you change the stage name then you MUST reference it by the new name. Dot syntax further confuses the issue as _movie.stage also references the stage, but changing the name of the stage using this syntax does not affect the association.

put _movie.window("stage").name
-- "stage"
 
_movie.stage.name = "test"
put _movie.window("stage").name
-- <throws a script error>
 
put _movie.window("test").name
-- "test"
 
put _movie.stage.name
-- "test"
 
put _player.windowList
-- [(window "test")]

Mouse Buttons Detected with KeyPressed

  • Left Mouse Button – keyPressed(128)
  • Right Mouse Button – keyPressed(129)
  • Middle Mouse Button – keyPressed(130)

Using keyPressed for the middle button should work on all standard 3-button mice. It may not function on mice with more than three buttons. The keyPressed needs to be placed in an on mouseDown or a frame handler. For best results, use a frame handler.

on enterFrame
if keyPressed(130) then
alert("You pressed the middle button")
end if
end

Multiple Instances of a MIAW

To open up multiple instances of a MIAW you must set the .dir file to read-only. This can be done through either the Explorer window (PC), the File Browser window (mac) or through an Xtra such as BuddyAPI (Please note, that it is not necessary to do so on macOS, as one file can be opened more than once on macOS. Also note, that you cannot set the readonly property for windows on macOS, you will always need a windows OS to set the readonly property for a file for windows). As well, you need to give each window a custom instance name. One way to accomplish this is to append the milliseconds onto the end, ie.

-- no spaces allowed
instanceName = "display_profile" & the milliseconds
window().new(instanceName)
-- assuming the file name is profile.dir
-- leave out the extension, that way Director will
-- look for profile.dir or profile.dxr
window(instanceName).fileName = "profile"
window().open(instanceName)

An example where you would use multiple instances of the same window is in a chat program where you have a private chat window popup to chat with another person. In this situation, it would be more useful to name the windows by the unique chatter and chattee names, eg. "codemonger_lisa369"

Pausing and Playing the Playhead

Even though they've been deprecated, these two oldies still work (tested in DMX2004).

-- to pause the playhead
pause
 
-- to play the playhead again
continue

DispatchCommand

credit to: Valentin Schmidt, Pedja, Kraig - Thu, 27 Jan 2005 Direct-L

DispatchCommand() is a lingo method found in UIHelper.x32 xtra which works in DMX2004 or above. It permits lingo to send events to the authoring environment via a code value (0 - 65535) allowing interaction with any menu entry in Director.


Examples: General

dispatchCommand(4104)  -- publish the movie with the last publish settings
dispatchCommand(4101)  -- saves the movie,
dispatchCommand(4103)  -- does a "Save and Compact"
dispatchcommand(35334) -- Recompiles all scripts
dispatchCommand(58370) -- clear the message window (bottom pane)


Examples: Open a script

castLib(1).selection = [[9, 9]]      -- Select the script member in cast library
dispatchCommand(9245)                -- Open script window

(Although you do not need this specific example, as the UIHelper xtra has a dedicated method to open a scripteditor window. You can even specify the char where to scroll to. To do so use: activateScriptEditor <int memberNum>, <int castLibNum>, <int selectionStart>, <int selectionEnd>)


Although a definitive list of valid command codes was never published, work by the Director community (Valentin, Pedja, Kriag) provided several resources.

Known command numbers - Short list of known, useful and working commands.

Full menu command list - Lists all menu items and corresponding comand code, as extracted from the menu resource of Director.

Publish from the commandline - Example by Valentin Schmidt on how to publish from command line.

UIHelper Xtra

Seconds in the Date Object

The date object (including the systemDate), contains an undocumented property, seconds.

dateObj = the systemDate -- get today's date from the computer
put dateObj.seconds
-- 81290
dateObj = date(2009, 12, 1)
put dateObj.seconds
-- 0
 
-- the seconds are zero by default. It must be set.
dateObj.seconds = 32000

The searchPathList Not Affected by clearGlobals

The _player.searchPathList is not affected by clearGlobals but can be passed from one movie to another after a 'go movie()' command. This means you can pass variables using the searchPathList without a clearGlobals affecting it. As well, even though it's meant for passing fully qualified paths, it will accept any datatype and will not throw an error.

global gTest
gTest = "This is a test"
_player.searchPathList = ["This is a test", 21, #customSymbol, [32, 45, 22, 8]]
_global.clearGlobals()
_global.showGlobals()
 
-- Global Variables --
version = "10.1.1"
 
put _player.searchPathList
 
-- ["This is a test", 21, #customSymbol, [32, 45, 22, 8]]

Here are all the syntax forms of the searchPathList:

-- Dot Syntax for Lingo and Javascript
_player.searchPathList
_player.searchPaths
 
-- Verbose Syntax
the searchPathList
the searchPaths

Mime Types for Shockwave

Make sure your server has the correct mime types for cct files set up. It's often the case that even though your server might serve dcr's correctly, it won't serve other formats in the shockwave family. Here's the full list of mime types for shockwave:

  • application/x-director dir
  • application/x-director dcr
  • application/x-director dxr
  • application/x-director cst
  • application/x-director cct
  • application/x-director cxt
  • application/x-director w3d
  • application/x-director swa


Link Resources:

Create Filmloop With Lingo

credit to: Brennan Young Sat, 6 Oct 2007 18:03:28 +0200 on Direct-L

mem = new(#filmloop)
mem.media = the score -- yields a filmloop

The more alert amongst you will realize that you have to use ALL the score, and you are almost certainly using the score for something else, no?

One workaround is to use an offscreen MIAW with an empty score reserved for exactly this purpose, another is to store the 'proper' score in another filmloop while you're generating the LDM, then dump the cached filmloop back into the score when you're done.

the score = member("oldScoreStoredinFilmloop").media

Still another is to do everything except the LDM/filmloop generation with imaging lingo directly to the stage. (Ugh).

Like I said, it's ugly, but it's doable if you really need it.

I've also had success using filmloops containing a frame full of placeholders occupying as many channels as I think I'll need, then 'tell sprite...'. There are some issues with mouse/frame events, and editable text, but it is fairly robust otherwise.

importFileInto with castLib files

If you want to dynamically link a new castLib to your movie at runtime (without using an xtra like castXtra), you can use:

dummyMember.importFileInto("c:\test.cst")

This will link "c:\test.cst" as additional castLib. Be careful, the member in member slot dummyMember will be deleted, therefor you have to make sure to use an empty member slot, e.g. by creating a new member on the fly (that will be deleted again right away):

put _movie.castLib.count
-- 1
new(#bitmap).importFileInto("c:\test.cst")
put _movie.castLib.count
-- 2
put _movie.castLib[2].name
-- "test"

Number of Members and Casts

The verbose and dot syntax for getting both the number of members and number of castlibs.

This gets the number of members of the first cast:

-- verbose
the number of members 
 
-- dot syntax
castlib(1).member.count

This gets the number of members of a specific cast library:

-- verbose
the number of members of castlib 1
the number of members of castlib "scripts"
 
-- dot syntax
castlib(2).member.count
castlib("scripts").member.count

This gets the number of cast libraries in the movie:

-- verbose
the number of castlibs
 
-- dot syntax
_movie.castlib.count

CompressedMedia

credit to: James Newton & Valentin Schmidt - Tue, 4 Sep 2007 Direct-L

Before you access the compressedMedia of the bitmap member, save the castLib in which it is stored. Also, you must use .importFileInto() instead of .fileName()

You can check if the compressedMedia is really compressed by comparing memberRef.media.length to memberRef.compressedMedia.length:

isCompressed = (memberRef.compressedMedia.length <> memberRef.media.length)


Vectors

Vector Shapes and Float Values

Although the vector points in a vertextList can contain floats, those values do not survive the process of saving the project; the floats are rounded to the nearest whole number. The only way to maintain the float precision is to store all vertexLists. Two methods of storage are: 1) In a field or text member, setting to the vectorShape member at runtime or 2) Store the values in the .comments property of the vector shape member itself.

mem = new(#vectorshape)
mem.name = "vectorshape"
mem.vertexList = [[#vertex: point(-66.6350, 37.8780), #handle1: point(-70.333, -36.1254), \
#handle2: point(-62.4209, 110.5532)], [#vertex: point(66.3000, -5.0066), \
#handle1: point(121.089, 56.1200), #handle2: point(11.7881, -66.4112)]]
 
-- at this point, if you save the project, close it, 
-- and then open it back up again you will get this:
put member("vectorshape").vertexList
[[#vertex: point(-67, 38), #handle1: point(-70, -36), #handle2: point(-62, 111)], \
[#vertex: point(66, -5), #handle1: point(121, 56), #handle2: point(12, -66)]]
 
-- a way around this might be to save the information during
-- authoring to the little-used .comments property of the member
member("vectorshape").comments = string(member("vectorshape").vertexList)
 
-- then, to load it back in:
member("vectorshape").vertexList = value(member("vectorshape").comments)

#extruder property of a vector shape cast member

It is possible to extrude vector shapes with the extrude3d command. But you have to build an extruder resource from a normal textmember, before you are able to apply the vertexList from the vector shape.

- create a text cast member

textMember = new(#text)

- initialize the member with any string

textMember.text = "a"

- extrude the text member's string into a 3D cast member

extruderResource = textMember.extrude3d(member("3D"))

- grab vertex list of vector shape cast member

tList = member("vector shape").vertexList

- update model resource

extruderResource.vertexList = tList

Now use that model resource as desired.

Typing Text in the Vector Shape Window

There is a special text entry mode in the vector editor of Director - open a vector window then type 'abc' (without the single quotes) and then start typing ... you get a sort-of plotter-style vector text...no font choice though – fairly useless for anything.


Work in Progress

Undoc'd Parameters in importFileInto()

-- Lingo-Syntax
member("myImage").importFileInto(fileToImport, [#trimWhitespace: false, #remapImageToStage: false, #dither: true])

When #trimWhiteSpace is set to FALSE, any white pixels surrounding the non-white content of the image will be left intact. When #trimWhiteSpace is TRUE, white pixels surrounding the non-white image content are removed. The default is TRUE.

#remapImageToStage prevents the new member from inheriting the bit depth of the stage. If the image is 8-bit, this ensures that the palette (if it is valid) is also imported. This parameter addresses the problem, that importFileInto() always uses the current bit depth of the stage. With this you can set it to always use 32-bit, but there is no way to define a lower bit depth. So you cannot create an 8-bit member with this command. The default is TRUE.

#dither set to TRUE, the image is dithered to the closest colors of the current palette, rather than remapped to the current palette. Also, you can use the undocumented dither values, 1215 and 1969. The default is FALSE.