Skip to content

Commit ae46402

Browse files
committed
Experimental Transform with children
1 parent 733d056 commit ae46402

2 files changed

Lines changed: 300 additions & 86 deletions

File tree

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
function TransformMatrix()
2+
{
3+
this.matrix = new Float32Array([1, 0, 0, 1, 0, 0]);
4+
}
5+
TransformMatrix.prototype.loadIdentity = function ()
6+
{
7+
var matrix = this.matrix;
8+
matrix[0] = 1;
9+
matrix[1] = 0;
10+
matrix[2] = 0;
11+
matrix[3] = 1;
12+
matrix[4] = 0;
13+
matrix[5] = 0;
14+
return this;
15+
};
16+
TransformMatrix.prototype.translate = function (x, y)
17+
{
18+
var matrix = this.matrix;
19+
matrix[4] = matrix[0] * x + matrix[2] * y + matrix[4];
20+
matrix[5] = matrix[1] * x + matrix[3] * y + matrix[5];
21+
return this;
22+
};
23+
TransformMatrix.prototype.scale = function (x, y)
24+
{
25+
var matrix = this.matrix;
26+
matrix[0] = matrix[0] * x;
27+
matrix[1] = matrix[1] * x;
28+
matrix[2] = matrix[2] * y;
29+
matrix[3] = matrix[3] * y;
30+
return this;
31+
};
32+
TransformMatrix.prototype.rotate = function (radian)
33+
{
34+
var matrix = this.matrix;
35+
var a = matrix[0];
36+
var b = matrix[1];
37+
var c = matrix[2];
38+
var d = matrix[3];
39+
var tcos = Math.cos(radian);
40+
var tsin = Math.sin(radian);
41+
42+
matrix[0] = a * tcos + c * tsin;
43+
matrix[1] = b * tcos + d * tsin;
44+
matrix[2] = a * -tsin + c * tcos;
45+
matrix[3] = b * -tsin + d * tcos;
46+
return this;
47+
};
48+
function Transform(root)
49+
{
50+
this.positionX = 0;
51+
this.positionY = 0;
52+
this.scaleX = 1;
53+
this.scaleY = 1;
54+
this.rotation = 0;
55+
this.localMatrix = new TransformMatrix();
56+
this.worldMatrix = new TransformMatrix();
57+
// Never iterate this list internally.
58+
// Only for user
59+
this.children = [];
60+
this.hasChildren = false;
61+
// Only valid if you are the root.
62+
// This probably needs to be on State and not here.
63+
this.flatChildrenArray = [];
64+
this.transformStack = [];
65+
this.childStack = [];
66+
this.childCount = 0;
67+
this.dirty = false;
68+
this.root = root || this;
69+
}
70+
// this must be called only once on the root of the tree. Never on children
71+
Transform.prototype.flattenTree = function (children, flatChildrenArray, childCount)
72+
{
73+
for (var index = 0, length = children.length; index < length; ++index)
74+
{
75+
flatChildrenArray[childCount++] = children[index];
76+
if (children[index].children.length > 0)
77+
{
78+
childCount = this.flattenTree(children[index].children, flatChildrenArray, childCount);
79+
flatChildrenArray[childCount++] = children[index]; // add ending tag
80+
}
81+
}
82+
return childCount;
83+
};
84+
Transform.prototype.addChild = function (transform)
85+
{
86+
this.root.dirty = true;
87+
this.hasChildren = true;
88+
transform.root = this.root;
89+
this.children.push(transform);
90+
};
91+
Transform.prototype.removeChild = function (transform)
92+
{
93+
var children = this.children;
94+
var index = children.indexOf(transform);
95+
if (index >= 0)
96+
{
97+
children.splice(index, 1);
98+
this.hasChildren = (children.length > 0);
99+
this.root.dirty = true;
100+
}
101+
};
102+
103+
// Only call this function once per frame. Should probably
104+
// be only available at State
105+
Transform.prototype.updateRoot = function ()
106+
{
107+
if (this.root !== this)
108+
{
109+
return;
110+
}
111+
var currentTransform;
112+
var currentChild = null;
113+
var stackLength = 0;
114+
var transformStack = this.transformStack;
115+
var childStack = this.childStack;
116+
var childrenArray = this.flatChildrenArray;
117+
if (this.dirty)
118+
{
119+
this.childCount = this.flattenTree(this.children, childrenArray, 0);
120+
this.dirty = false;
121+
}
122+
this.updateLocal();
123+
currentTransform = this.localMatrix;
124+
for (var index = 0, length = this.childCount; index < length; ++index)
125+
{
126+
var child = childrenArray[index];
127+
if (child !== currentChild)
128+
{
129+
child.update(currentTransform);
130+
if (child.hasChildren)
131+
{
132+
transformStack[stackLength] = currentTransform;
133+
childStack[stackLength++] = currentChild;
134+
currentTransform = child.worldMatrix;
135+
currentChild = child;
136+
}
137+
}
138+
else
139+
{
140+
currentTransform = transformStack[--stackLength];
141+
currentChild = childStack[stackLength];
142+
}
143+
}
144+
};
145+
Transform.prototype.update = function (parentTransformMatrix)
146+
{
147+
var parent = parentTransformMatrix.matrix;
148+
var world = this.worldMatrix.matrix;
149+
var localm this.localMatrix.loadIdentity();
150+
localm.translate(this.positionX, this.positionY);
151+
localm.rotate(this.rotation);
152+
var local = localm.scale(this.scaleX, this.scaleY).matrix;
153+
154+
world[0] = parent[0] * local[0] + parent[1] * local[2];
155+
world[1] = parent[0] * local[1] + parent[1] * local[3];
156+
world[2] = parent[2] * local[0] + parent[3] * local[2];
157+
world[3] = parent[2] * local[1] + parent[3] * local[3];
158+
world[4] = parent[4] * local[0] + parent[5] * local[2] + local[4];
159+
world[5] = parent[4] * local[1] + parent[5] * local[3] + local[5];
160+
};
161+
Transform.prototype.updateLocal = function ()
162+
{
163+
var local this.localMatrix.loadIdentity();
164+
local.translate(this.positionX, this.positionY);
165+
local.rotate(this.rotation);
166+
local.scale(this.scaleX, this.scaleY);
167+
};
168+
Object.defineProperties(Transform.prototype,{
169+
worldPositionX: {
170+
enumarable: true,
171+
get: function ()
172+
{
173+
return this.world[4];
174+
}
175+
},
176+
worldPositionY: {
177+
enumarable: true,
178+
get: function ()
179+
{
180+
return this.world[5];
181+
}
182+
},
183+
worldScaleX: {
184+
enumarable: true,
185+
get: function ()
186+
{
187+
var world = this.world;
188+
var a = world[0];
189+
var c = world[2];
190+
var a2 = a * a;
191+
var c2 = c * c;
192+
var sx = Math.sqrt(a2 + c2);
193+
return sx;
194+
}
195+
},
196+
worldScaleY: {
197+
enumarable: true,
198+
get: function ()
199+
{
200+
var world = this.world;
201+
var b = world[1];
202+
var d = world[3];
203+
var b2 = b * b;
204+
var d2 = d * d;
205+
var sy = Math.sqrt(b2 + d2);
206+
return sy;
207+
}
208+
},
209+
worldRotation: {
210+
enumarable: true,
211+
get: function ()
212+
{
213+
var world = this.world;
214+
var a = world[0];
215+
var c = world[2];
216+
var a2 = a * a;
217+
var c2 = c * c;
218+
return Math.acos(a / Math.sqrt(a2 + c2)) * (Math.atan(-c / a) < 0 ? -1 : 1);
219+
}
220+
}
221+
});

0 commit comments

Comments
 (0)