2 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 /* eslint-env browser */
19 /* eslint "brace-style": [2, "1tbs"] */
20 /* eslint "no-console": 0 */
21 /* eslint "no-underscore-dangle": 0 */
23 /*******************************************************************************
25 * The javascript counterpart to the C++ DALi wrapper.
27 * Provides helper functionality to make the use of the dali module.
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.
34 * This file combines several 'Modules' and could be split when using a
35 * a recombining web build tool.
38 ******************************************************************************/
40 // forward refs for lint
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.
48 //------------------------------------------------------------------------------
52 //------------------------------------------------------------------------------
55 * Matrix Multiplication
56 * @method matrixByMatrix
57 * @param {Array} A Matrix4 array
58 * @param {Array} B Matrix4 array
59 * @return {Array} Matrix4
61 dali.matrixByMatrix = function(A, B) {
64 var ret = [1, 0, 0, 0,
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];
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];
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];
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];
94 * Matrix Vector4 Multiplication
95 * @method matrixByVector
96 * @param {Array} A Matrix4 array
97 * @param {Array} v Vector4
98 * @return {Array} Vector4
100 dali.matrixByVector = function(A, v) {
108 if (v.length === 4) {
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
121 * Get Matrix Determinant
122 * @method matrixDeterminant
123 * @param {Array} A Matrix4 array
124 * @return {float} Determinant
126 dali.matrixDeterminant = function(A) {
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;
151 return n11 * m0 + n21 * m4 + n31 * m8 + n41 * m12;
155 * Matrix Multiplication by scalar
156 * @method matrixByScalar
157 * @param {Array} A Matrix4 array
158 * @param {float} s float
159 * @return {Array} Matrix4
161 dali.matrixByScalar = function(A, s) {
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
171 * Matrix Inverse. Raises if there is none.
172 * @method matrixInverse
173 * @param {Array} A Matrix4 array
174 * @return {Array} Inverse Matrix4
176 dali.matrixInverse = function(A) {
178 var ret = [1, 0, 0, 0,
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];
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];
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];
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];
204 var det = A[0] * ret[0] + A[1] * ret[4] + A[2] * ret[8] + A[3] * ret[12];
210 return dali.matrixByScalar(ret, 1 / det);
216 * @param {float} radians
217 * @return {float} degrees
219 dali.degree = function(radians) {
221 return (radians * 180.0) / Math.PI;
227 * @param {float} degree
228 * @return {float} radian
230 dali.radian = function(degrees) {
232 return (degrees / 180.0) * Math.PI;
237 * @method vectorLength
238 * @param {array} Vector4
239 * @return {float} The length of a vector
241 dali.vectorLength = function(array) {
243 var N = 3; // array.length;
246 for (var i = 0; i < N; ++i) {
247 length += array[i] * array[i];
249 return Math.sqrt(length);
253 * Length of a vector squared
254 * @method vectorLengthSquared
255 * @param {array} Vector4
256 * @return {float} The length of a vector squared
258 dali.vectorLengthSquared = function(array) {
260 var N = 3; // array.length;
263 for (var i = 0; i < N; ++i) {
264 length += array[i] * array[i];
272 * @param {array} Vector4
273 * @return {float} The normalized vector
275 dali.normalize = function(array) {
277 var N = 3; // array.length;
280 for (var i = 0; i < 3; ++i) {
281 length += array[i] * array[i];
283 length = Math.sqrt(length);
287 for (i = 0; i < N; ++i) {
288 ret.push(array[i] / length);
290 for (i = N; i < array.length; ++i) {
301 * AxisAngle conversion to Quaternion
302 * @method axisAngleToQuaternion
303 * @param {array} axisAngle Vector4 [Axis.x, Axis.y, Axis.z, Angle]
304 * @return {array} Quaternion
306 dali.axisAngleToQuaternion = function(axisAngle) {
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,
321 * Vector3 dot product
323 * @param {array} v1 Vector3
324 * @param {array} v2 Vector3
325 * @return {array} Quaternion
327 dali.vectorDot = function(v1, v2) {
329 return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2];
333 * Vector4 dot product
335 * @param {array} v1 Vector4
336 * @param {array} v2 Vector4
337 * @return {float} Dot product
339 dali.vectorDot4 = function(v1, v2) {
341 return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3];
345 * Vector3 cross product
346 * @method vectorCross
347 * @param {array} v1 Vector3
348 * @param {array} v2 Vector3
349 * @return {array} Vector3 cross product
351 dali.vectorCross = function(v1, v2) {
361 return [v1Y * v2Z - v1Z * v2Y,
362 v1Z * v2X - v1X * v2Z,
363 v1X * v2Y - v1Y * v2X
368 * VectorN dot product
369 * @method vectorByScalar
370 * @param {array} v1 VectorN
371 * @param {array} v2 VectorN
372 * @return {array} VectorN * s
374 dali.vectorByScalar = function(v1, s) {
377 for (var i = 0, len = v1.length; i < len; i++) {
384 * VectorN dot product
386 * @param {array} v1 VectorN
387 * @param {array} v2 VectorN
388 * @param {array} ..vN VectorN
389 * @return {array} v1 + v2 + ... + vN
391 dali.vectorAdd = function() {
393 var ret = arguments[0];
395 for (var i = 1, len = arguments.length; i < len; i++) {
396 var v = arguments[i];
397 for (var j = 0; j < l; j++) {
405 * Quaternion by quaternion
407 * @param {array} q1 Quaternion
408 * @param {array} q2 Quaternion
409 * @return {array} Quaternion
411 dali.quatByQuat = function(q1, q2) {
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)
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]
436 dali.quaternionToAxisAngle = function(q) {
438 var angle = Math.acos(q[3]);
439 var sine = Math.sin(angle);
442 throw "Cannot convert quaternion";
445 var sinfThetaInv = 1.0 / sine;
447 return [q[0] * sinfThetaInv,
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
462 dali.eulerToQuaternion = function(rXPitch, rYYaw, rZRoll)
464 var halfX = 0.5 * rXPitch;
465 var halfY = 0.5 * rYYaw;
466 var halfZ = 0.5 * rZRoll;
468 var cosX2 = Math.cos(halfX);
469 var cosY2 = Math.cos(halfY);
470 var cosZ2 = Math.cos(halfZ);
472 var sinX2 = Math.sin(halfX);
473 var sinY2 = Math.sin(halfY);
474 var sinZ2 = Math.sin(halfZ);
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 ];
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]
488 dali.eulerToAxisAngle = function(eulerInDegrees)
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?
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]
502 dali.axisAngleToEuler = function(axisAngle)
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);
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
516 dali.quaternionToMatrix = function(q) {
537 m[0] = 1.0 - 2.0 * (yy + zz);
538 m[1] = 2.0 * (xy + wz);
539 m[2] = 2.0 * (xz - wy);
542 m[4] = 2.0 * (xy - wz);
543 m[5] = 1.0 - 2.0 * (xx + zz);
544 m[6] = 2.0 * (yz + wx);
547 m[8] = 2.0 * (xz + wy);
548 m[9] = 2.0 * (yz - wx);
549 m[10] = 1.0 - 2.0 * (xx + yy);
561 * Quaternion to Euler
562 * @method quaternionToEuler
563 * @param {array} q Quaternion
564 * @return {array} Vector3 [roll, pitch, yaw]
566 dali.quaternionToEuler = function(q) {
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)];
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
591 dali.worldToScreen = function(position, renderTask) {
593 var useFirstRenderTask = false;
595 if (typeof renderTask === "undefined") {
596 useFirstRenderTask = true;
597 } else if (renderTask === null) { // null is an object
598 useFirstRenderTask = true;
601 if (useFirstRenderTask) {
602 var tasks = dali.stage.getRenderTaskList();
603 renderTask = tasks.getTask(0);
604 tasks.delete(); // wrapper
607 var camera = renderTask.getCameraActor();
608 var pos = renderTask.getCurrentViewportPosition();
609 var size = renderTask.getCurrentViewportSize();
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]];
624 camera.delete(); // wrapper
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],
633 * Gets matrix identity
634 * @method matrixIdentity
635 * @return {array} Matrix4 identity
637 dali.matrixIdentity = function() {
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
654 dali.matrixTransform = function(x, y, z) {
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
674 dali.screenToPlaneLocal = function(screenX, screenY, renderTask, planeOrientationMatrix, planeWidth, planeHeight) {
677 var camera = renderTask.getCameraActor();
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);
687 var inverseMvp = dali.matrixInverse(
688 dali.matrixByMatrix(modelView, camera.projectionMatrix));
690 var screenPos = [screenX - viewportX,
691 viewportH - (screenY - viewportY),
697 var oglScreenPos = [(screenPos[0] / viewportW) * 2 - 1, (screenPos[1] / viewportH) * 2 - 1, (screenPos[2]) * 2 - 1,
702 var nearPoint = dali.matrixByVector(inverseMvp, oglScreenPos);
704 if (nearPoint[3] === 0.0) {
705 throw "Unproject near fails";
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];
714 oglScreenPos[2] = 1.0 * 2 - 1;
716 var farPoint = dali.matrixByVector(inverseMvp, oglScreenPos);
718 if (farPoint[3] === 0.0) {
719 throw "Unproject far fails";
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];
727 if (!((farPoint[2] < 0) && (nearPoint[2] > 0))) {
728 throw "ray not crossing xy plane";
731 var dist = nearPoint[2] / (nearPoint[2] - farPoint[2]);
733 var intersect = [nearPoint[0] + (farPoint[0] - nearPoint[0]) * dist,
734 nearPoint[1] + (farPoint[1] - nearPoint[1]) * dist,
738 intersect[0] = intersect[0] + planeWidth * 0.5;
739 intersect[1] = intersect[1] + planeHeight * 0.5;
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
753 dali.screenToLocal = function(screenX, screenY, actor, renderTask) {
755 return dali.screenToPlaneLocal(screenX, screenY, renderTask, actor.worldMatrix, actor.size[0], actor.size[1]);
759 * Screen to local coordinates in the XY plane
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
767 dali.screenToXY = function(screenX, screenY, actor, renderTask) {
769 var size = dali.stage.getSize();
770 return dali.screenToPlaneLocal(screenX, screenY,
772 dali.matrixIdentity(),
778 * Screen to local coordinates in the YZ plane
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
786 dali.screenToYZ = function(screenX, screenY, actor, renderTask) {
788 var size = dali.stage.getSize();
789 var q = dali.axisAngleToQuaternion( [0, 1, 0, dali.radian(90)] );
790 return dali.screenToPlaneLocal(screenX, screenY,
792 dali.quaternionToMatrix(q),
798 * Screen to local coordinates in the XZ plane
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
806 dali.screenToXZ = function(screenX, screenY, actor, renderTask) {
808 var size = dali.stage.getSize();
809 var q = dali.axisAngleToQuaternion( [1, 0, 0, dali.radian(90)] );
810 return dali.screenToPlaneLocal(screenX, screenY,
812 dali.quaternionToMatrix(q),
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
824 dali.screenCoordinates = function(actor, renderTask) {
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;
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)
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
848 dali.screenToActor = function(actor, screenPos, renderTask) {
850 // , function will return coordinates in relation to actor`s anchorPoint (client coordinates).
851 var useFirstRenderTask = false;
853 if (typeof renderTask === "undefined") {
854 useFirstRenderTask = true;
855 } else if (renderTask === null) { // null is an object
856 useFirstRenderTask = true;
859 if (useFirstRenderTask) {
860 var tasks = dali.stage.getRenderTaskList();
861 renderTask = tasks.getTask(0);
862 tasks.delete(); // wrapper
865 var camera = renderTask.getCameraActor();
866 var vpp = renderTask.getCurrentViewportPosition();
867 var vps = renderTask.getCurrentViewportSize();
869 var mat = dali.matrixByMatrix(camera.projectionMatrix, camera.viewMatrix);
871 var inverseMvp = dali.matrixInverse(mat);
873 var x = screenPos[0];
874 var y = screenPos[1];
875 var z = screenPos[2];
877 var objectPos = dali.matrixByVector(inverseMvp,
879 [((x - vpp[0]) / vps[0]) * 2.0 - 1.0, ((y - vpp[1]) / vps[1]) * 2.0 - 1.0, (z * 2.0) - 1.0,
883 if (objectPos[3] === 0.0) {
884 throw "Cannot find screen Position";
887 objectPos[3] = 1 / objectPos[3];
889 return [objectPos[0] * objectPos[3],
890 objectPos[1] * objectPos[3],
891 objectPos[2] * objectPos[3],
897 //------------------------------------------------------------------------------
901 //------------------------------------------------------------------------------
904 * Cache to fix the dali get/set thread issue
906 * Property sets are cached and cleared at the renderFinished callback
908 dali.internalUniqueId = function() {
912 dali.internalUniqueId.prototype._id = 0;
913 dali.internalUniqueId.prototype.generateId = function() {
915 return ++dali.internalUniqueId.prototype._id;
918 dali.internalPropertyCacheEnable = true;
919 dali.internalPropertyCache = {};
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
928 dali.mergeObjects = function(o1, o2) {
932 // Property in destination object set; update its value.
933 if ( o2[p].constructor === Object){
934 o1[p] = dali.mergeObjects(o1[p], o2[p]);
940 // Property in destination object not set; create it and set its value.
947 //------------------------------------------------------------------------------
951 // Data dali can request during update & render loop.
953 //------------------------------------------------------------------------------
956 * Gets a glyph by rendering to a hidden browser canvas
959 dali.requestedGlyphImage = function(sFontFamily, sFontStyle, fFontSize, iChar) {
962 var buffer = document.createElement("canvas");
963 buffer.width = fFontSize;
964 buffer.height = fFontSize;
965 var ctx = buffer.getContext("2d");
967 ctx.font = sFontStyle + " " + fFontSize + "px " + sFontFamily;
968 ctx.fillText(String.fromCharCode(iChar), 0, 0 + fFontSize);
970 var imageData = ctx.getImageData(0, 0, fFontSize, fFontSize);
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 );
976 return imageData.data; // return uint8array; //
980 dali.postRenderFunction = undefined;
983 * End of renderering tasks
984 * - Reset the property cache
987 dali.requestedRenderFinished = function() {
989 // reset the temporary cache
990 dali.internalPropertyCache = {};
991 if(dali.postRenderFunction) {
992 dali.postRenderFunction();
996 dali.setCallbackGetGlyphImage(dali.requestedGlyphImage);
997 dali.setCallbackRenderFinished(dali.requestedRenderFinished);
999 //------------------------------------------------------------------------------
1001 // Property Marshalling Module
1003 // Javascript objects are adorned with dali properties as they are created or
1004 // fetched from the C++ api
1006 // Data is marshalled to avoid some of the necessary C++ memory management for
1007 // small property classes.
1009 //------------------------------------------------------------------------------
1010 dali.__propertyTypeJsLut = { boolean: dali.PropertyType.BOOLEAN,
1011 number: dali.PropertyType.FLOAT,
1012 string: dali.PropertyType.STRING };
1014 dali.__propertyValueCtor = {};
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]; } );
1028 dali.propertyTypeFromJsValue = function(value) {
1029 return dali.__propertyTypeJsLut[ typeof(value) ];
1032 dali.propertyValueCtor = function(propertyType) {
1033 return dali.__propertyValueCtor[ propertyType.value ];
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
1043 dali.DaliPropertyValue = function(object, name, value) {
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;
1059 type = object.getPropertyTypeFromName(name);
1061 if (type === dali.PropertyType.ROTATION) {
1062 if (value.length === 3) {
1063 setProperty = new dali.PropertyValueEuler(value);
1065 setProperty = new dali.PropertyValueAxisAngle(value);
1067 } else if (value.length) {
1068 if (type === dali.PropertyType.ARRAY) {
1069 setProperty = new dali.PropertyValueArray(value);
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]);
1079 setProperty = new dali.PropertyValueVector4(value);
1081 } else if (value.length === 9) {
1082 setProperty = new dali.PropertyValueMatrix3(value);
1083 } else if (value.length === 16) {
1084 setProperty = new dali.PropertyValueMatrix(value);
1086 throw new Error("Cannot set property");
1090 // todo; I think a map has a length....
1091 setProperty = new dali.PropertyValueMap(value);
1096 throw object.toString() + " " + name.toString() + " " + value.toString();
1098 throw name.toString() + " " + value.toString();
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
1112 dali.marshallProperty = function(p) {
1116 var type = p.getType();
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) {
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) {
1145 } else if (type === dali.PropertyType.MAP.value) {
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
1160 dali.marshallSetProperty = function(object, name, value) {
1162 var setProperty = new dali.DaliPropertyValue(object, name, value);
1166 object.setProperty(name, setProperty);
1168 //console.log("marshallSetProperty set property" + setProperty );
1169 setProperty.delete();
1171 if(dali.internalPropertyCacheEnable) {
1172 // set in cache to fix dali get/set problem
1173 if("getId" in object ) // only with actors
1175 var uniqueId = object.getId(); // _uniqueId;
1176 if (uniqueId !== undefined) {
1177 var objectDict = dali.internalPropertyCache[uniqueId];
1178 if (objectDict === undefined) {
1179 dali.internalPropertyCache[uniqueId] = {};
1181 dali.internalPropertyCache[uniqueId][name] = value;
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
1196 dali.marshallGetProperty = function(object, name) {
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) {
1217 p = object.getProperty(name);
1219 throw new Error("Property doesnt exist?");
1221 var type = p.getType();
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) {
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) {
1238 ret = p.getVector4();
1239 } else if (type === dali.PropertyType.MATRIX3.value) {
1241 ret = p.getMatrix3();
1242 } else if (type === dali.PropertyType.MATRIX.value) {
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) {
1253 } else if (type === dali.PropertyType.MAP.value) {
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.
1268 dali.internalSetupProperties = function(handle) {
1271 var props = handle.getProperties();
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
1280 Object.defineProperty(handle, name, {
1282 configurable: false,
1284 return dali.marshallGetProperty(handle, name);
1286 set: function(newValue) {
1287 dali.marshallSetProperty(handle, name, newValue);
1291 })(props.get(i), handle);
1294 // handle._uniqueId = dali.internalUniqueId.prototype.generateId();
1300 //------------------------------------------------------------------------------
1302 // Handle API Module
1304 // API Wrappers for some Dali.Handle methods to marshall properties
1306 //------------------------------------------------------------------------------
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
1315 dali.Handle.prototype.registerProperty = function(name, value) {
1319 var propertyValue = new dali.DaliPropertyValue(null, name, value);
1320 ret = this.__registerProperty(name, propertyValue);
1321 propertyValue.delete(); // wrapper
1322 Object.defineProperty(this, name, {
1324 configurable: false,
1326 return dali.marshallGetProperty(this, name);
1328 set: function(newValue) {
1329 dali.marshallSetProperty(this, name, newValue);
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
1343 dali.Handle.prototype.registerAnimatedProperty = function(name, value) {
1347 var propertyValue = new dali.DaliPropertyValue(null, name, value);
1348 ret = this.__registerAnimatedProperty(name, propertyValue);
1349 propertyValue.delete(); // wrapper
1350 Object.defineProperty(this, name, {
1352 configurable: false,
1354 return dali.marshallGetProperty(this, name);
1356 set: function(newValue) {
1357 dali.marshallSetProperty(this, name, newValue);
1363 //------------------------------------------------------------------------------
1367 //------------------------------------------------------------------------------
1368 dali.Stage.prototype.getRootLayer = function() {
1370 var root = this.__getRootLayer();
1371 dali.internalSetupProperties(root);
1375 //------------------------------------------------------------------------------
1377 // PropertyMap Module
1379 // API Wrappers for some Dali.PropertyMap methods to marshall properties
1381 //------------------------------------------------------------------------------
1384 * Insert a value into the PropertyMap
1386 * @param {string} key The key
1387 * @param {any} value Any Javascript value
1388 * @param {PropertyType} propertyType The Dali property type
1390 dali.PropertyMap.prototype.insert = function(key, value, propertyType) {
1393 var type = propertyType;
1395 if( propertyType === undefined ) { // can be optional
1396 propertyType = dali.propertyTypeFromJsValue(value);
1399 var constructor = dali.propertyValueCtor(propertyType);
1401 var setProperty = constructor( value );
1404 this.__insert(key, setProperty);
1405 setProperty.delete();
1410 * Get a value from the PropertyMap
1412 * @param {string} key The key
1413 * @return The Javascript value
1415 dali.PropertyMap.prototype.get = function(key) {
1417 var p = this.__get(key);
1419 var ret = dali.marshallProperty(p);
1421 // p.delete(); // @todo should we delete here?
1426 //------------------------------------------------------------------------------
1428 // PropertyBuffer Module
1430 // API Wrappers for some Dali.PropertyBuffer methods to marshall properties
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 }]
1443 var _propertyTypeInfo = {};
1444 function _createPropertyBuffer() {
1446 for(var i = 0; i < _propertyTypeInfoList.length; i++) {
1447 _propertyTypeInfo[ _propertyTypeInfoList[i][0] ] = _propertyTypeInfoList[i][1];
1451 _createPropertyBuffer();
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
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]
1467 * "acol": [ [0, 0, 0, 1],
1475 dali.createPropertyBuffer = function(info) {
1477 var format = new dali.PropertyMap();
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;
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;
1491 var buffer = new ArrayBuffer(dataLength * recordSize);
1493 var recordOffset = 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;
1504 view[0] = info.data[name][i];
1506 for(var k = 0; k < length; k++) {
1507 view[k] = info.data[name][i][k];
1512 recordOffset += recordSize;
1515 var propertyBuffer = new dali.PropertyBuffer(format);
1517 propertyBuffer.setData(buffer, dataLength);
1521 return propertyBuffer;
1524 //------------------------------------------------------------------------------
1528 // API Wrappers for some Dali.PropertyBuffer methods to marshall properties
1530 //------------------------------------------------------------------------------
1533 * Gets a parent with JS style property accessors
1535 * @return The parent
1537 dali.Actor.prototype.getParent = function() {
1539 var bareActor = this.__getParent();
1540 if(!bareActor.ok()) {
1541 bareActor.delete(); // wrapper
1544 // add properties to the bare Actor
1545 dali.internalSetupProperties(bareActor);
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
1556 dali.Actor.prototype.findChildById = function(index) {
1558 var bareActor = this.__findChildById(index);
1559 if(!bareActor.ok()) {
1560 bareActor.delete(); // wrapper
1563 dali.internalSetupProperties(bareActor);
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
1574 dali.Actor.prototype.findChildByName = function(name) {
1576 var bareActor = this.__findChildByName(name);
1577 if(!bareActor.ok()) {
1578 bareActor.delete(); // wrapper
1581 dali.internalSetupProperties(bareActor);
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
1592 dali.Actor.prototype.getChildAt = function(index) {
1594 var bareActor = this.__getChildAt(index);
1595 if(!bareActor.ok()) {
1596 bareActor.delete(); // wrapper
1599 dali.internalSetupProperties(bareActor);
1605 * add children of actor to collection in depth first manner
1608 dali.internalDepthFirstCollection = function(actor, collection) {
1610 for (var i = 0; i < actor.getChildCount(); i++) {
1611 var a = actor.getChildAt(i); // adds properties in dotted
1613 dali.internalDepthFirstCollection(a, collection);
1618 * Finds all children of the actor and adorns with JS style property accessors
1619 * @method findAllChildren
1620 * @return A list of children
1622 dali.Actor.prototype.findAllChildren = function() {
1625 dali.internalDepthFirstCollection(this, col);
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
1634 dali.Actor.prototype.getChildren = function() {
1637 for (var i = 0, len = this.getChildCount(); i < len; i++) {
1638 var c = this.getChildAt(i);
1645 * 'directChildren' kept for GUIBuilder support
1648 dali.Actor.prototype.directChildren = dali.Actor.prototype.getChildren;
1651 * Connects a callback to a signal by name
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
1658 dali.Actor.prototype.connect = function(signalName, callback, signalHolder) {
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;
1667 return this.__connect( signalHolder,
1671 var args = [dali.internalSetupProperties(arguments[0])];
1672 for(var i = 1; i < arguments.length; i++) {
1673 args.push( arguments[i] );
1675 cb.apply(null, args);
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
1692 dali.Actor.prototype.setPropertyNotification = function(property, condition, arg0, arg1, callback, signalHolder) {
1695 if(signalHolder === undefined) {
1696 // default js signal holder if none provided
1697 signalHolder = dali.jsSignalHolder;
1700 var index = this.getPropertyIndex(property);
1702 this.__setPropertyNotification(signalHolder, index, condition, arg0, arg1, callback);
1706 * Gets the renderer by index
1707 * @method getRendererAt
1708 * @param {int} index The index of the renderer
1709 * @return The Render or null
1711 dali.Actor.prototype.getRendererAt = function(index) {
1713 var renderer = this.__getRendererAt(index);
1714 if(!renderer.ok()) {
1715 renderer.delete(); // wrapper
1718 dali.internalSetupProperties(renderer);
1724 dali.__ActorConstructor = dali.Actor;
1727 * Construtor that adorns with JS style property accessors
1728 * @return The wrapped Dali.Actor object
1730 dali.Actor = function() {
1732 var a = new dali.__ActorConstructor();
1733 dali.internalSetupProperties(a);
1737 //------------------------------------------------------------------------------
1741 //------------------------------------------------------------------------------
1742 dali.__ShaderConstructor = dali.Shader;
1743 dali.Shader = function(vertex, fragment, hints) {
1745 var a = new dali.__ShaderConstructor(vertex, fragment, hints);
1746 dali.internalSetupProperties(a);
1750 dali.__MaterialConstructor = dali.Material;
1751 dali.Material = function(shader) {
1753 var a = new dali.__MaterialConstructor(shader);
1754 dali.internalSetupProperties(a);
1758 dali.__RendererConstructor = dali.Renderer;
1759 dali.Renderer = function(geometry, material) {
1761 var a = new dali.__RendererConstructor(geometry, material);
1762 dali.internalSetupProperties(a);
1766 //------------------------------------------------------------------------------
1770 //------------------------------------------------------------------------------
1771 dali.__PathConstructor = dali.Path;
1772 dali.Path = function() {
1774 var a = new dali.__PathConstructor();
1775 dali.internalSetupProperties(a);
1782 * @param {object} The object
1783 * @param {string} propertyName The objects property name
1784 * @param {any} value The value
1785 * @param {string} alphaFunction The alpha function
1786 * @param {float} delay The delay
1787 * @param {float} duration The duration
1789 dali.Animation.prototype.animateTo = function(object, propertyName, value, alphaFunction, delay, duration) {
1791 var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
1792 if (propertyValue) {
1793 this.__animateTo(object, propertyName, propertyValue, alphaFunction, delay, duration);
1794 propertyValue.delete();
1796 throw new Error("Unknown property?");
1803 * @param {object} The object
1804 * @param {string} propertyName The objects property name
1805 * @param {any} value The value
1806 * @param {string} alphaFunction The alpha function
1807 * @param {float} delay The delay
1808 * @param {float} duration The duration
1810 dali.Animation.prototype.animateBy = function(object, propertyName, value, alphaFunction, delay, duration) {
1812 var propertyValue = new dali.DaliPropertyValue(object, propertyName, value);
1813 if (propertyValue) {
1814 this.__animateBy(object, propertyName, propertyValue, alphaFunction, delay, duration);
1815 propertyValue.delete();
1817 throw new Error("Unknown property?");
1823 * @method animatePath
1824 * @param {object} The object
1825 * @param {Dali.Path} pathObject The path object
1826 * @param {array} forward The path forward vector
1827 * @param {string} alphaFunction The alpha function
1828 * @param {float} delay The delay
1829 * @param {float} duration The duration
1831 dali.Animation.prototype.animatePath = function(object, pathObject, forward, alphaFunction, delay, duration) {
1833 this.__animatePath(object, pathObject, forward, alphaFunction, delay, duration);
1837 * animateBetween a value
1838 * @method animateBetween
1839 * @param {object} The object
1840 * @param {string} propertyName The objects property name
1841 * @param {dali.KeyFrames} keyFrames The keyframes
1842 * @param {string} alphaFunction The alpha function
1843 * @param {float} delay The delay
1844 * @param {float} duration The duration
1846 dali.Animation.prototype.animateBetween = function(object, propertyName, keyFrames, alphaFunction, delay, duration, interpolation) {
1850 var daliKeyFrames = new dali.KeyFrames();
1852 for(var i = 0; i < keyFrames.length; i++) {
1853 if(keyFrames[i].length > 2) { // has alpha
1854 propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
1855 if(!propertyValue) {
1856 throw new Error("Unknown property?");
1858 daliKeyFrames.add(keyFrames[i][0], propertyValue, keyFrames[i][2]);
1859 propertyValue.delete();
1861 propertyValue = dali.DaliPropertyValue(null, null, keyFrames[i][1]);
1862 if(!propertyValue) {
1863 throw new Error("Unknown property?");
1865 daliKeyFrames.add(keyFrames[i][0], propertyValue);
1866 propertyValue.delete();
1870 this.__animateBetween(object, propertyName, daliKeyFrames, alphaFunction, delay, duration, interpolation);
1872 daliKeyFrames.delete();
1876 //------------------------------------------------------------------------------
1878 // RenderTask Module
1880 //------------------------------------------------------------------------------
1881 dali.RenderTask.prototype.getCameraActor = function() {
1883 var a = this.__getCameraActor();
1885 dali.internalSetupProperties(a);
1890 Object.defineProperty(dali.RenderTask.prototype, "x", {
1892 configurable: false,
1894 return this.getCurrentViewportPosition()[0];
1897 var pos = this.getCurrentViewportPosition();
1898 this.setViewportPosition(v, pos[1]);
1902 Object.defineProperty(dali.RenderTask.prototype, "y", {
1904 configurable: false,
1906 return this.getCurrentViewportPosition()[1];
1909 var pos = this.getCurrentViewportPosition();
1910 this.setViewportPosition(pos[0], v);
1914 Object.defineProperty(dali.RenderTask.prototype, "width", {
1916 configurable: false,
1918 return this.getCurrentViewportSize()[0];
1921 var pos = this.getCurrentViewportSize();
1922 this.setViewportSize(v, pos[1]);
1926 Object.defineProperty(dali.RenderTask.prototype, "height", {
1928 configurable: false,
1930 return this.getCurrentViewportSize()[1];
1933 var pos = this.getCurrentViewportSize();
1934 this.setViewportSize(pos[0], v);
1938 //------------------------------------------------------------------------------
1940 // Solid Actor Module
1942 //------------------------------------------------------------------------------
1945 * Create a solid color actor
1946 * @method createSolidColorActor
1947 * @param {array} color The color
1948 * @param {bool} border Whether to add a border
1949 * @param {array} color The border color
1950 * @param {float} borderSize The size of a border
1951 * @return {Dali.Actor} The Dali actor
1953 dali.createSolidColorActor = function(color, border, borderColor, borderSize) {
1955 var a = dali.__createSolidColorActor(color, border, borderColor, borderSize);
1956 dali.internalSetupProperties(a);
1960 //------------------------------------------------------------------------------
1962 // Mesh import support Module
1964 //------------------------------------------------------------------------------
1965 function ObjectLoader(fileObject) {
1969 this.meshByUUID = {};
1970 this.geomByUUID = {};
1971 this.matByUUID = {};
1973 this.fileObject = fileObject;
1976 function __longToArray(v) {
1978 return [((v >> 24) & 0xFF) / 255.0, ((v >> 16) & 0xFF) / 255.0, ((v >> 8) & 0xFF) / 255.0, (v & 0xFF) / 255.0];
1981 function __isBitSet(value, bit) {
1983 return (value & (1 << bit));
1986 ObjectLoader.prototype.__getMaterial = function(uuid) {
1988 if (!(uuid in this.matByUUID)) {
1989 for (var i = 0, len = this.fileObject.materials.length; i < len; i++) {
1990 var f_mat = this.fileObject["materials"][i];
1991 skewer.log(i + ":" + f_mat["uuid"] + " " + (f_mat["uuid"] === uuid));
1992 if (f_mat["uuid"] === uuid) {
1993 assert(f_mat["type"] === "MeshPhongMaterial");
1994 var mat = new dali.MaterialWrapper(uuid);
1995 mat.setDiffuseColor(__longToArray(f_mat["color"]));
1996 mat.setAmbientColor(__longToArray(f_mat["ambient"]));
1997 mat.setSpecularColor(__longToArray(f_mat["specular"]));
1998 mat.setEmissiveColor(__longToArray(f_mat["emmissive"]));
1999 mat.setShininess(f_mat["shininess"]);
2000 this.matByUUID[uuid] = mat;
2005 return this.matByUUID[uuid];
2008 ObjectLoader.prototype.__getMeshData = function(uuid, uuid_material) {
2010 if (!(uuid in this.meshByUUID)) {
2011 for (var i = 0, len = this.fileObject["geometries"].length; i < len; i++) {
2012 var f_geom = this.fileObject["geometries"][i];
2013 if (f_geom["uuid"] === uuid) {
2014 var f_indices, // file data
2020 if (!("metadata" in f_geom)) {
2021 f_geom["metadata"] = {
2023 }; // Warning: modified input!?
2026 if ("formatVersion" in f_geom["metadata"]) // then version 3.1
2028 f_indices = f_geom["indices"];
2029 f_posns = f_geom["vertices"];
2030 f_norms = f_geom["normals"];
2031 f_uvs = f_geom["uvs"];
2032 f_faces = f_geom["faces"];
2033 } else if (f_geom["type"] === "Geometry") // V4 clara io output? not standard???
2035 f_indices = f_geom["data"]["indices"];
2036 f_posns = f_geom["data"]["vertices"];
2037 f_norms = f_geom["data"]["normals"];
2038 f_uvs = f_geom["data"]["uvs"];
2039 f_faces = f_geom["data"]["faces"];
2040 } else if (f_geom["metadata"]["type"] === "Geometry") // V4
2042 f_indices = f_geom["indices"];
2043 f_posns = f_geom["vertices"];
2044 f_norms = f_geom["normals"];
2045 f_uvs = f_geom["uvs"];
2046 f_faces = f_geom["faces"];
2047 } else if (f_geom["metadata"]["type"] === "BufferGeometry") // V4
2049 f_posns = f_geom["data"]["attributes"]["position"]["array"];
2050 f_norms = f_geom["data"]["attributes"]["norms"]["array"];
2051 f_uvs = f_geom["data"]["attributes"]["uv"]["array"];
2056 // disregard empty arrays
2057 for (var i = 0; i < this.fileObject.uvs.length; i++) {
2058 if (this.fileObject.uvs[i].length)
2062 var verts = new dali.VectorVertex();
2063 var vert = []; //new dali.Vertex();
2064 for (var i = 0, len = f_posns.length / 3; i < len; i++) {
2065 vert.push(f_posns[(i * 3) + 0]);
2066 vert.push(f_posns[(i * 3) + 1]);
2067 vert.push(f_posns[(i * 3) + 2]);
2069 vert.push(0); // norm
2073 vert.push(0); // uvs
2076 verts.push_back(vert);
2079 var mesh = new dali.MeshDataWrapper();
2080 var faces = new dali.VectorFaceIndex();
2082 //faceSets.length = this.fileObject.materials;
2083 for (var i = 0, len = this.fileObject.materials.length; i < len; ++i) {
2084 // get materials and force them to be loaded up
2085 var mat = this.__getMaterial(this.fileObject.materials[i]["uuid"]);
2089 var idx_len = f_faces.length;
2090 var materialUUID = undefined;
2091 while (idx < idx_len) {
2092 var f_type = f_faces[idx++];
2093 var isQuad = __isBitSet(f_type, 0);
2094 var hasMaterial = __isBitSet(f_type, 1);
2095 var hasFaceUv = __isBitSet(f_type, 2);
2096 var hasFaceVertexUv = __isBitSet(f_type, 3);
2097 var hasFaceNormal = __isBitSet(f_type, 4);
2098 var hasFaceVertexNormal = __isBitSet(f_type, 5);
2099 var hasFaceColor = __isBitSet(f_type, 6);
2100 var hasFaceVertexColor = __isBitSet(f_type, 7);
2103 var faceVertexIndices;
2105 faces.push_back(f_faces[idx]);
2106 faces.push_back(f_faces[idx + 1]);
2107 faces.push_back(f_faces[idx + 2]);
2109 faces.push_back(f_faces[idx]);
2110 faces.push_back(f_faces[idx + 2]);
2111 faces.push_back(f_faces[idx + 3]);
2113 faceVertexIndices = [f_faces[idx],
2121 faces.push_back(f_faces[idx]);
2122 faces.push_back(f_faces[idx + 1]);
2123 faces.push_back(f_faces[idx + 2]);
2125 faceVertexIndices = [f_faces[idx],
2134 if (materialUUID === undefined) {
2135 materialUUID = this.fileObject.materials[f_faces[idx]]["uuid"];
2137 // different material per face is bonkers - I'm not going to support it.
2138 if (this.fileObject.materials[f_faces[idx]]["uuid"] !== materialUUID) {
2139 throw "Faces with different materials is not supported";
2147 for (var i = 0; i < nUvLayers; i++) {
2148 var uvLayer = self.fileObject.uvs[i];
2149 var uvIndex = f_faces[idx++];
2150 var u = uvLayer[uvIndex * 2];
2151 var v = uvLayer[uvIndex * 2 + 1];
2152 // discarded - tbd ?
2156 if (hasFaceVertexUv) {
2157 for (var i = 0; i < nUvLayers; i++) {
2158 var uvLayer = f_geom.uvs[i];
2160 for (var j = 0; j < nVertices; j++) {
2161 var uvIndex = f_faces[idx++];
2162 var u = uvLayer[uvIndex * 2];
2163 var v = uvLayer[uvIndex * 2 + 1];
2169 if (hasFaceNormal) {
2170 var normalIndex = f_faces[idx++] * 3;
2172 var x = f_geom.normals[normalIndex++];
2173 var y = f_geom.normals[normalIndex++];
2174 var z = f_geom.normals[normalIndex];
2176 for (var i = 0; i < faceVertexIndices.length; i++) {
2177 var v = vert.get(faceVertexIndices[i]);
2185 if (hasFaceVertexNormal) {
2186 for (var i = 0; i < nVertices; i++) {
2187 var normalIndex = faces[idx] * 3;
2188 var x = f_geom.normals[normalIndex++];
2189 var y = f_geom.normals[normalIndex++];
2190 var z = f_geom.normals[normalIndex];
2192 var v = vert.get(faces[idx]);
2199 // face.vertexNormals.push( normal );
2204 var color = f_faces[idx++];
2207 if (hasFaceVertexColor) {
2208 for (var i = 0; i < nVertices; i++) {
2209 var colorIndex = faces[idx++];
2210 var color = f_geom.colors[colorIndex]; // ??? f_geom.colors?
2211 // face.vertexColors.push( color );
2217 for (var i = 1, len = f_faces.length; i < len; i++) {
2218 faces.push_back(f_faces[i]);
2223 faces = new dali.VectorFaceIndex();
2224 for (var i = 1, len = f_indices.length; i < len; i++) {
2225 faces.push_back(f_indices[i]);
2231 for (var i = 0, len = f_posns.length; i < len; i++) {
2236 console.log(verts.size() + ":" + faces.size() + ":" + uuid_material);
2238 var material = this.__getMaterial(uuid_material);
2239 mesh.setLineData(verts, faces, material);
2242 this.meshByUUID[uuid] = mesh;
2247 } // for geom in geometries
2248 } // if uid ! in meshByUUID
2250 return this.meshByUUID[uuid];
2253 ObjectLoader.prototype.delete = function() {
2255 for (var a in this.meshByUUID) {
2258 this.meshByUUID = {};
2259 for (var b in this.matByUUID) {
2262 this.matByUUID = {};
2265 ObjectLoader.prototype.createMeshActors = function() {
2268 if ("object" in this.fileObject) {
2269 for (var i = 0, len = this.fileObject["object"]["children"].length; i < len; i++) {
2270 var child = this.fileObject["children"];
2271 if (child["type"] === "Mesh") {
2272 var meshData = this.__getMeshData(child["geometry"],
2274 ret.push(dali.__createMeshActor(meshData));
2283 parent = new dali.Actor();
2284 for (var a in ret) {
2293 dali.createMeshActor = function(threeDjs_formatV4) {
2295 var loader = new ObjectLoader(threeDjs_formatV4);
2296 return loader.createMeshActor();
2301 //------------------------------------------------------------------------------
2305 //------------------------------------------------------------------------------
2306 dali.hitTest = function(x, y) {
2308 var a = dali.__hitTest(x, y);
2310 dali.internalSetupProperties(a);
2318 //------------------------------------------------------------------------------
2322 //------------------------------------------------------------------------------
2325 * ShaderInfo class to get shader metadata.
2327 dali.ShaderInfo = function() {
2331 // supported uniforms
2332 dali.ShaderInfo.prototype._supportedUniformTypes = ["bool",
2335 "vec2", "vec3", "vec4",
2336 "bvec2", "bvec3", "bvec4",
2337 "ivec2", "ivec3", "ivec4",
2338 "mat2", "mat3", "mat4",
2343 // need to add a value to uniform registration call
2344 dali.ShaderInfo.prototype._supportedUniformValues = [0,
2347 [0.0, 0.0], [0.0, 0.0, 0.0], [0.0, 0.0, 0.0, 0.0],
2348 [0, 0], [0, 0, 0], [0, 0, 0, 0],
2349 [0, 0], [0, 0, 0], [0, 0, 0, 0],
2357 [1.0, 0.0, 0.0, 0.0,
2366 * Get shader metadata from compilation.
2368 * Compiles the shader. On error set 'hasError' and error strings. On Success
2369 * query gl for the attributes and uniforms in the shaders.
2371 * @param {object} gl ie from canvas.getContext("webgl")
2372 * @param {string} vertex shader
2373 * @param {string} fragment shader
2374 * @return {Object} shader metadata (see 'var info' below)
2376 dali.ShaderInfo.prototype.fromCompilation = function(gl, vertex, fragment) {
2380 vertex: vertex, // vertex source code
2381 fragment: fragment, // fragment source code
2382 attributes: {}, // {aName1: {name:"aName1", ... }
2383 uniforms: {}, // {uName1: {name:"uName1", type:"vec2", ...}
2384 uniformUISpec: {}, // {uName1: {ui:"slider", min:0, max:1, ...}
2385 attributeCount: 0, // Number of attributes
2386 uniformCount: 0, // Number of uniforms
2387 hasError: false, // compiles without error
2388 vertexError: "", // Vertex compilation error
2389 fragmentError: "", // Fragment compilation error
2390 linkError: "" // Linker error
2393 var vertexShader = gl.createShader(gl.VERTEX_SHADER);
2394 gl.shaderSource(vertexShader, vertex);
2395 gl.compileShader(vertexShader);
2397 // Check the compile status, return an error if failed
2398 if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
2399 info.hasError = true;
2400 info.vertexError = gl.getShaderInfoLog(vertexShader);
2403 var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
2404 gl.shaderSource(fragmentShader, fragment);
2405 gl.compileShader(fragmentShader);
2407 // Check the compile status, return an error if failed
2408 if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
2409 info.hasError = true;
2410 info.fragmentError = gl.getShaderInfoLog(fragmentShader);
2414 gl.deleteShader(vertexShader);
2415 gl.deleteShader(fragmentShader);
2416 return info; // ==> out
2418 var program = gl.createProgram();
2419 gl.attachShader(program, vertexShader);
2420 gl.attachShader(program, fragmentShader);
2422 gl.linkProgram(program);
2424 if(!gl.getProgramParameter(program, gl.LINK_STATUS)) {
2425 info.hasError = true;
2426 info.linkError = gl.getProgramInfoLog(program);
2427 gl.deleteProgram(program);
2428 gl.deleteShader(vertexShader);
2429 gl.deleteShader(fragmentShader);
2430 return info; // ==> out
2434 var activeUniforms = gl.getProgramParameter(program, gl.ACTIVE_UNIFORMS);
2435 var activeAttributes = gl.getProgramParameter(program, gl.ACTIVE_ATTRIBUTES);
2437 // Taken from the WebGl spec:
2438 // http://www.khronos.org/registry/webgl/specs/latest/1.0/#5.14
2440 0x8B50: "FLOAT_VEC2",
2441 0x8B51: "FLOAT_VEC3",
2442 0x8B52: "FLOAT_VEC4",
2447 0x8B57: "BOOL_VEC2",
2448 0x8B58: "BOOL_VEC3",
2449 0x8B59: "BOOL_VEC4",
2450 0x8B5A: "FLOAT_MAT2",
2451 0x8B5B: "FLOAT_MAT3",
2452 0x8B5C: "FLOAT_MAT4",
2453 0x8B5E: "SAMPLER_2D",
2454 0x8B60: "SAMPLER_CUBE",
2456 0x1401: "UNSIGNED_BYTE",
2458 0x1403: "UNSIGNED_SHORT",
2460 0x1405: "UNSIGNED_INT",
2464 // Loop through active uniforms
2465 for (i = 0; i < activeUniforms; i++) {
2466 var uniform = gl.getActiveUniform(program, i);
2467 info.uniforms[uniform.name] = {name: uniform.name,
2469 typeName: enums[uniform.type],
2470 size: uniform.size};
2471 info.uniformCount += uniform.size;
2474 // Loop through active attributes
2475 for (i = 0; i < activeAttributes; i++) {
2476 var attribute = gl.getActiveAttrib(program, i);
2477 info.attributes[attribute.name] = {name: attribute.name,
2478 type: attribute.type,
2479 typeName: enums[attribute.type],
2480 size: attribute.size};
2481 info.attributeCount += attribute.size;
2485 this._addUniformMetaData(vertex, info);
2486 this._addUniformMetaData(fragment, info);
2492 * add unform metadata from shader source comments
2493 * ie return as an object the comment following a uniform
2494 * uniform float uAlpha; // {"min":0, "max":1}
2497 dali.ShaderInfo.prototype._addUniformMetaData = function(src, metadata) {
2499 // Loop through active uniforms
2500 for(var name in metadata.uniforms) {
2501 var reguniform = new RegExp(name + "[^;]*;(.*)");
2503 var tmp = reguniform.exec(src);
2506 var uComments = tmp[1].trim();
2507 if(uComments.startsWith("//")) { // meta data in comments
2509 meta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
2510 if(typeof meta !== typeof ({})) {
2511 throw ("Uniform UI Spec in comments must be an object");
2519 metadata.uniformUISpec[name] = meta;
2525 * Get shader metadata from regex search.
2527 * Attempts a regex search to get the shader meta data.
2528 * Use fromCompilation() instead of this function wherever compilation is
2529 * possible as this approach will never work for all shaders.
2530 * Does no compilation or error checking but retains fields for
2531 * compatibility with .fromCompilation(...)
2532 * May return an error if the regex fails.
2534 * @param {string} vertex shader
2535 * @param {string} fragment shader
2536 * @return {Object} shader metadata (see 'var info' below)
2538 dali.ShaderInfo.prototype.fromRegEx = function(vertex, fragment) {
2540 var info = { // similar to this.fromCompilation()
2541 vertex: vertex, // source code
2543 attributes: {}, // {aName1: {name:"aName1", ... }
2544 uniforms: {}, // {uName1: {name:"uName1", type:"vec2", ...}
2547 uniformUISpec: {}, // {uName1: {ui:"slider", min:0, max:1, ...}
2548 hasError: false, // compiles without error
2556 metaVertex = this._getRegExMetaData(vertex);
2558 info.hasError = true;
2559 info.vertexError = e.message;
2565 metaFragment = this._getRegExMetaData(fragment);
2567 info.hasError = true;
2568 info.fragmentError = e.message;
2575 info.uniforms = metaVertex.uniformMetaData;
2576 info.uniformUISpec = metaVertex.uniformUISpec;
2578 for(name in metaFragment.uniformMetaData) {
2579 if( name in info.uniforms ) {
2580 info.uniforms[name] = dali.mergeObjects(info.uniforms[name], metaVertex.uniformMetaData);
2582 info.uniforms[name] = metaFragment.uniformMetaData[name];
2584 if( name in info.uniformUISpec ) {
2585 info.uniformUISpec[name] = dali.mergeObjects(info.uniformUISpec[name], metaVertex.uniformUISpec);
2587 info.uniformUISpec[name] = metaFragment.uniformUISpec[name];
2591 info.attributes = metaVertex.attributeMetaData;
2592 for(name in metaFragment.attributeMetaData) {
2593 if( name in metaVertex.attributeMetaData ) {
2594 info.attributes[name] = dali.mergeObjects(info.attributes[name], metaVertex.attributeMetaData);
2596 info.attributes[name] = metaFragment.attributeMetaData[name];
2604 * Returns a string with all comments removed
2607 dali.ShaderInfo.prototype._removeComments = function(str) {
2609 var uid = "_" + new Date(),
2615 /* Remove strings */
2616 .replace(/(['"])(\\\1|.)+?\1/g, function(match){
2617 primatives[primIndex] = match;
2618 return (uid + "") + primIndex++;
2621 /* Remove Regexes */
2622 .replace(/([^\/])(\/(?!\*|\/)(\\\/|.)+?\/[gim]{0,3})/g, function(match, $1, $2){
2623 primatives[primIndex] = $2;
2624 return $1 + (uid + "") + primIndex++;
2628 - Remove single-line comments that contain would-be multi-line delimiters
2629 E.g. // Comment /* <--
2630 - Remove multi-line comments that contain would be single-line delimiters
2633 .replace(/\/\/.*?\/?\*.+?(?=\n|\r|$)|\/\*[\s\S]*?\/\/[\s\S]*?\*\//g, "")
2636 Remove single and multi-line comments,
2637 no consideration of inner-contents
2639 .replace(/\/\/.+?(?=\n|\r|$)|\/\*[\s\S]+?\*\//g, "")
2642 Remove multi-line comments that have a replace ending (string/regex)
2643 Greedy, so no inner strings/regexes will stop it.
2645 .replace(RegExp("\\/\\*[\\s\\S]+" + uid + "\\d+", "g"), "")
2647 /* Bring back strings & regexes */
2648 .replace(RegExp(uid + "(\\d+)", "g"), function(match, n){
2649 return primatives[n];
2655 * Returns true if value is in the array
2658 dali.ShaderInfo.prototype._contains = function(array, value) {
2660 for(var i = 0; i < array.length; i++) {
2661 if(array[i] === value) {
2670 * Get the src meta data for unforms and attributes armed only with a regexp
2673 dali.ShaderInfo.prototype._getRegExMetaData = function(src) {
2675 var ret = {"uniforms": [], // ["uName1", ["uName2"]
2676 "uniformMetaData": {}, // {uName1: {type:"vec3,...}
2677 "uniformUISpec": {}, // {ui:"slider", min:..., max:...}
2678 "attributes": [], // ["aName2"]
2679 "attributeMetaData": {} // ["aName2"]
2682 // Undoubtedly this approach will be wrong. Hopefully on not too many corner cases...
2683 // A better way is to compile the source see (fromCompilation())
2684 // but that requres a gl context.
2687 var definesOut = /#define[ \t]+([A-Za-z_0-9]*)[ \t]+(.*)/g;
2689 var reg = /[ \t]?uniform[ ]*((?:lowp|mediump|highp)?[ \t]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t]*([A-Za-z0-9]*))[ \t]*(;|\[.*\][ \t]*;)(.*)/gi;
2691 var regAttrib = /[ \t]?attribute[ ]*((?:lowp|mediump|highp)?[ \t]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t]*([A-Za-z0-9]*))[ \t]*(;|\[.*\][ \t]*;)(.*)/gi;
2693 // 1. no commented out uniforms
2694 var noCommentSource = this._removeComments(src);
2696 var validUniforms = [];
2697 while ((tmp = reg.exec(noCommentSource))) {
2698 validUniforms.push( tmp[3] );
2701 while ((tmp = regAttrib.exec(noCommentSource))) {
2702 ret.attributes.push( tmp[3] );
2703 ret.attributeMetaData[ tmp[3] ] = {name: tmp[3], type: tmp[2] };
2706 // 2. replace defines
2708 while ((tmp = definesOut.exec(noCommentSource))) {
2709 defines.push([tmp[1], tmp[2]]);
2711 var defineDict = {};
2712 var defineList = [];
2713 while(defines.length) {
2714 var p = defines.pop();
2718 defineDict[n] = eval(v);
2719 defineList.push([n, defineDict[n]]);
2721 var d = /([A-Za-z]+[A-Za-z0-9]*)/g;
2722 while ((tmp = d.exec(v))) {
2723 if(tmp[0] in defineDict) {
2724 v = v.replace(tmp[0], defineDict[tmp[0]]);
2726 defines.push(p); // stick it back to try again. ...and endless loop if we can't(!)
2732 for(var i = 0; i < defineList.length; i++) {
2733 var re = new RegExp(defineList[i][0], "g");
2734 src = src.replace(re, defineList[i][1]);
2738 while ((tmp = reg.exec(src))) {
2739 if(!this._contains(validUniforms, tmp[3])) {
2744 var uArray = tmp[4].slice(0, -1);
2745 var uComments = tmp[5].trim();
2747 var uiSpecMeta = null;
2748 if(uComments.startsWith("//")) { // meta data in comments
2749 uiSpecMeta = eval("(" + uComments.substr(2) + ")"); // brackets to be expression not opening statement
2750 if(typeof uiSpecMeta !== typeof ({})) {
2751 throw ("Uniform UI Spec in comments must be an object");
2756 uiSpecMeta.name = tmp[3];
2757 ret.uniformUISpec[uName] = uiSpecMeta;
2766 if(uArray.search("[[]") >= 0) { // an array
2767 meta.count = Number(uArray.slice(1, -1));
2770 if(this._contains( this._supportedUniformTypes, uType) ) {
2771 if(meta.count !== 0) { // array
2772 for(var j = 0; j < meta.count; j++) {
2773 ret.uniforms.push( meta.name );
2774 ret.uniformMetaData[ meta.name ] = {type: meta.type,
2775 name: meta.name + "[" + j + "]",
2780 ret.uniforms.push( meta.name );
2781 ret.uniformMetaData[ meta.name ] = {type: meta.type,
2787 // not a base type so need to get the compound type
2788 var structFind = new RegExp( "(struct[ \t\n]*" + uType + "[^{]*{)([^}]*)", "g");
2789 var structLines = structFind.exec(src)[2].split(";");
2790 var structUniforms = [];
2793 for(var lineNo = 0; lineNo < structLines.length; lineNo++) {
2794 var line = structLines[lineNo].replace(/\n/g, "") + ";";
2796 var structReg = /[ \t\n]*((?:lowp|mediump|highp)?[ \t\n]*(bool|int|uint|float|[biu]?vec[234]|mat[234]x?[234]?|[^ ]*)[ \t\n]*([A-Za-z0-9]*))[ \t\n]*(;|\[.*\][ \t\n]*;)/gi;
2797 while ((tmpStruct = structReg.exec(line))) {
2798 structUniforms.push( { type: tmpStruct[2],
2800 count: meta.count } );
2804 if(meta.count === 0) {
2805 for(k = 0; k < structUniforms.length; k++) {
2806 name = uName + "." + structUniforms[k].name;
2807 ret.uniforms.push( name );
2808 ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
2812 structType: meta.type,
2813 structName: meta.name};
2816 for(var l = 0; l < meta.count; l++) {
2817 for(k = 0; k < structUniforms.length; k++) {
2818 name = uName + "[" + l + "]" + "." + structUniforms[k].name;
2819 ret.uniforms.push( name );
2820 ret.uniformMetaData[ name ] = {type: structUniforms[k].type,
2824 structType: meta.type,
2825 structName: meta.name};
2835 //------------------------------------------------------------------------------
2839 //------------------------------------------------------------------------------
2840 dali.Debug = function() {
2844 dali.Debug.prototype.printTypeProperties = function(typeName) {
2846 var t = new dali.TypeRegistry();
2847 var info = t.getTypeInfo(typeName);
2848 var props = info.getProperties();
2849 for (var i = 0; i < props.size(); i++) {
2850 console.log(i + ":" + props.get(i));
2852 info.delete(); // wrapper
2853 t.delete(); // wrapper
2856 dali.Debug.prototype.printProperties = function(o) {
2858 var props = o.getProperties();
2860 var len = props.size();
2861 for(var i = 0; i < len; i++) {
2862 var name = props.get(i);
2863 var type = o.getPropertyTypeName(name);
2864 if(type !== "NONE") {
2865 console.log(i + ":" + name + " " + type);
2867 type = o.getPropertyTypeName(name);
2868 console.log(i + ":" + name + " " + type + " (Not mangled)");
2871 props.delete(); // wrapper
2874 dali.Debug.prototype.printTypes = function() {
2877 var t = new dali.TypeRegistry();
2878 for (var i = 0; i < t.getTypeNameCount(); i++) {
2879 console.log(t.getTypeName(i));
2881 t.delete(); // wrapper
2885 dali._debugPrintParents = function(actor, list) {
2894 p = actor.getParent();
2899 // console.log("Cannot get parent", e);
2904 dali._debugPrintParents(p, list);
2908 dali.Debug.prototype.printTree = function(actor) {
2911 dali._debugPrintParents(actor, l);
2915 for (var i = l.length - 1; i >= 0; i--) {
2917 ti = a.getTypeInfo();
2918 console.log("|", Array(l.length - i).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
2921 ti = actor.getTypeInfo();
2922 console.log("*", Array(l.length + 1).join("*"), ti.getName(), "P", actor.position, "R", actor.orientation, actor.name);
2925 var children = actor.getChildren();
2926 for (var j = 0; j < children.length; j++) {
2928 ti = a.getTypeInfo();
2929 console.log("|", Array(l.length + 1 + 1 + j).join("-"), ti.getName(), "P", a.position, "R", a.orientation, a.name);
2934 dali.Debug.prototype.printRenderTask = function(rendertask) {
2936 console.log("[X,Y]", rendertask.getCurrentViewportPosition());
2937 console.log("[W,H]", rendertask.getCurrentViewportSize());
2939 var c = rendertask.getCameraActor();
2941 console.log("No Camera");
2943 console.log("Camera Pos:", c.position);
2944 console.log("Camera Rot:", c.orientation);
2945 console.log("Camera Inherit:", c.inheritRotation);
2946 console.log("Camera ParentOrigin:", c.parentOrigin);
2947 console.log("Camera AnchorPoint:", c.anchorPoint);
2955 console.log("Cannot get parent", e);
2959 console.log("Camera has no parent?");
2961 var ti = p.getTypeInfo();
2962 console.log("Parent Name", ti.getName());
2969 dali.Debug.prototype.printRenderTasks = function() {
2971 var stage = dali.stage;
2972 var taskList = stage.getRenderTaskList();
2973 for (var i = 0; i < taskList.getTaskCount(); i++) {
2974 var t = taskList.getTask(i);
2975 console.log("RenderTask:", i);
2976 this.printRenderTask(t);
2977 t.delete(); // wrapper
2979 taskList.delete(); // wrapper
2982 dali.Debug.prototype.findFirstActor = function(actor, predicateFunction) {
2984 for (var i = 0, len = actor.getChildCount(); i < len; i++) {
2985 var a = actor.getChildAt(i);
2986 var found = predicateFunction(a);
2990 var child = this.findFirstActor(a, predicateFunction);
2999 dali.Debug.prototype.depthVisit = function(actor, operation, dontDelete) {
3001 for (var i = 0, len = actor.getChildCount(); i < len; i++) {
3002 var a = actor.getChildAt(i);
3003 var done = operation(a);
3007 if (!this.depthVisit(a, operation, dontDelete)) {
3011 if (dontDelete !== undefined) {
3023 dali.operationPrintProperty = function(property, all) {
3025 return (function(actor) {
3026 if (property in actor) {
3027 dali.log(actor.getId() + "property:" + actor[property]);
3029 dali.log(actor.getId() + "property:n/a");
3035 dali.predicatePropertyEquals = function(property, value) {
3037 return (function(actor) {
3038 if (property in actor) {
3039 if (actor[property] === value) {
3047 dali.typeInheritsFrom = function(type, basename) {
3048 var inherits = false;
3050 var registry = new dali.TypeRegistry();
3052 var base = registry.getTypeInfo( type.getBaseName() );
3056 inherits = (base.getName() === basename);
3060 base = registry.getTypeInfo( base.getBaseName() );
3063 inherits = (base.getName() === basename);
3077 //------------------------------------------------------------------------------
3081 // Helper functions for creating front/top/left views with RenderTasks
3083 //------------------------------------------------------------------------------
3086 * Sets the clear colour in a RenderTask
3087 * @method setClearColor
3088 * @param {int} renderTaskIndex
3089 * @param {array} color The rgba colour array
3091 dali.setClearColor = function(renderTaskIndex, color) {
3093 var stage = dali.stage;
3094 var taskList = stage.getRenderTaskList();
3095 if (renderTaskIndex >= taskList.getTaskCount()) {
3096 console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3097 taskList.delete(); // wrapper
3100 var rendertask = taskList.getTask(renderTaskIndex);
3101 rendertask.setClearEnabled(true);
3102 rendertask.setClearColor(color);
3106 * Gets the clear colour of a RenderTask
3107 * @method setClearColor
3108 * @param {int} renderTaskIndex
3109 * @return {array} The rgba colour array
3111 dali.getClearColor = function(renderTaskIndex) {
3113 var stage = dali.stage;
3114 var taskList = stage.getRenderTaskList();
3115 if (renderTaskIndex >= taskList.getTaskCount()) {
3116 console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3117 taskList.delete(); // wrapper
3120 var rendertask = taskList.getTask(renderTaskIndex);
3121 return rendertask.getClearColor();
3125 * Set a front view camera with viewport x,y,w,h
3126 * @method setFrontView
3127 * @param {int} renderTaskIndex
3128 * @param {int} x Viewport X
3129 * @param {int} y Viewport Y
3130 * @param {int} w Viewport W
3131 * @param {int} h Viewport H
3133 dali.setFrontView = function(renderTaskIndex, x, y, w, h) {
3135 var stage = dali.stage;
3136 var taskList = stage.getRenderTaskList();
3137 if (renderTaskIndex >= taskList.getTaskCount()) {
3138 console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3139 taskList.delete(); // wrapper
3142 var rendertask = taskList.getTask(renderTaskIndex);
3144 var c = rendertask.getCameraActor();
3145 assert(c.ok(), "Rendertask has no valid camera actor");
3147 rendertask.setViewportPosition([x, y]);
3148 rendertask.setViewportSize([w, h]);
3149 c.position = [0, 0, 800];
3150 c.orientation = [0, 1, 0, 180];
3151 c.aspectRatio = w / h;
3153 c.delete(); // wrapper
3154 rendertask.delete(); // wrapper
3155 taskList.delete(); // wrapper
3159 * Set a top view camera with viewport x,y,w,h
3160 * @method setTopView
3161 * @param {int} renderTaskIndex
3162 * @param {int} x Viewport X
3163 * @param {int} y Viewport Y
3164 * @param {int} w Viewport W
3165 * @param {int} h Viewport H
3167 dali.setTopView = function(renderTaskIndex, x, y, w, h) {
3169 var stage = dali.stage;
3170 var taskList = stage.getRenderTaskList();
3171 if (renderTaskIndex >= taskList.getTaskCount()) {
3172 console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3173 taskList.delete(); // wrapper
3176 var rendertask = taskList.getTask(renderTaskIndex);
3178 var c = rendertask.getCameraActor();
3179 assert(c.ok(), "Rendertask has no valid camera actor");
3181 rendertask.setViewportPosition([x, y]);
3182 rendertask.setViewportSize([w, h]);
3184 var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
3185 var q2 = dali.axisAngleToQuaternion([1, 0, 0, dali.radian(-90)]); // pitch to look at scene
3186 var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
3188 c.position = [0, -800, 0]; // @todo; get 800 from dali not hard coded here
3189 c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
3190 c.aspectRatio = w / h;
3192 c.delete(); // wrapper
3193 rendertask.delete(); // wrapper
3194 taskList.delete(); // wrapper
3198 * Set a right view camera with viewport x,y,w,h
3199 * @method setRightView
3200 * @param {int} renderTaskIndex
3201 * @param {int} x Viewport X
3202 * @param {int} y Viewport Y
3203 * @param {int} w Viewport W
3204 * @param {int} h Viewport H
3206 dali.setRightView = function(renderTaskIndex, x, y, w, h) {
3208 var stage = dali.stage;
3209 var taskList = stage.getRenderTaskList();
3210 if (renderTaskIndex >= taskList.getTaskCount()) {
3211 console.log("RenderTaskIndex out of bounds:", renderTaskIndex);
3212 taskList.delete(); // wrapper
3215 var rendertask = taskList.getTask(renderTaskIndex);
3217 var c = rendertask.getCameraActor();
3218 assert(c.ok(), "Rendertask has no valid camera actor");
3220 rendertask.setViewportPosition([x, y]);
3221 rendertask.setViewportSize([w, h]);
3223 var q1 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(180)]); // yaw around to look at scene down -ve z
3224 var q2 = dali.axisAngleToQuaternion([0, 1, 0, dali.radian(90)]); // yaw again to look from right
3225 var q = dali.quaternionToAxisAngle(dali.quatByQuat(q1, q2));
3227 c.position = [800, 0, 0];
3228 c.orientation = [q[0], q[1], q[2], dali.degree(q[3])]; // @todo; should really all be in radians
3229 c.aspectRatio = w / h;
3231 c.delete(); // wrapper
3232 rendertask.delete(); // wrapper
3233 taskList.delete(); // wrapper
3237 * Remove all but one render task. Presumes RenderTasks are being use only for viewing windows.
3240 dali.onePane = function() {
3242 var stage = dali.stage;
3243 var taskList = stage.getRenderTaskList();
3247 for (i = 1, len = taskList.getTaskCount(); i < len; i++) {
3248 tasks.push(taskList.getTask(i));
3251 for (i = 0, len = tasks.length; i < len; i++) {
3252 var task = tasks[i];
3253 // delete the camera actors we created in twoPane and threePane
3254 var c = task.getCameraActor();
3256 var p = c.getParent();
3260 p.delete(); // wrapper
3262 c.delete(); // wrapper
3264 taskList.removeTask(task);
3265 task.delete(); // wrapper
3272 * Creates render tasks and cameras for a two pane view.
3273 * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
3274 * (in a separate function to allow window gutters)
3277 dali.twoPane = function() {
3281 var stage = dali.stage;
3282 var taskList = stage.getRenderTaskList();
3284 var defaultTask = taskList.getTask(0);
3285 var defaultCamera = defaultTask.getCameraActor();
3286 var defaultCameraParent = defaultCamera.getParent();
3289 t = taskList.createTask();
3291 var c = new dali.CameraActor(); // add camera for different viewpoint
3292 c.position = [0, 0, 800];
3293 c.orientation = [0, 1, 0, 180];
3294 c.parentOrigin = [0.5, 0.5, 0.5];
3295 c.anchorPoint = [0.5, 0.5, 0.5];
3296 t.setCameraActor(c);
3297 defaultCameraParent.add(c);
3298 c.delete(); // wrapper
3300 t.delete(); // wrapper
3302 defaultCameraParent.delete(); // wrapper
3303 defaultCamera.delete(); // wrapper
3304 defaultTask.delete(); // wrapper
3306 taskList.delete(); // wrapper
3310 * Creates render tasks and cameras for a three pane view.
3311 * Use setFrontView/Top/Right with 0-2 index to setup the actual views.
3312 * (in a separate function to allow window gutters)
3315 dali.threePane = function() {
3319 var stage = dali.stage;
3320 var taskList = stage.getRenderTaskList();
3322 var defaultTask = taskList.getTask(0);
3323 var defaultCamera = defaultTask.getCameraActor();
3324 var defaultCameraParent = defaultCamera.getParent();
3327 t = taskList.createTask();
3329 var c = new dali.CameraActor(); // add camera for different viewpoint
3330 c.position = [0, 0, 800];
3331 c.orientation = [0, 1, 0, 180];
3332 c.parentOrigin = [0.5, 0.5, 0.5];
3333 c.anchorPoint = [0.5, 0.5, 0.5];
3334 t.setCameraActor(c);
3335 defaultCameraParent.add(c);
3336 c.delete(); // wrapper
3338 t.delete(); // wrapper
3340 t = taskList.createTask();
3342 c = new dali.CameraActor(); // add camera for different viewpoint
3343 c.position = [0, 0, 800];
3344 c.orientation = [0, 1, 0, 180];
3345 c.parentOrigin = [0.5, 0.5, 0.5];
3346 c.anchorPoint = [0.5, 0.5, 0.5];
3347 t.setCameraActor(c);
3348 defaultCameraParent.add(c);
3349 c.delete(); // wrapper
3351 t.delete(); // wrapper
3353 defaultCameraParent.delete(); // wrapper
3354 defaultCamera.delete(); // wrapper
3355 defaultTask.delete(); // wrapper
3357 taskList.delete(); // wrapper
3360 //------------------------------------------------------------------------------
3362 // Dali Initialization Module
3364 //------------------------------------------------------------------------------
3367 * Create a Dali object by type name
3369 * @param {string} name The type name to create
3370 * @return A Dali handle to the Dali object
3372 dali.create = function(name) {
3375 var handle = dali.__createActor(name);
3378 handle.delete(); // handle
3379 handle = dali.__createHandle(name);
3382 dali.internalSetupProperties(handle);
3387 dali.updateFrame = function() {
3388 dali.__updateOnce();
3389 dali.__renderOnce();
3393 * Creates constructors for objects found in the TypeRegistry. Some objects are
3394 * individually wrapped. Sets some global objects eg. debug/stage.
3397 dali.init = function() {
3400 console.log( dali.VersionString() );
3402 dali.jsSignalHolder = new dali.SignalHolder(); // for js callbacks
3404 dali.debug = new dali.Debug();
3406 dali.stage = new dali.Stage();
3408 dali.getStage = function() { // duplication of dali.stage to stop regressions
3413 // Add constructor functions to dali from the type registry
3415 // Uses separate create functions to add methods for the different base classes.
3416 // Other generic access is by properties. Currently
3422 // |--------------+------------|
3424 // +----+------+ +----+---+ +----+--+
3425 // | Animation | | Handle | | Image |
3426 // +-----------+ +--------+ +-------+
3429 var t = new dali.TypeRegistry();
3431 // use the emscripten wrapping for these and not the typeregisitry creation function
3432 var useWrapping = { RenderTask: 1, RenderTaskList: 1, CameraActor: 1,
3434 Path: 1, Animation: 1,
3435 Handle: 1, Actor: 1,
3436 PropertyMap: 1, PropertyBuffer: 1,
3437 Image: 1, BufferImage: 1, EncodedBufferImage: 1,
3438 Geometry: 1, Material: 1, Shader: 1, Sampler: 1, Renderer: 1
3441 for (var i = 0; i < t.getTypeNameCount(); i++) {
3442 // anon function because of closure with defineProperty
3443 // (if just variable in loop then the variable 'address' is captured, not the value
3444 // so it becomes last value set)
3447 var info = t.getTypeInfo(name);
3449 if(dali.typeInheritsFrom(info, "Actor")) {
3450 createFunc = dali.__createActor;
3451 } else if(dali.typeInheritsFrom(info, "Handle")) {
3452 createFunc = dali.__createHandle;
3455 // @todo Dali error?? name lengths should never be zero
3456 if (name.length && !(name in useWrapping) ) {
3457 Object.defineProperty(dali, name, {
3459 configurable: false,
3462 // console.log(name);
3463 return dali.create(name);
3468 })(t.getTypeName(i));
3476 //------------------------------------------------------------------------------
3480 // Call postDaliWrapperRun() to indicate dali-wrapper.js has loaded
3481 // and other sequential tasks can run (js files can load async)
3483 //------------------------------------------------------------------------------
3486 if (Module.postDaliWrapperRun) {
3487 Module.postDaliWrapperRun();