Merge "Emscripten minimal adaptor build" into devel/master
[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, dataLength);
1516
1517   propertyBuffer.setData(buffer);
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 // ShaderEffect Module
1740 //
1741 //------------------------------------------------------------------------------
1742 dali.__ShaderEffectConstructor = dali.ShaderEffect;
1743 dali.ShaderEffect = function() {
1744   "use strict";
1745   var a = new dali.__PathConstructor();
1746   dali.internalSetupProperties(a);
1747   return a;
1748 };
1749
1750 //------------------------------------------------------------------------------
1751 //
1752 // New Mesh Module
1753 //
1754 //------------------------------------------------------------------------------
1755 dali.__ShaderConstructor = dali.Shader;
1756 dali.Shader = function(vertex, fragment, hints) {
1757   "use strict";
1758   var a = new dali.__ShaderConstructor(vertex, fragment, hints);
1759   dali.internalSetupProperties(a);
1760   return a;
1761 };
1762
1763 dali.__MaterialConstructor = dali.Material;
1764 dali.Material = function(shader) {
1765   "use strict";
1766   var a = new dali.__MaterialConstructor(shader);
1767   dali.internalSetupProperties(a);
1768   return a;
1769 };
1770
1771 dali.__RendererConstructor = dali.Renderer;
1772 dali.Renderer = function(geometry, material) {
1773   "use strict";
1774   var a = new dali.__RendererConstructor(geometry, material);
1775   dali.internalSetupProperties(a);
1776   return a;
1777 };
1778
1779 //------------------------------------------------------------------------------
1780 //
1781 // Animation Module
1782 //
1783 //------------------------------------------------------------------------------
1784 dali.__PathConstructor = dali.Path;
1785 dali.Path = function() {
1786   "use strict";
1787   var a = new dali.__PathConstructor();
1788   dali.internalSetupProperties(a);
1789   return a;
1790 };
1791
1792 /**
1793  * animateTo a value
1794  * @method animateTo
1795  * @param {object} The object
1796  * @param {string} propertyName The objects property name
1797  * @param {any} value The value
1798  * @param {string} alphaFunction The alpha function
1799  * @param {float} delay The delay
1800  * @param {float} duration The duration
1801  */
1802 dali.Animation.prototype.animateTo = function(object, propertyName, value, alphaFunction, delay, duration) {
1803   "use strict";
1804   var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
1805   if (propertyValue) {
1806     this.__animateTo(object, propertyName, propertyValue, alphaFunction, delay, duration);
1807     propertyValue.delete();
1808   } else {
1809     throw new Error("Unknown property?");
1810   }
1811 };
1812
1813 /**
1814  * animateBy a value
1815  * @method animateBy
1816  * @param {object} The object
1817  * @param {string} propertyName The objects property name
1818  * @param {any} value The value
1819  * @param {string} alphaFunction The alpha function
1820  * @param {float} delay The delay
1821  * @param {float} duration The duration
1822  */
1823 dali.Animation.prototype.animateBy = function(object, propertyName, value, alphaFunction, delay, duration) {
1824   "use strict";
1825   var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
1826   if (propertyValue) {
1827     this.__animateBy(object, propertyName, propertyValue, alphaFunction, delay, duration);
1828     propertyValue.delete();
1829   } else {
1830     throw new Error("Unknown property?");
1831   }
1832 };
1833
1834 /**
1835  * Animate a Path
1836  * @method animatePath
1837  * @param {object} The object
1838  * @param {Dali.Path} pathObject The path object
1839  * @param {array} forward The path forward vector
1840  * @param {string} alphaFunction The alpha function
1841  * @param {float} delay The delay
1842  * @param {float} duration The duration
1843  */
1844 dali.Animation.prototype.animatePath = function(object, pathObject, forward, alphaFunction, delay, duration) {
1845   "use strict";
1846   this.__animatePath(object, pathObject, forward, alphaFunction, delay, duration);
1847 };
1848
1849 /**
1850  * animateBetween a value
1851  * @method animateBetween
1852  * @param {object} The object
1853  * @param {string} propertyName The objects property name
1854  * @param {dali.KeyFrames} keyFrames The keyframes
1855  * @param {string} alphaFunction The alpha function
1856  * @param {float} delay The delay
1857  * @param {float} duration The duration
1858  */
1859 dali.Animation.prototype.animateBetween = function(object, propertyName, keyFrames, alphaFunction, delay, duration, interpolation) {
1860   "use strict";
1861   var propertyValue;
1862
1863   var daliKeyFrames = new dali.KeyFrames();
1864
1865   for(var i = 0; i < keyFrames.length; i++) {
1866     if(keyFrames[i].length > 2) { // has alpha
1867       propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
1868       if(!propertyValue) {
1869         throw new Error("Unknown property?");
1870       }
1871       daliKeyFrames.add(keyFrames[i][0], propertyValue, keyFrames[i][2]);
1872       propertyValue.delete();
1873     } else {
1874       propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
1875       if(!propertyValue) {
1876         throw new Error("Unknown property?");
1877       }
1878       daliKeyFrames.add(keyFrames[i][0], propertyValue);
1879       propertyValue.delete();
1880     }
1881   }
1882
1883   this.__animateBetween(object, propertyName, daliKeyFrames, alphaFunction, delay, duration, interpolation);
1884
1885   daliKeyFrames.delete();
1886
1887 };
1888
1889 //------------------------------------------------------------------------------
1890 //
1891 // RenderTask Module
1892 //
1893 //------------------------------------------------------------------------------
1894 dali.RenderTask.prototype.getCameraActor = function() {
1895   "use strict";
1896   var a = this.__getCameraActor();
1897   if (a.ok()) {
1898     dali.internalSetupProperties(a);
1899   }
1900   return a;
1901 };
1902
1903 Object.defineProperty(dali.RenderTask.prototype, "x", {
1904   enumerable: true,
1905   configurable: false,
1906   get: function() {
1907     return this.getCurrentViewportPosition()[0];
1908   },
1909   set: function(v) {
1910     var pos = this.getCurrentViewportPosition();
1911     this.setViewportPosition(v, pos[1]);
1912   }
1913 });
1914
1915 Object.defineProperty(dali.RenderTask.prototype, "y", {
1916   enumerable: true,
1917   configurable: false,
1918   get: function() {
1919     return this.getCurrentViewportPosition()[1];
1920   },
1921   set: function(v) {
1922     var pos = this.getCurrentViewportPosition();
1923     this.setViewportPosition(pos[0], v);
1924   }
1925 });
1926
1927 Object.defineProperty(dali.RenderTask.prototype, "width", {
1928   enumerable: true,
1929   configurable: false,
1930   get: function() {
1931     return this.getCurrentViewportSize()[0];
1932   },
1933   set: function(v) {
1934     var pos = this.getCurrentViewportSize();
1935     this.setViewportSize(v, pos[1]);
1936   }
1937 });
1938
1939 Object.defineProperty(dali.RenderTask.prototype, "height", {
1940   enumerable: true,
1941   configurable: false,
1942   get: function() {
1943     return this.getCurrentViewportSize()[1];
1944   },
1945   set: function(v) {
1946     var pos = this.getCurrentViewportSize();
1947     this.setViewportSize(pos[0], v);
1948   }
1949 });
1950
1951 //------------------------------------------------------------------------------
1952 //
1953 // Solid Actor Module
1954 //
1955 //------------------------------------------------------------------------------
1956
1957 /**
1958  * Create a solid color actor
1959  * @method createSolidColorActor
1960  * @param {array} color The color
1961  * @param {bool} border Whether to add a border
1962  * @param {array} color The border color
1963  * @param {float} borderSize The size of a border
1964  * @return {Dali.Actor} The Dali actor
1965  */
1966 dali.createSolidColorActor = function(color, border, borderColor, borderSize) {
1967   "use strict";
1968   var a = dali.__createSolidColorActor(color, border, borderColor, borderSize);
1969   dali.internalSetupProperties(a);
1970   return a;
1971 };
1972
1973 //------------------------------------------------------------------------------
1974 //
1975 // Mesh import support Module
1976 //
1977 //------------------------------------------------------------------------------
1978 function ObjectLoader(fileObject) {
1979   "use strict";
1980   // cached
1981   this.self = this;
1982   this.meshByUUID = {};
1983   this.geomByUUID = {};
1984   this.matByUUID = {};
1985
1986   this.fileObject = fileObject;
1987 }
1988
1989 function __longToArray(v) {
1990   "use strict";
1991   return [((v >> 24) & 0xFF) / 255.0, ((v >> 16) & 0xFF) / 255.0, ((v >> 8) & 0xFF) / 255.0, (v & 0xFF) / 255.0];
1992 }
1993
1994 function __isBitSet(value, bit) {
1995   "use strict";
1996   return (value & (1 << bit));
1997 }
1998
1999 ObjectLoader.prototype.__getMaterial = function(uuid) {
2000   "use strict";
2001   if (!(uuid in this.matByUUID)) {
2002     for (var i = 0, len = this.fileObject.materials.length; i < len; i++) {
2003       var f_mat = this.fileObject["materials"][i];
2004       skewer.log(i + ":" + f_mat["uuid"] + " " + (f_mat["uuid"] === uuid));
2005       if (f_mat["uuid"] === uuid) {
2006         assert(f_mat["type"] === "MeshPhongMaterial");
2007         var mat = new dali.MaterialWrapper(uuid);
2008         mat.setDiffuseColor(__longToArray(f_mat["color"]));
2009         mat.setAmbientColor(__longToArray(f_mat["ambient"]));
2010         mat.setSpecularColor(__longToArray(f_mat["specular"]));
2011         mat.setEmissiveColor(__longToArray(f_mat["emmissive"]));
2012         mat.setShininess(f_mat["shininess"]);
2013         this.matByUUID[uuid] = mat;
2014         break;
2015       }
2016     }
2017   }
2018   return this.matByUUID[uuid];
2019 };
2020
2021 ObjectLoader.prototype.__getMeshData = function(uuid, uuid_material) {
2022   "use strict";
2023   if (!(uuid in this.meshByUUID)) {
2024     for (var i = 0, len = this.fileObject["geometries"].length; i < len; i++) {
2025       var f_geom = this.fileObject["geometries"][i];
2026       if (f_geom["uuid"] === uuid) {
2027         var f_indices, // file data
2028             f_posns,
2029             f_norms,
2030             f_uvs,
2031             f_faces;
2032
2033         if (!("metadata" in f_geom)) {
2034           f_geom["metadata"] = {
2035             "type": ""
2036           }; // Warning: modified input!?
2037         }
2038
2039         if ("formatVersion" in f_geom["metadata"]) // then version 3.1
2040         {
2041           f_indices = f_geom["indices"];
2042           f_posns = f_geom["vertices"];
2043           f_norms = f_geom["normals"];
2044           f_uvs = f_geom["uvs"];
2045           f_faces = f_geom["faces"];
2046         } else if (f_geom["type"] === "Geometry") // V4 clara io output? not standard???
2047         {
2048           f_indices = f_geom["data"]["indices"];
2049           f_posns = f_geom["data"]["vertices"];
2050           f_norms = f_geom["data"]["normals"];
2051           f_uvs = f_geom["data"]["uvs"];
2052           f_faces = f_geom["data"]["faces"];
2053         } else if (f_geom["metadata"]["type"] === "Geometry") // V4
2054         {
2055           f_indices = f_geom["indices"];
2056           f_posns = f_geom["vertices"];
2057           f_norms = f_geom["normals"];
2058           f_uvs = f_geom["uvs"];
2059           f_faces = f_geom["faces"];
2060         } else if (f_geom["metadata"]["type"] === "BufferGeometry") // V4
2061         {
2062           f_posns = f_geom["data"]["attributes"]["position"]["array"];
2063           f_norms = f_geom["data"]["attributes"]["norms"]["array"];
2064           f_uvs = f_geom["data"]["attributes"]["uv"]["array"];
2065         }
2066
2067         var nUvLayers = 0;
2068
2069         // disregard empty arrays
2070         for (var i = 0; i < this.fileObject.uvs.length; i++) {
2071           if (this.fileObject.uvs[i].length)
2072             nUvLayers++;
2073         }
2074
2075         var verts = new dali.VectorVertex();
2076         var vert = []; //new dali.Vertex();
2077         for (var i = 0, len = f_posns.length / 3; i < len; i++) {
2078           vert.push(f_posns[(i * 3) + 0]);
2079           vert.push(f_posns[(i * 3) + 1]);
2080           vert.push(f_posns[(i * 3) + 2]);
2081
2082           vert.push(0); // norm
2083           vert.push(0);
2084           vert.push(0);
2085
2086           vert.push(0); // uvs
2087           vert.push(0);
2088
2089           verts.push_back(vert);
2090         }
2091
2092         var mesh = new dali.MeshDataWrapper();
2093         var faces = new dali.VectorFaceIndex();
2094         var faceSets = {};
2095         //faceSets.length = this.fileObject.materials;
2096         for (var i = 0, len = this.fileObject.materials.length; i < len; ++i) {
2097           // get materials and force them to be loaded up
2098           var mat = this.__getMaterial(this.fileObject.materials[i]["uuid"]);
2099         }
2100
2101         var idx = 0;
2102         var idx_len = f_faces.length;
2103         var materialUUID = undefined;
2104         while (idx < idx_len) {
2105           var f_type = f_faces[idx++];
2106           var isQuad = __isBitSet(f_type, 0);
2107           var hasMaterial = __isBitSet(f_type, 1);
2108           var hasFaceUv = __isBitSet(f_type, 2);
2109           var hasFaceVertexUv = __isBitSet(f_type, 3);
2110           var hasFaceNormal = __isBitSet(f_type, 4);
2111           var hasFaceVertexNormal = __isBitSet(f_type, 5);
2112           var hasFaceColor = __isBitSet(f_type, 6);
2113           var hasFaceVertexColor = __isBitSet(f_type, 7);
2114
2115           var nVertices = 3;
2116           var faceVertexIndices;
2117           if (isQuad) {
2118             faces.push_back(f_faces[idx]);
2119             faces.push_back(f_faces[idx + 1]);
2120             faces.push_back(f_faces[idx + 2]);
2121
2122             faces.push_back(f_faces[idx]);
2123             faces.push_back(f_faces[idx + 2]);
2124             faces.push_back(f_faces[idx + 3]);
2125
2126             faceVertexIndices = [f_faces[idx],
2127                                  f_faces[idx + 1],
2128                                  f_faces[idx + 2]
2129                                 ];
2130
2131             idx += 4;
2132             nVertices = 4;
2133           } else {
2134             faces.push_back(f_faces[idx]);
2135             faces.push_back(f_faces[idx + 1]);
2136             faces.push_back(f_faces[idx + 2]);
2137
2138             faceVertexIndices = [f_faces[idx],
2139                                  f_faces[idx + 1],
2140                                  f_faces[idx + 2]
2141                                 ];
2142
2143             idx += 3;
2144           }
2145
2146           if (hasMaterial) {
2147             if (materialUUID === undefined) {
2148               materialUUID = this.fileObject.materials[f_faces[idx]]["uuid"];
2149             } else {
2150               // different material per face is bonkers - I'm not going to support it.
2151               if (this.fileObject.materials[f_faces[idx]]["uuid"] !== materialUUID) {
2152                 throw "Faces with different materials is not supported";
2153               }
2154             }
2155             idx++;
2156           }
2157
2158
2159           if (hasFaceUv) {
2160             for (var i = 0; i < nUvLayers; i++) {
2161               var uvLayer = self.fileObject.uvs[i];
2162               var uvIndex = f_faces[idx++];
2163               var u = uvLayer[uvIndex * 2];
2164               var v = uvLayer[uvIndex * 2 + 1];
2165               // discarded - tbd ?
2166             }
2167           }
2168
2169           if (hasFaceVertexUv) {
2170             for (var i = 0; i < nUvLayers; i++) {
2171               var uvLayer = f_geom.uvs[i];
2172               var uvs = [];
2173               for (var j = 0; j < nVertices; j++) {
2174                 var uvIndex = f_faces[idx++];
2175                 var u = uvLayer[uvIndex * 2];
2176                 var v = uvLayer[uvIndex * 2 + 1];
2177                 // discarded- tbd ?
2178               }
2179             }
2180           }
2181
2182           if (hasFaceNormal) {
2183             var normalIndex = f_faces[idx++] * 3;
2184
2185             var x = f_geom.normals[normalIndex++];
2186             var y = f_geom.normals[normalIndex++];
2187             var z = f_geom.normals[normalIndex];
2188
2189             for (var i = 0; i < faceVertexIndices.length; i++) {
2190               var v = vert.get(faceVertexIndices[i]);
2191
2192               v[4] += x;
2193               v[5] += y;
2194               v[6] += z;
2195             }
2196           }
2197
2198           if (hasFaceVertexNormal) {
2199             for (var i = 0; i < nVertices; i++) {
2200               var normalIndex = faces[idx] * 3;
2201               var x = f_geom.normals[normalIndex++];
2202               var y = f_geom.normals[normalIndex++];
2203               var z = f_geom.normals[normalIndex];
2204
2205               var v = vert.get(faces[idx]);
2206
2207               v[4] += x;
2208               v[5] += y;
2209               v[6] += z;
2210
2211               idx += 1;
2212               // face.vertexNormals.push( normal );
2213             }
2214           }
2215
2216           if (hasFaceColor) {
2217             var color = f_faces[idx++];
2218           }
2219
2220           if (hasFaceVertexColor) {
2221             for (var i = 0; i < nVertices; i++) {
2222               var colorIndex = faces[idx++];
2223               var color = f_geom.colors[colorIndex]; // ??? f_geom.colors?
2224               // face.vertexColors.push( color );
2225             }
2226           }
2227
2228           var faces = null;
2229           if (f_faces) {
2230             for (var i = 1, len = f_faces.length; i < len; i++) {
2231               faces.push_back(f_faces[i]);
2232             }
2233           }
2234
2235           if (f_indices) {
2236             faces = new dali.VectorFaceIndex();
2237             for (var i = 1, len = f_indices.length; i < len; i++) {
2238               faces.push_back(f_indices[i]);
2239             }
2240           }
2241
2242           if (!faces) {
2243             faces = [];
2244             for (var i = 0, len = f_posns.length; i < len; i++) {
2245               faces.push(i);
2246             }
2247           }
2248
2249           console.log(verts.size() + ":" + faces.size() + ":" + uuid_material);
2250
2251           var material = this.__getMaterial(uuid_material);
2252           mesh.setLineData(verts, faces, material);
2253         }
2254
2255         this.meshByUUID[uuid] = mesh;
2256         verts.delete();
2257         faces.delete();
2258         break;
2259       } // if uuid found
2260     } // for geom in geometries
2261   } // if uid ! in meshByUUID
2262
2263   return this.meshByUUID[uuid];
2264 };
2265
2266 ObjectLoader.prototype.delete = function() {
2267   "use strict";
2268   for (var a in this.meshByUUID) {
2269     a.delete();
2270   }
2271   this.meshByUUID = {};
2272   for (var b in this.matByUUID) {
2273     b.delete();
2274   }
2275   this.matByUUID = {};
2276 };
2277
2278 ObjectLoader.prototype.createMeshActors = function() {
2279   "use strict";
2280   var ret = [];
2281   if ("object" in this.fileObject) {
2282     for (var i = 0, len = this.fileObject["object"]["children"].length; i < len; i++) {
2283       var child = this.fileObject["children"];
2284       if (child["type"] === "Mesh") {
2285         var meshData = this.__getMeshData(child["geometry"],
2286                                           child["material"]);
2287         ret.push(dali.__createMeshActor(meshData));
2288         meshData.delete();
2289       }
2290     }
2291   }
2292
2293   var parent;
2294
2295   if (ret) {
2296     parent = new dali.Actor();
2297     for (var a in ret) {
2298       parent.add(a);
2299       a.delete();
2300     }
2301   }
2302
2303   return parent;
2304 };
2305
2306 dali.createMeshActor = function(threeDjs_formatV4) {
2307   "use strict";
2308   var loader = new ObjectLoader(threeDjs_formatV4);
2309   return loader.createMeshActor();
2310 };
2311
2312
2313
2314 //------------------------------------------------------------------------------
2315 //
2316 // Hit test
2317 //
2318 //------------------------------------------------------------------------------
2319 dali.hitTest = function(x, y) {
2320   "use strict";
2321   var a = dali.__hitTest(x, y);
2322   if (a.ok()) {
2323     dali.internalSetupProperties(a);
2324     return a;
2325   } else {
2326     return null;
2327   }
2328 };
2329
2330
2331 //------------------------------------------------------------------------------
2332 //
2333 // Shader support
2334 //
2335 //------------------------------------------------------------------------------
2336
2337 /**
2338  * ShaderInfo class to get shader metadata.
2339  */
2340 dali.ShaderInfo = function() {
2341   "use strict";
2342 };
2343
2344 // supported uniforms
2345 dali.ShaderInfo.prototype._supportedUniformTypes = ["bool",
2346                                                     "int",
2347                                                     "float",
2348                                                     "vec2", "vec3", "vec4",
2349                                                     "bvec2", "bvec3", "bvec4",
2350                                                     "ivec2", "ivec3", "ivec4",
2351                                                     "mat2", "mat3", "mat4",
2352                                                     "sampler2D",
2353                                                     "samplerCube"
2354                                                    ];
2355
2356 // need to add a value to uniform registration call
2357 dali.ShaderInfo.prototype._supportedUniformValues = [0,
2358                                                      0,
2359                                                      0.0,
2360                                                      [0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0],
2361                                                      [0, 0], [0, 0, 0], [0, 0, 0, 0],
2362                                                      [0, 0], [0, 0, 0], [0, 0, 0, 0],
2363                                                      [1.0, 0.0,
2364                                                       0.0, 1.0
2365                                                      ],
2366                                                      [1.0, 0.0, 0.0,
2367                                                       0.0, 1.0, 0.0,
2368                                                       0.0, 0.0, 1.0
2369                                                      ],
2370                                                      [1.0, 0.0, 0.0, 0.0,
2371                                                       0.0, 1.0, 0.0, 0.0,
2372                                                       0.0, 0.0, 1.0, 0.0,
2373                                                       0.0, 0.0, 0.0, 1.0
2374                                                      ]
2375                                                     ];
2376
2377
2378 /**
2379  * Get shader metadata from compilation.
2380  *
2381  * Compiles the shader. On error set 'hasError' and error strings. On Success
2382  * query gl for the attributes and uniforms in the shaders.
2383  *
2384  * @param {object} gl ie from canvas.getContext("webgl")
2385  * @param {string} vertex shader
2386  * @param {string} fragment shader
2387  * @return {Object} shader metadata (see 'var info' below)
2388  */
2389 dali.ShaderInfo.prototype.fromCompilation = function(gl, vertex, fragment) {
2390   "use strict";
2391   var i;
2392   var info = {
2393     vertex: vertex,     // vertex source code
2394     fragment: fragment, // fragment source code
2395     attributes: {},     // {aName1: {name:"aName1", ... }
2396     uniforms: {},       // {uName1: {name:"uName1", type:"vec2", ...}
2397     uniformUISpec: {},  // {uName1: {ui:"slider", min:0, max:1, ...}
2398     attributeCount: 0,  // Number of attributes
2399     uniformCount: 0,    // Number of uniforms
2400     hasError: false,    // compiles without error
2401     vertexError: "",    // Vertex compilation error
2402     fragmentError: "",  // Fragment compilation error
2403     linkError: ""       // Linker error
2404   };
2405
2406   var vertexShader = gl.createShader(gl.VERTEX_SHADER);
2407   gl.shaderSource(vertexShader, vertex);
2408   gl.compileShader(vertexShader);
2409
2410   // Check the compile status, return an error if failed
2411   if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
2412     info.hasError = true;
2413     info.vertexError = gl.getShaderInfoLog(vertexShader);
2414   }
2415
2416   var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
2417   gl.shaderSource(fragmentShader, fragment);
2418   gl.compileShader(fragmentShader);
2419
2420   // Check the compile status, return an error if failed
2421   if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
2422     info.hasError = true;
2423     info.fragmentError = gl.getShaderInfoLog(fragmentShader);
2424   }
2425
2426   if(info.hasError) {
2427     gl.deleteShader(vertexShader);
2428     gl.deleteShader(fragmentShader);
2429     return info; // ==> out
2430   } else {
2431     var program = gl.createProgram();
2432     gl.attachShader(program, vertexShader);
2433     gl.attachShader(program, fragmentShader);
2434
2435     gl.linkProgram(program);
2436
2437     if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
2438       info.hasError = true;
2439       info.linkError = gl.getProgramInfoLog(program);
2440       gl.deleteProgram(program);
2441       gl.deleteShader(vertexShader);
2442       gl.deleteShader(fragmentShader);
2443       return info; // ==> out
2444     }
2445   }
2446
2447   var activeUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
2448   var activeAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
2449
2450   // Taken from the WebGl spec:
2451   // http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14
2452   var enums = {
2453     0x8B50: "FLOAT_VEC2",
2454     0x8B51: "FLOAT_VEC3",
2455     0x8B52: "FLOAT_VEC4",
2456     0x8B53: "INT_VEC2",
2457     0x8B54: "INT_VEC3",
2458     0x8B55: "INT_VEC4",
2459     0x8B56: "BOOL",
2460     0x8B57: "BOOL_VEC2",
2461     0x8B58: "BOOL_VEC3",
2462     0x8B59: "BOOL_VEC4",
2463     0x8B5A: "FLOAT_MAT2",
2464     0x8B5B: "FLOAT_MAT3",
2465     0x8B5C: "FLOAT_MAT4",
2466     0x8B5E: "SAMPLER_2D",
2467     0x8B60: "SAMPLER_CUBE",
2468     0x1400: "BYTE",
2469     0x1401: "UNSIGNED_BYTE",
2470     0x1402: "SHORT",
2471     0x1403: "UNSIGNED_SHORT",
2472     0x1404: "INT",
2473     0x1405: "UNSIGNED_INT",
2474     0x1406: "FLOAT"
2475   };
2476
2477   // Loop through active uniforms
2478   for (i = 0; i < activeUniforms; i++) {
2479     var uniform = gl.getActiveUniform(program, i);
2480     info.uniforms[uniform.name] = {name: uniform.name,
2481                                    type: uniform.type,
2482                                    typeName: enums[uniform.type],
2483                                    size: uniform.size};
2484     info.uniformCount += uniform.size;
2485   }
2486
2487   // Loop through active attributes
2488   for (i = 0; i < activeAttributes; i++) {
2489     var attribute = gl.getActiveAttrib(program, i);
2490     info.attributes[attribute.name] = {name: attribute.name,
2491                                        type: attribute.type,
2492                                        typeName: enums[attribute.type],
2493                                        size: attribute.size};
2494     info.attributeCount += attribute.size;
2495   }
2496
2497   // uniformUISpec
2498   this._addUniformMetaData(vertex, info);
2499   this._addUniformMetaData(fragment, info);
2500
2501   return info;
2502 };
2503
2504 /*
2505  * add unform metadata from shader source comments
2506  *  ie return as an object the comment following a uniform
2507  *     uniform float uAlpha; // {"min":0, "max":1}
2508  */
2509 /** private */
2510 dali.ShaderInfo.prototype._addUniformMetaData = function(src, metadata) {
2511   "use strict";
2512   // Loop through active uniforms
2513   for(var name in metadata.uniforms) {
2514     var reguniform = new RegExp(name + "[^;]*;(.*)");
2515
2516     var tmp = reguniform.exec(src);
2517     if(tmp && tmp[1]) {
2518       var meta;
2519       var uComments = tmp[1].trim();
2520       if(uComments.startsWith("//")) { // meta data in comments
2521         try {
2522           meta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
2523           if(typeof meta !== typeof ({})) {
2524             throw ("Uniform UI Spec in comments must be an object");
2525           }
2526         } catch (e) {
2527           meta = {};
2528         }
2529       } else {
2530         meta = {};
2531       }
2532       metadata.uniformUISpec[name] = meta;
2533     }
2534   }
2535 };
2536
2537 /**
2538  * Get shader metadata from regex search.
2539  *
2540  * Attempts a regex search to get the shader meta data.
2541  * Use fromCompilation() instead of this function wherever compilation is
2542  * possible as this approach will never work for all shaders.
2543  * Does no compilation or error checking but retains fields for
2544  * compatibility with .fromCompilation(...)
2545  * May return an error if the regex fails.
2546  *
2547  * @param {string} vertex shader
2548  * @param {string} fragment shader
2549  * @return  {Object} shader metadata (see 'var info' below)
2550  */
2551 dali.ShaderInfo.prototype.fromRegEx = function(vertex, fragment) {
2552   "use strict";
2553   var info = {          // similar to this.fromCompilation()
2554     vertex: vertex,     // source code
2555     fragment: fragment,
2556     attributes: {},     // {aName1: {name:"aName1", ... }
2557     uniforms: {},       // {uName1: {name:"uName1", type:"vec2", ...}
2558     attributeCount: 0,
2559     uniformCount: 0,
2560     uniformUISpec: {},  // {uName1: {ui:"slider", min:0, max:1, ...}
2561     hasError: false,    // compiles without error
2562     vertexError: "",
2563     fragmentError: "",
2564     linkError: ""
2565   };
2566
2567   var metaVertex;
2568   try {
2569     metaVertex = this._getRegExMetaData(vertex);
2570   } catch(e) {
2571     info.hasError = true;
2572     info.vertexError = e.message;
2573     return info;
2574   }
2575
2576   var metaFragment;
2577   try {
2578     metaFragment = this._getRegExMetaData(fragment);
2579   } catch(e) {
2580     info.hasError = true;
2581     info.fragmentError = e.message;
2582     return info;
2583   }
2584
2585   var name;
2586
2587   // merge
2588   info.uniforms = metaVertex.uniformMetaData;
2589   info.uniformUISpec = metaVertex.uniformUISpec;
2590
2591   for(name in metaFragment.uniformMetaData) {
2592     if( name in info.uniforms ) {
2593       info.uniforms[name] = dali.mergeObjects(info.uniforms[name], metaVertex.uniformMetaData);
2594     } else {
2595       info.uniforms[name] = metaFragment.uniformMetaData[name];
2596     }
2597     if( name in info.uniformUISpec ) {
2598       info.uniformUISpec[name] = dali.mergeObjects(info.uniformUISpec[name], metaVertex.uniformUISpec);
2599     } else {
2600       info.uniformUISpec[name] = metaFragment.uniformUISpec[name];
2601     }
2602   }
2603
2604   info.attributes = metaVertex.attributeMetaData;
2605   for(name in metaFragment.attributeMetaData) {
2606     if( name in metaVertex.attributeMetaData ) {
2607       info.attributes[name] = dali.mergeObjects(info.attributes[name], metaVertex.attributeMetaData);
2608     } else {
2609       info.attributes[name] = metaFragment.attributeMetaData[name];
2610     }
2611   }
2612
2613   return info;
2614 };
2615
2616 /*
2617  * Returns a string with all comments removed
2618  */
2619 /** private */
2620 dali.ShaderInfo.prototype._removeComments = function(str) {
2621   "use strict";
2622   var uid = "_" + new Date(),
2623       primatives = [],
2624       primIndex = 0;
2625
2626   return (
2627     str
2628     /* Remove strings */
2629       .replace(/(['"])(\\\1|.)+?\1/g, function(match){
2630         primatives[primIndex] = match;
2631         return (uid + "") + primIndex++;
2632       })
2633
2634     /* Remove Regexes */
2635       .replace(/([^\/])(\/(?!\*|\/)(\\\/|.)+?\/[gim]{0,3})/g, function(match, $1, $2){
2636         primatives[primIndex] = $2;
2637         return $1 + (uid + "") + primIndex++;
2638       })
2639
2640     /*
2641      - Remove single-line comments that contain would-be multi-line delimiters
2642      E.g. // Comment /* <--
2643      - Remove multi-line comments that contain would be single-line delimiters
2644      E.g. /* // <--
2645      */
2646       .replace(/\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//g, "")
2647
2648     /*
2649      Remove single and multi-line comments,
2650      no consideration of inner-contents
2651      */
2652       .replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g, "")
2653
2654     /*
2655      Remove multi-line comments that have a replace ending (string/regex)
2656      Greedy, so no inner strings/regexes will stop it.
2657      */
2658       .replace(RegExp("\\/\\*[\\s\\S]+" + uid + "\\d+", "g"), "")
2659
2660     /* Bring back strings & regexes */
2661       .replace(RegExp(uid + "(\\d+)", "g"), function(match, n){
2662         return primatives[n];
2663       })
2664   );
2665 };
2666
2667 /*
2668  * Returns true if value is in the array
2669  */
2670 /** private */
2671 dali.ShaderInfo.prototype._contains = function(array, value) {
2672   "use strict";
2673   for(var i = 0; i < array.length; i++) {
2674     if(array[i] === value) {
2675       return true;
2676     }
2677   }
2678   // else
2679   return false;
2680 };
2681
2682 /*
2683  * Get the src meta data for unforms and attributes armed only with a regexp
2684  */
2685 /** private */
2686 dali.ShaderInfo.prototype._getRegExMetaData = function(src) {
2687   "use strict";
2688   var ret = {"uniforms": [],         // ["uName1", ["uName2"]
2689              "uniformMetaData": {},  // {uName1: {type:"vec3,...}
2690              "uniformUISpec": {},    // {ui:"slider", min:..., max:...}
2691              "attributes": [],       // ["aName2"]
2692              "attributeMetaData": {} // ["aName2"]
2693             };
2694
2695   // Undoubtedly this approach will be wrong. Hopefully on not too many corner cases...
2696   // A better way is to compile the source see (fromCompilation())
2697   // but that requres a gl context.
2698   var tmp;
2699
2700   var definesOut = /#define[ \t]+([A-Za-z_0-9]*)[ \t]+(.*)/g;
2701
2702   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;
2703
2704   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;
2705
2706   // 1. no commented out uniforms
2707   var noCommentSource = this._removeComments(src);
2708
2709   var validUniforms = [];
2710   while ((tmp = reg.exec(noCommentSource))) {
2711     validUniforms.push( tmp[3] );
2712   }
2713
2714   while ((tmp = regAttrib.exec(noCommentSource))) {
2715     ret.attributes.push( tmp[3] );
2716     ret.attributeMetaData[ tmp[3] ] = {name: tmp[3], type: tmp[2] };
2717   }
2718
2719   // 2. replace defines
2720   var defines = [];
2721   while ((tmp = definesOut.exec(noCommentSource))) {
2722     defines.push([tmp[1], tmp[2]]);
2723   }
2724   var defineDict = {};
2725   var defineList = [];
2726   while(defines.length) {
2727     var p = defines.pop();
2728     var n = p[0];
2729     var v = p[1];
2730     try {
2731       defineDict[n] = eval(v);
2732       defineList.push([n, defineDict[n]]);
2733     } catch(e) {
2734       var d = /([A-Za-z]+[A-Za-z0-9]*)/g;
2735       while ((tmp = d.exec(v))) {
2736         if(tmp[0] in defineDict) {
2737           v = v.replace(tmp[0], defineDict[tmp[0]]);
2738         } else {
2739           defines.push(p); // stick it back to try again. ...and endless loop if we can't(!)
2740         }
2741       }
2742     }
2743   }
2744
2745   for(var i = 0; i < defineList.length; i++) {
2746     var re = new RegExp(defineList[i][0], "g");
2747     src = src.replace(re, defineList[i][1]);
2748   }
2749
2750   // 3. get uniforms
2751   while ((tmp = reg.exec(src))) {
2752     if(!this._contains(validUniforms, tmp[3])) {
2753       continue;
2754     }
2755     var uType = tmp[2];
2756     var uName = tmp[3];
2757     var uArray = tmp[4].slice(0, -1);
2758     var uComments = tmp[5].trim();
2759     var meta;
2760     var uiSpecMeta = null;
2761     if(uComments.startsWith("//")) { // meta data in comments
2762       uiSpecMeta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
2763       if(typeof uiSpecMeta !== typeof ({})) {
2764         throw ("Uniform UI Spec in comments must be an object");
2765       }
2766     }
2767
2768     if(uiSpecMeta) {
2769       uiSpecMeta.name = tmp[3];
2770       ret.uniformUISpec[uName] = uiSpecMeta;
2771     }
2772
2773     meta = {};
2774     meta.type = tmp[2];
2775     meta.name = tmp[3];
2776     meta.count = 0;
2777
2778     var name;
2779     if(uArray.search("[[]") >= 0) { // an array
2780       meta.count = Number(uArray.slice(1, -1));
2781     }
2782
2783     if(this._contains( this._supportedUniformTypes, uType) ) {
2784       if(meta.count !== 0) { // array
2785         for(var j = 0; j < meta.count; j++) {
2786           ret.uniforms.push( meta.name );
2787           ret.uniformMetaData[ meta.name ] = {type: meta.type,
2788                                               name: meta.name + "[" + j + "]",
2789                                               index: j,
2790                                               count: meta.count};
2791         }
2792       } else {
2793         ret.uniforms.push( meta.name );
2794         ret.uniformMetaData[ meta.name ] = {type: meta.type,
2795                                             name: meta.name,
2796                                             index: 0,
2797                                             count: 0};
2798       }
2799     } else {
2800       // not a base type so need to get the compound type
2801       var structFind = new RegExp( "(struct[ \t\n]*" + uType + "[^{]*{)([^}]*)", "g");
2802       var structLines = structFind.exec(src)[2].split(";");
2803       var structUniforms = [];
2804       var tmpStruct;
2805       var k;
2806       for(var lineNo = 0; lineNo < structLines.length; lineNo++) {
2807         var line = structLines[lineNo].replace(/\n/g, "") + ";";
2808         if(line !== ";") {
2809           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;
2810           while ((tmpStruct = structReg.exec(line))) {
2811             structUniforms.push( { type: tmpStruct[2],
2812                                    name: tmpStruct[3],
2813                                    count: meta.count } );
2814           }
2815         }
2816       }
2817       if(meta.count === 0) {
2818         for(k = 0; k < structUniforms.length; k++) {
2819           name = uName + "." + structUniforms[k].name;
2820           ret.uniforms.push( name );
2821           ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
2822                                          name: name,
2823                                          count: meta.count,
2824                                          index: 0,
2825                                          structType: meta.type,
2826                                          structName: meta.name};
2827         }
2828       } else { // array
2829         for(var l = 0; l < meta.count; l++) {
2830           for(k = 0; k < structUniforms.length; k++) {
2831             name = uName + "[" + l + "]" + "." + structUniforms[k].name;
2832             ret.uniforms.push( name );
2833             ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
2834                                            name: name,
2835                                            count: meta.count,
2836                                            index: l,
2837                                            structType: meta.type,
2838                                            structName: meta.name};
2839           }
2840         }
2841       }
2842     }
2843   }
2844
2845   return ret;
2846 };
2847
2848 //------------------------------------------------------------------------------
2849 //
2850 // Debug Module
2851 //
2852 //------------------------------------------------------------------------------
2853 dali.Debug = function() {
2854   "use strict";
2855 };
2856
2857 dali.Debug.prototype.printTypeProperties = function(typeName) {
2858   "use strict";
2859   var t = new dali.TypeRegistry();
2860   var info = t.getTypeInfo(typeName);
2861   var props = info.getProperties();
2862   for (var i = 0; i < props.size(); i++) {
2863     console.log(i + ":" + props.get(i));
2864   }
2865   info.delete(); // wrapper
2866   t.delete(); // wrapper
2867 };
2868
2869 dali.Debug.prototype.printProperties = function(o) {
2870   "use strict";
2871   var props = o.getProperties();
2872
2873   var len = props.size();
2874   for(var i = 0; i < len; i++) {
2875     var name = props.get(i);
2876     var type = o.getPropertyTypeName(name);
2877     if(type !== "NONE") {
2878       console.log(i + ":" + name + " " + type);
2879     } else {
2880       type = o.getPropertyTypeName(name);
2881       console.log(i + ":" + name + " " + type + " (Not mangled)");
2882     }
2883   }
2884   props.delete(); // wrapper
2885 };
2886
2887 dali.Debug.prototype.printTypes = function() {
2888   "use strict";
2889
2890   var t = new dali.TypeRegistry();
2891   for (var i = 0; i < t.getTypeNameCount(); i++) {
2892     console.log(t.getTypeName(i));
2893   }
2894   t.delete(); // wrapper
2895 };
2896
2897
2898 dali._debugPrintParents = function(actor, list) {
2899   "use strict";
2900   var p = null;
2901
2902   if (!actor.ok()) {
2903     return;
2904   }
2905
2906   try {
2907     p = actor.getParent();
2908     if (!p.ok()){
2909       p = null;
2910     }
2911   } catch (e) {
2912     // console.log("Cannot get parent", e);
2913   }
2914
2915   if (p) {
2916     list.push(p);
2917     dali._debugPrintParents(p, list);
2918   }
2919 };
2920
2921 dali.Debug.prototype.printTree = function(actor) {
2922   "use strict";
2923   var l = [];
2924   dali._debugPrintParents(actor, l);
2925   var a;
2926   var ti;
2927   console.log("---");
2928   for (var i = l.length - 1; i >= 0; i--) {
2929     a = l[i];
2930     ti = a.getTypeInfo();
2931     console.log("|", Array(l.length - i).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
2932     ti.delete();
2933   }
2934   ti = actor.getTypeInfo();
2935   console.log("*", Array(l.length + 1).join("*"), ti.getName(), "P", actor.position, "R", actor.orientation, actor.name);
2936   ti.delete();
2937
2938   var children = actor.getChildren();
2939   for (var j = 0; j < children.length; j++) {
2940     a = children[j];
2941     ti = a.getTypeInfo();
2942     console.log("|", Array(l.length + 1 + 1 + j).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
2943     ti.delete();
2944   }
2945 };
2946
2947 dali.Debug.prototype.printRenderTask = function(rendertask) {
2948   "use strict";
2949   console.log("[X,Y]", rendertask.getCurrentViewportPosition());
2950   console.log("[W,H]", rendertask.getCurrentViewportSize());
2951
2952   var c = rendertask.getCameraActor();
2953   if (!c.ok()) {
2954     console.log("No Camera");
2955   } else {
2956     console.log("Camera Pos:", c.position);
2957     console.log("Camera Rot:", c.orientation);
2958     console.log("Camera Inherit:", c.inheritRotation);
2959     console.log("Camera ParentOrigin:", c.parentOrigin);
2960     console.log("Camera AnchorPoint:", c.anchorPoint);
2961     var p = null;
2962     try {
2963       p = c.getParent();
2964       if(!p.ok()) {
2965         p = null;
2966       }
2967     } catch (e) {
2968       console.log("Cannot get parent", e);
2969     }
2970
2971     if (!p) {
2972       console.log("Camera has no parent?");
2973     } else {
2974       var ti = p.getTypeInfo();
2975       console.log("Parent Name", ti.getName());
2976       ti.delete();
2977       p.delete();
2978     }
2979   }
2980 };
2981
2982 dali.Debug.prototype.printRenderTasks = function() {
2983   "use strict";
2984   var stage = dali.stage;
2985   var taskList = stage.getRenderTaskList();
2986   for (var i = 0; i < taskList.getTaskCount(); i++) {
2987     var t = taskList.getTask(i);
2988     console.log("RenderTask:", i);
2989     this.printRenderTask(t);
2990     t.delete(); // wrapper
2991   }
2992   taskList.delete(); // wrapper
2993 };
2994
2995 dali.Debug.prototype.findFirstActor = function(actor, predicateFunction) {
2996   "use strict";
2997   for (var i = 0, len = actor.getChildCount(); i < len; i++) {
2998     var a = actor.getChildAt(i);
2999     var found = predicateFunction(a);
3000     if (found) {
3001       return a;
3002     }
3003     var child = this.findFirstActor(a, predicateFunction);
3004     if (child) {
3005       return child;
3006     }
3007     a.delete();
3008   }
3009   return null;
3010 };
3011
3012 dali.Debug.prototype.depthVisit = function(actor, operation, dontDelete) {
3013   "use strict";
3014   for (var i = 0, len = actor.getChildCount(); i < len; i++) {
3015     var a = actor.getChildAt(i);
3016     var done = operation(a);
3017     if (!done) {
3018       return false;
3019     }
3020     if (!this.depthVisit(a, operation, dontDelete)) {
3021       return false;
3022     }
3023     var doit = true;
3024     if (dontDelete !== undefined) {
3025       if (dontDelete) {
3026         doit = false;
3027       }
3028     }
3029     if (doit) {
3030       a.delete();
3031     }
3032   }
3033   return true;
3034 };
3035
3036 dali.operationPrintProperty = function(property, all) {
3037   "use strict";
3038   return (function(actor) {
3039     if (property in actor) {
3040       dali.log(actor.getId() + "property:" + actor[property]);
3041     } else {
3042       dali.log(actor.getId() + "property:n/a");
3043     }
3044     return all;
3045   });
3046 };
3047
3048 dali.predicatePropertyEquals = function(property, value) {
3049   "use strict";
3050   return (function(actor) {
3051     if (property in actor) {
3052       if (actor[property] === value) {
3053         return true;
3054       }
3055     }
3056     return false;
3057   });
3058 };
3059
3060 dali.typeInheritsFrom = function(type, basename) {
3061   var inherits = false;
3062
3063   var registry = new dali.TypeRegistry();
3064
3065   var base = registry.getTypeInfo( type.getBaseName() );
3066
3067   if(base.ok())
3068   {
3069     inherits = (base.getName() === basename);
3070
3071     while(!inherits)
3072     {
3073       base = registry.getTypeInfo( base.getBaseName() );
3074       if(base.ok())
3075       {
3076         inherits = (base.getName() === basename);
3077       }
3078       else
3079       {
3080         break;
3081       }
3082     }
3083   }
3084
3085   return inherits;
3086 };
3087
3088
3089
3090 //------------------------------------------------------------------------------
3091 //
3092 // View Module
3093 //
3094 // Helper functions for creating front/top/left views with RenderTasks
3095 //
3096 //------------------------------------------------------------------------------
3097
3098 /**
3099  * Sets the clear colour in a RenderTask
3100  * @method setClearColor
3101  * @param {int} renderTaskIndex
3102  * @param {array} color The rgba colour array
3103  */
3104 dali.setClearColor = function(renderTaskIndex, color) {
3105   "use strict";
3106   var stage = dali.stage;
3107   var taskList = stage.getRenderTaskList();
3108   if (renderTaskIndex >= taskList.getTaskCount()) {
3109     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3110     taskList.delete(); // wrapper
3111     return;
3112   }
3113   var rendertask = taskList.getTask(renderTaskIndex);
3114   rendertask.setClearEnabled(true);
3115   rendertask.setClearColor(color);
3116 };
3117
3118 /**
3119  * Gets the clear colour of a RenderTask
3120  * @method setClearColor
3121  * @param {int} renderTaskIndex
3122  * @return {array} The rgba colour array
3123  */
3124 dali.getClearColor = function(renderTaskIndex) {
3125   "use strict";
3126   var stage = dali.stage;
3127   var taskList = stage.getRenderTaskList();
3128   if (renderTaskIndex >= taskList.getTaskCount()) {
3129     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3130     taskList.delete(); // wrapper
3131     return null;
3132   }
3133   var rendertask = taskList.getTask(renderTaskIndex);
3134   return rendertask.getClearColor();
3135 };
3136
3137 /**
3138  * Set a front view camera with viewport x,y,w,h
3139  * @method setFrontView
3140  * @param {int} renderTaskIndex
3141  * @param {int} x Viewport X
3142  * @param {int} y Viewport Y
3143  * @param {int} w Viewport W
3144  * @param {int} h Viewport H
3145  */
3146 dali.setFrontView = function(renderTaskIndex, x, y, w, h) {
3147   "use strict";
3148   var stage = dali.stage;
3149   var taskList = stage.getRenderTaskList();
3150   if (renderTaskIndex >= taskList.getTaskCount()) {
3151     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3152     taskList.delete(); // wrapper
3153     return;
3154   }
3155   var rendertask = taskList.getTask(renderTaskIndex);
3156
3157   var c = rendertask.getCameraActor();
3158   assert(c.ok(), "Rendertask has no valid camera actor");
3159
3160   rendertask.setViewportPosition([x, y]);
3161   rendertask.setViewportSize([w, h]);
3162   c.position = [0, 0, 800];
3163   c.orientation = [0, 1, 0, 180];
3164   c.aspectRatio = w / h;
3165
3166   c.delete(); // wrapper
3167   rendertask.delete(); // wrapper
3168   taskList.delete(); // wrapper
3169 };
3170
3171 /**
3172  * Set a top view camera with viewport x,y,w,h
3173  * @method setTopView
3174  * @param {int} renderTaskIndex
3175  * @param {int} x Viewport X
3176  * @param {int} y Viewport Y
3177  * @param {int} w Viewport W
3178  * @param {int} h Viewport H
3179  */
3180 dali.setTopView = function(renderTaskIndex, x, y, w, h) {
3181   "use strict";
3182   var stage = dali.stage;
3183   var taskList = stage.getRenderTaskList();
3184   if (renderTaskIndex >= taskList.getTaskCount()) {
3185     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3186     taskList.delete(); // wrapper
3187     return;
3188   }
3189   var rendertask = taskList.getTask(renderTaskIndex);
3190
3191   var c = rendertask.getCameraActor();
3192   assert(c.ok(), "Rendertask has no valid camera actor");
3193
3194   rendertask.setViewportPosition([x, y]);
3195   rendertask.setViewportSize([w, h]);
3196
3197   var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
3198   var q2 = dali.axisAngleToQuaternion([1, 0, 0, dali.radian(-90)]); // pitch to look at scene
3199   var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
3200
3201   c.position = [0, -800, 0]; // @todo; get 800 from dali not hard coded here
3202   c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
3203   c.aspectRatio = w / h;
3204
3205   c.delete(); // wrapper
3206   rendertask.delete(); // wrapper
3207   taskList.delete(); // wrapper
3208 };
3209
3210 /**
3211  * Set a right view camera with viewport x,y,w,h
3212  * @method setRightView
3213  * @param {int} renderTaskIndex
3214  * @param {int} x Viewport X
3215  * @param {int} y Viewport Y
3216  * @param {int} w Viewport W
3217  * @param {int} h Viewport H
3218  */
3219 dali.setRightView = function(renderTaskIndex, x, y, w, h) {
3220   "use strict";
3221   var stage = dali.stage;
3222   var taskList = stage.getRenderTaskList();
3223   if (renderTaskIndex >= taskList.getTaskCount()) {
3224     console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3225     taskList.delete(); // wrapper
3226     return;
3227   }
3228   var rendertask = taskList.getTask(renderTaskIndex);
3229
3230   var c = rendertask.getCameraActor();
3231   assert(c.ok(), "Rendertask has no valid camera actor");
3232
3233   rendertask.setViewportPosition([x, y]);
3234   rendertask.setViewportSize([w, h]);
3235
3236   var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
3237   var q2 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(90)]); // yaw again to look from right
3238   var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
3239
3240   c.position = [800, 0, 0];
3241   c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
3242   c.aspectRatio = w / h;
3243
3244   c.delete(); // wrapper
3245   rendertask.delete(); // wrapper
3246   taskList.delete(); // wrapper
3247 };
3248
3249 /**
3250  * Remove all but one render task. Presumes RenderTasks are being use only for viewing windows.
3251  * @method onePane
3252  */
3253 dali.onePane = function() {
3254   "use strict";
3255   var stage = dali.stage;
3256   var taskList = stage.getRenderTaskList();
3257   var tasks = [];
3258   var i, len;
3259
3260   for (i = 1, len = taskList.getTaskCount(); i < len; i++) {
3261     tasks.push(taskList.getTask(i));
3262   }
3263
3264   for (i = 0, len = tasks.length; i < len; i++) {
3265     var task = tasks[i];
3266     // delete the camera actors we created in twoPane and threePane
3267     var c = task.getCameraActor();
3268     if (c.ok()) {
3269       var p = c.getParent();
3270       if (p.ok()) {
3271         p.remove(c);
3272       }
3273       p.delete(); // wrapper
3274     }
3275     c.delete(); // wrapper
3276
3277     taskList.removeTask(task);
3278     task.delete(); // wrapper
3279   }
3280
3281   taskList.delete();
3282 };
3283
3284 /**
3285  * Creates render tasks and cameras for a two pane view.
3286  * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
3287  * (in a separate function to allow window gutters)
3288  * @method twoPane
3289  */
3290 dali.twoPane = function() {
3291   "use strict";
3292   dali.onePane();
3293
3294   var stage = dali.stage;
3295   var taskList = stage.getRenderTaskList();
3296
3297   var defaultTask = taskList.getTask(0);
3298   var defaultCamera = defaultTask.getCameraActor();
3299   var defaultCameraParent = defaultCamera.getParent();
3300
3301   var t;
3302   t = taskList.createTask();
3303
3304   var c = new dali.CameraActor(); // add camera for different viewpoint
3305   c.position = [0, 0, 800];
3306   c.orientation = [0, 1, 0, 180];
3307   c.parentOrigin = [0.5, 0.5, 0.5];
3308   c.anchorPoint = [0.5, 0.5, 0.5];
3309   t.setCameraActor(c);
3310   defaultCameraParent.add(c);
3311   c.delete(); // wrapper
3312
3313   t.delete(); // wrapper
3314
3315   defaultCameraParent.delete(); // wrapper
3316   defaultCamera.delete(); // wrapper
3317   defaultTask.delete(); // wrapper
3318
3319   taskList.delete(); // wrapper
3320 };
3321
3322 /**
3323  * Creates render tasks and cameras for a three pane view.
3324  * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
3325  * (in a separate function to allow window gutters)
3326  * @method threePane
3327  */
3328 dali.threePane = function() {
3329   "use strict";
3330   dali.onePane();
3331
3332   var stage = dali.stage;
3333   var taskList = stage.getRenderTaskList();
3334
3335   var defaultTask = taskList.getTask(0);
3336   var defaultCamera = defaultTask.getCameraActor();
3337   var defaultCameraParent = defaultCamera.getParent();
3338
3339   var t;
3340   t = taskList.createTask();
3341
3342   var 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   t = taskList.createTask();
3354
3355   c = new dali.CameraActor(); // add camera for different viewpoint
3356   c.position = [0, 0, 800];
3357   c.orientation = [0, 1, 0, 180];
3358   c.parentOrigin = [0.5, 0.5, 0.5];
3359   c.anchorPoint = [0.5, 0.5, 0.5];
3360   t.setCameraActor(c);
3361   defaultCameraParent.add(c);
3362   c.delete(); // wrapper
3363
3364   t.delete(); // wrapper
3365
3366   defaultCameraParent.delete(); // wrapper
3367   defaultCamera.delete(); // wrapper
3368   defaultTask.delete(); // wrapper
3369
3370   taskList.delete(); // wrapper
3371 };
3372
3373 //------------------------------------------------------------------------------
3374 //
3375 // Dali Initialization Module
3376 //
3377 //------------------------------------------------------------------------------
3378
3379 /**
3380  * Create a Dali object by type name
3381  * @method create
3382  * @param {string} name The type name to create
3383  * @return A Dali handle to the Dali object
3384  */
3385 dali.create = function(name) {
3386   "use strict";
3387
3388   var handle = dali.__createActor(name);
3389
3390   if (!handle.ok()) {
3391     handle.delete(); // handle
3392     handle = dali.__createHandle(name);
3393   }
3394
3395   dali.internalSetupProperties(handle);
3396
3397   return handle;
3398 };
3399
3400 /**
3401  * Creates constructors for objects found in the TypeRegistry. Some objects are
3402  * individually wrapped. Sets some global objects eg. debug/stage.
3403  */
3404 /** private */
3405 dali.init = function() {
3406   "use strict";
3407
3408   console.log( dali.VersionString() );
3409
3410   dali.jsSignalHolder = new dali.SignalHolder(); // for js callbacks
3411
3412   dali.debug = new dali.Debug();
3413
3414   dali.stage = new dali.Stage();
3415
3416   dali.getStage = function() { // duplication of dali.stage to stop regressions
3417     return dali.stage;
3418   };
3419
3420   //
3421   // Add constructor functions to dali from the type registry
3422   //
3423   // Uses separate create functions to add methods for the different base classes.
3424   // Other generic access is by properties. Currently
3425   //
3426   //              +------------+
3427   //              | BaseHandle |
3428   //              +------+-----+
3429   //                     |
3430   //      |--------------+------------|
3431   //      |              |            |
3432   // +----+------+  +----+---+   +----+--+
3433   // | Animation |  | Handle |   | Image |
3434   // +-----------+  +--------+   +-------+
3435   //
3436
3437   var t = new dali.TypeRegistry();
3438
3439   // use the emscripten wrapping for these and not the typeregisitry creation function
3440   var useWrapping = { RenderTask: 1, RenderTaskList: 1, CameraActor: 1,
3441                       TypeInfo: 1,
3442                       Path: 1, Animation: 1,
3443                       Handle: 1, Actor: 1,
3444                       PropertyMap: 1, PropertyBuffer: 1,
3445                       ShaderEffect: 1,
3446                       Image: 1, BufferImage: 1, EncodedBufferImage: 1,
3447                       Geometry: 1, Material: 1, Shader: 1, Sampler: 1, Renderer: 1
3448                     };
3449
3450   for (var i = 0; i < t.getTypeNameCount(); i++) {
3451     // anon function because of closure with defineProperty
3452     // (if just variable in loop then the variable 'address' is captured, not the value
3453     //  so it becomes last value set)
3454     (function(name) {
3455       var createFunc;
3456       var info = t.getTypeInfo(name);
3457
3458       if(dali.typeInheritsFrom(info, "Actor")) {
3459         createFunc = dali.__createActor;
3460       } else if(dali.typeInheritsFrom(info, "Handle")) {
3461         createFunc = dali.__createHandle;
3462       }
3463
3464       // @todo Dali error?? name lengths should never be zero
3465       if (name.length && !(name in useWrapping) ) {
3466         Object.defineProperty(dali, name, {
3467           enumerable: true,
3468           configurable: false,
3469           get: function() {
3470             return function() {
3471               // console.log(name);
3472               return dali.create(name);
3473             };
3474           }
3475         });
3476       }
3477     })(t.getTypeName(i));
3478   }
3479
3480   dali.__updateOnce();
3481   dali.__renderOnce();
3482
3483 }(); // call init
3484
3485 //------------------------------------------------------------------------------
3486 //
3487 // Post run
3488 //
3489 // Call postDaliWrapperRun() to indicate dali-wrapper.js has loaded
3490 // and other sequential tasks can run (js files can load async)
3491 //
3492 //------------------------------------------------------------------------------
3493 if(Module)
3494 {
3495   if (Module.postDaliWrapperRun) {
3496     Module.postDaliWrapperRun();
3497   }
3498 }