Revert "[Tizen] Fix build errors in adaptor-uv by ecore wayland"
[platform/core/uifw/dali-adaptor.git] / adaptors / emscripten / wrappers / dali-wrapper.js
1 /*
2  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 /* eslint-env browser */
19 /* eslint "brace-style": [2, "1tbs"] */
20 /* eslint "no-console": 0 */
21 /* eslint "no-underscore-dangle": 0 */
22
23 /*******************************************************************************
24  *
25  * The javascript counterpart to the C++ DALi wrapper.
26  *
27  * Provides helper functionality to make the use of the dali module.
28  *
29  * Where possible it creates a natural Javascript API. One problem
30  * is that wrapped C++ objects must be explicitly deleted '<obj>.delete()'.
31  * This is because javascript in the browser has no available hook to watch
32  * for an objects destruction.
33  *
34  * This file combines several 'Modules' and could be split when using a
35  * a recombining web build tool.
36  *
37  *
38  ******************************************************************************/
39
40 // forward refs for lint
41 var Module;
42 // On upgrading to emscripten 1.34.2 and -s EXPORT_NAME="dali" on emcc command
43 // line no longer seems to work so set it here.
44 var dali = Module;
45 var document;
46 var console;
47
48 //------------------------------------------------------------------------------
49 //
50 // Math Module
51 //
52 //------------------------------------------------------------------------------
53
54 /**
55  * Matrix Multiplication
56  * @method matrixByMatrix
57  * @param {Array} A Matrix4 array
58  * @param {Array} B Matrix4 array
59  * @return {Array} Matrix4
60  */
61 dali.matrixByMatrix = function(A, B) {
62   "use strict";
63
64   var ret = [1, 0, 0, 0,
65              0, 1, 0, 0,
66              0, 0, 1, 0,
67              0, 0, 0, 1
68             ];
69
70   ret[0] = A[0] * B[0] + A[1] * B[4] + A[2] * B[8] + A[3] * B[12];
71   ret[4] = A[4] * B[0] + A[5] * B[4] + A[6] * B[8] + A[7] * B[12];
72   ret[8] = A[8] * B[0] + A[9] * B[4] + A[10] * B[8] + A[11] * B[12];
73   ret[12] = A[12] * B[0] + A[13] * B[4] + A[14] * B[8] + A[15] * B[12];
74
75   ret[1] = A[0] * B[1] + A[1] * B[5] + A[2] * B[9] + A[3] * B[13];
76   ret[5] = A[4] * B[1] + A[5] * B[5] + A[6] * B[9] + A[7] * B[13];
77   ret[9] = A[8] * B[1] + A[9] * B[5] + A[10] * B[9] + A[11] * B[13];
78   ret[13] = A[12] * B[1] + A[13] * B[5] + A[14] * B[9] + A[15] * B[13];
79
80   ret[2] = A[0] * B[2] + A[1] * B[6] + A[2] * B[10] + A[3] * B[14];
81   ret[6] = A[4] * B[2] + A[5] * B[6] + A[6] * B[10] + A[7] * B[14];
82   ret[10] = A[8] * B[2] + A[9] * B[6] + A[10] * B[10] + A[11] * B[14];
83   ret[14] = A[12] * B[2] + A[13] * B[6] + A[14] * B[10] + A[15] * B[14];
84
85   ret[3] = A[0] * B[3] + A[1] * B[7] + A[2] * B[11] + A[3] * B[15];
86   ret[7] = A[4] * B[3] + A[5] * B[7] + A[6] * B[11] + A[7] * B[15];
87   ret[11] = A[8] * B[3] + A[9] * B[7] + A[10] * B[11] + A[11] * B[15];
88   ret[15] = A[12] * B[3] + A[13] * B[7] + A[14] * B[11] + A[15] * B[15];
89
90   return ret;
91 };
92
93 /**
94  * Matrix Vector4 Multiplication
95  * @method matrixByVector
96  * @param {Array} A Matrix4 array
97  * @param {Array} v Vector4
98  * @return {Array} Vector4
99  */
100 dali.matrixByVector = function(A, v) {
101   "use strict";
102
103   var x = v[0];
104   var y = v[1];
105   var z = v[2];
106   var w = 1;
107
108   if (v.length === 4) {
109     w = v[3];
110   }
111
112   return [
113     A[0] * x + A[4] * y + A[8] * z + A[12] * w,
114     A[1] * x + A[5] * y + A[9] * z + A[13] * w,
115     A[2] * x + A[6] * y + A[10] * z + A[14] * w,
116     A[3] * x + A[7] * y + A[11] * z + A[15] * w
117   ];
118 };
119
120 /**
121  * Get Matrix Determinant
122  * @method matrixDeterminant
123  * @param {Array} A Matrix4 array
124  * @return {float} Determinant
125  */
126 dali.matrixDeterminant = function(A) {
127   "use strict";
128
129   var n11 = A[0],
130       n12 = A[4],
131       n13 = A[8],
132       n14 = A[12];
133   var n21 = A[1],
134       n22 = A[5],
135       n23 = A[9],
136       n24 = A[13];
137   var n31 = A[2],
138       n32 = A[6],
139       n33 = A[10],
140       n34 = A[14];
141   var n41 = A[3],
142       n42 = A[7],
143       n43 = A[11],
144       n44 = A[15];
145
146   var m0 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44;
147   var m4 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44;
148   var m8 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44;
149   var m12 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;
150
151   return n11 * m0 + n21 * m4 + n31 * m8 + n41 * m12;
152 };
153
154 /**
155  * Matrix Multiplication by scalar
156  * @method matrixByScalar
157  * @param {Array} A Matrix4 array
158  * @param {float} s float
159  * @return {Array} Matrix4
160  */
161 dali.matrixByScalar = function(A, s) {
162   "use strict";
163   return [A[0] * s, A[1] * s, A[2] * s, A[3] * s,
164           A[4] * s, A[5] * s, A[6] * s, A[7] * s,
165           A[8] * s, A[9] * s, A[10] * s, A[11] * s,
166           A[12] * s, A[13] * s, A[14] * s, A[15] * s
167          ];
168 };
169
170 /**
171  * Matrix Inverse. Raises if there is none.
172  * @method matrixInverse
173  * @param {Array} A Matrix4 array
174  * @return {Array} Inverse Matrix4
175  */
176 dali.matrixInverse = function(A) {
177   "use strict";
178   var ret = [1, 0, 0, 0,
179              0, 1, 0, 0,
180              0, 0, 1, 0,
181              0, 0, 0, 1
182             ];
183
184   ret[0] = A[5] * A[10] * A[15] - A[5] * A[11] * A[14] - A[9] * A[6] * A[15] + A[9] * A[7] * A[14] + A[13] * A[6] * A[11] - A[13] * A[7] * A[10];
185   ret[4] = -A[4] * A[10] * A[15] + A[4] * A[11] * A[14] + A[8] * A[6] * A[15] - A[8] * A[7] * A[14] - A[12] * A[6] * A[11] + A[12] * A[7] * A[10];
186   ret[8] = A[4] * A[9] * A[15] - A[4] * A[11] * A[13] - A[8] * A[5] * A[15] + A[8] * A[7] * A[13] + A[12] * A[5] * A[11] - A[12] * A[7] * A[9];
187   ret[12] = -A[4] * A[9] * A[14] + A[4] * A[10] * A[13] + A[8] * A[5] * A[14] - A[8] * A[6] * A[13] - A[12] * A[5] * A[10] + A[12] * A[6] * A[9];
188
189   ret[1] = -A[1] * A[10] * A[15] + A[1] * A[11] * A[14] + A[9] * A[2] * A[15] - A[9] * A[3] * A[14] - A[13] * A[2] * A[11] + A[13] * A[3] * A[10];
190   ret[5] = A[0] * A[10] * A[15] - A[0] * A[11] * A[14] - A[8] * A[2] * A[15] + A[8] * A[3] * A[14] + A[12] * A[2] * A[11] - A[12] * A[3] * A[10];
191   ret[9] = -A[0] * A[9] * A[15] + A[0] * A[11] * A[13] + A[8] * A[1] * A[15] - A[8] * A[3] * A[13] - A[12] * A[1] * A[11] + A[12] * A[3] * A[9];
192   ret[13] = A[0] * A[9] * A[14] - A[0] * A[10] * A[13] - A[8] * A[1] * A[14] + A[8] * A[2] * A[13] + A[12] * A[1] * A[10] - A[12] * A[2] * A[9];
193
194   ret[2] = A[1] * A[6] * A[15] - A[1] * A[7] * A[14] - A[5] * A[2] * A[15] + A[5] * A[3] * A[14] + A[13] * A[2] * A[7] - A[13] * A[3] * A[6];
195   ret[6] = -A[0] * A[6] * A[15] + A[0] * A[7] * A[14] + A[4] * A[2] * A[15] - A[4] * A[3] * A[14] - A[12] * A[2] * A[7] + A[12] * A[3] * A[6];
196   ret[10] = A[0] * A[5] * A[15] - A[0] * A[7] * A[13] - A[4] * A[1] * A[15] + A[4] * A[3] * A[13] + A[12] * A[1] * A[7] - A[12] * A[3] * A[5];
197   ret[14] = -A[0] * A[5] * A[14] + A[0] * A[6] * A[13] + A[4] * A[1] * A[14] - A[4] * A[2] * A[13] - A[12] * A[1] * A[6] + A[12] * A[2] * A[5];
198
199   ret[3] = -A[1] * A[6] * A[11] + A[1] * A[7] * A[10] + A[5] * A[2] * A[11] - A[5] * A[3] * A[10] - A[9] * A[2] * A[7] + A[9] * A[3] * A[6];
200   ret[7] = A[0] * A[6] * A[11] - A[0] * A[7] * A[10] - A[4] * A[2] * A[11] + A[4] * A[3] * A[10] + A[8] * A[2] * A[7] - A[8] * A[3] * A[6];
201   ret[11] = -A[0] * A[5] * A[11] + A[0] * A[7] * A[9] + A[4] * A[1] * A[11] - A[4] * A[3] * A[9] - A[8] * A[1] * A[7] + A[8] * A[3] * A[5];
202   ret[15] = A[0] * A[5] * A[10] - A[0] * A[6] * A[9] - A[4] * A[1] * A[10] + A[4] * A[2] * A[9] + A[8] * A[1] * A[6] - A[8] * A[2] * A[5];
203
204   var det = A[0] * ret[0] + A[1] * ret[4] + A[2] * ret[8] + A[3] * ret[12];
205
206   if (det === 0) {
207     throw "no inverse";
208   }
209
210   return dali.matrixByScalar(ret, 1 / det);
211 };
212
213 /**
214  * Radian to degree
215  * @method degree
216  * @param {float} radians
217  * @return {float} degrees
218  */
219 dali.degree = function(radians) {
220   "use strict";
221   return (radians * 180.0) / Math.PI;
222 };
223
224 /**
225  * Degree to Radians
226  * @method radian
227  * @param {float} degree
228  * @return {float} radian
229  */
230 dali.radian = function(degrees) {
231   "use strict";
232   return (degrees / 180.0) * Math.PI;
233 };
234
235 /**
236  * Length of a vector
237  * @method vectorLength
238  * @param {array} Vector4
239  * @return {float} The length of a vector
240  */
241 dali.vectorLength = function(array) {
242   "use strict";
243   var N = 3; // array.length;
244
245   var length = 0;
246   for (var i = 0; i < N; ++i) {
247     length += array[i] * array[i];
248   }
249   return Math.sqrt(length);
250 };
251
252 /**
253  * Length of a vector squared
254  * @method vectorLengthSquared
255  * @param {array} Vector4
256  * @return {float} The length of a vector squared
257  */
258 dali.vectorLengthSquared = function(array) {
259   "use strict";
260   var N = 3; // array.length;
261
262   var length = 0;
263   for (var i = 0; i < N; ++i) {
264     length += array[i] * array[i];
265   }
266   return length;
267 };
268
269 /**
270  * Normalized vector
271  * @method normalize
272  * @param {array} Vector4
273  * @return {float} The normalized vector
274  */
275 dali.normalize = function(array) {
276   "use strict";
277   var N = 3; // array.length;
278
279   var length = 0;
280   for (var i = 0; i < 3; ++i) {
281     length += array[i] * array[i];
282   }
283   length = Math.sqrt(length);
284
285   if (length !== 0) {
286     var ret = [];
287     for (i = 0; i < N; ++i) {
288       ret.push(array[i] / length);
289     }
290     for (i = N; i < array.length; ++i) {
291       ret.push(array[i]);
292     }
293     return ret;
294   } else {
295     return array;
296   }
297
298 };
299
300 /**
301  * AxisAngle conversion to Quaternion
302  * @method axisAngleToQuaternion
303  * @param {array} axisAngle Vector4 [Axis.x, Axis.y, Axis.z, Angle]
304  * @return {array} Quaternion
305  */
306 dali.axisAngleToQuaternion = function(axisAngle) {
307   "use strict";
308   var an = dali.normalize(axisAngle);
309   var angle = axisAngle[axisAngle.length - 1];
310   var halfTheta = angle * 0.5;
311   var sinThetaByTwo = Math.sin(halfTheta);
312   var cosThetaByTwo = Math.cos(halfTheta);
313   return [an[0] * sinThetaByTwo,
314           an[1] * sinThetaByTwo,
315           an[2] * sinThetaByTwo,
316           cosThetaByTwo
317          ];
318 };
319
320 /**
321  * Vector3 dot product
322  * @method vectorDot
323  * @param {array} v1 Vector3
324  * @param {array} v2 Vector3
325  * @return {array} Quaternion
326  */
327 dali.vectorDot = function(v1, v2) {
328   "use strict";
329   return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
330 };
331
332 /**
333  * Vector4 dot product
334  * @method vectorDot
335  * @param {array} v1 Vector4
336  * @param {array} v2 Vector4
337  * @return {float} Dot product
338  */
339 dali.vectorDot4 = function(v1, v2) {
340   "use strict";
341   return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
342 };
343
344 /**
345  * Vector3 cross product
346  * @method vectorCross
347  * @param {array} v1 Vector3
348  * @param {array} v2 Vector3
349  * @return {array} Vector3 cross product
350  */
351 dali.vectorCross = function(v1, v2) {
352   "use strict";
353   var v1X = v1[0];
354   var v1Y = v1[1];
355   var v1Z = v1[2];
356
357   var v2X = v2[0];
358   var v2Y = v2[1];
359   var v2Z = v2[2];
360
361   return [v1Y * v2Z - v1Z * v2Y,
362           v1Z * v2X - v1X * v2Z,
363           v1X * v2Y - v1Y * v2X
364          ];
365 };
366
367 /**
368  * VectorN dot product
369  * @method vectorByScalar
370  * @param {array} v1 VectorN
371  * @param {array} v2 VectorN
372  * @return {array} VectorN * s
373  */
374 dali.vectorByScalar = function(v1, s) {
375   "use strict";
376   var ret = [];
377   for (var i = 0, len = v1.length; i < len; i++) {
378     ret.push(v1[i] * s);
379   }
380   return ret;
381 };
382
383 /**
384  * VectorN dot product
385  * @method vectorAdd
386  * @param {array} v1 VectorN
387  * @param {array} v2 VectorN
388  * @param {array} ..vN VectorN
389  * @return {array} v1 + v2 + ... + vN
390  */
391 dali.vectorAdd = function() {
392   "use strict";
393   var ret = arguments[0];
394   var l = ret.length;
395   for (var i = 1, len = arguments.length; i < len; i++) {
396     var v = arguments[i];
397     for (var j = 0; j < l; j++) {
398       ret[j] += v[j];
399     }
400   }
401   return ret;
402 };
403
404 /**
405  * Quaternion by quaternion
406  * @method quatByQuat
407  * @param {array} q1 Quaternion
408  * @param {array} q2 Quaternion
409  * @return {array} Quaternion
410  */
411 dali.quatByQuat = function(q1, q2) {
412   "use strict";
413   var q1X = q1[0];
414   var q1Y = q1[1];
415   var q1Z = q1[2];
416   var q1W = q1[3];
417
418   var q2X = q2[0];
419   var q2Y = q2[1];
420   var q2Z = q2[2];
421   var q2W = q2[3];
422
423   return [q1Y * q2Z - q1Z * q2Y + q1W * q2X + q1X * q2W,
424           q1Z * q2X - q1X * q2Z + q1W * q2Y + q1Y * q2W,
425           q1X * q2Y - q1Y * q2X + q1W * q2Z + q1Z * q2W,
426           q1W * q2W - dali.vectorDot(q1, q2)
427          ];
428 };
429
430 /**
431  * Quaternion to Vector4 Axis angle
432  * @method quaternionToAxisAngle
433  * @param {array} q Quaternion
434  * @return {array} Vector4 [Axis.x, Axis.y, Axis.z, Angle]
435  */
436 dali.quaternionToAxisAngle = function(q) {
437   "use strict";
438   var angle = Math.acos(q[3]);
439   var sine = Math.sin(angle);
440
441   if (sine === 0.0) {
442     throw "Cannot convert quaternion";
443   }
444
445   var sinfThetaInv = 1.0 / sine;
446
447   return [q[0] * sinfThetaInv,
448           q[1] * sinfThetaInv,
449           q[2] * sinfThetaInv,
450           angle * 2.0
451          ];
452 };
453
454 /**
455  * Euler angles to Quaternion
456  * @method eulerToQuaternion
457  * @param {float} rxPitch Euler radians pitch
458  * @param {float} ryYaw Euler radians yaw
459  * @param {float} rzRoll Euler radians roll
460  * @return {array} Quaternion
461  */
462 dali.eulerToQuaternion = function(rXPitch, rYYaw, rZRoll)
463 {
464   var halfX = 0.5 * rXPitch;
465   var halfY = 0.5 * rYYaw;
466   var halfZ = 0.5 * rZRoll;
467
468   var cosX2 = Math.cos(halfX);
469   var cosY2 = Math.cos(halfY);
470   var cosZ2 = Math.cos(halfZ);
471
472   var sinX2 = Math.sin(halfX);
473   var sinY2 = Math.sin(halfY);
474   var sinZ2 = Math.sin(halfZ);
475
476   return [ cosZ2 * cosY2 * sinX2 - sinZ2 * sinY2 * cosX2,
477            cosZ2 * sinY2 * cosX2 + sinZ2 * cosY2 * sinX2,
478            sinZ2 * cosY2 * cosX2 - cosZ2 * sinY2 * sinX2,
479            cosZ2 * cosY2 * cosX2 + sinZ2 * sinY2 * sinX2 ];
480 };
481
482 /**
483  * Euler angles to Vector4 Axis angle
484  * @method eulerToAxisAngle
485  * @param {float} eulerInDegrees
486  * @return {array} Vector4 [Axis.x, Axis.y, Axis.z, Angle]
487  */
488 dali.eulerToAxisAngle = function(eulerInDegrees)
489 {
490   var q = dali.eulerToQuaternion(dali.radian(eulerInDegrees[0]),dali.radian(eulerInDegrees[1]), dali.radian(eulerInDegrees[2]));
491   var aa = dali.quaternionToAxisAngle(q);
492   aa[3] = dali.degree(aa[3]); // @todo - radian?
493   return aa;
494 };
495
496 /**
497  * Axis angle to Euler
498  * @method axisAngleToEuler
499  * @param {float} axisAngle [Axis.x, Axis.y, Axis.z, Angle]
500  * @return {array} Vector4 [roll, pitch, yaw]
501  */
502 dali.axisAngleToEuler = function(axisAngle)
503 {
504   // presume return from dali.js is degrees
505   axisAngle[3] = dali.radian(axisAngle[3]);
506   var q = dali.axisAngleToQuaternion(axisAngle);
507   return dali.quaternionToEuler(q).map(dali.degree);
508 };
509
510 /**
511  * Euler angles to Vector4 Axis angle
512  * @method quaternionToMatrix
513  * @param {float} axisAngle [Axis.x, Axis.y, Axis.z, Angle]
514  * @return {array} Vector4
515  */
516 dali.quaternionToMatrix = function(q) {
517   "use strict";
518   var x = q[0];
519   var y = q[1];
520   var z = q[2];
521   var w = q[3];
522   var xx = x * x;
523   var yy = y * y;
524   var zz = z * z;
525   var xy = x * y;
526   var xz = x * z;
527   var wx = w * x;
528   var wy = w * y;
529   var wz = w * z;
530   var yz = y * z;
531
532   var m = [1, 0, 0, 0,
533            0, 1, 0, 0,
534            0, 0, 1, 0,
535            0, 0, 0, 1];
536
537   m[0] = 1.0 - 2.0 * (yy + zz);
538   m[1] = 2.0 * (xy + wz);
539   m[2] = 2.0 * (xz - wy);
540   m[3] = 0.0;
541
542   m[4] = 2.0 * (xy - wz);
543   m[5] = 1.0 - 2.0 * (xx + zz);
544   m[6] = 2.0 * (yz + wx);
545   m[7] = 0.0;
546
547   m[8] = 2.0 * (xz + wy);
548   m[9] = 2.0 * (yz - wx);
549   m[10] = 1.0 - 2.0 * (xx + yy);
550   m[11] = 0.0;
551
552   m[12] = 0.0;
553   m[13] = 0.0;
554   m[14] = 0.0;
555   m[15] = 1.0;
556
557   return m;
558 };
559
560 /**
561  * Quaternion to Euler
562  * @method quaternionToEuler
563  * @param {array} q Quaternion
564  * @return {array} Vector3 [roll, pitch, yaw]
565  */
566 dali.quaternionToEuler = function(q) {
567   "use strict";
568   var x = q[0];
569   var y = q[1];
570   var z = q[2];
571   var w = q[3];
572
573   var sqw = w * w;
574   var sqx = x * x;
575   var sqy = y * y;
576   var sqz = z * z;
577
578   return [ Math.atan2(2.0 * (y * z + x * w), -sqx - sqy + sqz + sqw),
579            Math.asin(-2.0 * (x * z - y * w)),
580            Math.atan2(2.0 * (x * y + z * w), sqx - sqy - sqz + sqw)];
581 };
582
583
584 /**
585  * Gets screen coordinates of world position
586  * @method worldToScreen
587  * @param {array} position array
588  * @param {Dali.RenderTask} renderTask Dali RenderTask object
589  * @return {array} Vector3 Screen position
590  */
591 dali.worldToScreen = function(position, renderTask) {
592   "use strict";
593   var useFirstRenderTask = false;
594
595   if (typeof renderTask === "undefined") {
596     useFirstRenderTask = true;
597   } else if (renderTask === null) { // null is an object
598     useFirstRenderTask = true;
599   }
600
601   if (useFirstRenderTask) {
602     var tasks = dali.stage.getRenderTaskList();
603     renderTask = tasks.getTask(0);
604     tasks.delete(); // wrapper
605   }
606
607   var camera = renderTask.getCameraActor();
608   var pos = renderTask.getCurrentViewportPosition();
609   var size = renderTask.getCurrentViewportSize();
610
611   var mat = dali.matrixByMatrix(camera.viewMatrix, camera.projectionMatrix);
612   var p = dali.matrixByVector(mat, position);
613   var depthRange = [0, 1];
614   var viewport = [pos[0], pos[1], size[0], size[1]];
615
616   var div;
617   // homogenous divide
618   if(0.0 === p[3]) {
619     div = 1.0;
620   } else {
621     div = 1 / p[3];
622   }
623
624   camera.delete(); // wrapper
625
626   return [
627     (1 + p[0] * div) * viewport[2] / 2 + viewport[0], (1 - p[1] * div) * viewport[3] / 2 + viewport[1], (p[2] * div) * (depthRange[1] - depthRange[0]) + depthRange[0],
628     div
629   ];
630 };
631
632 /**
633  * Gets matrix identity
634  * @method matrixIdentity
635  * @return {array} Matrix4 identity
636  */
637 dali.matrixIdentity = function() {
638   "use strict";
639   return [1, 0, 0, 0,
640           0, 1, 0, 0,
641           0, 0, 1, 0,
642           0, 0, 0, 1
643          ];
644 };
645
646 /**
647  * Gets matrix identity with position transformation
648  * @method matrixTransform
649  * @param {float} x X position
650  * @param {float} y Y position
651  * @param {float} z Z position
652  * @return {array} Matrix4
653  */
654 dali.matrixTransform = function(x, y, z) {
655   "use strict";
656   return [1, 0, 0, 0,
657           0, 1, 0, 0,
658           0, 0, 1, 0,
659           x, y, z, 1
660          ];
661 };
662
663 /**
664  * Gets matrix identity with position transformation
665  * @method screenToPlaneLocal
666  * @param {float} screenX Screen X position
667  * @param {float} screenY Screen Y position
668  * @param {Dali.RenderTask} Dali RenderTask
669  * @param {array} planeOrientationMatrix
670  * @param {float} planeWidth
671  * @param {float} planeHeight
672  * @return {array} Local coordinates
673  */
674 dali.screenToPlaneLocal = function(screenX, screenY, renderTask, planeOrientationMatrix, planeWidth, planeHeight) {
675   "use strict";
676
677   var camera = renderTask.getCameraActor();
678
679   var pos = renderTask.getCurrentViewportPosition();
680   var size = renderTask.getCurrentViewportSize();
681   var viewportX = pos[0];
682   var viewportY = pos[1];
683   var viewportW = size[0];
684   var viewportH = size[1];
685   var modelView = dali.matrixByMatrix(planeOrientationMatrix, camera.viewMatrix);
686
687   var inverseMvp = dali.matrixInverse(
688     dali.matrixByMatrix(modelView, camera.projectionMatrix));
689
690   var screenPos = [screenX - viewportX,
691                    viewportH - (screenY - viewportY),
692                    0.0, 1.0
693                   ];
694
695   screenPos[2] = 0.0;
696
697   var oglScreenPos = [(screenPos[0] / viewportW) * 2 - 1, (screenPos[1] / viewportH) * 2 - 1, (screenPos[2]) * 2 - 1,
698                       1
699                      ];
700
701
702   var nearPoint = dali.matrixByVector(inverseMvp, oglScreenPos);
703
704   if (nearPoint[3] === 0.0) {
705     throw "Unproject near fails";
706   }
707
708   nearPoint[3] = 1 / nearPoint[3];
709   nearPoint[0] = nearPoint[0] * nearPoint[3];
710   nearPoint[1] = nearPoint[1] * nearPoint[3];
711   nearPoint[2] = nearPoint[2] * nearPoint[3];
712
713
714   oglScreenPos[2] = 1.0 * 2 - 1;
715
716   var farPoint = dali.matrixByVector(inverseMvp, oglScreenPos);
717
718   if (farPoint[3] === 0.0) {
719     throw "Unproject far fails";
720   }
721
722   farPoint[3] = 1 / farPoint[3];
723   farPoint[0] = farPoint[0] * farPoint[3];
724   farPoint[1] = farPoint[1] * farPoint[3];
725   farPoint[2] = farPoint[2] * farPoint[3];
726
727   if (!((farPoint[2] < 0) && (nearPoint[2] > 0))) {
728     throw "ray not crossing xy plane";
729   }
730
731   var dist = nearPoint[2] / (nearPoint[2] - farPoint[2]);
732
733   var intersect = [nearPoint[0] + (farPoint[0] - nearPoint[0]) * dist,
734                    nearPoint[1] + (farPoint[1] - nearPoint[1]) * dist,
735                    0.0
736                   ];
737
738   intersect[0] = intersect[0] + planeWidth * 0.5;
739   intersect[1] = intersect[1] + planeHeight * 0.5;
740
741   return intersect;
742 };
743
744 /**
745  * Gets matrix identity with position transformation
746  * @method screenToLocal
747  * @param {float} screenX Screen X position
748  * @param {float} screenY Screen Y position
749  * @param {Dali.Actor} actor Dali Actor
750  * @param {Dali.RenderTask} renderTask Dali RenderTask
751  * @return {array} Local coordinates
752  */
753 dali.screenToLocal = function(screenX, screenY, actor, renderTask) {
754   "use strict";
755   return dali.screenToPlaneLocal(screenX, screenY, renderTask, actor.worldMatrix, actor.size[0], actor.size[1]);
756 };
757
758 /**
759  * Screen to local coordinates in the XY plane
760  * @method screenToXY
761  * @param {float} screenX Screen X position
762  * @param {float} screenY Screen Y position
763  * @param {Dali.Actor} actor Dali Actor
764  * @param {Dali.RenderTask} renderTask Dali RenderTask
765  * @return {array} Local coordinates
766  */
767 dali.screenToXY = function(screenX, screenY, actor, renderTask) {
768   "use strict";
769   var size = dali.stage.getSize();
770   return dali.screenToPlaneLocal(screenX, screenY,
771                                  renderTask,
772                                  dali.matrixIdentity(),
773                                  size[0],
774                                  size[1]);
775 };
776
777 /**
778  * Screen to local coordinates in the YZ plane
779  * @method screenToYZ
780  * @param {float} screenX Screen X position
781  * @param {float} screenY Screen Y position
782  * @param {Dali.Actor} actor Dali Actor
783  * @param {Dali.RenderTask} renderTask Dali RenderTask
784  * @return {array} Local coordinates
785  */
786 dali.screenToYZ = function(screenX, screenY, actor, renderTask) {
787   "use strict";
788   var size = dali.stage.getSize();
789   var q = dali.axisAngleToQuaternion( [0, 1, 0, dali.radian(90)] );
790   return dali.screenToPlaneLocal(screenX, screenY,
791                                  renderTask,
792                                  dali.quaternionToMatrix(q),
793                                  size[0],
794                                  size[1]);
795 };
796
797 /**
798  * Screen to local coordinates in the XZ plane
799  * @method screenToXZ
800  * @param {float} screenX Screen X position
801  * @param {float} screenY Screen Y position
802  * @param {Dali.Actor} actor Dali Actor
803  * @param {Dali.RenderTask} renderTask Dali RenderTask
804  * @return {array} Local coordinates
805  */
806 dali.screenToXZ = function(screenX, screenY, actor, renderTask) {
807   "use strict";
808   var size = dali.stage.getSize();
809   var q = dali.axisAngleToQuaternion( [1, 0, 0, dali.radian(90)] );
810   return dali.screenToPlaneLocal(screenX, screenY,
811                                  renderTask,
812                                  dali.quaternionToMatrix(q),
813                                  size[0],
814                                  size[1]);
815 };
816
817 /**
818  * Screen coordinates for the given renderTask
819  * @method screenCoordinates
820  * @param {Dali.Actor} actor Dali Actor
821  * @param {Dali.RenderTask} renderTask Dali RenderTask
822  * @return {array} Local coordinates
823  */
824 dali.screenCoordinates = function(actor, renderTask) {
825   "use strict";
826   var size = actor.size;
827   var w2 = size[0] / 2;
828   var h2 = size[1] / 2;
829   var actorWorldMatrix = actor.worldMatrix;
830   var actorWorldPosition = actor.worldPosition;
831
832   return {
833     topLeft: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [-w2, -h2, 0]), renderTask),
834     topRight: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [+w2, -h2, 0]), renderTask),
835     bottomRight: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [+w2, +h2, 0]), renderTask),
836     bottomLeft: dali.worldToScreen(dali.matrixByVector(actorWorldMatrix, [-w2, +h2, 0]), renderTask),
837     centre: dali.worldToScreen(actorWorldPosition, renderTask)
838   };
839 };
840
841 /**
842  * Screen coordinates for the given renderTask
843  * @method screenCoordinates
844  * @param {Dali.Actor} actor Dali Actor
845  * @param {Dali.RenderTask} renderTask Dali RenderTask
846  * @return {array} Local coordinates
847  */
848 dali.screenToActor = function(actor, screenPos, renderTask) {
849   "use strict";
850   // , function will return coordinates in relation to actor`s anchorPoint (client coordinates).
851   var useFirstRenderTask = false;
852
853   if (typeof renderTask === "undefined") {
854     useFirstRenderTask = true;
855   } else if (renderTask === null) { // null is an object
856     useFirstRenderTask = true;
857   }
858
859   if (useFirstRenderTask) {
860     var tasks = dali.stage.getRenderTaskList();
861     renderTask = tasks.getTask(0);
862     tasks.delete(); // wrapper
863   }
864
865   var camera = renderTask.getCameraActor();
866   var vpp = renderTask.getCurrentViewportPosition();
867   var vps = renderTask.getCurrentViewportSize();
868
869   var mat = dali.matrixByMatrix(camera.projectionMatrix, camera.viewMatrix);
870
871   var inverseMvp = dali.matrixInverse(mat);
872
873   var x = screenPos[0];
874   var y = screenPos[1];
875   var z = screenPos[2];
876
877   var objectPos = dali.matrixByVector(inverseMvp,
878                                       // normalized +-1
879                                       [((x - vpp[0]) / vps[0]) * 2.0 - 1.0, ((y - vpp[1]) / vps[1]) * 2.0 - 1.0, (z * 2.0) - 1.0,
880                                        1.0
881                                       ]);
882
883   if (objectPos[3] === 0.0) {
884     throw "Cannot find screen Position";
885   }
886
887   objectPos[3] = 1 / objectPos[3];
888
889   return [objectPos[0] * objectPos[3],
890           objectPos[1] * objectPos[3],
891           objectPos[2] * objectPos[3],
892           objectPos[3]
893          ];
894 };
895
896
897 //------------------------------------------------------------------------------
898 //
899 // Utils Module
900 //
901 //------------------------------------------------------------------------------
902
903 /**
904  * Cache to fix the dali get/set thread issue
905  *
906  * Property sets are cached and cleared at the renderFinished callback
907  */
908 dali.internalUniqueId = function() {
909   "use strict";
910 };
911
912 dali.internalUniqueId.prototype._id = 0;
913 dali.internalUniqueId.prototype.generateId = function() {
914   "use strict";
915   return ++dali.internalUniqueId.prototype._id;
916 };
917
918 dali.internalPropertyCacheEnable = true;
919 dali.internalPropertyCache = {};
920
921 /**
922  * Merge two objects together in a simplistic key,value merge
923  * @method mergeObjects
924  * @param {object} o1 first object
925  * @param {object} o2 second object
926  * @return {object} The merged objects
927  */
928 dali.mergeObjects = function(o1, o2) {
929   "use strict";
930   for (var p in o2) {
931     try {
932       // Property in destination object set; update its value.
933       if ( o2[p].constructor === Object){
934         o1[p] = dali.mergeObjects(o1[p], o2[p]);
935
936       } else {
937         o1[p] = o2[p];
938       }
939     } catch(e) {
940       // Property in destination object not set; create it and set its value.
941       o1[p] = o2[p];
942     }
943   }
944   return o1;
945 };
946
947 //------------------------------------------------------------------------------
948 //
949 // Callbacks Module
950 //
951 // Data dali can request during update & render loop.
952 //
953 //------------------------------------------------------------------------------
954
955 /**
956  * Gets a glyph by rendering to a hidden browser canvas
957  */
958 /** @private */
959 dali.requestedGlyphImage = function(sFontFamily, sFontStyle, fFontSize, iChar) {
960   "use strict";
961
962   var buffer = document.createElement("canvas");
963   buffer.width = fFontSize;
964   buffer.height = fFontSize;
965   var ctx = buffer.getContext("2d");
966
967   ctx.font = sFontStyle + " " + fFontSize + "px " + sFontFamily;
968   ctx.fillText(String.fromCharCode(iChar), 0, 0 + fFontSize);
969
970   var imageData = ctx.getImageData(0, 0, fFontSize, fFontSize);
971
972   // emscripten checks only for this type if array in converting to strings
973   // (getImageData() returns Uint8CheckedArray or some such)
974   //  var uint8array = new Uint8Array( imageData.data );
975
976   return imageData.data; // return uint8array; //
977 };
978
979 /** @private */
980 dali.postRenderFunction = undefined;
981
982 /*
983  * End of renderering tasks
984  *  - Reset the property cache
985  */
986 /** @private */
987 dali.requestedRenderFinished = function() {
988   "use strict";
989   // reset the temporary cache
990   dali.internalPropertyCache = {};
991   if(dali.postRenderFunction) {
992     dali.postRenderFunction();
993   }
994 };
995
996 dali.setCallbackGetGlyphImage(dali.requestedGlyphImage);
997 dali.setCallbackRenderFinished(dali.requestedRenderFinished);
998
999 //------------------------------------------------------------------------------
1000 //
1001 // Property Marshalling Module
1002 //
1003 // Javascript objects are adorned with dali properties as they are created or
1004 // fetched from the C++ api
1005 //
1006 // Data is marshalled to avoid some of the necessary C++ memory management for
1007 // small property classes.
1008 //
1009 //------------------------------------------------------------------------------
1010 dali.__propertyTypeJsLut = { boolean: dali.PropertyType.BOOLEAN,
1011                              number: dali.PropertyType.FLOAT,
1012                              string: dali.PropertyType.STRING };
1013
1014 dali.__propertyValueCtor = {};
1015
1016 [ [dali.PropertyType.INTEGER.value, dali.PropertyValueInteger],
1017   [dali.PropertyType.FLOAT.value, dali.PropertyValueFloat],
1018   [dali.PropertyType.STRING.value, dali.PropertyValueString],
1019   [dali.PropertyType.VECTOR2.value, dali.PropertyValueVector2],
1020   [dali.PropertyType.VECTOR3.value, dali.PropertyValueVector3],
1021   [dali.PropertyType.VECTOR4.value, dali.PropertyValueVector4],
1022   [dali.PropertyType.MATRIX.value, dali.PropertyValueMatrix],
1023   [dali.PropertyType.MATRIX3.value, dali.PropertyValueMatrix3],
1024   [dali.PropertyType.ARRAY.value, dali.PropertyValueArray],
1025   [dali.PropertyType.MAP.value, dali.PropertyValueMap],
1026   [dali.PropertyType.RECTANGLE.value, dali.PropertyValueIntRect] ].map( function(ab) { dali.__propertyValueCtor[ ab[0] ] = ab[1]; } );
1027
1028 dali.propertyTypeFromJsValue = function(value) {
1029   return dali.__propertyTypeJsLut[ typeof(value) ];
1030 };
1031
1032 dali.propertyValueCtor = function(propertyType) {
1033   return dali.__propertyValueCtor[ propertyType.value ];
1034 };
1035
1036 /**
1037  * Create a Dali PropertyValue from a javascript value.
1038  * @method DaliPropertyValue
1039  * @param {object} object to retrieve the property type when value is an object
1040  * @param {string} name The name of the property
1041  * @return {Dali.PropertyValue} A Dali PropertyValue which must be '.delete()' when finished with
1042  */
1043 dali.DaliPropertyValue = function(object, name, value) {
1044   "use strict";
1045
1046   var setProperty = false;
1047   if (typeof (value) === "boolean") {
1048     setProperty = new dali.PropertyValueBoolean(value);
1049   } else if (typeof (value) === "number") {
1050     setProperty = new dali.PropertyValueFloat(value);
1051   } else if (typeof (value) === "string") {
1052     setProperty = new dali.PropertyValueString(value);
1053   } else if (typeof (value) === "object") {
1054     if (value.constructor === dali.PropertyValueValue) {
1055       setProperty = value;
1056     } else {
1057       var type = false;
1058       if (object) {
1059         type = object.getPropertyTypeFromName(name);
1060       }
1061       if (type === dali.PropertyType.ROTATION) {
1062         if (value.length === 3) {
1063           setProperty = new dali.PropertyValueEuler(value);
1064         } else {
1065           setProperty = new dali.PropertyValueAxisAngle(value);
1066         }
1067       } else if (value.length) {
1068         if (type === dali.PropertyType.ARRAY) {
1069           setProperty = new dali.PropertyValueArray(value);
1070         } else {
1071           if (value.length === 2) {
1072             setProperty = new dali.PropertyValueVector2(value);
1073           } else if (value.length === 3) {
1074             setProperty = new dali.PropertyValueVector3(value);
1075           } else if (value.length === 4) {
1076             if (type === dali.PropertyType.RECTANGLE) {
1077               setProperty = new dali.PropertyValueIntRect(value[0], value[1], value[2], value[3]);
1078             } else {
1079               setProperty = new dali.PropertyValueVector4(value);
1080             }
1081           } else if (value.length === 9) {
1082             setProperty = new dali.PropertyValueMatrix3(value);
1083           } else if (value.length === 16) {
1084             setProperty = new dali.PropertyValueMatrix(value);
1085           } else {
1086             throw new Error("Cannot set property");
1087           }
1088         }
1089       } else {
1090         // todo; I think a map has a length....
1091         setProperty = new dali.PropertyValueMap(value);
1092       }
1093     }
1094   } else {
1095     if (object) {
1096       throw object.toString() + " " + name.toString() + " " + value.toString();
1097     } else {
1098       throw name.toString() + " " + value.toString();
1099     }
1100   }
1101
1102   return setProperty;
1103 };
1104
1105 /**
1106  * Get the value type held in a PropertyValue and call '.delete()' to drop the C++ backing object
1107  * @method marshallProperty
1108  * @param {Dali.PropertyValue} p A Dali PropertyValue. This will be '.delete()'ed.
1109  * @return {any} The value held
1110  */
1111 /** @private */
1112 dali.marshallProperty = function(p) {
1113   "use strict";
1114
1115   var ret;
1116   var type = p.getType();
1117
1118   if (type === 0) {
1119     // raise?
1120     throw new Error("Property has no type?");
1121   } else if (type === dali.PropertyType.BOOLEAN.value) {
1122     ret = p.getBoolean();
1123   } else if (type === dali.PropertyType.FLOAT.value) {
1124     ret = p.getFloat();
1125   } else if (type === dali.PropertyType.INTEGER.value) {
1126     ret = p.getInteger();
1127   } else if (type === dali.PropertyType.VECTOR2.value) {
1128     ret = p.getVector2();
1129   } else if (type === dali.PropertyType.VECTOR3.value) {
1130     ret = p.getVector3();
1131   } else if (type === dali.PropertyType.VECTOR4.value) {
1132     ret = p.getVector4();
1133   } else if (type === dali.PropertyType.MATRIX3.value) {
1134     ret = p.getMatrix3();
1135   } else if (type === dali.PropertyType.MATRIX.value) {
1136     ret = p.getMatrix();
1137   } else if( type === dali.PropertyType.RECTANGLE ) {
1138     ret = p.getIntRect();
1139   } else if (type === dali.PropertyType.ROTATION.value) {
1140     ret = p.getRotation();
1141   } else if (type === dali.PropertyType.STRING.value) {
1142     ret = p.getString();
1143   } else if (type === dali.PropertyType.ARRAY.value) {
1144     ret = p.getArray();
1145   } else if (type === dali.PropertyType.MAP.value) {
1146     ret = p.getMap();
1147   }
1148   p.delete();
1149   return ret;
1150 };
1151
1152 /**
1153  * Set a value on an object by creating and deleting a Dali PropertyValue object
1154  * @method marshallSetProperty
1155  * @param {object} object The object who's property to set from
1156  * @param {string} name The property name
1157  * @param {any} value The Javascript value
1158  */
1159 /** @private */
1160 dali.marshallSetProperty = function(object, name, value) {
1161   "use strict";
1162   var setProperty = new dali.DaliPropertyValue(object, name, value);
1163
1164   if (setProperty) {
1165
1166     object.setProperty(name, setProperty);
1167
1168     //console.log("marshallSetProperty set property" + setProperty );
1169     setProperty.delete();
1170
1171     if(dali.internalPropertyCacheEnable) {
1172       // set in cache to fix dali get/set problem
1173       if("getId" in object ) // only with actors
1174       {
1175         var uniqueId = object.getId(); // _uniqueId;
1176         if (uniqueId !== undefined) {
1177           var objectDict = dali.internalPropertyCache[uniqueId];
1178           if (objectDict === undefined) {
1179             dali.internalPropertyCache[uniqueId] = {};
1180           }
1181           dali.internalPropertyCache[uniqueId][name] = value;
1182         }
1183       }
1184     }
1185   }
1186 };
1187
1188 /**
1189  * Get a Javascript value from an object by creating and deleting a PropertyValue
1190  * @method marshallGetProperty
1191  * @param {object} object The object who's property to get from
1192  * @param {string} name The property name
1193  * @return {any} The value of the property
1194  */
1195 /** @private */
1196 dali.marshallGetProperty = function(object, name) {
1197   "use strict";
1198
1199   if(dali.internalPropertyCacheEnable) {
1200     // is the value live in the cache? if so use that value instead
1201     if("getId" in object) { // only with actors
1202       var uniqueId = object.getId(); // _uniqueId;
1203       if (uniqueId !== undefined) {
1204         var objectDict = dali.internalPropertyCache[uniqueId];
1205         if (objectDict !== undefined) {
1206           var value = dali.internalPropertyCache[uniqueId][name];
1207           if (value !== undefined) {
1208             return value;
1209           }
1210         }
1211       }
1212     }
1213   }
1214
1215   var ret;
1216   var p;
1217   p = object.getProperty(name);
1218   if (!p) {
1219     throw new Error("Property doesnt exist?");
1220   }
1221   var type = p.getType();
1222
1223   if (type === 0) {
1224     // raise?
1225     throw new Error("Property has no type?");
1226   } else if (type === dali.PropertyType.BOOLEAN.value) {
1227     ret = p.getBoolean();
1228   } else if (type === dali.PropertyType.FLOAT.value) {
1229     ret = p.getFloat();
1230   } else if (type === dali.PropertyType.INTEGER.value) {
1231     ret = p.getInteger();
1232   } else if (type === dali.PropertyType.VECTOR2.value) {
1233     ret = p.getVector2();
1234   } else if (type === dali.PropertyType.VECTOR3.value) {
1235     ret = p.getVector3();
1236   } else if (type === dali.PropertyType.VECTOR4.value) {
1237     // VECTOR4
1238     ret = p.getVector4();
1239   } else if (type === dali.PropertyType.MATRIX3.value) {
1240     // MATRIX3
1241     ret = p.getMatrix3();
1242   } else if (type === dali.PropertyType.MATRIX.value) {
1243     // MATRIX
1244     ret = p.getMatrix();
1245   } else if( type === dali.PropertyType.RECTANGLE ) {
1246     ret = p.getIntRect();
1247   } else if (type === dali.PropertyType.ROTATION.value) {
1248     ret = p.getRotation();
1249   } else if (type === dali.PropertyType.STRING.value) {
1250     ret = p.getString();
1251   } else if (type === dali.PropertyType.ARRAY.value) {
1252     ret = p.getArray();
1253   } else if (type === dali.PropertyType.MAP.value) {
1254     ret = p.getMap();
1255   }
1256   p.delete();
1257   return ret;
1258 };
1259
1260
1261 /**
1262  * Set property accessors on the given handle for each property found on the handle
1263  * @method internalSetupProperties
1264  * @param {Dali.BaseHandle} handle A Dali property holding object
1265  * @return {Dali.BaseHandle} The same handle which has property accessors.
1266  */
1267 /** @private */
1268 dali.internalSetupProperties = function(handle) {
1269   "use strict";
1270   if(handle.ok()) {
1271     var props = handle.getProperties();
1272
1273     for (var i = 0; i < props.size(); i++) {
1274       // anon function because of closure with defineProperty
1275       // (if just variable in loop then the variable 'address' is captured, not the value
1276       //  so it becomes last value set)
1277       (function(name, object) {
1278         // @todo Dali error?? name lengths should never be zero
1279         if (name.length) {
1280           Object.defineProperty(handle, name, {
1281             enumerable: true,
1282             configurable: false,
1283             get: function() {
1284               return dali.marshallGetProperty(handle, name);
1285             },
1286             set: function(newValue) {
1287               dali.marshallSetProperty(handle, name, newValue);
1288             }
1289           });
1290         }
1291       })(props.get(i), handle);
1292     }
1293
1294     // handle._uniqueId = dali.internalUniqueId.prototype.generateId();
1295   }
1296
1297   return handle;
1298 };
1299
1300 //------------------------------------------------------------------------------
1301 //
1302 // Handle API Module
1303 //
1304 // API Wrappers for some Dali.Handle methods to marshall properties
1305 //
1306 //------------------------------------------------------------------------------
1307
1308 /**
1309  * Register a new property and add JS style property accessors
1310  * @method registerProperty
1311  * @param {string} name The property name
1312  * @param {any} value Any Javascript value
1313  * @return {int} The registered properties ID
1314  */
1315 dali.Handle.prototype.registerProperty = function(name, value) {
1316   "use strict";
1317   var ret = -1;
1318
1319   var propertyValue = new dali.DaliPropertyValue(null, name, value);
1320   ret = this.__registerProperty(name, propertyValue);
1321   propertyValue.delete(); // wrapper
1322   Object.defineProperty(this, name, {
1323     enumerable: true,
1324     configurable: false,
1325     get: function() {
1326       return dali.marshallGetProperty(this, name);
1327     },
1328     set: function(newValue) {
1329       dali.marshallSetProperty(this, name, newValue);
1330     }
1331   });
1332
1333   return ret;
1334 };
1335
1336 /**
1337  * Register a new animated property
1338  * @method registerAnimatedProperty
1339  * @param {string} name The property name
1340  * @param {any} value Any Javascript value
1341  * @return {int} The registered properties ID
1342  */
1343 dali.Handle.prototype.registerAnimatedProperty = function(name, value) {
1344   "use strict";
1345   var ret = -1;
1346
1347   var propertyValue = new dali.DaliPropertyValue(null, name, value);
1348   ret = this.__registerAnimatedProperty(name, propertyValue);
1349   propertyValue.delete(); // wrapper
1350   Object.defineProperty(this, name, {
1351     enumerable: true,
1352     configurable: false,
1353     get: function() {
1354       return dali.marshallGetProperty(this, name);
1355     },
1356     set: function(newValue) {
1357       dali.marshallSetProperty(this, name, newValue);
1358     }
1359   });
1360   return ret;
1361 };
1362
1363 //------------------------------------------------------------------------------
1364 //
1365 // Stage Module
1366 //
1367 //------------------------------------------------------------------------------
1368 dali.Stage.prototype.getRootLayer = function() {
1369   "use strict";
1370   var root = this.__getRootLayer();
1371   dali.internalSetupProperties(root);
1372   return root;
1373 };
1374
1375 //------------------------------------------------------------------------------
1376 //
1377 // PropertyMap Module
1378 //
1379 // API Wrappers for some Dali.PropertyMap methods to marshall properties
1380 //
1381 //------------------------------------------------------------------------------
1382
1383 /**
1384  * Insert a value into the PropertyMap
1385  * @method insert
1386  * @param {string} key The key
1387  * @param {any} value Any Javascript value
1388  * @param {PropertyType} propertyType The Dali property type
1389  */
1390 dali.PropertyMap.prototype.insert = function(key, value, propertyType) {
1391   "use strict";
1392
1393   var type = propertyType;
1394
1395   if( propertyType === undefined ) { // can be optional
1396     propertyType = dali.propertyTypeFromJsValue(value);
1397   }
1398
1399   var constructor = dali.propertyValueCtor(propertyType);
1400
1401   var setProperty = constructor( value );
1402
1403   if(setProperty) {
1404     this.__insert(key, setProperty);
1405     setProperty.delete();
1406   }
1407 };
1408
1409 /**
1410  * Get a value from the PropertyMap
1411  * @method get
1412  * @param {string} key The key
1413  * @return The Javascript value
1414  */
1415 dali.PropertyMap.prototype.get = function(key) {
1416   "use strict";
1417   var p = this.__get(key);
1418
1419   var ret = dali.marshallProperty(p);
1420
1421   // p.delete(); // @todo should we delete here?
1422
1423   return ret;
1424 };
1425
1426 //------------------------------------------------------------------------------
1427 //
1428 // PropertyBuffer Module
1429 //
1430 // API Wrappers for some Dali.PropertyBuffer methods to marshall properties
1431 //
1432 //------------------------------------------------------------------------------
1433 var _propertyTypeInfoList = [
1434   [ dali.PropertyType.FLOAT.value, { size: 4, length: 1, dataView: Float32Array }],
1435   [ dali.PropertyType.INTEGER.value, { size: 4, length: 1, dataView: Int32Array }],
1436   [ dali.PropertyType.VECTOR2.value, { size: 2 * 4, length: 2, dataView: Float32Array }],
1437   [ dali.PropertyType.VECTOR3.value, { size: 3 * 4, length: 3, dataView: Float32Array }],
1438   [ dali.PropertyType.VECTOR4.value, { size: 4 * 4, length: 4, dataView: Float32Array }],
1439   [ dali.PropertyType.MATRIX3.value, { size: 9 * 4, length: 9, dataView: Float32Array }],
1440   [ dali.PropertyType.MATRIX.value, { size: 16 * 4, length: 16, dataView: Float32Array }]
1441 ];
1442
1443 var _propertyTypeInfo = {};
1444 function _createPropertyBuffer() {
1445   "use strict";
1446   for(var i = 0; i < _propertyTypeInfoList.length; i++) {
1447     _propertyTypeInfo[ _propertyTypeInfoList[i][0] ] = _propertyTypeInfoList[i][1];
1448   }
1449 }
1450
1451 _createPropertyBuffer();
1452
1453 /**
1454  * Create a Dali.PropertyBuffer from an info dictionary
1455  * @method createPropertyBuffer
1456  * @param {object} info
1457  * @param {any} value Any Javascript value
1458  * @param {PropertyType} propertyType The Dali property type
1459  * @example
1460  * var verts = createPropertyBuffer( {format: [ ["apos", dali.PropertyType.VECTOR2],
1461  *                                              ["acol", dali.PropertyType.VECTOR4] ],
1462  *                                    data: { "apos": [ [-halfQuadSize, -halfQuadSize],
1463  *                                                      [+halfQuadSize, -halfQuadSize],
1464  *                                                      [-halfQuadSize, +halfQuadSize],
1465  *                                                      [+halfQuadSize, +halfQuadSize]
1466  *                                                    ],
1467  *                                            "acol": [ [0, 0, 0, 1],
1468  *                                                      [1, 0, 1, 1],
1469  *                                                      [0, 1, 0, 1],
1470  *                                                      [1, 1, 1, 1]
1471  *                                                    ]
1472  *                                          }
1473  *                                   }
1474  */
1475 dali.createPropertyBuffer = function(info) {
1476   "use strict";
1477   var format = new dali.PropertyMap();
1478   var dataLength;
1479   var recordSize = 0;
1480   var i;
1481   for(i = 0; i < info.format.length; i++) {
1482     format.insert(info.format[i][0], info.format[i][1].value, dali.PropertyType.INTEGER);
1483     if(dataLength === undefined) {
1484       dataLength = info.data[info.format[i][0]].length;
1485     }
1486     assert(info.data[info.format[i][0]]);
1487     assert(dataLength === info.data[info.format[i][0]].length);
1488     recordSize += _propertyTypeInfo[info.format[i][1].value].size;
1489   }
1490
1491   var buffer = new ArrayBuffer(dataLength * recordSize);
1492
1493   var recordOffset = 0;
1494   var offset = 0;
1495   for(i = 0; i < dataLength; i++) {
1496     for(var j = 0; j < info.format.length; j++) {
1497       var name = info.format[j][0];
1498       var type = info.format[j][1].value;
1499       var length = _propertyTypeInfo[type].length;
1500       var DataView = _propertyTypeInfo[type].dataView;
1501       var view = new DataView(buffer, recordOffset + offset, length);
1502       offset += _propertyTypeInfo[type].size;
1503       if(length === 1) {
1504         view[0] = info.data[name][i];
1505       } else {
1506         for(var k = 0; k < length; k++) {
1507           view[k] = info.data[name][i][k];
1508         }
1509       }
1510     }
1511     offset = 0;
1512     recordOffset += recordSize;
1513   }
1514
1515   var propertyBuffer = new dali.PropertyBuffer(format);
1516
1517   propertyBuffer.setData(buffer, dataLength);
1518
1519   format.delete(); //
1520
1521   return propertyBuffer;
1522 };
1523
1524 //------------------------------------------------------------------------------
1525 //
1526 // Actor Module
1527 //
1528 // API Wrappers for some Dali.PropertyBuffer methods to marshall properties
1529 //
1530 //------------------------------------------------------------------------------
1531
1532 /**
1533  * Gets a parent with JS style property accessors
1534  * @method getParent
1535  * @return The parent
1536  */
1537 dali.Actor.prototype.getParent = function() {
1538   "use strict";
1539   var bareActor = this.__getParent();
1540   if(!bareActor.ok()) {
1541     bareActor.delete(); // wrapper
1542     bareActor = null;
1543   } else {
1544     // add properties to the bare Actor
1545     dali.internalSetupProperties(bareActor);
1546   }
1547   return bareActor;
1548 };
1549
1550 /**
1551  * Finds child by ID and adorns with JS style property accessors
1552  * @method findChildById
1553  * @param {int} index The ID of the child
1554  * @return The found child or null
1555  */
1556 dali.Actor.prototype.findChildById = function(index) {
1557   "use strict";
1558   var bareActor = this.__findChildById(index);
1559   if(!bareActor.ok()) {
1560     bareActor.delete(); // wrapper
1561     bareActor = null;
1562   } else {
1563     dali.internalSetupProperties(bareActor);
1564   }
1565   return bareActor;
1566 };
1567
1568 /**
1569  * Finds child by name and adorns with JS style property accessors
1570  * @method findChildByName
1571  * @param {string} name The ID of the child
1572  * @return The found child or null
1573  */
1574 dali.Actor.prototype.findChildByName = function(name) {
1575   "use strict";
1576   var bareActor = this.__findChildByName(name);
1577   if(!bareActor.ok()) {
1578     bareActor.delete(); // wrapper
1579     bareActor = null;
1580   } else {
1581     dali.internalSetupProperties(bareActor);
1582   }
1583   return bareActor;
1584 };
1585
1586 /**
1587  * Gets child at child index and adorns with JS style property accessors
1588  * @method getChildAt
1589  * @param {int} index The ID of the child
1590  * @return The found child or null
1591  */
1592 dali.Actor.prototype.getChildAt = function(index) {
1593   "use strict";
1594   var bareActor = this.__getChildAt(index);
1595   if(!bareActor.ok()) {
1596     bareActor.delete(); // wrapper
1597     bareActor = null;
1598   } else {
1599     dali.internalSetupProperties(bareActor);
1600   }
1601   return bareActor;
1602 };
1603
1604 /*
1605  * add children of actor to collection in depth first manner
1606  */
1607 /** @private */
1608 dali.internalDepthFirstCollection = function(actor, collection) {
1609   "use strict";
1610   for (var i = 0; i < actor.getChildCount(); i++) {
1611     var a = actor.getChildAt(i); // adds properties in dotted
1612     collection.push(a);
1613     dali.internalDepthFirstCollection(a, collection);
1614   }
1615 };
1616
1617 /**
1618  * Finds all children of the actor and adorns with JS style property accessors
1619  * @method findAllChildren
1620  * @return A list of children
1621  */
1622 dali.Actor.prototype.findAllChildren = function() {
1623   "use strict";
1624   var col = [];
1625   dali.internalDepthFirstCollection(this, col);
1626   return col;
1627 };
1628
1629 /**
1630  * Gets a childFinds all children of the actor and adorns with JS style property accessors
1631  * @method getChildren
1632  * @return A list of children
1633  */
1634 dali.Actor.prototype.getChildren = function() {
1635   "use strict";
1636   var col = [];
1637   for (var i = 0, len = this.getChildCount(); i < len; i++) {
1638     var c = this.getChildAt(i);
1639     col.push(c);
1640   }
1641   return col;
1642 };
1643
1644 /**
1645  * 'directChildren' kept for GUIBuilder support
1646  * @deprecated
1647  */
1648 dali.Actor.prototype.directChildren = dali.Actor.prototype.getChildren;
1649
1650 /**
1651  * Connects a callback to a signal by name
1652  * @method connect
1653  * @param {string} signalName The signal to connect to
1654  * @param {function} callback The callback to call
1655  * @param {Dali.SignalHolder} The signal holder object that can signal connection deletion
1656  * @return true if connection was possible
1657  */
1658 dali.Actor.prototype.connect = function(signalName, callback, signalHolder) {
1659   "use strict";
1660   // wrap in closure so we can setup properties in . notation
1661   // and add actor methods to c++ raw Actor
1662   if(signalHolder === undefined) {
1663     // default js signal holder if none provided
1664     signalHolder = dali.jsSignalHolder;
1665   }
1666
1667   return this.__connect( signalHolder,
1668                          signalName,
1669                          (function(cb) {
1670                            return function() {
1671                              var args = [dali.internalSetupProperties(arguments[0])];
1672                              for(var i = 1; i < arguments.length; i++) {
1673                                args.push( arguments[i] );
1674                              }
1675                              cb.apply(null, args);
1676                            };
1677                          })(callback)
1678                        );
1679 };
1680
1681 /**
1682  * Connects a callback to a property notification
1683  * @method setPropertyNotification
1684  * @param {string} property The property name
1685  * @param {string} condition The condition [False,LessTHan,GreaterThan,Inside,Outside,Step,VariableStep]
1686  * @param {any} arg0 The first property notification argument
1687  * @param {any} arg1 The second property notification argument
1688  * @param {function} callback The callback function
1689  * @param {Dali.SignalHolder} The signal holder object that can signal connection deletion
1690  * @return true if connection was possible
1691  */
1692 dali.Actor.prototype.setPropertyNotification = function(property, condition, arg0, arg1, callback, signalHolder) {
1693   "use strict";
1694
1695   if(signalHolder === undefined) {
1696     // default js signal holder if none provided
1697     signalHolder = dali.jsSignalHolder;
1698   }
1699
1700   var index = this.getPropertyIndex(property);
1701
1702   this.__setPropertyNotification(signalHolder, index, condition, arg0, arg1, callback);
1703 };
1704
1705 /**
1706  * Gets the renderer by index
1707  * @method getRendererAt
1708  * @param {int} index The index of the renderer
1709  * @return The Render or null
1710  */
1711 dali.Actor.prototype.getRendererAt = function(index) {
1712   "use strict";
1713   var renderer = this.__getRendererAt(index);
1714   if(!renderer.ok()) {
1715     renderer.delete(); // wrapper
1716     renderer = null;
1717   } else {
1718     dali.internalSetupProperties(renderer);
1719   }
1720   return renderer;
1721 };
1722
1723 /** private */
1724 dali.__ActorConstructor = dali.Actor;
1725
1726 /**
1727  * Construtor that adorns with JS style property accessors
1728  * @return The wrapped Dali.Actor object
1729  */
1730 dali.Actor = function() {
1731   "use strict";
1732   var a = new dali.__ActorConstructor();
1733   dali.internalSetupProperties(a);
1734   return a;
1735 };
1736
1737 //------------------------------------------------------------------------------
1738 //
1739 // New Mesh Module
1740 //
1741 //------------------------------------------------------------------------------
1742 dali.__ShaderConstructor = dali.Shader;
1743 dali.Shader = function(vertex, fragment, hints) {
1744   "use strict";
1745   var a = new dali.__ShaderConstructor(vertex, fragment, hints);
1746   dali.internalSetupProperties(a);
1747   return a;
1748 };
1749
1750 dali.__MaterialConstructor = dali.Material;
1751 dali.Material = function(shader) {
1752   "use strict";
1753   var a = new dali.__MaterialConstructor(shader);
1754   dali.internalSetupProperties(a);
1755   return a;
1756 };
1757
1758 dali.__RendererConstructor = dali.Renderer;
1759 dali.Renderer = function(geometry, material) {
1760   "use strict";
1761   var a = new dali.__RendererConstructor(geometry, material);
1762   dali.internalSetupProperties(a);
1763   return a;
1764 };
1765
1766 //------------------------------------------------------------------------------
1767 //
1768 // Animation Module
1769 //
1770 //------------------------------------------------------------------------------
1771 dali.__PathConstructor = dali.Path;
1772 dali.Path = function() {
1773   "use strict";
1774   var a = new dali.__PathConstructor();
1775   dali.internalSetupProperties(a);
1776   return a;
1777 };
1778
1779 /**
1780  * animateTo a value
1781  * @method animateTo
1782  * @param {object} The object
1783  * @param {string} propertyName The objects property name
1784  * @param {any} value The value
1785  * @param {string} alphaFunction The alpha function
1786  * @param {float} delay The delay
1787  * @param {float} duration The duration
1788  */
1789 dali.Animation.prototype.animateTo = function(object, propertyName, value, alphaFunction, delay, duration) {
1790   "use strict";
1791   var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
1792   if (propertyValue) {
1793     this.__animateTo(object, propertyName, propertyValue, alphaFunction, delay, duration);
1794     propertyValue.delete();
1795   } else {
1796     throw new Error("Unknown property?");
1797   }
1798 };
1799
1800 /**
1801  * animateBy a value
1802  * @method animateBy
1803  * @param {object} The object
1804  * @param {string} propertyName The objects property name
1805  * @param {any} value The value
1806  * @param {string} alphaFunction The alpha function
1807  * @param {float} delay The delay
1808  * @param {float} duration The duration
1809  */
1810 dali.Animation.prototype.animateBy = function(object, propertyName, value, alphaFunction, delay, duration) {
1811   "use strict";
1812   var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
1813   if (propertyValue) {
1814     this.__animateBy(object, propertyName, propertyValue, alphaFunction, delay, duration);
1815     propertyValue.delete();
1816   } else {
1817     throw new Error("Unknown property?");
1818   }
1819 };
1820
1821 /**
1822  * Animate a Path
1823  * @method animatePath
1824  * @param {object} The object
1825  * @param {Dali.Path} pathObject The path object
1826  * @param {array} forward The path forward vector
1827  * @param {string} alphaFunction The alpha function
1828  * @param {float} delay The delay
1829  * @param {float} duration The duration
1830  */
1831 dali.Animation.prototype.animatePath = function(object, pathObject, forward, alphaFunction, delay, duration) {
1832   "use strict";
1833   this.__animatePath(object, pathObject, forward, alphaFunction, delay, duration);
1834 };
1835
1836 /**
1837  * animateBetween a value
1838  * @method animateBetween
1839  * @param {object} The object
1840  * @param {string} propertyName The objects property name
1841  * @param {dali.KeyFrames} keyFrames The keyframes
1842  * @param {string} alphaFunction The alpha function
1843  * @param {float} delay The delay
1844  * @param {float} duration The duration
1845  */
1846 dali.Animation.prototype.animateBetween = function(object, propertyName, keyFrames, alphaFunction, delay, duration, interpolation) {
1847   "use strict";
1848   var propertyValue;
1849
1850   var daliKeyFrames = new dali.KeyFrames();
1851
1852   for(var i = 0; i < keyFrames.length; i++) {
1853     if(keyFrames[i].length > 2) { // has alpha
1854       propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
1855       if(!propertyValue) {
1856         throw new Error("Unknown property?");
1857       }
1858       daliKeyFrames.add(keyFrames[i][0], propertyValue, keyFrames[i][2]);
1859       propertyValue.delete();
1860     } else {
1861       propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
1862       if(!propertyValue) {
1863         throw new Error("Unknown property?");
1864       }
1865       daliKeyFrames.add(keyFrames[i][0], propertyValue);
1866       propertyValue.delete();
1867     }
1868   }
1869
1870   this.__animateBetween(object, propertyName, daliKeyFrames, alphaFunction, delay, duration, interpolation);
1871
1872   daliKeyFrames.delete();
1873
1874 };
1875
1876 //------------------------------------------------------------------------------
1877 //
1878 // RenderTask Module
1879 //
1880 //------------------------------------------------------------------------------
1881 dali.RenderTask.prototype.getCameraActor = function() {
1882   "use strict";
1883   var a = this.__getCameraActor();
1884   if (a.ok()) {
1885     dali.internalSetupProperties(a);
1886   }
1887   return a;
1888 };
1889
1890 Object.defineProperty(dali.RenderTask.prototype, "x", {
1891   enumerable: true,
1892   configurable: false,
1893   get: function() {
1894     return this.getCurrentViewportPosition()[0];
1895   },
1896   set: function(v) {
1897     var pos = this.getCurrentViewportPosition();
1898     this.setViewportPosition(v, pos[1]);
1899   }
1900 });
1901
1902 Object.defineProperty(dali.RenderTask.prototype, "y", {
1903   enumerable: true,
1904   configurable: false,
1905   get: function() {
1906     return this.getCurrentViewportPosition()[1];
1907   },
1908   set: function(v) {
1909     var pos = this.getCurrentViewportPosition();
1910     this.setViewportPosition(pos[0], v);
1911   }
1912 });
1913
1914 Object.defineProperty(dali.RenderTask.prototype, "width", {
1915   enumerable: true,
1916   configurable: false,
1917   get: function() {
1918     return this.getCurrentViewportSize()[0];
1919   },
1920   set: function(v) {
1921     var pos = this.getCurrentViewportSize();
1922     this.setViewportSize(v, pos[1]);
1923   }
1924 });
1925
1926 Object.defineProperty(dali.RenderTask.prototype, "height", {
1927   enumerable: true,
1928   configurable: false,
1929   get: function() {
1930     return this.getCurrentViewportSize()[1];
1931   },
1932   set: function(v) {
1933     var pos = this.getCurrentViewportSize();
1934     this.setViewportSize(pos[0], v);
1935   }
1936 });
1937
1938 //------------------------------------------------------------------------------
1939 //
1940 // Solid Actor Module
1941 //
1942 //------------------------------------------------------------------------------
1943
1944 /**
1945  * Create a solid color actor
1946  * @method createSolidColorActor
1947  * @param {array} color The color
1948  * @param {bool} border Whether to add a border
1949  * @param {array} color The border color
1950  * @param {float} borderSize The size of a border
1951  * @return {Dali.Actor} The Dali actor
1952  */
1953 dali.createSolidColorActor = function(color, border, borderColor, borderSize) {
1954   "use strict";
1955   var a = dali.__createSolidColorActor(color, border, borderColor, borderSize);
1956   dali.internalSetupProperties(a);
1957   return a;
1958 };
1959
1960 //------------------------------------------------------------------------------
1961 //
1962 // Mesh import support Module
1963 //
1964 //------------------------------------------------------------------------------
1965 function ObjectLoader(fileObject) {
1966   "use strict";
1967   // cached
1968   this.self = this;
1969   this.meshByUUID = {};
1970   this.geomByUUID = {};
1971   this.matByUUID = {};
1972
1973   this.fileObject = fileObject;
1974 }
1975
1976 function __longToArray(v) {
1977   "use strict";
1978   return [((v >> 24) & 0xFF) / 255.0, ((v >> 16) & 0xFF) / 255.0, ((v >> 8) & 0xFF) / 255.0, (v & 0xFF) / 255.0];
1979 }
1980
1981 function __isBitSet(value, bit) {
1982   "use strict";
1983   return (value & (1 << bit));
1984 }
1985
1986 ObjectLoader.prototype.__getMaterial = function(uuid) {
1987   "use strict";
1988   if (!(uuid in this.matByUUID)) {
1989     for (var i = 0, len = this.fileObject.materials.length; i < len; i++) {
1990       var f_mat = this.fileObject["materials"][i];
1991       skewer.log(i + ":" + f_mat["uuid"] + " " + (f_mat["uuid"] === uuid));
1992       if (f_mat["uuid"] === uuid) {
1993         assert(f_mat["type"] === "MeshPhongMaterial");
1994         var mat = new dali.MaterialWrapper(uuid);
1995         mat.setDiffuseColor(__longToArray(f_mat["color"]));
1996         mat.setAmbientColor(__longToArray(f_mat["ambient"]));
1997         mat.setSpecularColor(__longToArray(f_mat["specular"]));
1998         mat.setEmissiveColor(__longToArray(f_mat["emmissive"]));
1999         mat.setShininess(f_mat["shininess"]);
2000         this.matByUUID[uuid] = mat;
2001         break;
2002       }
2003     }
2004   }
2005   return this.matByUUID[uuid];
2006 };
2007
2008 ObjectLoader.prototype.__getMeshData = function(uuid, uuid_material) {
2009   "use strict";
2010   if (!(uuid in this.meshByUUID)) {
2011     for (var i = 0, len = this.fileObject["geometries"].length; i < len; i++) {
2012       var f_geom = this.fileObject["geometries"][i];
2013       if (f_geom["uuid"] === uuid) {
2014         var f_indices, // file data
2015             f_posns,
2016             f_norms,
2017             f_uvs,
2018             f_faces;
2019
2020         if (!("metadata" in f_geom)) {
2021           f_geom["metadata"] = {
2022             "type": ""
2023           }; // Warning: modified input!?
2024         }
2025
2026         if ("formatVersion" in f_geom["metadata"]) // then version 3.1
2027         {
2028           f_indices = f_geom["indices"];
2029           f_posns = f_geom["vertices"];
2030           f_norms = f_geom["normals"];
2031           f_uvs = f_geom["uvs"];
2032           f_faces = f_geom["faces"];
2033         } else if (f_geom["type"] === "Geometry") // V4 clara io output? not standard???
2034         {
2035           f_indices = f_geom["data"]["indices"];
2036           f_posns = f_geom["data"]["vertices"];
2037           f_norms = f_geom["data"]["normals"];
2038           f_uvs = f_geom["data"]["uvs"];
2039           f_faces = f_geom["data"]["faces"];
2040         } else if (f_geom["metadata"]["type"] === "Geometry") // V4
2041         {
2042           f_indices = f_geom["indices"];
2043           f_posns = f_geom["vertices"];
2044           f_norms = f_geom["normals"];
2045           f_uvs = f_geom["uvs"];
2046           f_faces = f_geom["faces"];
2047         } else if (f_geom["metadata"]["type"] === "BufferGeometry") // V4
2048         {
2049           f_posns = f_geom["data"]["attributes"]["position"]["array"];
2050           f_norms = f_geom["data"]["attributes"]["norms"]["array"];
2051           f_uvs = f_geom["data"]["attributes"]["uv"]["array"];
2052         }
2053
2054         var nUvLayers = 0;
2055
2056         // disregard empty arrays
2057         for (var i = 0; i < this.fileObject.uvs.length; i++) {
2058           if (this.fileObject.uvs[i].length)
2059             nUvLayers++;
2060         }
2061
2062         var verts = new dali.VectorVertex();
2063         var vert = []; //new dali.Vertex();
2064         for (var i = 0, len = f_posns.length / 3; i < len; i++) {
2065           vert.push(f_posns[(i * 3) + 0]);
2066           vert.push(f_posns[(i * 3) + 1]);
2067           vert.push(f_posns[(i * 3) + 2]);
2068
2069           vert.push(0); // norm
2070           vert.push(0);
2071           vert.push(0);
2072
2073           vert.push(0); // uvs
2074           vert.push(0);
2075
2076           verts.push_back(vert);
2077         }
2078
2079         var mesh = new dali.MeshDataWrapper();
2080         var faces = new dali.VectorFaceIndex();
2081         var faceSets = {};
2082         //faceSets.length = this.fileObject.materials;
2083         for (var i = 0, len = this.fileObject.materials.length; i < len; ++i) {
2084           // get materials and force them to be loaded up
2085           var mat = this.__getMaterial(this.fileObject.materials[i]["uuid"]);
2086         }
2087
2088         var idx = 0;
2089         var idx_len = f_faces.length;
2090         var materialUUID = undefined;
2091         while (idx < idx_len) {
2092           var f_type = f_faces[idx++];
2093           var isQuad = __isBitSet(f_type, 0);
2094           var hasMaterial = __isBitSet(f_type, 1);
2095           var hasFaceUv = __isBitSet(f_type, 2);
2096           var hasFaceVertexUv = __isBitSet(f_type, 3);
2097           var hasFaceNormal = __isBitSet(f_type, 4);
2098           var hasFaceVertexNormal = __isBitSet(f_type, 5);
2099           var hasFaceColor = __isBitSet(f_type, 6);
2100           var hasFaceVertexColor = __isBitSet(f_type, 7);
2101
2102           var nVertices = 3;
2103           var faceVertexIndices;
2104           if (isQuad) {
2105             faces.push_back(f_faces[idx]);
2106             faces.push_back(f_faces[idx + 1]);
2107             faces.push_back(f_faces[idx + 2]);
2108
2109             faces.push_back(f_faces[idx]);
2110             faces.push_back(f_faces[idx + 2]);
2111             faces.push_back(f_faces[idx + 3]);
2112
2113             faceVertexIndices = [f_faces[idx],
2114                                  f_faces[idx + 1],
2115                                  f_faces[idx + 2]
2116                                 ];
2117
2118             idx += 4;
2119             nVertices = 4;
2120           } else {
2121             faces.push_back(f_faces[idx]);
2122             faces.push_back(f_faces[idx + 1]);
2123             faces.push_back(f_faces[idx + 2]);
2124
2125             faceVertexIndices = [f_faces[idx],
2126                                  f_faces[idx + 1],
2127                                  f_faces[idx + 2]
2128                                 ];
2129
2130             idx += 3;
2131           }
2132
2133           if (hasMaterial) {
2134             if (materialUUID === undefined) {
2135               materialUUID = this.fileObject.materials[f_faces[idx]]["uuid"];
2136             } else {
2137               // different material per face is bonkers - I'm not going to support it.
2138               if (this.fileObject.materials[f_faces[idx]]["uuid"] !== materialUUID) {
2139                 throw "Faces with different materials is not supported";
2140               }
2141             }
2142             idx++;
2143           }
2144
2145
2146           if (hasFaceUv) {
2147             for (var i = 0; i < nUvLayers; i++) {
2148               var uvLayer = self.fileObject.uvs[i];
2149               var uvIndex = f_faces[idx++];
2150               var u = uvLayer[uvIndex * 2];
2151               var v = uvLayer[uvIndex * 2 + 1];
2152               // discarded - tbd ?
2153             }
2154           }
2155
2156           if (hasFaceVertexUv) {
2157             for (var i = 0; i < nUvLayers; i++) {
2158               var uvLayer = f_geom.uvs[i];
2159               var uvs = [];
2160               for (var j = 0; j < nVertices; j++) {
2161                 var uvIndex = f_faces[idx++];
2162                 var u = uvLayer[uvIndex * 2];
2163                 var v = uvLayer[uvIndex * 2 + 1];
2164                 // discarded- tbd ?
2165               }
2166             }
2167           }
2168
2169           if (hasFaceNormal) {
2170             var normalIndex = f_faces[idx++] * 3;
2171
2172             var x = f_geom.normals[normalIndex++];
2173             var y = f_geom.normals[normalIndex++];
2174             var z = f_geom.normals[normalIndex];
2175
2176             for (var i = 0; i < faceVertexIndices.length; i++) {
2177               var v = vert.get(faceVertexIndices[i]);
2178
2179               v[4] += x;
2180               v[5] += y;
2181               v[6] += z;
2182             }
2183           }
2184
2185           if (hasFaceVertexNormal) {
2186             for (var i = 0; i < nVertices; i++) {
2187               var normalIndex = faces[idx] * 3;
2188               var x = f_geom.normals[normalIndex++];
2189               var y = f_geom.normals[normalIndex++];
2190               var z = f_geom.normals[normalIndex];
2191
2192               var v = vert.get(faces[idx]);
2193
2194               v[4] += x;
2195               v[5] += y;
2196               v[6] += z;
2197
2198               idx += 1;
2199               // face.vertexNormals.push( normal );
2200             }
2201           }
2202
2203           if (hasFaceColor) {
2204             var color = f_faces[idx++];
2205           }
2206
2207           if (hasFaceVertexColor) {
2208             for (var i = 0; i < nVertices; i++) {
2209               var colorIndex = faces[idx++];
2210               var color = f_geom.colors[colorIndex]; // ??? f_geom.colors?
2211               // face.vertexColors.push( color );
2212             }
2213           }
2214
2215           var faces = null;
2216           if (f_faces) {
2217             for (var i = 1, len = f_faces.length; i < len; i++) {
2218               faces.push_back(f_faces[i]);
2219             }
2220           }
2221
2222           if (f_indices) {
2223             faces = new dali.VectorFaceIndex();
2224             for (var i = 1, len = f_indices.length; i < len; i++) {
2225               faces.push_back(f_indices[i]);
2226             }
2227           }
2228
2229           if (!faces) {
2230             faces = [];
2231             for (var i = 0, len = f_posns.length; i < len; i++) {
2232               faces.push(i);
2233             }
2234           }
2235
2236           console.log(verts.size() + ":" + faces.size() + ":" + uuid_material);
2237
2238           var material = this.__getMaterial(uuid_material);
2239           mesh.setLineData(verts, faces, material);
2240         }
2241
2242         this.meshByUUID[uuid] = mesh;
2243         verts.delete();
2244         faces.delete();
2245         break;
2246       } // if uuid found
2247     } // for geom in geometries
2248   } // if uid ! in meshByUUID
2249
2250   return this.meshByUUID[uuid];
2251 };
2252
2253 ObjectLoader.prototype.delete = function() {
2254   "use strict";
2255   for (var a in this.meshByUUID) {
2256     a.delete();
2257   }
2258   this.meshByUUID = {};
2259   for (var b in this.matByUUID) {
2260     b.delete();
2261   }
2262   this.matByUUID = {};
2263 };
2264
2265 ObjectLoader.prototype.createMeshActors = function() {
2266   "use strict";
2267   var ret = [];
2268   if ("object" in this.fileObject) {
2269     for (var i = 0, len = this.fileObject["object"]["children"].length; i < len; i++) {
2270       var child = this.fileObject["children"];
2271       if (child["type"] === "Mesh") {
2272         var meshData = this.__getMeshData(child["geometry"],
2273                                           child["material"]);
2274         ret.push(dali.__createMeshActor(meshData));
2275         meshData.delete();
2276       }
2277     }
2278   }
2279
2280   var parent;
2281
2282   if (ret) {
2283     parent = new dali.Actor();
2284     for (var a in ret) {
2285       parent.add(a);
2286       a.delete();
2287     }
2288   }
2289
2290   return parent;
2291 };
2292
2293 dali.createMeshActor = function(threeDjs_formatV4) {
2294   "use strict";
2295   var loader = new ObjectLoader(threeDjs_formatV4);
2296   return loader.createMeshActor();
2297 };
2298
2299
2300
2301 //------------------------------------------------------------------------------
2302 //
2303 // Hit test
2304 //
2305 //------------------------------------------------------------------------------
2306 dali.hitTest = function(x, y) {
2307   "use strict";
2308   var a = dali.__hitTest(x, y);
2309   if (a.ok()) {
2310     dali.internalSetupProperties(a);
2311     return a;
2312   } else {
2313     return null;
2314   }
2315 };
2316
2317
2318 //------------------------------------------------------------------------------
2319 //
2320 // Shader support
2321 //
2322 //------------------------------------------------------------------------------
2323
2324 /**
2325  * ShaderInfo class to get shader metadata.
2326  */
2327 dali.ShaderInfo = function() {
2328   "use strict";
2329 };
2330
2331 // supported uniforms
2332 dali.ShaderInfo.prototype._supportedUniformTypes = ["bool",
2333                                                     "int",
2334                                                     "float",
2335                                                     "vec2", "vec3", "vec4",
2336                                                     "bvec2", "bvec3", "bvec4",
2337                                                     "ivec2", "ivec3", "ivec4",
2338                                                     "mat2", "mat3", "mat4",
2339                                                     "sampler2D",
2340                                                     "samplerCube"
2341                                                    ];
2342
2343 // need to add a value to uniform registration call
2344 dali.ShaderInfo.prototype._supportedUniformValues = [0,
2345                                                      0,
2346                                                      0.0,
2347                                                      [0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0],
2348                                                      [0, 0], [0, 0, 0], [0, 0, 0, 0],
2349                                                      [0, 0], [0, 0, 0], [0, 0, 0, 0],
2350                                                      [1.0, 0.0,
2351                                                       0.0, 1.0
2352                                                      ],
2353                                                      [1.0, 0.0, 0.0,
2354                                                       0.0, 1.0, 0.0,
2355                                                       0.0, 0.0, 1.0
2356                                                      ],
2357                                                      [1.0, 0.0, 0.0, 0.0,
2358                                                       0.0, 1.0, 0.0, 0.0,
2359                                                       0.0, 0.0, 1.0, 0.0,
2360                                                       0.0, 0.0, 0.0, 1.0
2361                                                      ]
2362                                                     ];
2363
2364
2365 /**
2366  * Get shader metadata from compilation.
2367  *
2368  * Compiles the shader. On error set 'hasError' and error strings. On Success
2369  * query gl for the attributes and uniforms in the shaders.
2370  *
2371  * @param {object} gl ie from canvas.getContext("webgl")
2372  * @param {string} vertex shader
2373  * @param {string} fragment shader
2374  * @return {Object} shader metadata (see 'var info' below)
2375  */
2376 dali.ShaderInfo.prototype.fromCompilation = function(gl, vertex, fragment) {
2377   "use strict";
2378   var i;
2379   var info = {
2380     vertex: vertex,     // vertex source code
2381     fragment: fragment, // fragment source code
2382     attributes: {},     // {aName1: {name:"aName1", ... }
2383     uniforms: {},       // {uName1: {name:"uName1", type:"vec2", ...}
2384     uniformUISpec: {},  // {uName1: {ui:"slider", min:0, max:1, ...}
2385     attributeCount: 0,  // Number of attributes
2386     uniformCount: 0,    // Number of uniforms
2387     hasError: false,    // compiles without error
2388     vertexError: "",    // Vertex compilation error
2389     fragmentError: "",  // Fragment compilation error
2390     linkError: ""       // Linker error
2391   };
2392
2393   var vertexShader = gl.createShader(gl.VERTEX_SHADER);
2394   gl.shaderSource(vertexShader, vertex);
2395   gl.compileShader(vertexShader);
2396
2397   // Check the compile status, return an error if failed
2398   if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
2399     info.hasError = true;
2400     info.vertexError = gl.getShaderInfoLog(vertexShader);
2401   }
2402
2403   var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
2404   gl.shaderSource(fragmentShader, fragment);
2405   gl.compileShader(fragmentShader);
2406
2407   // Check the compile status, return an error if failed
2408   if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
2409     info.hasError = true;
2410     info.fragmentError = gl.getShaderInfoLog(fragmentShader);
2411   }
2412
2413   if(info.hasError) {
2414     gl.deleteShader(vertexShader);
2415     gl.deleteShader(fragmentShader);
2416     return info; // ==> out
2417   } else {
2418     var program = gl.createProgram();
2419     gl.attachShader(program, vertexShader);
2420     gl.attachShader(program, fragmentShader);
2421
2422     gl.linkProgram(program);
2423
2424     if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
2425       info.hasError = true;
2426       info.linkError = gl.getProgramInfoLog(program);
2427       gl.deleteProgram(program);
2428       gl.deleteShader(vertexShader);
2429       gl.deleteShader(fragmentShader);
2430       return info; // ==> out
2431     }
2432   }
2433
2434   var activeUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
2435   var activeAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
2436
2437   // Taken from the WebGl spec:
2438   // http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14
2439   var enums = {
2440     0x8B50: "FLOAT_VEC2",
2441     0x8B51: "FLOAT_VEC3",
2442     0x8B52: "FLOAT_VEC4",
2443     0x8B53: "INT_VEC2",
2444     0x8B54: "INT_VEC3",
2445     0x8B55: "INT_VEC4",
2446     0x8B56: "BOOL",
2447     0x8B57: "BOOL_VEC2",
2448     0x8B58: "BOOL_VEC3",
2449     0x8B59: "BOOL_VEC4",
2450     0x8B5A: "FLOAT_MAT2",
2451     0x8B5B: "FLOAT_MAT3",
2452     0x8B5C: "FLOAT_MAT4",
2453     0x8B5E: "SAMPLER_2D",
2454     0x8B60: "SAMPLER_CUBE",
2455     0x1400: "BYTE",
2456     0x1401: "UNSIGNED_BYTE",
2457     0x1402: "SHORT",
2458     0x1403: "UNSIGNED_SHORT",
2459     0x1404: "INT",
2460     0x1405: "UNSIGNED_INT",
2461     0x1406: "FLOAT"
2462   };
2463
2464   // Loop through active uniforms
2465   for (i = 0; i < activeUniforms; i++) {
2466     var uniform = gl.getActiveUniform(program, i);
2467     info.uniforms[uniform.name] = {name: uniform.name,
2468                                    type: uniform.type,
2469                                    typeName: enums[uniform.type],
2470                                    size: uniform.size};
2471     info.uniformCount += uniform.size;
2472   }
2473
2474   // Loop through active attributes
2475   for (i = 0; i < activeAttributes; i++) {
2476     var attribute = gl.getActiveAttrib(program, i);
2477     info.attributes[attribute.name] = {name: attribute.name,
2478                                        type: attribute.type,
2479                                        typeName: enums[attribute.type],
2480                                        size: attribute.size};
2481     info.attributeCount += attribute.size;
2482   }
2483
2484   // uniformUISpec
2485   this._addUniformMetaData(vertex, info);
2486   this._addUniformMetaData(fragment, info);
2487
2488   return info;
2489 };
2490
2491 /*
2492  * add unform metadata from shader source comments
2493  *  ie return as an object the comment following a uniform
2494  *     uniform float uAlpha; // {"min":0, "max":1}
2495  */
2496 /** private */
2497 dali.ShaderInfo.prototype._addUniformMetaData = function(src, metadata) {
2498   "use strict";
2499   // Loop through active uniforms
2500   for(var name in metadata.uniforms) {
2501     var reguniform = new RegExp(name + "[^;]*;(.*)");
2502
2503     var tmp = reguniform.exec(src);
2504     if(tmp && tmp[1]) {
2505       var meta;
2506       var uComments = tmp[1].trim();
2507       if(uComments.startsWith("//")) { // meta data in comments
2508         try {
2509           meta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
2510           if(typeof meta !== typeof ({})) {
2511             throw ("Uniform UI Spec in comments must be an object");
2512           }
2513         } catch (e) {
2514           meta = {};
2515         }
2516       } else {
2517         meta = {};
2518       }
2519       metadata.uniformUISpec[name] = meta;
2520     }
2521   }
2522 };
2523
2524 /**
2525  * Get shader metadata from regex search.
2526  *
2527  * Attempts a regex search to get the shader meta data.
2528  * Use fromCompilation() instead of this function wherever compilation is
2529  * possible as this approach will never work for all shaders.
2530  * Does no compilation or error checking but retains fields for
2531  * compatibility with .fromCompilation(...)
2532  * May return an error if the regex fails.
2533  *
2534  * @param {string} vertex shader
2535  * @param {string} fragment shader
2536  * @return  {Object} shader metadata (see 'var info' below)
2537  */
2538 dali.ShaderInfo.prototype.fromRegEx = function(vertex, fragment) {
2539   "use strict";
2540   var info = {          // similar to this.fromCompilation()
2541     vertex: vertex,     // source code
2542     fragment: fragment,
2543     attributes: {},     // {aName1: {name:"aName1", ... }
2544     uniforms: {},       // {uName1: {name:"uName1", type:"vec2", ...}
2545     attributeCount: 0,
2546     uniformCount: 0,
2547     uniformUISpec: {},  // {uName1: {ui:"slider", min:0, max:1, ...}
2548     hasError: false,    // compiles without error
2549     vertexError: "",
2550     fragmentError: "",
2551     linkError: ""
2552   };
2553
2554   var metaVertex;
2555   try {
2556     metaVertex = this._getRegExMetaData(vertex);
2557   } catch(e) {
2558     info.hasError = true;
2559     info.vertexError = e.message;
2560     return info;
2561   }
2562
2563   var metaFragment;
2564   try {
2565     metaFragment = this._getRegExMetaData(fragment);
2566   } catch(e) {
2567     info.hasError = true;
2568     info.fragmentError = e.message;
2569     return info;
2570   }
2571
2572   var name;
2573
2574   // merge
2575   info.uniforms = metaVertex.uniformMetaData;
2576   info.uniformUISpec = metaVertex.uniformUISpec;
2577
2578   for(name in metaFragment.uniformMetaData) {
2579     if( name in info.uniforms ) {
2580       info.uniforms[name] = dali.mergeObjects(info.uniforms[name], metaVertex.uniformMetaData);
2581     } else {
2582       info.uniforms[name] = metaFragment.uniformMetaData[name];
2583     }
2584     if( name in info.uniformUISpec ) {
2585       info.uniformUISpec[name] = dali.mergeObjects(info.uniformUISpec[name], metaVertex.uniformUISpec);
2586     } else {
2587       info.uniformUISpec[name] = metaFragment.uniformUISpec[name];
2588     }
2589   }
2590
2591   info.attributes = metaVertex.attributeMetaData;
2592   for(name in metaFragment.attributeMetaData) {
2593     if( name in metaVertex.attributeMetaData ) {
2594       info.attributes[name] = dali.mergeObjects(info.attributes[name], metaVertex.attributeMetaData);
2595     } else {
2596       info.attributes[name] = metaFragment.attributeMetaData[name];
2597     }
2598   }
2599
2600   return info;
2601 };
2602
2603 /*
2604  * Returns a string with all comments removed
2605  */
2606 /** private */
2607 dali.ShaderInfo.prototype._removeComments = function(str) {
2608   "use strict";
2609   var uid = "_" + new Date(),
2610       primatives = [],
2611       primIndex = 0;
2612
2613   return (
2614     str
2615     /* Remove strings */
2616       .replace(/(['"])(\\\1|.)+?\1/g, function(match){
2617         primatives[primIndex] = match;
2618         return (uid + "") + primIndex++;
2619       })
2620
2621     /* Remove Regexes */
2622       .replace(/([^\/])(\/(?!\*|\/)(\\\/|.)+?\/[gim]{0,3})/g, function(match, $1, $2){
2623         primatives[primIndex] = $2;
2624         return $1 + (uid + "") + primIndex++;
2625       })
2626
2627     /*
2628      - Remove single-line comments that contain would-be multi-line delimiters
2629      E.g. // Comment /* <--
2630      - Remove multi-line comments that contain would be single-line delimiters
2631      E.g. /* // <--
2632      */
2633       .replace(/\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//g, "")
2634
2635     /*
2636      Remove single and multi-line comments,
2637      no consideration of inner-contents
2638      */
2639       .replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g, "")
2640
2641     /*
2642      Remove multi-line comments that have a replace ending (string/regex)
2643      Greedy, so no inner strings/regexes will stop it.
2644      */
2645       .replace(RegExp("\\/\\*[\\s\\S]+" + uid + "\\d+", "g"), "")
2646
2647     /* Bring back strings & regexes */
2648       .replace(RegExp(uid + "(\\d+)", "g"), function(match, n){
2649         return primatives[n];
2650       })
2651   );
2652 };
2653
2654 /*
2655  * Returns true if value is in the array
2656  */
2657 /** private */
2658 dali.ShaderInfo.prototype._contains = function(array, value) {
2659   "use strict";
2660   for(var i = 0; i < array.length; i++) {
2661     if(array[i] === value) {
2662       return true;
2663     }
2664   }
2665   // else
2666   return false;
2667 };
2668
2669 /*
2670  * Get the src meta data for unforms and attributes armed only with a regexp
2671  */
2672 /** private */
2673 dali.ShaderInfo.prototype._getRegExMetaData = function(src) {
2674   "use strict";
2675   var ret = {"uniforms": [],         // ["uName1", ["uName2"]
2676              "uniformMetaData": {},  // {uName1: {type:"vec3,...}
2677              "uniformUISpec": {},    // {ui:"slider", min:..., max:...}
2678              "attributes": [],       // ["aName2"]
2679              "attributeMetaData": {} // ["aName2"]
2680             };
2681
2682   // Undoubtedly this approach will be wrong. Hopefully on not too many corner cases...
2683   // A better way is to compile the source see (fromCompilation())
2684   // but that requres a gl context.
2685   var tmp;
2686
2687   var definesOut = /#define[ \t]+([A-Za-z_0-9]*)[ \t]+(.*)/g;
2688
2689   var reg = /[ \t]?uniform[ ]*((?:lowp|mediump|highp)?[ \t]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t]*([A-Za-z0-9]*))[ \t]*(;|\[.*\][ \t]*;)(.*)/gi;
2690
2691   var regAttrib = /[ \t]?attribute[ ]*((?:lowp|mediump|highp)?[ \t]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t]*([A-Za-z0-9]*))[ \t]*(;|\[.*\][ \t]*;)(.*)/gi;
2692
2693   // 1. no commented out uniforms
2694   var noCommentSource = this._removeComments(src);
2695
2696   var validUniforms = [];
2697   while ((tmp = reg.exec(noCommentSource))) {
2698     validUniforms.push( tmp[3] );
2699   }
2700
2701   while ((tmp = regAttrib.exec(noCommentSource))) {
2702     ret.attributes.push( tmp[3] );
2703     ret.attributeMetaData[ tmp[3] ] = {name: tmp[3], type: tmp[2] };
2704   }
2705
2706   // 2. replace defines
2707   var defines = [];
2708   while ((tmp = definesOut.exec(noCommentSource))) {
2709     defines.push([tmp[1], tmp[2]]);
2710   }
2711   var defineDict = {};
2712   var defineList = [];
2713   while(defines.length) {
2714     var p = defines.pop();
2715     var n = p[0];
2716     var v = p[1];
2717     try {
2718       defineDict[n] = eval(v);
2719       defineList.push([n, defineDict[n]]);
2720     } catch(e) {
2721       var d = /([A-Za-z]+[A-Za-z0-9]*)/g;
2722       while ((tmp = d.exec(v))) {
2723         if(tmp[0] in defineDict) {
2724           v = v.replace(tmp[0], defineDict[tmp[0]]);
2725         } else {
2726           defines.push(p); // stick it back to try again. ...and endless loop if we can't(!)
2727         }
2728       }
2729     }
2730   }
2731
2732   for(var i = 0; i < defineList.length; i++) {
2733     var re = new RegExp(defineList[i][0], "g");
2734     src = src.replace(re, defineList[i][1]);
2735   }
2736
2737   // 3. get uniforms
2738   while ((tmp = reg.exec(src))) {
2739     if(!this._contains(validUniforms, tmp[3])) {
2740       continue;
2741     }
2742     var uType = tmp[2];
2743     var uName = tmp[3];
2744     var uArray = tmp[4].slice(0, -1);
2745     var uComments = tmp[5].trim();
2746     var meta;
2747     var uiSpecMeta = null;
2748     if(uComments.startsWith("//")) { // meta data in comments
2749       uiSpecMeta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
2750       if(typeof uiSpecMeta !== typeof ({})) {
2751         throw ("Uniform UI Spec in comments must be an object");
2752       }
2753     }
2754
2755     if(uiSpecMeta) {
2756       uiSpecMeta.name = tmp[3];
2757       ret.uniformUISpec[uName] = uiSpecMeta;
2758     }
2759
2760     meta = {};
2761     meta.type = tmp[2];
2762     meta.name = tmp[3];
2763     meta.count = 0;
2764
2765     var name;
2766     if(uArray.search("[[]") >= 0) { // an array
2767       meta.count = Number(uArray.slice(1, -1));
2768     }
2769
2770     if(this._contains( this._supportedUniformTypes, uType) ) {
2771       if(meta.count !== 0) { // array
2772         for(var j = 0; j < meta.count; j++) {
2773           ret.uniforms.push( meta.name );
2774           ret.uniformMetaData[ meta.name ] = {type: meta.type,
2775                                               name: meta.name + "[" + j + "]",
2776                                               index: j,
2777                                               count: meta.count};
2778         }
2779       } else {
2780         ret.uniforms.push( meta.name );
2781         ret.uniformMetaData[ meta.name ] = {type: meta.type,
2782                                             name: meta.name,
2783                                             index: 0,
2784                                             count: 0};
2785       }
2786     } else {
2787       // not a base type so need to get the compound type
2788       var structFind = new RegExp( "(struct[ \t\n]*" + uType + "[^{]*{)([^}]*)", "g");
2789       var structLines = structFind.exec(src)[2].split(";");
2790       var structUniforms = [];
2791       var tmpStruct;
2792       var k;
2793       for(var lineNo = 0; lineNo < structLines.length; lineNo++) {
2794         var line = structLines[lineNo].replace(/\n/g, "") + ";";
2795         if(line !== ";") {
2796           var structReg = /[ \t\n]*((?:lowp|mediump|highp)?[ \t\n]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t\n]*([A-Za-z0-9]*))[ \t\n]*(;|\[.*\][ \t\n]*;)/gi;
2797           while ((tmpStruct = structReg.exec(line))) {
2798             structUniforms.push( { type: tmpStruct[2],
2799                                    name: tmpStruct[3],
2800                                    count: meta.count } );
2801           }
2802         }
2803       }
2804       if(meta.count === 0) {
2805         for(k = 0; k < structUniforms.length; k++) {
2806           name = uName + "." + structUniforms[k].name;
2807           ret.uniforms.push( name );
2808           ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
2809                                          name: name,
2810                                          count: meta.count,
2811                                          index: 0,
2812                                          structType: meta.type,
2813                                          structName: meta.name};
2814         }
2815       } else { // array
2816         for(var l = 0; l < meta.count; l++) {
2817           for(k = 0; k < structUniforms.length; k++) {
2818             name = uName + "[" + l + "]" + "." + structUniforms[k].name;
2819             ret.uniforms.push( name );
2820             ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
2821                                            name: name,
2822                                            count: meta.count,
2823                                            index: l,
2824                                            structType: meta.type,
2825                                            structName: meta.name};
2826           }
2827         }
2828       }
2829     }
2830   }
2831
2832   return ret;
2833 };
2834
2835 //------------------------------------------------------------------------------
2836 //
2837 // Debug Module
2838 //
2839 //------------------------------------------------------------------------------
2840 dali.Debug = function() {
2841   "use strict";
2842 };
2843
2844 dali.Debug.prototype.printTypeProperties = function(typeName) {
2845   "use strict";
2846   var t = new dali.TypeRegistry();
2847   var info = t.getTypeInfo(typeName);
2848   var props = info.getProperties();
2849   for (var i = 0; i < props.size(); i++) {
2850     console.log(i + ":" + props.get(i));
2851   }
2852   info.delete(); // wrapper
2853   t.delete(); // wrapper
2854 };
2855
2856 dali.Debug.prototype.printProperties = function(o) {
2857   "use strict";
2858   var props = o.getProperties();
2859
2860   var len = props.size();
2861   for(var i = 0; i < len; i++) {
2862     var name = props.get(i);
2863     var type = o.getPropertyTypeName(name);
2864     if(type !== "NONE") {
2865       console.log(i + ":" + name + " " + type);
2866     } else {
2867       type = o.getPropertyTypeName(name);
2868       console.log(i + ":" + name + " " + type + " (Not mangled)");
2869     }
2870   }
2871   props.delete(); // wrapper
2872 };
2873
2874 dali.Debug.prototype.printTypes = function() {
2875   "use strict";
2876
2877   var t = new dali.TypeRegistry();
2878   for (var i = 0; i < t.getTypeNameCount(); i++) {
2879     console.log(t.getTypeName(i));
2880   }
2881   t.delete(); // wrapper
2882 };
2883
2884
2885 dali._debugPrintParents = function(actor, list) {
2886   "use strict";
2887   var p = null;
2888
2889   if (!actor.ok()) {
2890     return;
2891   }
2892
2893   try {
2894     p = actor.getParent();
2895     if (!p.ok()){
2896       p = null;
2897     }
2898   } catch (e) {
2899     // console.log("Cannot get parent", e);
2900   }
2901
2902   if (p) {
2903     list.push(p);
2904     dali._debugPrintParents(p, list);
2905   }
2906 };
2907
2908 dali.Debug.prototype.printTree = function(actor) {
2909   "use strict";
2910   var l = [];
2911   dali._debugPrintParents(actor, l);
2912   var a;
2913   var ti;
2914   console.log("---");
2915   for (var i = l.length - 1; i >= 0; i--) {
2916     a = l[i];
2917     ti = a.getTypeInfo();
2918     console.log("|", Array(l.length - i).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
2919     ti.delete();
2920   }
2921   ti = actor.getTypeInfo();
2922   console.log("*", Array(l.length + 1).join("*"), ti.getName(), "P", actor.position, "R", actor.orientation, actor.name);
2923   ti.delete();
2924
2925   var children = actor.getChildren();
2926   for (var j = 0; j < children.length; j++) {
2927     a = children[j];
2928     ti = a.getTypeInfo();
2929     console.log("|", Array(l.length + 1 + 1 + j).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
2930     ti.delete();
2931   }
2932 };
2933
2934 dali.Debug.prototype.printRenderTask = function(rendertask) {
2935   "use strict";
2936   console.log("[X,Y]", rendertask.getCurrentViewportPosition());
2937   console.log("[W,H]", rendertask.getCurrentViewportSize());
2938
2939   var c = rendertask.getCameraActor();
2940   if (!c.ok()) {
2941     console.log("No Camera");
2942   } else {
2943     console.log("Camera Pos:", c.position);
2944     console.log("Camera Rot:", c.orientation);
2945     console.log("Camera Inherit:", c.inheritRotation);
2946     console.log("Camera ParentOrigin:", c.parentOrigin);
2947     console.log("Camera AnchorPoint:", c.anchorPoint);
2948     var p = null;
2949     try {
2950       p = c.getParent();
2951       if(!p.ok()) {
2952         p = null;
2953       }
2954     } catch (e) {
2955       console.log("Cannot get parent", e);
2956     }
2957
2958     if (!p) {
2959       console.log("Camera has no parent?");
2960     } else {
2961       var ti = p.getTypeInfo();
2962       console.log("Parent Name", ti.getName());
2963       ti.delete();
2964       p.delete();
2965     }
2966   }
2967 };
2968
2969 dali.Debug.prototype.printRenderTasks = function() {
2970   "use strict";
2971   var stage = dali.stage;
2972   var taskList = stage.getRenderTaskList();
2973   for (var i = 0; i < taskList.getTaskCount(); i++) {
2974     var t = taskList.getTask(i);
2975     console.log("RenderTask:", i);
2976     this.printRenderTask(t);
2977     t.delete(); // wrapper
2978   }
2979   taskList.delete(); // wrapper
2980 };
2981
2982 dali.Debug.prototype.findFirstActor = function(actor, predicateFunction) {
2983   "use strict";
2984   for (var i = 0, len = actor.getChildCount(); i < len; i++) {
2985     var a = actor.getChildAt(i);
2986     var found = predicateFunction(a);
2987     if (found) {
2988       return a;
2989     }
2990     var child = this.findFirstActor(a, predicateFunction);
2991     if (child) {
2992       return child;
2993     }
2994     a.delete();
2995   }
2996   return null;
2997 };
2998
2999 dali.Debug.prototype.depthVisit = function(actor, operation, dontDelete) {
3000   "use strict";
3001   for (var i = 0, len = actor.getChildCount(); i < len; i++) {
3002     var a = actor.getChildAt(i);
3003     var done = operation(a);
3004     if (!done) {
3005       return false;
3006     }
3007     if (!this.depthVisit(a, operation, dontDelete)) {
3008       return false;
3009     }
3010     var doit = true;
3011     if (dontDelete !== undefined) {
3012       if (dontDelete) {
3013         doit = false;
3014       }
3015     }
3016     if (doit) {
3017       a.delete();
3018     }
3019   }
3020   return true;
3021 };
3022
3023 dali.operationPrintProperty = function(property, all) {
3024   "use strict";
3025   return (function(actor) {
3026     if (property in actor) {
3027       dali.log(actor.getId() + "property:" + actor[property]);
3028     } else {
3029       dali.log(actor.getId() + "property:n/a");
3030     }
3031     return all;
3032   });
3033 };
3034
3035 dali.predicatePropertyEquals = function(property, value) {
3036   "use strict";
3037   return (function(actor) {
3038     if (property in actor) {
3039       if (actor[property] === value) {
3040         return true;
3041       }
3042     }
3043     return false;
3044   });
3045 };
3046
3047 dali.typeInheritsFrom = function(type, basename) {
3048   var inherits = false;
3049
3050   var registry = new dali.TypeRegistry();
3051
3052   var base = registry.getTypeInfo( type.getBaseName() );
3053
3054   if(base.ok())
3055   {
3056     inherits = (base.getName() === basename);
3057
3058     while(!inherits)
3059     {
3060       base = registry.getTypeInfo( base.getBaseName() );
3061       if(base.ok())
3062       {
3063         inherits = (base.getName() === basename);
3064       }
3065       else
3066       {
3067         break;
3068       }
3069     }
3070   }
3071
3072   return inherits;
3073 };
3074
3075
3076
3077 //------------------------------------------------------------------------------
3078 //
3079 // View Module
3080 //
3081 // Helper functions for creating front/top/left views with RenderTasks
3082 //
3083 //------------------------------------------------------------------------------
3084
3085 /**
3086  * Sets the clear colour in a RenderTask
3087  * @method setClearColor
3088  * @param {int} renderTaskIndex
3089  * @param {array} color The rgba colour array
3090  */
3091 dali.setClearColor = function(renderTaskIndex, color) {
3092   "use strict";
3093   var stage = dali.stage;
3094   var taskList = stage.getRenderTaskList();
3095   if (renderTaskIndex >= taskList.getTaskCount()) {
3096     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3097     taskList.delete(); // wrapper
3098     return;
3099   }
3100   var rendertask = taskList.getTask(renderTaskIndex);
3101   rendertask.setClearEnabled(true);
3102   rendertask.setClearColor(color);
3103 };
3104
3105 /**
3106  * Gets the clear colour of a RenderTask
3107  * @method setClearColor
3108  * @param {int} renderTaskIndex
3109  * @return {array} The rgba colour array
3110  */
3111 dali.getClearColor = function(renderTaskIndex) {
3112   "use strict";
3113   var stage = dali.stage;
3114   var taskList = stage.getRenderTaskList();
3115   if (renderTaskIndex >= taskList.getTaskCount()) {
3116     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3117     taskList.delete(); // wrapper
3118     return null;
3119   }
3120   var rendertask = taskList.getTask(renderTaskIndex);
3121   return rendertask.getClearColor();
3122 };
3123
3124 /**
3125  * Set a front view camera with viewport x,y,w,h
3126  * @method setFrontView
3127  * @param {int} renderTaskIndex
3128  * @param {int} x Viewport X
3129  * @param {int} y Viewport Y
3130  * @param {int} w Viewport W
3131  * @param {int} h Viewport H
3132  */
3133 dali.setFrontView = function(renderTaskIndex, x, y, w, h) {
3134   "use strict";
3135   var stage = dali.stage;
3136   var taskList = stage.getRenderTaskList();
3137   if (renderTaskIndex >= taskList.getTaskCount()) {
3138     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3139     taskList.delete(); // wrapper
3140     return;
3141   }
3142   var rendertask = taskList.getTask(renderTaskIndex);
3143
3144   var c = rendertask.getCameraActor();
3145   assert(c.ok(), "Rendertask has no valid camera actor");
3146
3147   rendertask.setViewportPosition([x, y]);
3148   rendertask.setViewportSize([w, h]);
3149   c.position = [0, 0, 800];
3150   c.orientation = [0, 1, 0, 180];
3151   c.aspectRatio = w / h;
3152
3153   c.delete(); // wrapper
3154   rendertask.delete(); // wrapper
3155   taskList.delete(); // wrapper
3156 };
3157
3158 /**
3159  * Set a top view camera with viewport x,y,w,h
3160  * @method setTopView
3161  * @param {int} renderTaskIndex
3162  * @param {int} x Viewport X
3163  * @param {int} y Viewport Y
3164  * @param {int} w Viewport W
3165  * @param {int} h Viewport H
3166  */
3167 dali.setTopView = function(renderTaskIndex, x, y, w, h) {
3168   "use strict";
3169   var stage = dali.stage;
3170   var taskList = stage.getRenderTaskList();
3171   if (renderTaskIndex >= taskList.getTaskCount()) {
3172     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3173     taskList.delete(); // wrapper
3174     return;
3175   }
3176   var rendertask = taskList.getTask(renderTaskIndex);
3177
3178   var c = rendertask.getCameraActor();
3179   assert(c.ok(), "Rendertask has no valid camera actor");
3180
3181   rendertask.setViewportPosition([x, y]);
3182   rendertask.setViewportSize([w, h]);
3183
3184   var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
3185   var q2 = dali.axisAngleToQuaternion([1, 0, 0, dali.radian(-90)]); // pitch to look at scene
3186   var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
3187
3188   c.position = [0, -800, 0]; // @todo; get 800 from dali not hard coded here
3189   c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
3190   c.aspectRatio = w / h;
3191
3192   c.delete(); // wrapper
3193   rendertask.delete(); // wrapper
3194   taskList.delete(); // wrapper
3195 };
3196
3197 /**
3198  * Set a right view camera with viewport x,y,w,h
3199  * @method setRightView
3200  * @param {int} renderTaskIndex
3201  * @param {int} x Viewport X
3202  * @param {int} y Viewport Y
3203  * @param {int} w Viewport W
3204  * @param {int} h Viewport H
3205  */
3206 dali.setRightView = function(renderTaskIndex, x, y, w, h) {
3207   "use strict";
3208   var stage = dali.stage;
3209   var taskList = stage.getRenderTaskList();
3210   if (renderTaskIndex >= taskList.getTaskCount()) {
3211     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3212     taskList.delete(); // wrapper
3213     return;
3214   }
3215   var rendertask = taskList.getTask(renderTaskIndex);
3216
3217   var c = rendertask.getCameraActor();
3218   assert(c.ok(), "Rendertask has no valid camera actor");
3219
3220   rendertask.setViewportPosition([x, y]);
3221   rendertask.setViewportSize([w, h]);
3222
3223   var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
3224   var q2 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(90)]); // yaw again to look from right
3225   var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
3226
3227   c.position = [800, 0, 0];
3228   c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
3229   c.aspectRatio = w / h;
3230
3231   c.delete(); // wrapper
3232   rendertask.delete(); // wrapper
3233   taskList.delete(); // wrapper
3234 };
3235
3236 /**
3237  * Remove all but one render task. Presumes RenderTasks are being use only for viewing windows.
3238  * @method onePane
3239  */
3240 dali.onePane = function() {
3241   "use strict";
3242   var stage = dali.stage;
3243   var taskList = stage.getRenderTaskList();
3244   var tasks = [];
3245   var i, len;
3246
3247   for (i = 1, len = taskList.getTaskCount(); i < len; i++) {
3248     tasks.push(taskList.getTask(i));
3249   }
3250
3251   for (i = 0, len = tasks.length; i < len; i++) {
3252     var task = tasks[i];
3253     // delete the camera actors we created in twoPane and threePane
3254     var c = task.getCameraActor();
3255     if (c.ok()) {
3256       var p = c.getParent();
3257       if (p.ok()) {
3258         p.remove(c);
3259       }
3260       p.delete(); // wrapper
3261     }
3262     c.delete(); // wrapper
3263
3264     taskList.removeTask(task);
3265     task.delete(); // wrapper
3266   }
3267
3268   taskList.delete();
3269 };
3270
3271 /**
3272  * Creates render tasks and cameras for a two pane view.
3273  * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
3274  * (in a separate function to allow window gutters)
3275  * @method twoPane
3276  */
3277 dali.twoPane = function() {
3278   "use strict";
3279   dali.onePane();
3280
3281   var stage = dali.stage;
3282   var taskList = stage.getRenderTaskList();
3283
3284   var defaultTask = taskList.getTask(0);
3285   var defaultCamera = defaultTask.getCameraActor();
3286   var defaultCameraParent = defaultCamera.getParent();
3287
3288   var t;
3289   t = taskList.createTask();
3290
3291   var c = new dali.CameraActor(); // add camera for different viewpoint
3292   c.position = [0, 0, 800];
3293   c.orientation = [0, 1, 0, 180];
3294   c.parentOrigin = [0.5, 0.5, 0.5];
3295   c.anchorPoint = [0.5, 0.5, 0.5];
3296   t.setCameraActor(c);
3297   defaultCameraParent.add(c);
3298   c.delete(); // wrapper
3299
3300   t.delete(); // wrapper
3301
3302   defaultCameraParent.delete(); // wrapper
3303   defaultCamera.delete(); // wrapper
3304   defaultTask.delete(); // wrapper
3305
3306   taskList.delete(); // wrapper
3307 };
3308
3309 /**
3310  * Creates render tasks and cameras for a three pane view.
3311  * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
3312  * (in a separate function to allow window gutters)
3313  * @method threePane
3314  */
3315 dali.threePane = function() {
3316   "use strict";
3317   dali.onePane();
3318
3319   var stage = dali.stage;
3320   var taskList = stage.getRenderTaskList();
3321
3322   var defaultTask = taskList.getTask(0);
3323   var defaultCamera = defaultTask.getCameraActor();
3324   var defaultCameraParent = defaultCamera.getParent();
3325
3326   var t;
3327   t = taskList.createTask();
3328
3329   var c = new dali.CameraActor(); // add camera for different viewpoint
3330   c.position = [0, 0, 800];
3331   c.orientation = [0, 1, 0, 180];
3332   c.parentOrigin = [0.5, 0.5, 0.5];
3333   c.anchorPoint = [0.5, 0.5, 0.5];
3334   t.setCameraActor(c);
3335   defaultCameraParent.add(c);
3336   c.delete(); // wrapper
3337
3338   t.delete(); // wrapper
3339
3340   t = taskList.createTask();
3341
3342   c = new dali.CameraActor(); // add camera for different viewpoint
3343   c.position = [0, 0, 800];
3344   c.orientation = [0, 1, 0, 180];
3345   c.parentOrigin = [0.5, 0.5, 0.5];
3346   c.anchorPoint = [0.5, 0.5, 0.5];
3347   t.setCameraActor(c);
3348   defaultCameraParent.add(c);
3349   c.delete(); // wrapper
3350
3351   t.delete(); // wrapper
3352
3353   defaultCameraParent.delete(); // wrapper
3354   defaultCamera.delete(); // wrapper
3355   defaultTask.delete(); // wrapper
3356
3357   taskList.delete(); // wrapper
3358 };
3359
3360 //------------------------------------------------------------------------------
3361 //
3362 // Dali Initialization Module
3363 //
3364 //------------------------------------------------------------------------------
3365
3366 /**
3367  * Create a Dali object by type name
3368  * @method create
3369  * @param {string} name The type name to create
3370  * @return A Dali handle to the Dali object
3371  */
3372 dali.create = function(name) {
3373   "use strict";
3374
3375   var handle = dali.__createActor(name);
3376
3377   if (!handle.ok()) {
3378     handle.delete(); // handle
3379     handle = dali.__createHandle(name);
3380   }
3381
3382   dali.internalSetupProperties(handle);
3383
3384   return handle;
3385 };
3386
3387 dali.updateFrame = function() {
3388   dali.__updateOnce();
3389   dali.__renderOnce();
3390 };
3391
3392 /**
3393  * Creates constructors for objects found in the TypeRegistry. Some objects are
3394  * individually wrapped. Sets some global objects eg. debug/stage.
3395  */
3396 /** private */
3397 dali.init = function() {
3398   "use strict";
3399
3400   console.log( dali.VersionString() );
3401
3402   dali.jsSignalHolder = new dali.SignalHolder(); // for js callbacks
3403
3404   dali.debug = new dali.Debug();
3405
3406   dali.stage = new dali.Stage();
3407
3408   dali.getStage = function() { // duplication of dali.stage to stop regressions
3409     return dali.stage;
3410   };
3411
3412   //
3413   // Add constructor functions to dali from the type registry
3414   //
3415   // Uses separate create functions to add methods for the different base classes.
3416   // Other generic access is by properties. Currently
3417   //
3418   //              +------------+
3419   //              | BaseHandle |
3420   //              +------+-----+
3421   //                     |
3422   //      |--------------+------------|
3423   //      |              |            |
3424   // +----+------+  +----+---+   +----+--+
3425   // | Animation |  | Handle |   | Image |
3426   // +-----------+  +--------+   +-------+
3427   //
3428
3429   var t = new dali.TypeRegistry();
3430
3431   // use the emscripten wrapping for these and not the typeregisitry creation function
3432   var useWrapping = { RenderTask: 1, RenderTaskList: 1, CameraActor: 1,
3433                       TypeInfo: 1,
3434                       Path: 1, Animation: 1,
3435                       Handle: 1, Actor: 1,
3436                       PropertyMap: 1, PropertyBuffer: 1,
3437                       Image: 1, BufferImage: 1, EncodedBufferImage: 1,
3438                       Geometry: 1, Material: 1, Shader: 1, Sampler: 1, Renderer: 1
3439                     };
3440
3441   for (var i = 0; i < t.getTypeNameCount(); i++) {
3442     // anon function because of closure with defineProperty
3443     // (if just variable in loop then the variable 'address' is captured, not the value
3444     //  so it becomes last value set)
3445     (function(name) {
3446       var createFunc;
3447       var info = t.getTypeInfo(name);
3448
3449       if(dali.typeInheritsFrom(info, "Actor")) {
3450         createFunc = dali.__createActor;
3451       } else if(dali.typeInheritsFrom(info, "Handle")) {
3452         createFunc = dali.__createHandle;
3453       }
3454
3455       // @todo Dali error?? name lengths should never be zero
3456       if (name.length && !(name in useWrapping) ) {
3457         Object.defineProperty(dali, name, {
3458           enumerable: true,
3459           configurable: false,
3460           get: function() {
3461             return function() {
3462               // console.log(name);
3463               return dali.create(name);
3464             };
3465           }
3466         });
3467       }
3468     })(t.getTypeName(i));
3469   }
3470
3471   dali.updateFrame();
3472
3473 }(); // call init
3474
3475
3476 //------------------------------------------------------------------------------
3477 //
3478 // Post run
3479 //
3480 // Call postDaliWrapperRun() to indicate dali-wrapper.js has loaded
3481 // and other sequential tasks can run (js files can load async)
3482 //
3483 //------------------------------------------------------------------------------
3484 if(Module)
3485 {
3486   if (Module.postDaliWrapperRun) {
3487     Module.postDaliWrapperRun();
3488   }
3489 }