Category Archive: Tutorial

Return value of Matrix3D.recompose() method

The [Help] of the Matrix3D.recompose() method tells about its return value as follows:

Returns false if any of the scale elements are zero.

But this is not true. Try the code below, in the 7th statement of which the third element, the z coordinate, of the scale Vector3D instance is set to zero.

var myMatrix3D:Matrix3D = new Matrix3D();
trace(myMatrix3D.decompose());
// Output: Vector3D(0, 0, 0),Vector3D(0, 0, 0),Vector3D(1, 1, 1)
var myVector:Vector.<Vector3D> = new Vector.<Vector3D>();
myVector.push(new Vector3D());  // translation
myVector.push(new Vector3D());  // rotation
myVector.push(new Vector3D(1, 1, 0));  // scale
trace(myMatrix3D.recompose(myVector));
// Output: true
trace(myMatrix3D.decompose());
// Output: Vector3D(0, -1.9986319541931152, 0),Vector3D(-1.5707963705062866, NaN, 0),Vector3D(7.667765755019554e-19, -1.998608112335205, 1.9719639421382673e-19)

The method returns true as long as the argument of Vector instance has three Vector3D elements. Therefore, the explanation in the [Help] should be rewritten as follows:

Returns false if any of the Vector3D elements of the Vector instance as the argument don’t exist or are null.

Note: The coordinates of Vector3D elements come to be invalid values if any of the scale elements are zero.

Calculation in the Utils3D.projectVectors() method

The Utils3D.projectVectors() method projects a Vector of three-dimensional space coordinates to a Vector of two-dimensional space coordinates. And the method also sets the t value of the uvt data.

Calculation in the Utils3D.projectVectors() method

Values for the calculation in the Utils3D.projectVectors() method

The Utils3D.projectVectors() method calculates t value of the uvt data by the following formula:

t value = 1 / (Distance to the origin + z coordinate value)

Also, the method calculates projected x and y values by the following formula:

Projected x or y value = Three-dimensional space x or y coordinate * Focal length * t value

The frame action below compares the results of calculation by the formulas above with the methods’. And [Output] is as follows:

0,0,0.0004 // uvt data
0.0004 // Calculated t value
20,20 // Projected x and y coordinates
20 // Calculated two-dimensional space x or y coordinate

var myPerspective:PerspectiveProjection = new PerspectiveProjection();
var myMatrix3D:Matrix3D = new Matrix3D();
var nDistance:Number = 1000;  // Distance to the origin
var nX:Number = 100;  // Three-dimensional space x or y coordinate
var nZ:Number = 1500;  // Three-dimensional z coordinate
var vertices3D:Vector.<Number> = Vector.<Number>([nX, nX, nZ]);
var vertices2D:Vector.<Number> = new Vector.<Number>();
var uvtData:Vector.<Number> = Vector.<Number>([0, 0, 0]);
var nT:Number = 1/(nDistance + nZ);  // t value
myPerspective.focalLength = 500;  // Focal length 
myMatrix3D.appendTranslation(0, 0, nDistance);
myMatrix3D.append(myPerspective.toMatrix3D());
Utils3D.projectVectors(myMatrix3D, vertices3D, vertices2D, uvtData);
trace(uvtData);  // uvt data
trace(nT);  // Calculated t value
trace(vertices2D);  // Projected x and y coordinates
trace(nX * myPerspective.focalLength * nT);  // Calculated two-dimensional space x or y coordinate

Rotating an instance with the y axis

Try to rotate a MovieClip instance named my_mc 80 degrees with the y axis. The trace() function in the code below displays information in the [Output] panel as follows:

80.00003182368921 1.3962639570236206

var nRotationY:Number = 80;
my_mc.rotationY = 0;
var myMatrix3D:Matrix3D = my_mc.transform.matrix3D;
myMatrix3D.prependRotation(nRotationY, Vector3D.Y_AXIS);
trace(my_mc.rotationY, myMatrix3D.decompose()[1].y);

Rotating an instance 80 degrees

Then change the number of degrees in the variable, nRotationY, to 100. The code seems to rotate an instance 100 degrees. However, the number of degrees shown in the [Output] panel is still 80.

80.00003182368921 1.3962639570236206

var nRotationY:Number = 100;  // 80;
my_mc.rotationY = 0;
var myMatrix3D:Matrix3D = my_mc.transform.matrix3D;
myMatrix3D.prependRotation(nRotationY, Vector3D.Y_AXIS);
trace(my_mc.rotationY, myMatrix3D.decompose()[1].y);

Rotating an instance 100 degrees

The following code reveals the reason.

0 80.00003182368921 0
Vector3D(0, 1.3962639570236206, 0)
180.00000500895632 80.00003182368921 180.00000500895632
Vector3D(3.1415927410125732, 1.3962639570236206, 3.1415927410125732)

var mySprite:Sprite = new Sprite();
var axis:Vector3D = Vector3D.Y_AXIS;  // Vector3D.X_AXIS  // Try to change this
mySprite.rotationY = 0;
var myMatrix3D:Matrix3D = mySprite.transform.matrix3D;
myMatrix3D.prependRotation(80, axis);
xTrace(mySprite);
myMatrix3D.prependRotation(20, axis);
xTrace(mySprite);
function xTrace(targetSprite:Sprite):void {
	trace(targetSprite.rotationX, targetSprite.rotationY, targetSprite.rotationZ);
	trace(targetSprite.transform.matrix3D.decompose()[1]);
}

When the Matrix3D.prependRotation() method rotates an instance 100 degrees with y axis, it is only rotated 80 degrees but is flipped with x and z axes.

The appearance of the instance is all right. But the number of degrees is not good. Besides, 100 degrees can be set with x or z axis. It means that the result of y axis is not consistent. Therefore, I suspect that this is a bug.

Three types of transformation objects in the Transform class

The Transform class has several kinds of transformation objects as its properties.

The Transform class provides access to color adjustment properties and two- or three-dimensional transformation objects that can be applied to a display object.

I noticed three types of properties from the point of view of getting and seting their values.

The first example is the Transform.matrix property. It does not provide its Matrix object reference but its copy. It means that operations to the copy will not affect to the property’s Matrix object. To set a Matrix object to the Transform.matrix property, the object should be assigned to the property.

var mySprite:Sprite = new Sprite();
var myMatrix:Matrix = new Matrix();
mySprite.transform.matrix = myMatrix;
myMatrix.translate(100, 50);
trace(mySprite.transform.matrix);
// Output: (a=1, b=0, c=0, d=1, tx=0, ty=0)
mySprite.transform.matrix = myMatrix;
trace(mySprite.transform.matrix);
// Output: (a=1, b=0, c=0, d=1, tx=100, ty=50)
myMatrix = mySprite.transform.matrix;
myMatrix.scale(2, 1.5);
trace(mySprite.transform.matrix);
// Output: (a=1, b=0, c=0, d=1, tx=100, ty=50)
trace(mySprite.transform.matrix == myMatrix);  // Output: false

The second example is the Transform.matrix3D property. Unlike to the Transform.matrix property, a Matrix3D object’s reference is obtained from the property. Therefore, once its reference is gotten, operations to the reference affects to the Transform.matrix3D property.

var mySprite:Sprite = new Sprite();
var myMatrix3D:Matrix3D = new Matrix3D();
mySprite.transform.matrix3D = myMatrix3D;
myMatrix3D.prependTranslation(100, 50, 0);
trace(mySprite.transform.matrix3D.position);
// Output: Vector3D(100, 50, 0)
trace(mySprite.transform.matrix3D == myMatrix3D);  // Output: true

The third one is the Transform.perspectiveProjection property. When a new PerspectiveProjection instance is assigned to the property, operations to the instance do not affect to the property as well as the Transform.matrix property. Then, try to get the object from the property and set it to a variable again. You can operate the variable as if it was the object reference of the property. However the variable’s object is not evaluated to be equal to the property’s value. It is a mysterious property, isn’t it.

var mySprite:Sprite = new Sprite();
var myPerspective:PerspectiveProjection = new PerspectiveProjection();
mySprite.transform.perspectiveProjection = myPerspective;
myPerspective.fieldOfView = 20;
trace(mySprite.transform.perspectiveProjection.fieldOfView);  // Output: 55
myPerspective = mySprite.transform.perspectiveProjection;
myPerspective.fieldOfView = 100;
trace(mySprite.transform.perspectiveProjection.fieldOfView);  // Output: 100
trace(mySprite.transform.perspectiveProjection == myPerspective);
// Output: false

“Private” classes might cause a compile error

BeInteractive! (blog written by Yoshihiro Shindo) reported a bug of “private” classes (defined outside of the package block). Two or more “private” classes might cause a compile error, which tells that a local variable declared in a main class (inside the package) is undefined in Flash CS4 Professional.

1120: Access of undefined property s.

Compile error #1120

Compile error #1120

I found another condition of the error. If a “private” class inherits a class other than Object the compile error will be prevented.

package {
	import flash.display.Sprite;
	public class PrivateClassIssue extends Sprite {
		public function PrivateClassIssue() {
			var s:String = 'hello';
			trace(s);
		}
	}
}
class Foo {}
class Bar extends Array {}  // inherits Array class

Calculation of focalLength

[Help] of PerspectiveProjection.focalLength property says:

During the perspective transformation, the focalLength is calculated dynamically using the angle of the field of view and the stage’s aspect ratio (stage width divided by stage height).

However as far as I tested it, the stage height does not affect the result of focalLength property’s value. It is calculated from only the stage width by the following formula:

tan(fieldOfView/2) = (stageWidth/2)/focalLength
focalLength = stageWidth/2 tan(fieldOfView/2)

From [Help] of PerspectiveProjection
*From [Help] of PerspectiveProjection

focal length and field of view

focal length and field of view

Therefore the function below returns focal length by passing field of view.

// Frame action
function getFocalLength(nFieldOfView:Number):Number {
	var falf_tan:Number = Math.tan(nFieldOfView / 2 * Math.PI / 180);
	return stage.stageWidth/2/falf_tan;
}


[Note]: With Stage.scaleMode property set to StageScaleMode.NO_SCALE, the value of Stage.stageWidth property can be changed when the browser window is resized. However the PerspectiveProjection.focalLength would be calculated by the original width of the stage set with the [Property] inspector.

The revised function below can return the right result in the case:

// Frame action
var originalMode:String = stage.scaleMode;
stage.scaleMode = StageScaleMode.EXACT_FIT;
var myStageWidth:int = stage.stageWidth;
stage.scaleMode = originalMode;
function getFocalLength(nFieldOfView:Number):Number {
	var falf_tan:Number = Math.tan(nFieldOfView / 2 * Math.PI / 180);
	// return stage.stageWidth/2/falf_tan;
	return myStageWidth/2/falf_tan;
}

Setting String to DataGridColumn.cellRenderer property

Reference of a class to render the items in a column can be set to DataGridColumn.cellRenderer property as the following frame action:

// Frame action
import fl.controls.DataGrid;
import fl.controls.dataGridClasses.DataGridColumn;
var myColmn:DataGridColumn = new DataGridColumn("data");
var myDataGrid:DataGrid = new DataGrid();
myDataGrid.addColumn(myColmn);
// myColmn.cellRenderer = "CustomCellRenderer";  // Error #2007
myColmn.cellRenderer = CustomCellRenderer;  // OK
myDataGrid.addItem({data: "test"});
addChild(myDataGrid);

[Help] also tells that the type of the property’s value can be String. However setting a String class name causes Error #2007 like the below. The error would be shown if the comment-outed statement was validated instead in the sample above.

TypeError:Error #2007:Parameter child must be non-null.

I happened to see DataGridColumn.cellRenderer property in ActionScript 2.0 Components Language Reference. It says that the property is “a linkage identifier for a symbol”.

Therefore, I tried to create an empty MovieClip symbol and to set the class to [Class] of [Linkage]. Then the String class name set to the property in the code above worked properly without an error. As my conclusion, a String class name might only be used for the class set to [Class] of [Linkage].

Symbol Properties

Resizing the drop down list of ComboBox when removeItem() is called

When items in a CombBox compnent instance are removed with ComboBox.removeItem() method, its size of drop down list will not be adjusted. I suspect that this behavior might be a bug because ComboBox.removeItemAt() method properly reset its size.

Combobox.removeItem() -> Combobox.removeitem()

In order to set size of the drop down list properly call UIComponent.validateNow() method after an item is removed with the method like the following code:

// Frame action
import fl.controls.ComboBox;
var myComboBox:ComboBox = new ComboBox();
addChild(myComboBox);
myComboBox.addEventListener(Event.CHANGE, xSelected);
myComboBox.addItem({label:"Dreamweaver CS4", data:"html"});
myComboBox.addItem({label:"Fireworks CS4", data:"png"});
myComboBox.addItem({label:"Flash CS4 Professional", data:"fla"});
function xSelected(eventObject:Event):void {
	var myItem:Object = myComboBox.getItemAt(0);
	myComboBox.removeItem(myItem);
	myComboBox.validateNow();  // Insert this statement.
}

In the ComboBox class ComboBox.removeItemAt() method calls UIComponent.invalidate() method after deleting an item with List.removeItemAt() method.

public function removeItemAt(index:uint):void {
	list.removeItemAt(index);
	invalidate(InvalidationType.DATA);
}

However, ComboBox.removeItem() method does not call the method.

public function removeItem(item:Object):Object {
	return list.removeItem(item);
}

Therefore, UIComponent.invalidate() method could be used instead of UIComponent.validateNow() method.

// Frame action
import fl.core.InvalidationType;
import fl.controls.ComboBox;
var myComboBox:ComboBox = new ComboBox();
addChild(myComboBox);
myComboBox.addEventListener(Event.CHANGE, xSelected);
myComboBox.addItem({label:"Dreamweaver CS4", data:"html"});
myComboBox.addItem({label:"Fireworks CS4", data:"png"});
myComboBox.addItem({label:"Flash CS4 Professional", data:"fla"});
function xSelected(eventObject:Event):void {
	var myItem:Object = myComboBox.getItemAt(0);
	myComboBox.removeItem(myItem);
	myComboBox.invalidate(InvalidationType.DATA);  // Insert this statement.
}

Jikkyo Generator and Youtube API

Jikkyo Generator 2010

Hi, my name is Yasuhiko Nishimura and I am an interactive designer at Business Architects.
The Jikkyo Generator 2010 website build by us went live in May.

The previous version Jikkyo Generator 2008 was integrated with eyeVio for the videos but to enable more users to enjoy the website the new release features integration with YouTube.

In this entry I will explain a bit more about the integration with the YouTube API.
(This entry will be about AS2)

Click here to read more »

Smart Gradient API

Honestly flash’s default Gradient API is kind of crap. Therefore I made alternative methods that enables you define gradient easily. Instead of nasty gradient box matrix, my api use more human friendly parameter, Point and Number specified radius. So you can easily create gradient as if you use flash IDE.

//API for Linear Gradient Fill
beginLinearGradientFill([0x000000,0xfffffff],[1,1],[0,255], startPoint:Point, endPoint:Point);

//API for Radial Gradient Fill
beginRadialGradientFill([0x000000,0xffffff],[1.0,1.0],[0,255], centerPoint:Point, radius:Number);

Below is snipets.
Click here to read more »

ForcibleLoader: Loads AVM1 SWF files into AVM2

By default, Flash Player loads a movie as an instance of the AVM1Movie class if you load a SWF file with a version lower than 9 by the Loader class in AS3. This means you can’t touch any MovieClips in the such SWF file through the Loader. But sometimes we want to do it. I created a solution to this problem – ForcibleLoader

var loader:Loader = Loader(addChild(new Loader()));
var fLoader:ForcibleLoader = new ForcibleLoader(loader);
fLoader.load(new URLRequest('swf7.swf'));

This is how to use it. It loads every SWF file including files under version 9 into the Loader as a AVM2 movie. So now you can access MovieClips in the SWF file through the instance of Loader.

Note: It will not work well if the SWF file contains ActionScript2 because ForcibleLoader doesn't convert any scripts.

Vector3D.w property for multiplication

Vector3D.project() method in [Help] of Flash CS4 Professional says:

If the current Vector3D object is the result of multiplying a Vector3D object by a projection Matrix3D object, the w property can hold the transform value.

However a Vector3D.w property does not hold its original value. I suppose that the method for multiplication is the Matrix3D.transformVector(). Then see the result of the following script:

var myMatrix3D:Matrix3D = new Matrix3D();
var myVector3D:Vector3D = new Vector3D();
trace(myVector3D, myVector3D.w);  // Output: Vector3D(0, 0, 0) 0
myVector3D = myMatrix3D.transformVector(myVector3D);
trace(myVector3D, myVector3D.w);  // Output: Vector3D(0, 0, 0) 1

The default value of the Vector3D.w property is 0. But it is changed into 1 as the result of multiplication. The property does not hold the original value. No number multiplied by 0 can result to 1.

On the other hand, the Vector3D.add() and the Vector3D.subtract() methods reset Vector3D.w property to 0. The property is ignored by these methods.

While the Matrix3D.transformVector() method set the Vector3D.w property's value of the multiplying Vector3D instance to 1, the method does not ignore the property but multiplies it by the Matrix3D instance.

The code below creates a Matrix3D instance, of which the fourth row is set to [4, 3, 2, 5]. The result value of the Vector3D.w property after multiplication is 34. The value is the dot product of the multiplying Vector3D instance (whose Vector3D.w property is 1) and the fourth row of Matrix3D instance.

(4, 3, 2, 5)•(4, 3, 2, 1) = 4x4 + 3x3 + 2x2 + 5x1 = 34

Multiplying a Vector3D by a Matrix3D

var myMatrix3D:Matrix3D = new Matrix3D();
var myRawData:Vector.<Number> = myMatrix3D.rawData;
var myVector3D:Vector3D = new Vector3D(4,3,2);
trace(myVector3D, myVector3D.w);  // Output: Vector3D(4, 3, 2) 0
myRawData[3] = 4;
myRawData[7] = 3;
myRawData[11] = 2;
myRawData[15] = 5;
myMatrix3D.rawData = myRawData;
myVector3D = myMatrix3D.transformVector(myVector3D);
trace(myVector3D, myVector3D.w);  // Output: Vector3D(4, 3, 2) 34

I assume that the sentence in the [Help] quoted in this article implies this process. But it is hard to understand from the expression especially for non-english speaking people. At least it should be mentioned that the Vector3D.w property's value of the multiplying Vector3D instance is set to 1.