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