(Touch) Remove Usage of TouchEvent
[platform/core/uifw/dali-demo.git] / emscripten-examples / dali-toy.js
1 /*
2  * Copyright (c) 2015 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 /*global  */
19 /* eslint-env browser */
20 /* eslint "brace-style": [2, "1tbs"] */
21 /* eslint "no-console": 0 */
22 /* eslint "no-underscore-dangle": 0 */
23
24 //
25 // Dali browser application for testing the javascript API.
26 //
27
28 // browser variables defined for eslint
29 var $;
30 var ace;
31 var dali;
32 // var canvas;
33 var app;
34 var eventHandler;
35 var assert;
36
37 //
38 // Global state
39 //
40 var test;
41 var database;
42
43 var uiApp;
44 var uiJavascriptTab;
45 var uiImageTab;
46 var uiShaderTab;
47
48
49 var actorIdToShaderSet = {};    // actor id to shader
50 var compiledShaders = {};       // compiled shaders by name
51
52 var animationList = [];         // list of animations that have been added [ { animation: new dali.Animation(), properties: [] } ]
53 var animationSelectionIndex;    // selected animation
54
55 //
56 //
57 // Demo Shaders
58 //
59 //
60 var shaderSourceSelection = 0;
61 var shaderSources = [
62   {
63     name: "pass through texture",
64     hints: "",
65     vertex:
66     "\n" +
67       "attribute mediump vec3 aPosition;\n" +
68       "attribute mediump vec2 aTexCoord;\n" +
69       "varying mediump vec2 vTexCoord;\n" +
70       "uniform mediump vec3 uSize;\n" +
71       "uniform mediump mat4 uModelView;\n" +
72       "uniform mediump mat4 uProjection;\n" +
73       "uniform mediump mat4 uMvpMatrix;\n" +
74       "\n" +
75       "void main(void)\n" +
76       "{\n" +
77       "  mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n" +
78       "  vertexPosition.xyz *= uSize;\n" +
79       "  gl_Position = uMvpMatrix * vertexPosition;\n" +
80       "  vTexCoord = aTexCoord;\n" +
81       "}\n",
82     fragment: "precision mediump float;\n" +
83       "\n" +
84       "uniform sampler2D sTexture;\n" +
85       "uniform mediump vec4 uColor;\n" +
86       "varying mediump vec2 vTexCoord;\n" +
87       "\n" +
88       "void main()\n" +
89       "{\n" +
90       "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor;\n" +
91       "}\n"
92   },
93   {
94     name: "pass through color",
95     hints: "",
96     vertex: "\n" +
97       "attribute mediump vec3 aPosition;\n" +
98       "attribute mediump vec2 aTexCoord;\n" +
99       "varying mediump vec2 vTexCoord;\n" +
100       "uniform mediump vec3 uSize;\n" +
101       "uniform mediump mat4 uModelView;\n" +
102       "uniform mediump mat4 uProjection;\n" +
103       "\n" +
104       "void main(void)\n" +
105       "{\n" +
106       "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
107       "  vertexPosition.xyz *= uSize;\n" +
108       "  vTexCoord = aTexCoord;\n" +
109       "}\n",
110     fragment: "precision mediump float;\n" +
111       "\n" +
112       "uniform mediump vec4 uColor;\n" +
113       "varying mediump vec2 vTexCoord;\n" +
114       "\n" +
115       "void main()\n" +
116       "{\n" +
117       "  gl_FragColor = vColor * uColor;\n" +
118       "}\n"
119   },
120   {
121     name: "sRGB Correction",
122     hints: "",
123     vertex: "\n" +
124       "uniform mediump mat4 uModelView;\n" +
125       "uniform mediump mat4 uProjection;\n" +
126       "uniform mediump mat4 uModelMatrix;\n" +
127       "attribute mediump vec3 aPosition;\n" +
128       "attribute mediump vec2 aTexCoord;\n" +
129       "varying mediump vec2 vTexCoord;\n" +
130       "uniform mediump vec3 uSize;\n" +
131       "\n" +
132       "void main(void)\n" +
133       "{\n" +
134       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
135       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
136       "  vTexCoord = aTexCoord;\n" +
137       "}\n",
138     fragment: "precision mediump float;\n" +
139       "\n" +
140       "uniform mediump vec4 uColor;\n" +
141       "uniform sampler2D sTexture;\n" +
142       "varying mediump vec2 vTexCoord;\n" +
143       "\n" +
144       "void main()\n" +
145       "{\n" +
146       "vec4 col = texture2D( sTexture, vTexCoord ) * uColor;\n" +
147       "vec3 mask = vec3(greaterThan(col.rgb, vec3(0.0031308)));\n" +
148       "vec3 o = mix(col.rgb * 12.92, \n" +
149       "             pow(col.rgb, vec3(1.0/2.4)) * 1.055 - 0.055, \n" +
150       "             mask);\n" +
151       "gl_FragColor = vec4(o.r, o.g, o.b, col.a);\n" +
152       "}\n"
153   },
154   {
155     name: "adjust brightness",
156     hints: "",
157     animateTo: [ ["uGain", 1.0, "Linear", 0, 3],
158                  ["uOffset", 0.2, "Linear", 0, 3] ],
159     vertex:
160     "\n" +
161       "uniform mediump mat4 uModelView;\n" +
162       "uniform mediump mat4 uProjection;\n" +
163       "attribute mediump vec3 aPosition;\n" +
164       "attribute mediump vec2 aTexCoord;\n" +
165       "varying mediump vec2 vTexCoord;\n" +
166       "uniform mediump vec3 uSize;\n" +
167       "\n" +
168       "void main(void)\n" +
169       "{\n" +
170       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
171       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
172       "  vTexCoord = aTexCoord;\n" +
173       "}\n" +
174       "\n" +
175       "",
176     fragment:
177     "precision mediump float;\n" +
178       "\n" +
179       "uniform mediump vec4 uColor;\n" +
180       "uniform sampler2D sTexture;\n" +
181       "varying mediump vec2 vTexCoord;\n" +
182       "\n" +
183       "uniform float uGain; // {default:1.0} \n" +
184       "uniform float uOffset; // {default:0.0} \n" +
185       "void main()\n" +
186       "{\n" +
187       "    vec4 t = texture2D( sTexture, vTexCoord );\n" +
188       "    \n" +
189       "    float y = 0.0 + (0.299 *t.r) + 0.587*t.g + 0.114*t.b;\n" +
190       "    float cb= 128.0-(0.168736*t.r)-0.331264*t.g+0.5*t.b;\n" +
191       "    float cr= 128.0+(0.5*t.r)-(0.418688*t.g)-0.081312*t.b;\n" +
192       "    \n" +
193       "    y = (y*uGain) + uOffset;\n" +
194       "    \n" +
195       "    vec4 col = vec4(t.a);\n" +
196       "    \n" +
197       "    col.r = y + 1.402*(cr-128.0);\n" +
198       "    col.g = y - 0.34414*(cb-128.0)-0.71414*(cr-128.0);\n" +
199       "    col.b = y + 1.722*(cb-128.0);\n" +
200       "    \n" +
201       "    \n" +
202       "    gl_FragColor = col * uColor;\n" +
203       "}\n" +
204       "\n" +
205       ""
206   },
207   {
208     name: "wavey",
209     hints: "",
210     animateTo: [ ["uAmplitude", 0.2, "Linear", 0, 3],
211                         ["uFrequency", 4, "Linear", 0, 3] ],
212     vertex:  "\n" +
213       "uniform mediump mat4 uModelView;\n" +
214       "uniform mediump mat4 uProjection;\n" +
215       "attribute mediump vec3 aPosition;\n" +
216       "attribute mediump vec2 aTexCoord;\n" +
217       "varying mediump vec2 vTexCoord;\n" +
218       "uniform mediump vec3 uSize;\n" +
219       "\n" +
220       "void main(void)\n" +
221       "{\n" +
222       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
223       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
224       "  vTexCoord = aTexCoord;\n" +
225       "}\n",
226     fragment: "precision mediump float;\n" +
227       "\n" +
228       "uniform mediump vec4 uColor;\n" +
229       "uniform sampler2D sTexture;\n" +
230       "varying mediump vec2 vTexCoord;\n" +
231       "\n" +
232       "uniform float uAmplitude;  //  {default:0.4, description:\"amplitude in x\"} \n" +
233       "uniform float uFrequency;  // {default: 4, description:\"frequence in y\"} \n" +
234       "void main()\n" +
235       "{\n" +
236       "  vec2 uv = vTexCoord.xy;\n" +
237       "\n" +
238       "  uv.x += sin(uv.y * 3.14 * uFrequency) * uAmplitude;\n" +
239       "  \n" +
240       "  vec4 color = texture2D(sTexture, uv);\n" +
241       "  \n" +
242       "  gl_FragColor = color;\n" +
243       "}\n"
244   },
245   {
246     name: "melt",
247     hints: "",
248     animateTo: [ ["uFactor", -4.0, "Linear", 0, 3] ],
249     vertex:
250     "\n" +
251       "uniform mediump mat4 uModelView;\n" +
252       "uniform mediump mat4 uProjection;\n" +
253       "attribute mediump vec3 aPosition;\n" +
254       "attribute mediump vec2 aTexCoord;\n" +
255       "varying mediump vec2 vTexCoord;\n" +
256       "uniform mediump vec3 uSize;\n" +
257       "\n" +
258       "void main(void)\n" +
259       "{\n" +
260       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
261       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
262       "  vTexCoord = aTexCoord;\n" +
263       "}\n" +
264       "\n" +
265       "",
266     fragment:
267     "precision mediump float;\n" +
268       "\n" +
269       "uniform mediump vec4 uColor;\n" +
270       "uniform sampler2D sTexture;\n" +
271       "varying mediump vec2 vTexCoord;\n" +
272       "\n" +
273       "uniform float uFactor; // {default:0.2, description:\"drip factor\"} \n" +
274       "\n" +
275       "    \n" +
276       "float random( vec2 p )\n" +
277       "{\n" +
278       "    float q = p.x * 269.5 + p.y * 183.3;\n" +
279       "  return fract( sin( q ) * 43758.5453 );\n" +
280       "}\n" +
281       "\n" +
282       "void main()\n" +
283       "{\n" +
284       "  vec2 uv = vTexCoord.xy;\n" +
285       "  \n" +
286       "  float kindaRandom = (texture2D(sTexture, vec2(uv.x,0.5)).r + texture2D(sTexture, vec2(0.5,uv.x)).r) / 2.0;\n" +
287       "  \n" +
288       "  //kindaRandom = random( vec2(texture2D(sTexture, vec2(uv.x,0.5)).r, texture2D(sTexture, vec2(0.5,uv.y)).g) );\n" +
289       "  \n" +
290       "  uv.y +=  uFactor * kindaRandom;\n" +
291       "  \n" +
292       "\n" +
293       "  gl_FragColor = texture2D( sTexture, uv ) * uColor;\n" +
294       "}\n" +
295       "\n" +
296       "\n" +
297       ""
298   },
299   {
300     name: "round window",
301     hints: "",
302     animateTo: [ ["uRadius", 0.8, "Linear", 0, 3] ],
303     vertex: "\n" +
304       "uniform mediump mat4 uModelView;\n" +
305       "uniform mediump mat4 uProjection;\n" +
306       "attribute mediump vec3 aPosition;\n" +
307       "attribute mediump vec2 aTexCoord;\n" +
308       "varying mediump vec2 vTexCoord;\n" +
309       "\n" +
310       "void main(void)\n" +
311       "{\n" +
312       "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
313       "  vTexCoord = aTexCoord;\n" +
314       "}\n",
315     fragment: "precision lowp float;\n" +
316       "\n" +
317       "uniform mediump vec4 uColor;\n" +
318       "uniform sampler2D sTexture;\n" +
319       "\n" +
320       "uniform lowp float uRadius; // {default: 0.2}  \n" +
321       "varying mediump vec2 vTexCoord;\n" +
322       "void main()\n" +
323       "{\n" +
324       "  precision lowp float;\n" +
325       "  lowp vec2 pos= vec2(vTexCoord.x-0.5,vTexCoord.y-0.5);\n" +
326       "  lowp float radius = dot(pos, pos ) ;\n" +
327       "  if( radius > (uRadius*uRadius) )\n" +
328       "    discard;\n" +
329       "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor ;\n" +
330       "}\n"
331   },
332   {
333     name: "mosaic",
334     hints: "",
335     animateTo: [ ["uPixelFactor", 0.3, "Linear", 0, 3] ],
336     vertex: "\n" +
337       "uniform mediump mat4 uModelView;\n" +
338       "uniform mediump mat4 uProjection;\n" +
339       "attribute mediump vec3 aPosition;\n" +
340       "attribute mediump vec2 aTexCoord;\n" +
341       "varying mediump vec2 vTexCoord;\n" +
342       "uniform mediump vec3 uSize;\n" +
343       "\n" +
344       "void main(void)\n" +
345       "{\n" +
346       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
347       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
348       "  vTexCoord = aTexCoord;\n" +
349       "}\n",
350     fragment: "precision mediump float;\n" +
351       "\n" +
352       "uniform mediump vec4 uColor;\n" +
353       "uniform sampler2D sTexture;\n" +
354       "varying mediump vec2 vTexCoord;\n" +
355       "\n" +
356       "  \n" +
357       "uniform float uPixelFactor; //  {default:0.1, min:0.0, max:0.3} \n" +
358       "\n" +
359       "\n" +
360       "float smooth(float f) {\n" +
361       "  return 32.0*f*f*(0.25*f*f-0.5*f+0.25)+0.5;\n" +
362       "}\n" +
363       "\n" +
364       "void main()\n" +
365       "{\n" +
366       "  vec2 resolution = vec2(1,1); // uniform vec2 resolution;\n" +
367       "  //uPixelFactor = 8.0 + 8.0 * (0.5 + 0.5 * sin(globaltime * 0.25));\n" +
368       "  vec2 chunkCoord = floor(vTexCoord.xy / uPixelFactor) * uPixelFactor;\n" +
369       "  vec2 locCoord = (vTexCoord.xy - chunkCoord) / uPixelFactor;\n" +
370       "  vec4 color = vec4(floor(5.0 * texture2D(sTexture, chunkCoord / resolution.xy).xyz) / 5.0, 1.0);\n" +
371       "  float grey = (color.x + color.y + color.z) / 3.0;\n" +
372       "  gl_FragColor = color * smooth(locCoord.x) * smooth(locCoord.y);\n" +
373       "}\n"
374   },
375   {
376     name: "burn",
377     hints: "",
378     animateTo: [ ["uThresh", 0.8, "Linear", 0, 3] ],
379     vertex:
380     "\n" +
381       "uniform mediump mat4 uModelView;\n" +
382       "uniform mediump mat4 uProjection;\n" +
383       "attribute mediump vec3 aPosition;\n" +
384       "attribute mediump vec2 aTexCoord;\n" +
385       "varying mediump vec2 vTexCoord;\n" +
386       "uniform mediump vec3 uSize;\n" +
387       "\n" +
388       "void main(void)\n" +
389       "{\n" +
390       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
391       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
392       "  vTexCoord = aTexCoord;\n" +
393       "}\n" +
394       "\n" +
395       "\n" +
396       "\n" +
397       "",
398     fragment:
399     "precision mediump float;\n" +
400       "\n" +
401       "uniform mediump vec4 uColor;\n" +
402       "uniform sampler2D sTexture;\n" +
403       "varying mediump vec2 vTexCoord;\n" +
404       "\n" +
405       "\n" +
406       "float uScale = 2.0;  // {default:10.0, description:\"noise texture scaling\"} \n" +
407       "uniform float uThresh;  // {default:1.1, description:\"threshold of noise for burn\"} \n" +
408       "\n" +
409       "float random( vec2 p )\n" +
410       "{\n" +
411       "    float q = p.x * 269.5 + p.y * 183.3;\n" +
412       "  return fract( sin( q ) * 43758.5453 );\n" +
413       "}\n" +
414       "\n" +
415       "float noise( vec2 point )\n" +
416       "{\n" +
417       "  vec2 p = floor( point );\n" +
418       "  vec2 f = fract( point );\n" +
419       "  return mix(\n" +
420       "    mix( random( p + vec2( 0.0, 0.0 ) ), random( p + vec2( 1.0, 0.0 ) ), f.x ),\n" +
421       "    mix( random( p + vec2( 0.0, 1.0 ) ), random( p + vec2( 1.0, 1.0 ) ), f.x ),\n" +
422       "    f.y\n" +
423       "  );\n" +
424       "}\n" +
425       "\n" +
426       "float fractal( vec2 point )\n" +
427       "{\n" +
428       "    float sum = 0.0;\n" +
429       "    float scale = 0.5;\n" +
430       "    for ( int i = 0; i <  5; i++ )\n" +
431       "  {\n" +
432       "    sum += noise( point ) * scale;\n" +
433       "    point *= 2.0;\n" +
434       "        scale /= 2.0;\n" +
435       "  }\n" +
436       "    \n" +
437       "  return sum;\n" +
438       "}\n" +
439       "\n" +
440       "\n" +
441       "void main( )\n" +
442       "{\n" +
443       "  vec2 point = vTexCoord.xy / uScale;\n" +
444       "    //point.x += iGlobalTime * 0.1;\n" +
445       "    float noise    = fractal( point * 20.0 );\n" +
446       "    \n" +
447       "    vec2 uv = vTexCoord.xy; // iResolution.xy;\n" +
448       "    //uv.y = 1.0-uv.y;\n" +
449       "    gl_FragColor = texture2D(sTexture, uv);\n" +
450       "    \n" +
451       "    if(noise <  uThresh)\n" +
452       "    {\n" +
453       "        gl_FragColor = vec4(1.0, 0.5, 0.0, 1.0);\n" +
454       "    }\n" +
455       "    if(noise <  uThresh - 0.05)\n" +
456       "    {\n" +
457       "        gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n" +
458       "    }\n" +
459       "    if(noise <  uThresh - 0.1)\n" +
460       "    {\n" +
461       "    \n" +
462       "        gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0); // use discard?\n" +
463       "    }\n" +
464       "}\n" +
465       "\n" +
466       "\n" +
467       ""
468   },
469   {
470     name: "ripple 2D",
471     hints: "",
472     animateTo: [ ["uAmplitude", 0.1, "Linear", 0, 3],
473                  ["uTime", 6, "Linear", 0, 3] ],
474     vertex: "\n" +
475       "uniform mediump mat4 uModelView;\n" +
476       "uniform mediump mat4 uProjection;\n" +
477       "attribute mediump vec3 aPosition;\n" +
478       "attribute mediump vec2 aTexCoord;\n" +
479       "varying mediump vec2 vTexCoord;\n" +
480       "\n" +
481       "void main(void)\n" +
482       "{\n" +
483       "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
484       "  vTexCoord = aTexCoord;\n" +
485       "}\n" +
486       "\n" +
487       "",
488     fragment:
489     "precision mediump float;\n" +
490       "\n" +
491       "uniform mediump vec4 uColor;\n" +
492       "uniform sampler2D sTexture;\n" +
493       "varying mediump vec2 vTexCoord;\n" +
494       "\n" +
495       "uniform float uAmplitude; // {default:0.02, min:0.0, max:1.0}\n" +
496       "uniform float uTime;\n" +
497       "uniform mediump vec4 sTextureRect;\n" +
498       "void main()\n" +
499       "{\n" +
500       "  highp vec2 textureSize = sTextureRect.zw - sTextureRect.xy;\n" +
501       "  highp vec2 pos = -1.0 + 2.0 * vTexCoord.st/textureSize;\n" +
502       "  highp float len = length(pos);\n" +
503       "  highp vec2 texCoord = vTexCoord.st/textureSize + pos/len * sin( len * 12.0 - uTime * 4.0 ) * uAmplitude; \n" +
504       "  gl_FragColor = texture2D(sTexture, texCoord) * uColor;\n" +
505       "}\n" +
506       "\n" +
507       "\n" +
508       ""
509   },
510   {
511     name: "emboss combine",
512     hints: "",
513     animateTo: [ ["uWeight", [10.0, 10.0, 10.0, 10.0], "Linear", 0, 3] ],
514     vertex: "\n" +
515       "uniform mediump mat4 uModelView;\n" +
516       "uniform mediump mat4 uProjection;\n" +
517       "attribute mediump vec3 aPosition;\n" +
518       "attribute mediump vec2 aTexCoord;\n" +
519       "varying mediump vec2 vTexCoord;\n" +
520       "uniform mediump vec3 uSize;\n" +
521       "\n" +
522       "void main(void)\n" +
523       "{\n" +
524       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
525       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
526       "  vTexCoord = aTexCoord;\n" +
527       "}\n" +
528       "\n" +
529       "",
530     fragment: "precision mediump float;\n" +
531       "\n" +
532       "uniform mediump vec4 uColor;\n" +
533       "uniform sampler2D sTexture;\n" +
534       "varying mediump vec2 vTexCoord;\n" +
535       "\n" +
536       "const int KERNEL_SIZE = 9;\n" +
537       "\n" +
538       "uniform vec4 uWeight; // {default: [10,10,10,10] }\n" +
539       "\n" +
540       "// Gaussian kernel\n" +
541       "float kernel[KERNEL_SIZE];\n" +
542       "\n" +
543       "float width  = 512.0;\n" +
544       "float height = 512.0;\n" +
545       "\n" +
546       "float step_w = 1.0/width;\n" +
547       "float step_h = 1.0/height;\n" +
548       "\n" +
549       "vec2 offset[KERNEL_SIZE];\n" +
550       "\n" +
551       "void main(void)\n" +
552       "{\n" +
553       "  precision mediump float;\n" +
554       "\n" +
555       "  vec4 sum = vec4(0.0);\n" +
556       "\n" +
557       "  offset[0] = vec2(-step_w, -step_h);\n" +
558       "  offset[1] = vec2(0.0, -step_h);\n" +
559       "  offset[2] = vec2(step_w, -step_h);\n" +
560       "\n" +
561       "  offset[3] = vec2(-step_w, 0.0);\n" +
562       "  offset[4] = vec2(0.0, 0.0);\n" +
563       "  offset[5] = vec2(step_w, 0.0);\n" +
564       "\n" +
565       "  offset[6] = vec2(-step_w, step_h);\n" +
566       "  offset[7] = vec2(0.0, step_h);\n" +
567       "  offset[8] = vec2(step_w, step_h);\n" +
568       "\n" +
569       "  // guassian blur\n" +
570       "  // kernel[0] = 1.0/16.0;  kernel[1] = 2.0/16.0;  kernel[2] = 1.0/16.0;\n" +
571       "  // kernel[3] = 2.0/16.0;  kernel[4] = 4.0/16.0;  kernel[5] = 2.0/16.0;\n" +
572       "  // kernel[6] = 1.0/16.0;  kernel[7] = 2.0/16.0;  kernel[8] = 1.0/16.0;\n" +
573       "\n" +
574       "  // laplace\n" +
575       "  // kernel[0] = 0.0;  kernel[1] = 1.0;  kernel[2] = 0.0;\n" +
576       "  // kernel[3] = 1.0;  kernel[4] = -4.0; kernel[5] = 1.0;\n" +
577       "  // kernel[6] = 0.0;  kernel[7] = 1.0;  kernel[8] = 0.0;\n" +
578       "\n" +
579       "  // edge\n" +
580       "  // kernel[0] = -1.0;  kernel[1] = -1.0; kernel[2] = -1.0;\n" +
581       "  // kernel[3] = -1.0;  kernel[4] = +9.0; kernel[5] = -1.0;\n" +
582       "  // kernel[6] = -1.0;  kernel[7] = -1.0; kernel[8] = -1.0;\n" +
583       "\n" +
584       "  // Embossing\n" +
585       "  // 2  0  0\n" +
586       "  // 0 -1  0\n" +
587       "  // 0  0 -1\n" +
588       "  kernel[0] = 2.0;  kernel[1] = 0.0;  kernel[2] = 0.0;\n" +
589       "  kernel[3] = 0.0;  kernel[4] = -1.0; kernel[5] = 0.0;\n" +
590       "  kernel[6] = 0.0;  kernel[7] = 0.0;  kernel[8] =-1.0;\n" +
591       "\n" +
592       "    vec4 tmp = texture2D(sTexture, vTexCoord.st + offset[0]);\n" +
593       "    sum += tmp * kernel[0];\n" +
594       "\n" +
595       "    tmp = texture2D(sTexture, vTexCoord.st + offset[1]);\n" +
596       "    sum += tmp * kernel[1];\n" +
597       "\n" +
598       "    tmp = texture2D(sTexture, vTexCoord.st + offset[2]);\n" +
599       "    sum += tmp * kernel[2];\n" +
600       "\n" +
601       "    tmp = texture2D(sTexture, vTexCoord.st + offset[3]);\n" +
602       "    sum += tmp * kernel[3];\n" +
603       "\n" +
604       "    tmp = texture2D(sTexture, vTexCoord.st + offset[4]);\n" +
605       "    sum += tmp * kernel[4];\n" +
606       "\n" +
607       "    tmp = texture2D(sTexture, vTexCoord.st + offset[5]);\n" +
608       "    sum += tmp * kernel[5];\n" +
609       "\n" +
610       "    tmp = texture2D(sTexture, vTexCoord.st + offset[6]);\n" +
611       "    sum += tmp * kernel[6];\n" +
612       "\n" +
613       "    tmp = texture2D(sTexture, vTexCoord.st + offset[7]);\n" +
614       "    sum += tmp * kernel[7];\n" +
615       "\n" +
616       "    tmp = texture2D(sTexture, vTexCoord.st + offset[8]);\n" +
617       "    sum += tmp * kernel[8];\n" +
618       "\n" +
619       "    sum = texture2D(sTexture, vTexCoord.xy) + (sum * uWeight);\n" +
620       "\n" +
621       "  gl_FragColor = sum;\n" +
622       "}\n"
623   },
624   {
625     name: "blur",
626     hints: "",
627     vertex: "\n" +
628       "uniform mediump mat4 uModelView;\n" +
629       "uniform mediump mat4 uProjection;\n" +
630       "uniform mediump vec3 uSize;\n" +
631       "attribute mediump vec3 aPosition;\n" +
632       "attribute mediump vec2 aTexCoord;\n" +
633       "varying mediump vec2 vTexCoord;\n" +
634       "\n" +
635       "void main(void)\n" +
636       "{\n" +
637       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
638       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
639       "  vTexCoord = aTexCoord;\n" +
640       "}\n" +
641       "\n" +
642       "",
643     fragment:
644     "\n" +
645       "precision mediump float;\n" +
646       "\n" +
647       "uniform mediump vec4 uColor;\n" +
648       "uniform sampler2D sTexture;\n" +
649       "varying mediump vec2 vTexCoord;\n" +
650       "\n" +
651       "\n" +
652       "#define PI2 6.283184\n" +
653       "\n" +
654       "#define CV 0.1\n" +
655       "#define ST 0.05\n" +
656       "\n" +
657       "uniform float uFactor; // {default: 0.5, min:0.0, max:1.0}\n" +
658       "\n" +
659       "vec4 colorat(vec2 uv) {\n" +
660       "  return texture2D(sTexture, uv);\n" +
661       "}\n" +
662       "vec4 blur(vec2 uv) { // convolve\n" +
663       "  vec4 col = vec4(0.0);\n" +
664       "  for(float r0 = 0.0; r0 < 1.0; r0 += ST) {\n" +
665       "    float r = r0 * CV;\n" +
666       "    for(float a0 = 0.0; a0 < 1.0; a0 += ST) {\n" +
667       "      float a = a0 * PI2;\n" +
668       "      col += colorat(uv + vec2(cos(a), sin(a)) * r);\n" +
669       "    }\n" +
670       "  }\n" +
671       "  col *= ST * ST;\n" +
672       "  return col;\n" +
673       "}\n" +
674       "\n" +
675       "\n" +
676       "\n" +
677       "void main() {\n" +
678       "  vec2 uv = vTexCoord.xy;\n" +
679       "  gl_FragColor = blur(uv) * uFactor + ((1.0-uFactor) * texture2D(sTexture, uv));\n" +
680       "}\n" +
681       "\n"
682   },
683   {name: "image-click",
684    hints: "",
685    animateTo: [ ["uRadius", 0.3, "Linear", 0, 0.3] ],
686    vertex: "\n" +
687    "uniform mediump mat4 uModelView;\n" +
688    "uniform mediump mat4 uProjection;\n" +
689    "attribute mediump vec3 aPosition;\n" +
690    "attribute mediump vec2 aTexCoord;\n" +
691    "varying mediump vec2 vTexCoord;\n" +
692    "uniform mediump vec3 uSize;\n" +
693    "\n" +
694    "void main(void)\n" +
695    "{\n" +
696    "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
697    "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
698    "  vTexCoord = aTexCoord;\n" +
699    "}\n" +
700    "\n" +
701    "",
702    fragment:
703    "precision lowp float;\n" +
704    "\n" +
705    "uniform mediump vec4 uColor;\n" +
706    "varying mediump vec2 vTexCoord;\n" +
707    "uniform sampler2D sTexture;\n" +
708    "\n" +
709    "uniform lowp float uRadius; // {default 0.2, min:0, max:0.3, description:\"touch radius and brightness mix\"\n" +
710    "vec2 offset = vec2(0.3,-0.2); // offset from center; for touch point (todo - make uniform)\n" +
711    "\n" +
712    "void main()\n" +
713    "{\n" +
714    "  precision lowp float;\n" +
715    "  lowp vec2 pos= vec2(vTexCoord.x-0.5-offset.x,vTexCoord.y-0.5-offset.y);\n" +
716    "  lowp float radius = dot(pos, pos ) ;\n" +
717    "\n" +
718    " //  use sRGB correction to brighten image\n" +
719    "    vec4 col = texture2D( sTexture, vTexCoord ) * uColor;\n" +
720    "    vec3 mask = vec3(greaterThan(col.rgb, vec3(0.0031308)));\n" +
721    "    vec3 o = mix(col.rgb * 12.92, \n" +
722    "             pow(col.rgb, vec3(1.0/2.4)) * 1.055 - 0.055, \n" +
723    "             mask);\n" +
724    "    \n" +
725    "    vec3 diff = o - col.rgb;\n" +
726    "    diff *= uRadius * 3.0;\n" +
727    "    o = col.rgb + diff;\n" +
728    "    \n" +
729    "    gl_FragColor = vec4(o.r, o.g, o.b, col.a);\n" +
730    "\n" +
731    "  if( radius <= (uRadius*uRadius) )\n" +
732    "  {\n" +
733    "    gl_FragColor += vec4(0.1);\n" +
734    "  }\n" +
735    "  \n" +
736    "}\n" +
737    "\n" +
738    ""
739   },
740   {name: "iris effect",
741    hints: "",
742    animateTo: [ ["uRadius", 1.0, "Linear", 0, 0.3],
743                 ["uCenter", [0.2, 0.2], "Linear", 0, 0.0],
744                 ["uBlendFactor", 1.0, "Linear", 0, 0.0]
745               ],
746    vertex:
747    "\n" +
748    "uniform mediump mat4 uModelView;\n" +
749    "uniform mediump mat4 uProjection;\n" +
750    "attribute mediump vec3 aPosition;\n" +
751    "attribute mediump vec2 aTexCoord;\n" +
752    "varying mediump vec2 vTexCoord;\n" +
753    "uniform mediump vec3 uSize;\n" +
754    "\n" +
755    "uniform mediump vec2 uCenter; // { default: [0.7, 0.7] } \n" +
756    "varying mediump vec2 vRelativePosition;\n" +
757    "\n" +
758    "void main()\n" +
759    "{\n" +
760    "    mediump vec3 vertexPosition = aPosition * uSize;\n" +
761    "    mediump vec4 world = uModelView * vec4(vertexPosition,1.0);\n" +
762    "    gl_Position = uProjection * world;\n" +
763    "\n" +
764    "    vTexCoord = aTexCoord;\n" +
765    "    vRelativePosition = aTexCoord - uCenter;\n" +
766    "}\n" +
767    "\n" +
768    "\n" +
769    "",
770    fragment:
771    "\n" +
772    "uniform mediump vec4 uColor;\n" +
773    "uniform sampler2D sTexture;\n" +
774    "varying mediump vec2 vTexCoord;\n" +
775    "\n" +
776    "uniform mediump float uRadius; // {default:0.5} \n" +
777    "uniform mediump float uBlendFactor; // {default:2} \n" +
778    "varying mediump vec2 vRelativePosition;\n" +
779    "void main()\n" +
780    "{\n" +
781    "   mediump float delta = (length(vRelativePosition) - uRadius);\n" +
782    "   delta = clamp(0.0 - delta * uBlendFactor, 0.0, 1.0);\n" +
783    "   gl_FragColor = texture2D(sTexture, vTexCoord) * uColor;\n" +
784    "   gl_FragColor.a *= delta;\n" +
785    "}\n" +
786    "\n" +
787    ""
788   },
789   {name: "mirror effect",
790    hints: "",
791    animateTo: [ ["uDepth", 0.5, "Linear", 0, 0.0],
792                 ["uAlpha", 1.0, "Linear", 0, 0.0]
793               ],
794    vertex:
795    "\n" +
796    "uniform mediump mat4 uModelView;\n" +
797    "uniform mediump mat4 uProjection;\n" +
798    "attribute mediump vec3 aPosition;\n" +
799    "attribute mediump vec2 aTexCoord;\n" +
800    "varying mediump vec2 vTexCoord;\n" +
801    "uniform mediump vec3 uSize;\n" +
802    "\n" +
803    "void main()\n" +
804    "{\n" +
805    "  mediump vec3 pos = aPosition * uSize;\n" +
806    "  pos.y = pos.y * 3.0;\n" +
807    "  mediump vec4 world = uModelView * vec4(pos,1.0);\n" +
808    "  gl_Position = uProjection * world;\n" +
809    "  vTexCoord = aTexCoord;\n" +
810    "}\n" +
811    "\n" +
812    "",
813    fragment:
814    "\n" +
815    "uniform mediump vec4 uColor;\n" +
816    "uniform sampler2D sTexture;\n" +
817    "varying mediump vec2 vTexCoord;\n" +
818    "\n" +
819    "uniform  mediump float  uDepth; // {default: 0.3 }\n" +
820    "uniform  mediump float  uAlpha; // {default: 10.0 }\n" +
821    "void main()\n" +
822    "{\n" +
823    " if(vTexCoord.y < 1.0 / 3.0)\n" +
824    " {\n" +
825    "   gl_FragColor = vec4(0.0, 0.0, 0.0, 0.0);\n" +
826    " }\n" +
827    " else if(vTexCoord.y < 2.0 / 3.0)\n" +
828    " {\n" +
829    "   gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x, vTexCoord.y * 3.0 - 1.0)) * uColor;\n" +
830    "   gl_FragColor.a *= uAlpha;\n" +
831    " }\n" +
832    " else\n" +
833    " {\n" +
834    "   highp float darkness = 3.0 - vTexCoord.y * 3.0;\n" +
835    "   darkness = (1.0 - 1.0 / uDepth + darkness * 1.0/ uDepth) * 0.65;\n" +
836    "   highp vec4 color = texture2D(sTexture, vec2(vTexCoord.x, -vTexCoord.y *3.0 + 3.0)) * uColor;\n" +
837    "   color.a *= uAlpha;\n" +
838    "   gl_FragColor = color * vec4(darkness, darkness, darkness, darkness);\n" +
839    " }\n" +
840    "}\n" +
841    ""
842   },
843   {name: "square dissolve",
844    animateTo: [ ["uRows", 0.4, "Linear", 0, 0.0],
845                 ["uColumns", 0.4, "Linear", 0, 0.0],
846                 ["texSize", [100, 100], "Linear", 0, 0.0],
847                 ["uStep", 1, "Linear", 0, 3.0]
848               ],
849    hints: " grid blending",
850    vertex: "\n" +
851    "uniform mediump mat4 uModelView;\n" +
852    "uniform mediump mat4 uProjection;\n" +
853    "attribute mediump vec3 aPosition;\n" +
854    "attribute mediump vec2 aTexCoord;\n" +
855    "varying mediump vec2 vTexCoord;\n" +
856    "\n" +
857    "void main(void)\n" +
858    "{\n" +
859    "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
860    "  vTexCoord = aTexCoord;\n" +
861    "}\n" +
862    "\n" +
863    "",
864    fragment:
865    "\n" +
866    "uniform mediump vec4 uColor;\n" +
867    "uniform sampler2D sTexture;\n" +
868    "varying mediump vec2 vTexCoord;\n" +
869    "\n" +
870    "uniform  mediump vec2   texSize;\n" +
871    "uniform  mediump float  uStep;\n" +
872    "uniform  mediump float  uRows;\n" +
873    "uniform  mediump float  uColumns;\n" +
874    "uniform sampler2D sTexture;\n" +
875    "void main()\n" +
876    "{\n" +
877    "  mediump vec2 mosaicSize = vec2(1.0 / uRows, 1.0 / uColumns);\n" +
878    "  mediump vec2 intXY = vec2(vTexCoord.x * texSize.x, vTexCoord.y * texSize.y);\n" +
879    "  mediump vec2 XYMosaic = vec2(floor(intXY.x / mosaicSize.x) * mosaicSize.x, floor(intXY.y / mosaicSize.y) * mosaicSize.y);\n" +
880    "  mediump vec2 UVMosaic = vec2(XYMosaic.x /texSize.x, XYMosaic.y / texSize.y);\n" +
881    "  mediump vec4 noiseVec = texture2D(sEffect, UVMosaic);\n" +
882    "  mediump float intensity = (noiseVec[0] + noiseVec[1] + noiseVec[2] + noiseVec[3]) / 4.0;\n" +
883    "  if(intensity < uStep)\n" +
884    "    gl_FragColor = vec4(0.1, 0.1, 0.1, 1.0);\n" +
885    "  else\n" +
886    "    gl_FragColor = texture2D(sTexture, vTexCoord);\n" +
887    "  gl_FragColor *= uColor;\n" +
888    "}\n" +
889    "\n" +
890    ""
891   },
892   {name: "swirl",
893    hints: " grid blending",
894    animateTo: [ ["uCenter", [0.5, 0.5], "Linear", 0, 0.0],
895                 ["uTextureSize", [100, 100], "Linear", 0, 0.0],
896                 ["uRadius", 1.0, "Linear", 0, 3.0],
897                 ["uAngle", 3.0, "Linear", 0, 3.0]
898               ],
899    vertex: "\n" +
900    "uniform mediump mat4 uModelView;\n" +
901    "uniform mediump mat4 uProjection;\n" +
902    "attribute mediump vec3 aPosition;\n" +
903    "attribute mediump vec2 aTexCoord;\n" +
904    "varying mediump vec2 vTexCoord;\n" +
905    "uniform mediump vec3 uSize;\n" +
906    "\n" +
907    "void main(void)\n" +
908    "{\n" +
909    "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
910    "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
911    "  vTexCoord = aTexCoord;\n" +
912    "}\n" +
913    "\n" +
914    "",
915    fragment: "\n" +
916    "uniform mediump vec4 uColor;\n" +
917    "uniform sampler2D sTexture;\n" +
918    "uniform mediump vec4 sTextureRect;\n" +
919    "\n" +
920    "uniform mediump vec2  uTextureSize;\n" +
921    "uniform highp float uRadius;\n" +
922    "uniform highp float uAngle;\n" +
923    "uniform mediump vec2  uCenter;\n" +
924    "varying mediump vec2 vTexCoord;\n" +
925    "void main()\n" +
926    "{\n" +
927    "  highp vec2 textureCenter = (sTextureRect.xy + sTextureRect.zw) * 0.5;\n" +
928    "  textureCenter = vTexCoord.st - textureCenter;\n" +
929    "  highp float distance = length(textureCenter);\n" +
930    "  if (distance >= uRadius)\n" +
931    "    discard;\n" +
932    "  highp float percent = (uRadius - distance) / uRadius;\n" +
933    "  highp float theta = percent * percent * uAngle * 4.0;\n" +
934    "  highp float sinTheta = sin(theta);\n" +
935    "  highp float cosTheta = cos(theta);\n" +
936    "// if warp, loose the sign from sin\n" +
937    "  bool warp = true;\n" +
938    "  if( warp )\n" +
939    "  {\n" +
940    "    textureCenter = vec2( dot( textureCenter, vec2(cosTheta, sinTheta) ),\n" +
941    "                          dot( textureCenter, vec2(sinTheta, cosTheta) ) );\n" +
942    "  }\n" +
943    "  else\n" +
944    "  {\n" +
945    "    textureCenter = vec2( dot( textureCenter, vec2(cosTheta, -sinTheta) ),\n" +
946    "                        dot( textureCenter, vec2(sinTheta, cosTheta) ) );\n" +
947    "  }\n" +
948    "  textureCenter += uCenter;\n" +
949    "  gl_FragColor = texture2D( sTexture, textureCenter ) * uColor;\n" +
950    "}\n" +
951    "\n" +
952    "\n" +
953    ""
954   },
955   {name: "drop shadow",
956    vertex:
957    "\n" +
958    "uniform mediump mat4 uModelView;\n" +
959    "uniform mediump mat4 uProjection;\n" +
960    "attribute mediump vec3 aPosition;\n" +
961    "attribute mediump vec2 aTexCoord;\n" +
962    "varying mediump vec2 vTexCoord;\n" +
963    "uniform mediump vec3 uSize;\n" +
964    "\n" +
965    "void main()\n" +
966    "{\n" +
967    "  mediump vec3 pos = aPosition * uSize;\n" +
968    "  pos.y = pos.y * 1.1;  \n" +
969    "  pos.x = pos.x * 1.1;\n" +
970    "  \n" +
971    "  mediump vec4 world = uModelView * vec4(pos,1.0);\n" +
972    "  gl_Position = uProjection * world;\n" +
973    "  vTexCoord = aTexCoord;\n" +
974    "}\n" +
975    "\n" +
976    "\n" +
977    "",
978    fragment:
979    "\n" +
980    "uniform mediump vec4 uColor;\n" +
981    "uniform sampler2D sTexture;\n" +
982    "varying mediump vec2 vTexCoord;\n" +
983    "\n" +
984    "void main()\n" +
985    "{\n" +
986    " if(vTexCoord.y <   0.05)\n" +
987    " {\n" +
988    "   discard;\n" +
989    "   gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n" +
990    " }\n" +
991    " else if(vTexCoord.x <   0.05)\n" +
992    " {\n" +
993    "   discard;\n" +
994    "    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);\n" +
995    " }\n" +
996    " else if(vTexCoord.y <   0.95 && vTexCoord.x <   0.95)\n" +
997    " {\n" +
998    "   gl_FragColor = texture2D(sTexture, vec2(vTexCoord.x/ (1.0/1.1) - 0.05, vTexCoord.y / (1.0/1.0) - 0.05 )) * uColor;\n" +
999    " }\n" +
1000    " else\n" +
1001    " {\n" +
1002    "   if(vTexCoord.y <   0.1 || vTexCoord.x <   0.1)\n" +
1003    "   {\n" +
1004    "       discard;\n" +
1005    "   }\n" +
1006    "   else\n" +
1007    "   {\n" +
1008    "     gl_FragColor = vec4(0.2, 0.2, 0.2, 1.0);\n" +
1009    "   }\n" +
1010    " }\n" +
1011    "}\n" +
1012    "\n" +
1013    "\n" +
1014    "",
1015    hints: ""
1016   },
1017   {
1018     name: "noise",
1019     hints: "",
1020     vertex: "\n" +
1021       "uniform mediump mat4 uModelView;\n" +
1022       "uniform mediump mat4 uProjection;\n" +
1023       "attribute mediump vec3 aPosition;\n" +
1024       "attribute mediump vec2 aTexCoord;\n" +
1025       "varying mediump vec2  vTexCoord;\n" +
1026       "uniform mediump vec3 uSize;    \n" +
1027       "\n" +
1028       "void main(void)\n" +
1029       "{\n" +
1030       "  mediump vec3 vertexPosition = aPosition * uSize;\n" +
1031       "\n" +
1032       "  gl_Position = uProjection * uModelView * vec4(vertexPosition, 1.0);\n" +
1033       "  vTexCoord = aTexCoord;\n" +
1034       "}\n" +
1035       "\n" +
1036       "",
1037     fragment:
1038     "\n" +
1039       "precision mediump float;\n" +
1040       "\n" +
1041       "uniform mediump vec4 uColor;\n" +
1042       "varying mediump vec2  vTexCoord;\n" +
1043       "\n" +
1044       "// noise\n" +
1045       "float noise(vec2 pos)\n" +
1046       "{\n" +
1047       " return fract( sin( dot(pos*0.001 ,vec2(24.12357, 36.789) ) ) * 12345.123);\n" +
1048       "}\n" +
1049       "\n" +
1050       "\n" +
1051       "// blur noise\n" +
1052       "float smooth_noise(vec2 pos)\n" +
1053       "{\n" +
1054       " return   ( noise(pos + vec2(1,1)) + noise(pos + vec2(1,1)) + noise(pos + vec2(1,1)) + noise(pos + vec2(1,1)) ) / 16.0\n" +
1055       "     + ( noise(pos + vec2(1,0)) + noise(pos + vec2(-1,0)) + noise(pos + vec2(0,1)) + noise(pos + vec2(0,-1)) ) / 8.0\n" +
1056       "       + noise(pos) / 4.0;\n" +
1057       "}\n" +
1058       "\n" +
1059       "\n" +
1060       "// linear interpolation\n" +
1061       "float interpolate_noise(vec2 pos)\n" +
1062       "{\n" +
1063       "float a, b, c, d;\n" +
1064       " \n" +
1065       " a = smooth_noise(floor(pos));\n" +
1066       " b = smooth_noise(vec2(floor(pos.x+1.0), floor(pos.y)));\n" +
1067       " c = smooth_noise(vec2(floor(pos.x), floor(pos.y+1.0)));\n" +
1068       " d = smooth_noise(vec2(floor(pos.x+1.0), floor(pos.y+1.0)));\n" +
1069       "\n" +
1070       " a = mix(a, b, fract(pos.x));\n" +
1071       " b = mix(c, d, fract(pos.x));\n" +
1072       " a = mix(a, b, fract(pos.y));\n" +
1073       " \n" +
1074       " return a;\n" +
1075       "}\n" +
1076       "\n" +
1077       "\n" +
1078       "float perlin_noise(vec2 pos)\n" +
1079       "{\n" +
1080       " float n;\n" +
1081       " \n" +
1082       " n = interpolate_noise(pos*0.0625)*0.5;\n" +
1083       " n += interpolate_noise(pos*0.125)*0.25;\n" +
1084       " n += interpolate_noise(pos*0.025)*0.225;\n" +
1085       " n += interpolate_noise(pos*0.05)*0.0625;\n" +
1086       " n += interpolate_noise(pos)*0.03125;\n" +
1087       " return n;\n" +
1088       "}\n" +
1089       "\n" +
1090       "\n" +
1091       "\n" +
1092       "void main()\n" +
1093       "{\n" +
1094       " vec2 pos = vTexCoord.xy;\n" +
1095       " float c, n;\n" +
1096       "\n" +
1097       "\n" +
1098       " n = perlin_noise(pos);\n" +
1099       "\n" +
1100       "\n" +
1101       " vec2 p = pos; // / iResolution.xy;\n" +
1102       "\n" +
1103       " if(p.y <  0.333) // last row\n" +
1104       "{\n" +
1105       "  \n" +
1106       "  if(p.x <  0.333)\n" +
1107       "    c = abs(cos(n*10.0));\n" +
1108       "  else if(p.x <  0.666)\n" +
1109       "    c = cos(pos.x*0.02 + n*10.0);//*0.5+0.5;\n" +
1110       "  else\n" +
1111       "  {\n" +
1112       "    pos *= 0.05;\n" +
1113       "    c = abs(sin(pos.x+n*5.0)*cos(pos.y+n*5.0));\n" +
1114       "  }\n" +
1115       " }\n" +
1116       " else if(p.y <  0.666) // middle row\n" +
1117       " {\n" +
1118       "   \n" +
1119       "   if(p.x <  0.333)\n" +
1120       "   {\n" +
1121       "     pos *= 0.05;\n" +
1122       "     pos += vec2(10.0, 10.0);\n" +
1123       "     c = sqrt(pos.x * pos.x + pos.y * pos.y);\n" +
1124       "    c = fract(c+n);\n" +
1125       " }\n" +
1126       " else if(p.x <  0.666)\n" +
1127       " {\n" +
1128       "  c = max(1.0 - mod(pos.x*0.5, 80.3+n*4.0)*0.5, 1.0 -  mod(pos.y*0.5, 80.3+n*4.0)*0.5);\n" +
1129       "  c = max(c, 0.5*max(1.0 - mod(pos.x*0.5+40.0, 80.3+n*4.0)*0.5, 1.0 -  mod(pos.y*0.5+40.0, 80.3+n*4.0)*0.5));\n" +
1130       " }\n" +
1131       " else\n" +
1132       "  c = abs(cos(pos.x*0.1 + n*20.0));// mod(pos.x*0.1, cos(pos.x));\n" +
1133       " }\n" +
1134       " else // first row\n" +
1135       " {\n" +
1136       "   if(p.x <  0.333)\n" +
1137       "     c = noise(pos);\n" +
1138       "   else if(p.x <  0.666)\n" +
1139       "     c = n;\n" +
1140       "   else\n" +
1141       "     c =max(fract(n*20.0), max(fract(n*5.0), fract(n*10.0)));\n" +
1142       " }\n" +
1143       "\n" +
1144       " gl_FragColor = vec4(c, c, c, 1.0);\n" +
1145       "}\n" +
1146       "\n" +
1147       ""
1148   }
1149 ];
1150
1151 //
1152 // Demo Javascript snippets
1153 //
1154 //
1155 var javascriptSources =
1156 [
1157   {
1158     name: "XX. Regression tests",
1159     source: "\n" +
1160       "clear();\n" +
1161       "var test = new Test();\n" +
1162       "test.regression(); // results in developer console (F12)\n" +
1163       "\n"
1164   },
1165   {
1166     name: "10. ImageView",
1167     source:"\n" +
1168       "var a = new dali.ImageView();\n" +
1169       "\n" +
1170       "var img = imageFromUiBuffer(\"field\");\n" +
1171       "\n" +
1172       "a.setImage(img);\n" +
1173       "\n" +
1174       "a.size = [100,100,1];\n" +
1175       "\n" +
1176       "dali.stage.add(a)\n" +
1177       ""
1178   },
1179   {
1180     name: "01. Colored Quad",
1181     source: "var halfQuadSize = 0.5;\n" +
1182       "\n" +
1183       "// using helper function to create property buffer\n" +
1184       "var verts = dali.createPropertyBuffer( {format: [ [\"aPosition\", dali.PropertyType.VECTOR3],\n" +
1185       "                                                [\"aCol\", dali.PropertyType.VECTOR4] ],\n" +
1186       "                                        data: { \"aPosition\": [ [-halfQuadSize, -halfQuadSize, 0.0],\n" +
1187       "                                                               [+halfQuadSize, -halfQuadSize, 0.0],\n" +
1188       "                                                               [-halfQuadSize, +halfQuadSize, 0.0],\n" +
1189       "                                                               [+halfQuadSize, +halfQuadSize, 0.0]\n" +
1190       "                                                               ],\n" +
1191       "                                           \"aCol\": [ [0, 0, 0, 1],\n" +
1192       "                                                       [1, 0, 1, 1],\n" +
1193       "                                                       [0, 1, 0, 1],\n" +
1194       "                                                       [1, 1, 1, 1]\n" +
1195       "                                                     ]\n" +
1196       "                                             }\n" +
1197       "                                      }\n" +
1198       "                                    );\n" +
1199       "\n" +
1200       "var indices = dali.createPropertyBuffer( { format: [ [\"indices\", dali.PropertyType.INTEGER]],\n" +
1201       "                                             data: { \"indices\": [0, 3, 1, 0, 2, 3] } } ) ;\n" +
1202       "\n" +
1203       "var geometry = new dali.Geometry();\n" +
1204       "\n" +
1205       "geometry.addVertexBuffer(verts);\n" +
1206       "geometry.setIndexBuffer(indices);\n" +
1207       "\n" +
1208       "var vertex = \"\" +\n" +
1209       "      \"attribute mediump vec3 aPosition;\" +\n" +
1210       "      \"attribute mediump vec4 aCol;\" +\n" +
1211       "      \"uniform mediump mat4 uMvpMatrix;\" +\n" +
1212       "      \"uniform mediump vec3 uSize;\" +\n" +
1213       "      \"uniform lowp vec4 uColor;\" +\n" +
1214       "      \"varying lowp vec4 vColor;\" +\n" +
1215       "      \"\" +\n" +
1216       "      \"void main()\" +\n" +
1217       "      \"{\" +\n" +
1218       "      \"  vColor = aCol * uColor;\" +\n" +
1219       "      \"  mediump vec4 vertexPosition = vec4(aPosition,1.0);\" +\n" +
1220       "      \"  vertexPosition.xyz *= uSize;\" +\n" +
1221       "      \"  gl_Position = uMvpMatrix * vertexPosition;\" +\n" +
1222       "      \"}\";\n" +
1223       "\n" +
1224       "var fragment = \"\" +\n" +
1225       "      \"varying lowp vec4 vColor;\" +\n" +
1226       "      \"uniform lowp vec4 uColor;\" +\n" +
1227       "      \"\" +\n" +
1228       "      \"void main()\" +\n" +
1229       "      \"{\" +\n" +
1230       "      \"  gl_FragColor = vColor * uColor;\" +\n" +
1231       "      \"}\";\n" +
1232       "\n" +
1233       "var shader = new dali.Shader(vertex, fragment, dali.ShaderHints.HINT_NONE);\n" +
1234       "\n" +
1235       "var material = new dali.Material(shader);\n" +
1236       "\n" +
1237       "var renderer = new dali.Renderer(geometry, material);\n" +
1238       "\n" +
1239       "var actor = new dali.Actor();\n" +
1240       "\n" +
1241       "actor.addRenderer(renderer);\n" +
1242       "\n" +
1243       "dali.stage.add(actor);\n" +
1244       "\n" +
1245       "actor.parentOrigin = [0.5, 0.5, 0.0];\n" +
1246       "actor.size = [100,100,1];\n" +
1247       "\n" +
1248       ""
1249   },
1250   {
1251     name: "02. Textured Quad",
1252     source: "var halfQuadSize = 0.5;\n" +
1253       "\n" +
1254       "// using helper function to create property buffer\n" +
1255       "var verts = dali.createPropertyBuffer( {format: [ [\"aPosition\", dali.PropertyType.VECTOR3],\n" +
1256       "                                                  [\"aTexCoord\", dali.PropertyType.VECTOR2] ],\n" +
1257       "                                          data: { \"aPosition\": [ [-halfQuadSize, -halfQuadSize, 0.0],\n" +
1258       "                                                                 [+halfQuadSize, -halfQuadSize, 0.0],\n" +
1259       "                                                                 [-halfQuadSize, +halfQuadSize, 0.0],\n" +
1260       "                                                                 [+halfQuadSize, +halfQuadSize, 0.0]\n" +
1261       "                                                               ],\n" +
1262       "                                                  \"aTexCoord\": [ [0, 0],\n" +
1263       "                                                                 [1, 0],\n" +
1264       "                                                                 [0, 1],\n" +
1265       "                                                                 [1, 1]\n" +
1266       "                                                               ]\n" +
1267       "                                                }\n" +
1268       "                                     });\n" +
1269       "\n" +
1270       "var indices = dali.createPropertyBuffer( { format: [ [\"indices\", dali.PropertyType.INTEGER]],\n" +
1271       "                                           data: { \"indices\": [0, 3, 1, 0, 2, 3] } } ) ;\n" +
1272       "\n" +
1273       "var geometry = new dali.Geometry();\n" +
1274       "\n" +
1275       "geometry.addVertexBuffer(verts);\n" +
1276       "geometry.setIndexBuffer(indices);\n" +
1277       "\n" +
1278       "var shader = shaderFromUiBuffer(\"pass through texture\");\n" +
1279       "\n" +
1280       "var material = new dali.Material(shader);\n" +
1281       "\n" +
1282       "var image = imageFromUiBuffer(\"ducks\");\n" +
1283       "var sampler = new dali.Sampler();\n" +
1284       "material.addTexture(image, \"sTexture\", sampler);\n" +
1285       "\n" +
1286       "var renderer = new dali.Renderer(geometry, material);\n" +
1287       "\n" +
1288       "var actor = new dali.Actor();\n" +
1289       "\n" +
1290       "actor.addRenderer(renderer);\n" +
1291       "\n" +
1292       "dali.stage.add(actor);\n" +
1293       "\n" +
1294       "actor.parentOrigin = [0.5, 0.5, 0.0];\n" +
1295       "actor.size = [100,100,1];\n" +
1296       "\n" +
1297       "\n" +
1298       ""
1299   },
1300   {
1301     name: "03. Shaded Quads",
1302     source: "var halfQuadSize = 0.5;\n" +
1303       "\n" +
1304       "// using helper function to create property buffer\n" +
1305       "var verts = dali.createPropertyBuffer( {format: [ [\"aPosition\", dali.PropertyType.VECTOR3],\n" +
1306       "                                                  [\"aTexCoord\", dali.PropertyType.VECTOR2] ],\n" +
1307       "                                          data: { \"aPosition\": [ [-halfQuadSize, -halfQuadSize, 0.0],\n" +
1308       "                                                                 [+halfQuadSize, -halfQuadSize, 0.0],\n" +
1309       "                                                                 [-halfQuadSize, +halfQuadSize, 0.0],\n" +
1310       "                                                                 [+halfQuadSize, +halfQuadSize, 0.0]\n" +
1311       "                                                               ],\n" +
1312       "                                                  \"aTexCoord\": [ [0, 0],\n" +
1313       "                                                                 [1, 0],\n" +
1314       "                                                                 [0, 1],\n" +
1315       "                                                                 [1, 1]\n" +
1316       "                                                               ]\n" +
1317       "                                                }\n" +
1318       "                                     });\n" +
1319       "\n" +
1320       "\n" +
1321       "var indices = dali.createPropertyBuffer( { format: [ [\"indices\", dali.PropertyType.INTEGER]],\n" +
1322       "                                      data: { \"indices\": [0, 3, 1, 0, 2, 3] } } ) ;\n" +
1323       "\n" +
1324       "var geometry = new dali.Geometry();\n" +
1325       "\n" +
1326       "geometry.addVertexBuffer(verts);\n" +
1327       "geometry.setIndexBuffer(indices);\n" +
1328       "\n" +
1329       "\n" +
1330       "// some shader buffers for textured quad\n" +
1331       "var names = [\"adjust brightness\", \"blur\", \"burn\", \"drop shadow\", \"emboss combine\",\n" +
1332       "             \"image-click\", \"melt\", \"ripple 2D\", \"mirror effect\", \"iris effect\",\n" +
1333       "             \"mosaic\", \"round window\", \"swirl\", \"noise\"];\n" +
1334       "\n" +
1335       "var n = Math.floor(Math.sqrt(names.length));\n" +
1336       "var c = 0;\n" +
1337       "var x = -(0.5*n*100);\n" +
1338       "var y = -(0.5*n*100);\n" +
1339       "\n" +
1340       "for(var i = 0; i < names.length; i++) {\n" +
1341       "  var shader = shaderFromUiBuffer(names[i]);\n" +
1342       "\n" +
1343       "  var material = new dali.Material(shader);\n" +
1344       "\n" +
1345       "  var image = imageFromUiBuffer(\"ducks\");\n" +
1346       "  var sampler = new dali.Sampler();\n" +
1347       "  material.addTexture(image, \"sTexture\", sampler);\n" +
1348       "\n" +
1349       "  var renderer = new dali.Renderer(geometry, material);\n" +
1350       "\n" +
1351       "  var actor = new dali.Actor();\n" +
1352       "\n" +
1353       "  actor.name =  \"actor for shader:\" + names[i];\n" +
1354       "\n" +
1355       "  actor.addRenderer(renderer);\n" +
1356       "\n" +
1357       "  dali.stage.add(actor);\n" +
1358       "\n" +
1359       "  actor.parentOrigin = [0.5, 0.5, 0.0];\n" +
1360       "  actor.size = [100,100,1];\n" +
1361       "\n" +
1362       "  actor.position = [x,\n" +
1363       "                    y + (c*110), \n" +
1364       "                    0];\n" +
1365       "\n" +
1366       "  if(c>n) {\n" +
1367       "     c = 0;\n" +
1368       "     x += 110;\n" +
1369       "  } else {\n" +
1370       "      c += 1;\n" +
1371       "  }\n" +
1372       "\n" +
1373       "}\n" +
1374       "\n" +
1375       ""
1376   },
1377   {
1378     name: "04. Animation",
1379     source: "var halfQuadSize = 0.5;\n" +
1380       "\n" +
1381       "// use helper function to create property buffer\n" +
1382       "var verts = dali.createPropertyBuffer( {format: [ [\"aPosition\", dali.PropertyType.VECTOR3],\n" +
1383       "                                                  [\"aTexCoord\", dali.PropertyType.VECTOR2] ],\n" +
1384       "                                          data: { \"aPosition\": [ [-halfQuadSize, -halfQuadSize, 0.0],\n" +
1385       "                                                                 [+halfQuadSize, -halfQuadSize, 0.0],\n" +
1386       "                                                                 [-halfQuadSize, +halfQuadSize, 0.0],\n" +
1387       "                                                                 [+halfQuadSize, +halfQuadSize, 0.0]\n" +
1388       "                                                               ],\n" +
1389       "                                                  \"aTexCoord\": [ [0, 0],\n" +
1390       "                                                                 [1, 0],\n" +
1391       "                                                                 [0, 1],\n" +
1392       "                                                                 [1, 1]\n" +
1393       "                                                               ]\n" +
1394       "                                                }\n" +
1395       "                                     });\n" +
1396       "\n" +
1397       "var indices = dali.createPropertyBuffer( { format: [ [\"indices\", dali.PropertyType.INTEGER]],\n" +
1398       "                                           data: { \"indices\": [0, 3, 1, 0, 2, 3] } } ) ;\n" +
1399       "\n" +
1400       "var geometry = new dali.Geometry();\n" +
1401       "\n" +
1402       "geometry.addVertexBuffer(verts);\n" +
1403       "geometry.setIndexBuffer(indices);\n" +
1404       "\n" +
1405       "var vertex = \"\" + \n" +
1406       "      \"// atributes\\n\" + \n" +
1407       "      \"attribute mediump vec3 aPosition;\\n\" + \n" +
1408       "      \"attribute mediump vec2 aTexCoord;\\n\" + \n" +
1409       "      \"// inbuilt\\n\" + \n" +
1410       "      \"uniform mediump mat4 uMvpMatrix;\\n\" + \n" +
1411       "      \"uniform mediump vec3 uSize;\\n\" + \n" +
1412       "      \"uniform lowp vec4 uColor;\\n\" + \n" +
1413       "      \"// varying\\n\" + \n" +
1414       "      \"varying mediump vec2 vTexCoord;\\n\" + \n" +
1415       "      \"\\n\" + \n" +
1416       "      \"void main()\\n\" + \n" +
1417       "      \"{\\n\" + \n" +
1418       "      \"  mediump vec4 vertexPosition = vec4(aPosition, 1.0);\\n\" + \n" +
1419       "      \"  vertexPosition.xyz *= uSize;\\n\" + \n" +
1420       "      \"  gl_Position = uMvpMatrix * vertexPosition;\\n\" + \n" +
1421       "      \"  vTexCoord = aTexCoord;\\n\" + \n" +
1422       "      \"}\";\n" +
1423       "\n" +
1424       "var fragment = \"\" + \n" +
1425       "      \"uniform lowp vec4 uColor;\\n\" + \n" +
1426       "      \"uniform sampler2D sTexture;\\n\" + \n" +
1427       "      \"varying mediump vec2 vTexCoord;\\n\" + \n" +
1428       "      \"\\n\" + \n" +
1429       "      \"void main()\\n\" + \n" +
1430       "      \"{\\n\" + \n" +
1431       "      \"  gl_FragColor = texture2D(sTexture, vTexCoord) * uColor;\\n\" + \n" +
1432       "      \"}\";\n" +
1433       "\n" +
1434       "var shader = new dali.Shader(vertex, fragment, dali.ShaderHints.HINT_NONE);\n" +
1435       "\n" +
1436       "var material = new dali.Material(shader);\n" +
1437       "\n" +
1438       "var image = imageFromUiBuffer(\"ducks\");\n" +
1439       "var sampler = new dali.Sampler();\n" +
1440       "material.addTexture(image, \"sTexture\",sampler);\n" +
1441       "\n" +
1442       "var renderer = new dali.Renderer(geometry, material);\n" +
1443       "\n" +
1444       "var actor = new dali.Actor();\n" +
1445       "\n" +
1446       "actor.addRenderer(renderer);\n" +
1447       "\n" +
1448       "dali.stage.add(actor);\n" +
1449       "\n" +
1450       "actor.parentOrigin = [0.5, 0.5, 0.0];\n" +
1451       "actor.size = [100,100,1];\n" +
1452       "\n" +
1453       "\n" +
1454       "var animation = new dali.Animation(9);\n" +
1455       "\n" +
1456       "animation.animateTo(actor, \"orientation\", [0,90,0], \"linear\", 0, 3);\n" +
1457       "animation.animateTo(actor, \"orientation\", [0,0,0], \"linear\", 6, 3);\n" +
1458       "\n" +
1459       "var p = new dali.Path();\n" +
1460       "\n" +
1461       "p.addPoint( [0,0,0] );\n" +
1462       "p.addPoint( [200,200,200] );\n" +
1463       "p.addPoint( [0,0,-200] );\n" +
1464       "p.addPoint( [0,-200,-900] );\n" +
1465       "p.addPoint( [0,0,0] );\n" +
1466       "\n" +
1467       "p.generateControlPoints(0.43);\n" +
1468       "\n" +
1469       "animation.animatePath( actor, p, [1,0,0], \"linear\", 0, 6);\n" +
1470       "\n" +
1471       "//animation.setEndAction(dali.EndAction.Discard);\n" +
1472       "\n" +
1473       "animation.play();\n" +
1474       "\n" +
1475       "\n" +
1476       ""
1477   },
1478   {
1479     name: "05. Event driven Animation",
1480     source: "var halfQuadSize = 0.5;\n" +
1481       "\n" +
1482       "// use helper function to create property buffer\n" +
1483       "var verts = dali.createPropertyBuffer( {format: [ [\"aPosition\", dali.PropertyType.VECTOR3],\n" +
1484       "                                                  [\"aTexCoord\", dali.PropertyType.VECTOR2] ],\n" +
1485       "                                          data: { \"aPosition\": [ [-halfQuadSize, -halfQuadSize, 0.0],\n" +
1486       "                                                                 [+halfQuadSize, -halfQuadSize, 0.0],\n" +
1487       "                                                                 [-halfQuadSize, +halfQuadSize, 0.0],\n" +
1488       "                                                                 [+halfQuadSize, +halfQuadSize, 0.0]\n" +
1489       "                                                               ],\n" +
1490       "                                                  \"aTexCoord\": [ [0, 0],\n" +
1491       "                                                                 [1, 0],\n" +
1492       "                                                                 [0, 1],\n" +
1493       "                                                                 [1, 1]\n" +
1494       "                                                               ]\n" +
1495       "                                                }\n" +
1496       "                                     });\n" +
1497       "\n" +
1498       "var indices = dali.createPropertyBuffer( { format: [ [\"indices\", dali.PropertyType.INTEGER]],\n" +
1499       "                                           data: { \"indices\": [0, 3, 1, 0, 2, 3] } } ) ;\n" +
1500       "\n" +
1501       "var geometry = new dali.Geometry();\n" +
1502       "\n" +
1503       "geometry.addVertexBuffer(verts);\n" +
1504       "geometry.setIndexBuffer(indices);\n" +
1505       "\n" +
1506       "var vertex = \"\" +\n" +
1507       "      \"// atributes\\n\" + \n" +
1508       "      \"attribute mediump vec3 aPosition;\\n\" + \n" +
1509       "      \"attribute mediump vec2 aTexCoord;\\n\" + \n" +
1510       "      \"// inbuilt\\n\" + \n" +
1511       "      \"uniform mediump mat4 uMvpMatrix;\\n\" + \n" +
1512       "      \"uniform mediump vec3 uSize;\\n\" + \n" +
1513       "      \"uniform lowp vec4 uColor;\\n\" + \n" +
1514       "      \"// varying\\n\" + \n" +
1515       "      \"varying mediump vec2 vTexCoord;\\n\" + \n" +
1516       "      \"\\n\" + \n" +
1517       "      \"void main()\\n\" + \n" +
1518       "      \"{\\n\" + \n" +
1519       "      \"  mediump vec4 vertexPosition = vec4(aPosition, 1.0);\\n\" + \n" +
1520       "      \"  vertexPosition.xyz *= uSize;\\n\" + \n" +
1521       "      \"  gl_Position = uMvpMatrix * vertexPosition;\\n\" + \n" +
1522       "      \"  vTexCoord = aTexCoord;\\n\" + \n" +
1523       "      \"}\";\n" +
1524       "\n" +
1525       "var fragment = \"\" +\n" +
1526       "      \"uniform lowp vec4 uColor;\\n\" + \n" +
1527       "      \"uniform sampler2D sTexture;\\n\" + \n" +
1528       "      \"varying mediump vec2 vTexCoord;\\n\" + \n" +
1529       "      \"\\n\" + \n" +
1530       "      \"void main()\\n\" + \n" +
1531       "      \"{\\n\" + \n" +
1532       "      \"  gl_FragColor = texture2D(sTexture, vTexCoord) * uColor;\\n\" + \n" +
1533       "      \"}\";\n" +
1534       "\n" +
1535       "var shader = new dali.Shader(vertex, fragment, dali.ShaderHints.HINT_NONE);\n" +
1536       "\n" +
1537       "var material = new dali.Material(shader);\n" +
1538       "\n" +
1539       "var image = imageFromUiBuffer(\"ducks\");\n" +
1540       "var sampler = new dali.Sampler();\n" +
1541       "material.addTexture(image, \"sTexture\", sampler);\n" +
1542       "\n" +
1543       "var renderer = new dali.Renderer(geometry, material);\n" +
1544       "\n" +
1545       "var actor = new dali.Actor();\n" +
1546       "\n" +
1547       "actor.addRenderer(renderer);\n" +
1548       "\n" +
1549       "dali.stage.add(actor);\n" +
1550       "\n" +
1551       "actor.parentOrigin = [0.5, 0.5, 0.0];\n" +
1552       "actor.size = [100,100,1];\n" +
1553       "\n" +
1554       "var actor2 = new dali.Actor();\n" +
1555       "\n" +
1556       "// @todo?? why can I no reuse the same renderer?\n" +
1557       "//actor2.addRenderer(renderer);\n" +
1558       "var renderer2 = new dali.Renderer(geometry, material);\n" +
1559       "actor2.addRenderer(renderer2);\n" +
1560       "\n" +
1561       "dali.stage.add(actor2);\n" +
1562       "\n" +
1563       "actor2.position = [-200,0,0];\n" +
1564       "actor2.parentOrigin = [0.5, 0.5, 0.0];\n" +
1565       "actor2.size = [100,100,1];\n" +
1566       "\n" +
1567       "var animation = new dali.Animation(9);\n" +
1568       "\n" +
1569       "animation.animateTo(actor, \"orientation\", [0,90,0], \"linear\", 0, 3);\n" +
1570       "animation.animateTo(actor, \"orientation\", [0,0,0], \"linear\", 6, 3);\n" +
1571       "\n" +
1572       "var p = new dali.Path();\n" +
1573       "\n" +
1574       "p.addPoint( [0,0,0] );\n" +
1575       "p.addPoint( [200,200,200] );\n" +
1576       "p.addPoint( [0,0,-200] );\n" +
1577       "p.addPoint( [0,-200,-900] );\n" +
1578       "p.addPoint( [0,0,0] );\n" +
1579       "\n" +
1580       "p.generateControlPoints(0.43);\n" +
1581       "\n" +
1582       "animation.animatePath( actor, p, [1,0,0], \"linear\", 0, 6);\n" +
1583       "\n" +
1584       "function onTouched(actor, e) {\n" +
1585       "  for(var i = 0; i < e.points.length; i++) {\n" +
1586       "      if(e.points[i].state === \"DOWN\") {\n" +
1587       "        console.log(e);\n" +
1588       "        animation.play();\n" +
1589       "        return;\n" +
1590       "      }\n" +
1591       "  }\n" +
1592       "}\n" +
1593       "\n" +
1594       "actor2.connect(\"touch\", onTouched);\n" +
1595       "\n" +
1596       "\n" +
1597       ""
1598   },
1599   {
1600     name: "06. Offscreen",
1601     source: "\n" +
1602       "// todo"
1603   },
1604   {
1605     name: "07. DALi toy pseudo dsl",
1606     source: "\n" +
1607       "//\n" +
1608       "// @todo\n" +
1609       "//\n" +
1610       "addTo(\"stage\",\n" +
1611       "      image({\n" +
1612       "        name:\"img\",\n" +
1613       "        image:\"ducks\",\n" +
1614       "        size:[100,100,1]\n" +
1615       "      }),\n" +
1616       "      image({\n" +
1617       "        name:\"img2\",\n" +
1618       "        tag:\"listitem\",\n" +
1619       "        image:\"field\",\n" +
1620       "        position:[100,0,0],\n" +
1621       "        size:[100,100,1]\n" +
1622       "      }),\n" +
1623       "      image({\n" +
1624       "        name:\"img3\",\n" +
1625       "        tag:\"listitem\",\n" +
1626       "        image:\"funnyface\",\n" +
1627       "        position:[100,0,0],\n" +
1628       "        size:[100,100,1]\n" +
1629       "      }),\n" +
1630       "      image({\n" +
1631       "        name:\"img4\",\n" +
1632       "        tag:\"listitem\",\n" +
1633       "        image:\"girl1\",\n" +
1634       "        position:[100,0,0],\n" +
1635       "        size:[100,100,1]\n" +
1636       "      })\n" +
1637       ");\n" +
1638       "\n" +
1639       "\n" +
1640       "when(\"img\", \"touchedDown\",\n" +
1641       "    set(\"sensitive\", true),\n" +
1642       "    set(\"size\", to([200,200,200])),\n" +
1643       "    set(\"img2\", \"size\", to([200,200,200], 0,3, \"ease_in\")),\n" +
1644       "    set(excludeFrom(tagged(\"scrollitem\"), \"myimage\"), path(0,3, \"ease_in\", \"path0\")),\n" +
1645       "    endAction(\"Discard\")\n" +
1646       "    then(set(\"img4\", \"hide\"),\n" +
1647       "         play(\"anAnim\"))    );\n" +
1648       "    \n" +
1649       "\n" +
1650       "\n"
1651   }
1652 ];
1653
1654 function log(errorLog) {
1655   console.log(errorLog);
1656 }
1657
1658 function consoleAssert( test, message )
1659 {
1660   // using this rather than inbuild assert
1661   // it lets dali carry on for some reason
1662   if(!test)
1663   {
1664     throw message;
1665   }
1666 }
1667
1668 function consoleLogErrorEvent(event) {
1669   "use strict";
1670   console.log("Error");
1671   console.dir(event);
1672   if(event.target) {
1673     if(event.target.result) {
1674       event.target.result.close();
1675     }
1676   }
1677 }
1678
1679 function consoleLogSuccess(message) {
1680   "use strict";
1681   return function() {
1682     console.log("Success:" + message);
1683   };
1684 }
1685
1686
1687 /**
1688  * Gets embedded base64 images embedded in the HTML file
1689  */
1690 function getStockImageData(index) {
1691   "use strict";
1692   var name = "testImage" + index;
1693   // need to draw it off screen first? @todo
1694   var c = document.createElement("canvas");
1695   var img = document.getElementById(name);
1696   c.width = img.naturalWidth;
1697   c.height = img.naturalHeight;
1698   var context = c.getContext("2d");
1699   context.drawImage(img, 0, 0 );
1700   var imageData = context.getImageData(0, 0, img.naturalWidth, img.naturalHeight); // <-ImageData
1701   return imageData;
1702 }
1703
1704 function formatValue(value)
1705 {
1706   if(typeof(value) === "number") {
1707     if(value === 3.4028234663852886e+38)
1708     {
1709       return "MAX_FLOAT";
1710     } else if(value === Number.MAX_VALUE) {
1711       return "MAX_DBL";
1712     } else if(value === 2147483647) {
1713       return "MAX_INT";
1714     } else if(value === 9223372036854775807) {
1715       return "MAX_INT64";
1716     } else {
1717       return value.toFixed(3);
1718     }
1719   } else {
1720     return value;
1721   }
1722 }
1723
1724 /**
1725  * Add bootstrap column for single value (not array)
1726  */
1727 function add1ColElement(elem, value)
1728 {
1729   var e = document.createElement("div");
1730   e.className = "col-md-3";
1731   e.innerHTML = formatValue(value);
1732   elem.appendChild(e);
1733
1734   e = document.createElement("div");
1735   e.className = "col-md-3";
1736   e.innerHTML = "";
1737   elem.appendChild(e);
1738
1739   e = document.createElement("div");
1740   e.className = "col-md-3";
1741   e.innerHTML = "";
1742   elem.appendChild(e);
1743
1744   e = document.createElement("div");
1745   e.className = "col-md-3";
1746   e.innerHTML = "";
1747   elem.appendChild(e);
1748
1749   return e;
1750 }
1751
1752 /*
1753  * Add bootstrap column for array of 2 value
1754  */
1755 function add2ColElement(elem, value)
1756 {
1757   var e = document.createElement("div");
1758   e.className = "col-md-3";
1759   e.innerHTML = formatValue(value[0]);
1760   elem.appendChild(e);
1761
1762   e = document.createElement("div");
1763   e.className = "col-md-3";
1764   e.innerHTML = formatValue(value[1]);
1765   elem.appendChild(e);
1766
1767   e = document.createElement("div");
1768   e.className = "col-md-3";
1769   e.innerHTML = "";
1770   elem.appendChild(e);
1771
1772   e = document.createElement("div");
1773   e.className = "col-md-3";
1774   e.innerHTML = "";
1775   elem.appendChild(e);
1776
1777   return e;
1778 }
1779
1780 /*
1781  * Add bootstrap table cell for array of 3 value
1782  */
1783 function add3ColElement(elem, value)
1784 {
1785   var e = document.createElement("div");
1786   e.className = "col-md-3";
1787   e.innerHTML = formatValue(value[0]);
1788   elem.appendChild(e);
1789
1790   e = document.createElement("div");
1791   e.className = "col-md-3";
1792   e.innerHTML = formatValue(value[1]);
1793   elem.appendChild(e);
1794
1795   e = document.createElement("div");
1796   e.className = "col-md-3";
1797   e.innerHTML = formatValue(value[2]);
1798   elem.appendChild(e);
1799
1800   e = document.createElement("div");
1801   e.className = "col-md-3";
1802   e.innerHTML = "";
1803   elem.appendChild(e);
1804   return e;
1805 }
1806
1807 /*
1808  * Add bootstrap table cell for array of 4 value
1809  */
1810 function add4ColElement(elem, value)
1811 {
1812   var e = document.createElement("div");
1813   e.className = "col-md-3";
1814   e.innerHTML = formatValue(value[0]);
1815   elem.appendChild(e);
1816
1817   e = document.createElement("div");
1818   e.className = "col-md-3";
1819   e.innerHTML = formatValue(value[1]);
1820   elem.appendChild(e);
1821
1822   e = document.createElement("div");
1823   e.className = "col-md-3";
1824   e.innerHTML = formatValue(value[2]);
1825   elem.appendChild(e);
1826
1827   e = document.createElement("div");
1828   e.className = "col-md-3";
1829   e.innerHTML = formatValue(value[3]);
1830   elem.appendChild(e);
1831   return e;
1832 }
1833
1834 /*
1835  * Add a bootstrap table cell for property 'name' for an actor
1836  */
1837 function createElementForActorProperty(actor, name) {
1838   "use strict";
1839   var elem = document.createElement("div");
1840
1841   var value = actor[name];
1842   var type = typeof value;
1843
1844   if(name === "maximumSize") {
1845     value = value;
1846   }
1847
1848   if(type === "string" || type === "number" || type === "boolean") {
1849     elem.className = "row";
1850     add1ColElement(elem, value);
1851   } else if(value === undefined) {
1852     elem.className = "row";
1853     add1ColElement(elem, "???undefined???");
1854   } else {
1855     var r;
1856     var length = value.length;
1857     if(length === 2) {
1858       elem.className = "row";
1859       add2ColElement(elem, value);
1860     } else if(length === 3) {
1861       elem.className = "row";
1862       add3ColElement(elem, value);
1863     } else if(length === 4) {
1864       elem.className = "row";
1865       add4ColElement(elem, value);
1866     } else if(length === 9) {
1867       r = document.createElement("div");
1868       r.className = "row";
1869       add3ColElement(r, value.slice(0, 3));
1870       elem.appendChild(r);
1871
1872       r = document.createElement("div");
1873       r.className = "row";
1874       add3ColElement(r, value.slice(3, 6));
1875       elem.appendChild(r);
1876
1877       r = document.createElement("div");
1878       r.className = "row";
1879       add3ColElement(r, value.slice(6, 9));
1880       elem.appendChild(r);
1881     } else if(length === 16) {
1882       r = document.createElement("div");
1883       r.className = "row";
1884       add4ColElement(r, value.slice(0, 4));
1885       elem.appendChild(r);
1886
1887       r = document.createElement("div");
1888       r.className = "row";
1889       add4ColElement(r, value.slice(4, 8));
1890       elem.appendChild(r);
1891
1892       r = document.createElement("div");
1893       r.className = "row";
1894       add4ColElement(r, value.slice(8, 12));
1895       elem.appendChild(r);
1896
1897       r = document.createElement("div");
1898       r.className = "row";
1899       add4ColElement(r, value.slice(12, 16));
1900       elem.appendChild(r);
1901     }
1902   }
1903
1904   return elem;
1905 }
1906
1907 /**
1908  * Adds a bootstrap table to show the actor properties
1909  */
1910 function onActorSelected(actor) {
1911   "use strict";
1912   var i;
1913   var name;
1914   var gridBlock;
1915   var nameBlock;
1916   var valueBlock;
1917   var actorId;
1918
1919   //
1920   // recreate property tab
1921   //
1922   var elem = document.getElementById("selected");
1923
1924   removeAllChildren(elem);
1925
1926   //
1927   // setup property view
1928   //
1929   if (actor) {
1930     actorId = actor.getId();
1931
1932     var p = document.createElement("div");
1933     p.innerHTML = "<h3><b>" + actor.name + "</b> [<b>" + actorId + "</b>] (<b>" + actor.position + "</b>)</h3>";
1934     elem.appendChild(p);
1935
1936     var parent = actor.getParent();
1937     if(parent) {
1938       p = document.createElement("div");
1939       p.innerHTML =
1940         "<p>" +
1941         "(Parent: <b>" + parent.name + "</b> [<b>" + parent.getId() + "</b>] (<b>" + parent.position + "</b>)" +
1942         " Anchored: <b>" + actor.anchorPoint + "</b>" +
1943         " ParentOrigin: <b>" + actor.parentOrigin + "</b> )" +
1944         "</p>";
1945       elem.appendChild(p);
1946     }
1947
1948     if( actorId in actorIdToShaderSet &&
1949         "shaderEffect" in actorIdToShaderSet[actorId]) { // if has compiled
1950       var shaderOptions = actorIdToShaderSet[actorId];
1951       var uniforms = dali.sourceUniformMetaData(shaderOptions.vertex);
1952       uniforms = uniforms.concat(dali.sourceUniformMetaData(shaderOptions.fragment));
1953
1954       var shader = getShader(actor);
1955
1956       if(uniforms.length) {
1957         gridBlock = document.createElement("div");
1958         gridBlock.className = "row";
1959
1960         nameBlock = document.createElement("div");
1961         nameBlock.className = "col-md-5";
1962         nameBlock.innerHTML = "<u>Shader Uniforms:</u>";
1963         gridBlock.appendChild(nameBlock);
1964
1965         valueBlock = document.createElement("div");
1966         valueBlock.className = "col-md-7";
1967         valueBlock.innerHTML = "";
1968         gridBlock.appendChild(valueBlock);
1969
1970         elem.appendChild(gridBlock);
1971
1972         for(i = 0; i < uniforms.length; i++) {
1973           var type = uniforms[i].type;
1974           name = uniforms[i].name;
1975           gridBlock = document.createElement("div");
1976           gridBlock.className = "row";
1977
1978           nameBlock = document.createElement("div");
1979           nameBlock.className = "col-md-5";
1980           nameBlock.innerHTML = type + " " + name + "<i> (Animatable) </i>";
1981
1982           gridBlock.appendChild(nameBlock);
1983
1984           valueBlock = document.createElement("div");
1985           valueBlock.className = "col-md-7";
1986           valueBlock.innerHTML = shader[ name ];
1987           gridBlock.appendChild(valueBlock);
1988
1989           elem.appendChild(gridBlock);
1990
1991         }
1992       }
1993
1994     }
1995
1996     // getproperties returns std::vector<string>
1997     var props = actor.getProperties();
1998
1999     gridBlock = document.createElement("div");
2000     gridBlock.className = "row";
2001
2002     nameBlock = document.createElement("div");
2003     nameBlock.className = "col-md-5";
2004     nameBlock.innerHTML = "<u>Properties:</ul>";
2005     gridBlock.appendChild(nameBlock);
2006
2007     valueBlock = document.createElement("div");
2008     valueBlock.className = "col-md-7";
2009     valueBlock.innerHTML = "";
2010     gridBlock.appendChild(valueBlock);
2011
2012     elem.appendChild(gridBlock);
2013
2014
2015     for (i = 0; i < props.size(); i++) {
2016       name = props.get(i);
2017
2018       gridBlock = document.createElement("div");
2019       gridBlock.className = "row";
2020
2021       var animatable = actor.isPropertyAnimatable(actor.getPropertyIndex(name));
2022
2023       nameBlock = document.createElement("div");
2024       nameBlock.className = "col-md-5";
2025       if(animatable) {
2026         nameBlock.innerHTML = "'" + name + "'" + "<i> (animatable)</i>";
2027       } else {
2028         nameBlock.innerHTML = "'" + name + "'";
2029       }
2030       gridBlock.appendChild(nameBlock);
2031
2032       valueBlock = document.createElement("div");
2033       valueBlock.className = "col-md-7";
2034
2035       valueBlock.appendChild( createElementForActorProperty(actor, name) );
2036
2037       gridBlock.appendChild(valueBlock);
2038
2039       elem.appendChild(gridBlock);
2040     }
2041
2042     props.delete();
2043
2044   }
2045
2046 }
2047
2048 /**
2049  * creates page element and set namesValues array
2050  */
2051 function createElement(elementName, namesValues) {
2052   "use strict";
2053   var e = document.createElement(elementName);
2054   for(var name in namesValues) {
2055     e[name] = namesValues[name];
2056   }
2057   return e;
2058 }
2059
2060 /**
2061  * create element with innerHTML
2062  */
2063 function createElementInnerHTML(elementName, innerHTML) {
2064   "use strict";
2065   return createElement(elementName, {"innerHTML": innerHTML});
2066 }
2067
2068 /**
2069  * remove all the children from the element
2070  */
2071 function removeAllChildren(elem) {
2072   "use strict";
2073   var count = elem.children.length;
2074   for (var i = 0; i < count; i++) {
2075     elem.removeChild(elem.children[0]);
2076   }
2077 }
2078
2079 /**
2080  *
2081  */
2082 function onChangeSetDataChanged(e) {
2083   e.currentTarget["data-changed"] = true;
2084 }
2085
2086 /**
2087  * creates a document input element [ ]
2088  */
2089 function inputElem(type, propObject, property, val, arrayIndex) {
2090   "use strict";
2091   var e = document.createElement("input");
2092   e.type = type;
2093   // for number then step of any means it can be a real number not just integer
2094   e.step = "any";
2095   e.value = val;
2096   e.className = "form-control";
2097   e["data-value"] = val;
2098   e["data-arrayIndex"] = arrayIndex;
2099   e["data-changed"] = false;
2100   e.addEventListener("changed", onChangeSetDataChanged);
2101   return e;
2102 }
2103
2104 /**
2105  * creates an input 2 element [ , ]
2106  */
2107 function inputElem2(type, propObject, property, val, startIndex) {
2108   "use strict";
2109   var d = document.createElement("div");
2110   var a = inputElem("number", propObject, property, val[startIndex], startIndex);
2111   a.className = "col-md-3";
2112   d.appendChild(a);
2113   a = inputElem("number", propObject, property, val[startIndex + 1], startIndex + 1);
2114   a.className = "col-md-3";
2115   d.appendChild(a);
2116   a.className = "col-md-3";
2117   d.appendChild(a);
2118   a = createElement("div");
2119   a.className = "col-md-3";
2120   d.appendChild(a);
2121   return d;
2122 }
2123
2124 /**
2125  * creates an input 3 element [ , , ]
2126  */
2127 function inputElem3(type, propObject, property, val, startIndex) {
2128   "use strict";
2129   var d = document.createElement("div");
2130   var a = inputElem("number", propObject, property, val[startIndex], startIndex);
2131   a.className = "col-md-3";
2132   d.appendChild(a);
2133   a = inputElem("number", propObject, property, val[startIndex + 1], startIndex + 1);
2134   a.className = "col-md-3";
2135   d.appendChild(a);
2136   a = inputElem("number", propObject, property, val[startIndex + 2], startIndex + 2);
2137   a.className = "col-md-3";
2138   d.appendChild(a);
2139   a = createElement("div");
2140   a.className = "col-md-3";
2141   d.appendChild(a);
2142   return d;
2143 }
2144
2145 /**
2146  * creates an input 4 element [ , , , ]
2147  */
2148 function inputElem4(type, propObject, property, val, startIndex) {
2149   "use strict";
2150   var d = document.createElement("div");
2151   var a = inputElem("number", propObject, property, val[startIndex], startIndex);
2152   a.className = "col-md-3";
2153   d.appendChild(a);
2154   a = inputElem("number", propObject, property, val[startIndex + 1], startIndex + 1);
2155   a.className = "col-md-3";
2156   d.appendChild(a);
2157   a = inputElem("number", propObject, property, val[startIndex + 2], startIndex + 2);
2158   a.className = "col-md-3";
2159   d.appendChild(a);
2160   a = inputElem("number", propObject, property, val[startIndex + 3], startIndex + 3);
2161   a.className = "col-md-3";
2162   d.appendChild(a);
2163   return d;
2164 }
2165
2166 /**
2167  * creates a document input element for an actor/shader's property
2168  */
2169 function createInputElement(actorShader, propertyName, value) {
2170 // always4 ja columns
2171   "use strict";
2172   var type = typeof value;
2173
2174   var e;
2175   if(type === "string") {
2176     e = inputElem("string", actorShader, propertyName, value);
2177   } else if(type === "number") {
2178     e = inputElem("number", actorShader, propertyName, value);
2179   } else if(type === "boolean") {
2180     e = inputElem("checkbox", actorShader, propertyName, value);
2181   } else {
2182     var length = value.length;
2183     if(length === 2) {
2184       e = inputElem2("number", actorShader, propertyName, value, 0);
2185     } else if(length === 3) {
2186       e = inputElem3("number", actorShader, propertyName, value, 0);
2187     } else if(length === 4) {
2188       e = inputElem4("number", actorShader, propertyName, value, 0);
2189     } else if(length === 9) {
2190       e = createElement("div");
2191       e.appendChild( inputElem3("number", actorShader, propertyName, value, 0) );
2192       e.appendChild( inputElem3("number", actorShader, propertyName, value, 3) );
2193       e.appendChild( inputElem3("number", actorShader, propertyName, value, 6) );
2194     } else if(length === 16) {
2195       e = createElement("div");
2196       e.appendChild( inputElem4("number", actorShader, propertyName, value, 0) );
2197       e.appendChild( inputElem4("number", actorShader, propertyName, value, 4) );
2198       e.appendChild( inputElem4("number", actorShader, propertyName, value, 8) );
2199       e.appendChild( inputElem4("number", actorShader, propertyName, value, 12) );
2200     } else {
2201       throw "should not happen";
2202     }
2203   }
2204
2205   return e;
2206 }
2207
2208 /**
2209  * Selects an actor by id
2210  */
2211 function selectActor(id) { // from html tree
2212   "use strict";
2213   if(id === null) {
2214     eventHandler.selectActor(null);
2215   } else {
2216     var root = dali.stage.getRootLayer();
2217     var actor = root.findChildById(id);
2218     if (actor) {
2219       eventHandler.selectActor(actor);
2220     }
2221     root.delete(); // wrapper
2222   }
2223 }
2224
2225 /**
2226  * Rebuild the document actor property display
2227  */
2228 function rebuildTree() {
2229   "use strict";
2230   // remove childred
2231   var e = document.getElementById("tree");
2232   var count = e.children.length;
2233   for (var i = 0; i < count; i++) {
2234     e.removeChild(e.children[0]);
2235   }
2236
2237   // <ul class="nav nav-list">
2238   //      <li><label class="tree-toggler nav-header">Header 1</label>
2239
2240   var root = dali.stage.getRootLayer() ; // dali.stage.rootRotationActor;
2241
2242   var recurse = function(parentElement, actor) {
2243     var children = actor.getChildren();
2244     if (children) {
2245       var ul = null;
2246
2247       for (var i = 0; i < children.length; ++i) {
2248         var child = children[i];
2249
2250         if (child.name[0] !== "*") {
2251
2252           var li = document.createElement("li");
2253
2254           var a = document.createElement("a");
2255           a.href = "javascript:selectActor(" + child.getId() + ");";
2256           a.text = "(" + child.getId() + ") '" + child.name + "'";
2257           li.appendChild(a);
2258
2259           if (ul === null) {
2260             ul = document.createElement("ul");
2261             ul.className = "nav-tree";
2262           }
2263
2264           ul.appendChild(li);
2265
2266           recurse(li, child);
2267
2268           // finish with the child wrapper
2269           child.delete();
2270         }
2271       }
2272
2273       if (ul) {
2274         parentElement.appendChild(ul);
2275       }
2276     }
2277   };
2278
2279   recurse(e, root);
2280
2281   root.delete(); // wrapper
2282 }
2283
2284
2285 /**
2286  * Eventhandler class; Touch handling abstraction.
2287  *
2288  * handling functions can be registered to get touch events
2289  */
2290 function EventHandler() {
2291   "use strict";
2292   // public
2293   this.mouseX = 0;
2294   this.mouseY = 0;
2295   this.mouse_buttons = 0;
2296   this.mouseDownPosition = [0, 0, 0];
2297   this.dragDx = 0;
2298   this.dragDy = 0;
2299   this.touchedActor = null; // set if actor is touched (left click)
2300   //private
2301   // this.selectedActor = null;
2302   this.mouseIsDown = 0;
2303   this.metaKey = 0;
2304   this.altKey = 0;
2305   this.ctrlKey = 0;
2306   this.shiftKey = 0;
2307   // handlers; use register("MouseDragStart", func); where for func(eventHandler)
2308   this.handlersMouseMove = []; // valid; touchedActor(can be null), mouseX, mouseY
2309   this.handlersMouseDrag = []; // valid; touchedActor(can be null), dragDx, dragDy
2310   this.handlersSelect = []; // valid; touchedActor(can be null), dragDx, dragDy
2311   this.handlersDeselect = []; // valid; touchedActor(can be null), dragDx, dragDy
2312 }
2313
2314 /*
2315  * Register a handler, ie register("MouseMove", moveFunc)
2316  */
2317 EventHandler.prototype.register = function(name, handler) {
2318   "use strict";
2319   var handlers = this["handlers" + name];
2320   if (!(handler in handlers)) {
2321     handlers.push(handler);
2322   }
2323 };
2324
2325 /*
2326  * Unregister a handler
2327  */
2328 EventHandler.prototype.unRegister = function(name, handler) {
2329   "use strict";
2330   var handlers = this["handlers" + name];
2331   var index = handlers.index(handler);
2332   if (index >= 0) {
2333     handlers.splice(index, 1);
2334   }
2335 };
2336
2337 /*
2338  * update the mouse state
2339  */
2340 EventHandler.prototype.updateMouseState = function(canvas, e) {
2341   "use strict";
2342   var rect = canvas.getBoundingClientRect(); // in window
2343   this.mouseX = e.clientX - rect.left; // from window
2344   this.mouseY = e.clientY - (rect.bottom - rect.height);
2345   this.mouse_buttons = e.button; //  0|1|2 left|middle|rigtht
2346 };
2347
2348 /*
2349  * mouse down
2350  */
2351 EventHandler.prototype.mouseDown = function(canvas, e) {
2352   "use strict";
2353   this.mouseIsDown = 1;
2354   this.updateMouseState(canvas, e);
2355   this.mouseDownPosition = [this.mouseX, this.mouseY, 0];
2356   var hitActor = dali.hitTest(this.mouseX, this.mouseY);
2357   var tid = -1;
2358   var hid = -2;
2359   if (this.touchedActor) {
2360     tid = this.touchedActor.getId();
2361   }
2362   if (hitActor) {
2363     hid = hitActor.getId();
2364   }
2365
2366   if (hid !== tid) {
2367     if (tid > 0) {
2368       this.handleEvent(this.handlersDeselect);
2369       this.touchedActor = null;
2370     }
2371   }
2372
2373   this.selectActor(hitActor);
2374
2375   // dali is 0==down,1==up,2==motion
2376   dali.sendMouseEvent(this.mouseX, this.mouseY, 0);
2377   // console.log("mouseDown", this.mouseX, this.mouseY, this.mouseIsDown, 0);
2378 };
2379
2380 /*
2381  * set the touchedActor
2382  */
2383 EventHandler.prototype.selectActor = function(hitActor) {
2384   "use strict";
2385   if (hitActor) {
2386     this.handleEvent(this.handlersDeselect);
2387
2388     var layer = dali.stage.getRootLayer();
2389     if (hitActor.getId() === dali.stage.rootRotationActor.getId()) {
2390       // dont select our rotation actor
2391       hitActor = null;
2392     } else {
2393       // dont select the root layer
2394       if (hitActor.getId() === layer.getId()) {
2395         hitActor = null;
2396       }
2397     }
2398     layer.delete(); // wrapper
2399
2400     this.touchedActor = hitActor;
2401   } else {
2402     if(this.touchedActor) {
2403       this.handleEvent(this.handlersDeselect);
2404     }
2405     this.touchedActor = null;
2406   }
2407
2408   this.handleEvent(this.handlersSelect);
2409 };
2410
2411 /*
2412  * canvas mouse move handler
2413  */
2414 EventHandler.prototype.mouseMove = function(canvas, e) {
2415   "use strict";
2416   this.updateMouseState(canvas, e);
2417
2418   if(this.mouseIsDown) {
2419     // if (this.touchedActor) {
2420     this.dragDx = (this.mouseX - this.mouseDownPosition[0]);
2421     this.dragDy = (this.mouseY - this.mouseDownPosition[1]);
2422     // }
2423
2424     this.handleEvent(this.handlersMouseDrag);
2425   }
2426
2427   this.handleEvent(this.handlersMouseMove);
2428
2429   // dali is 0==down,1==up,2==motion
2430   dali.sendMouseEvent(this.mouseX, this.mouseY, 2);
2431   // console.log("mouseMove", this.mouseX, this.mouseY, this.mouseIsDown, 2);
2432 };
2433
2434 /*
2435  * canvas mouse up handler
2436  */
2437 EventHandler.prototype.mouseUp = function(canvas, e) {
2438   "use strict";
2439   this.mouseIsDown = 0;
2440   this.updateMouseState(canvas, e);
2441   this.dragDx = (this.mouseX - this.mouseDownPosition[0]);
2442   this.dragDy = (this.mouseY - this.mouseDownPosition[1]);
2443
2444   // dali is 0==down,1==up,2==motion
2445   dali.sendMouseEvent(this.mouseX, this.mouseY, 1);
2446   // console.log("mouseUp", this.mouseX, this.mouseY, this.mouseIsDown, 1);
2447
2448 };
2449
2450
2451 /*
2452  * canvas mouse wheel handler
2453  */
2454 EventHandler.prototype.mouseWheel = function(canvas, e) {
2455   "use strict";
2456   // multiples of +120 for up, -120 for down
2457   var clicks = e.wheelDelta / 120;
2458
2459   var taskList = dali.stage.getRenderTaskList();
2460   var task = taskList.getTask(0);
2461   var cameraActor = task.getCameraActor();
2462
2463   var fov = cameraActor.fieldOfView;
2464   cameraActor.fieldOfView = fov + (clicks / 180.0 * Math.PI);
2465
2466   taskList.delete();
2467   task.delete();
2468   cameraActor.delete();
2469   // console.log(e.wheelDelta);
2470 };
2471
2472 /*
2473  * call given handlers
2474  */
2475 EventHandler.prototype.handleEvent = function(handlers) {
2476   for (var i = 0, len = handlers.length; i < len; i++) {
2477     var handler = handlers[i];
2478     handler(this);
2479   }
2480 };
2481
2482 /*
2483  * canvas key down handler
2484  */
2485 EventHandler.prototype.keyDown = function(canvas, e) {
2486   this.metaKey = e.metaKey;
2487   this.altKey = e.altKey;
2488   this.ctrlKey = e.ctrlKey;
2489   this.shiftKey = e.shiftKey;
2490 };
2491
2492 /*
2493  * canvas key up handler
2494  */
2495 EventHandler.prototype.keyUp = function(canvas, e) {
2496   this.metaKey = e.metaKey;
2497   this.altKey = e.altKey;
2498   this.ctrlKey = e.ctrlKey;
2499   this.shiftKey = e.shiftKey;
2500 };
2501
2502 //
2503 // Actor list helpers; applies function to all actors in the list
2504 //
2505 var ActorList = {
2506   doAll: function(actors, func) {
2507     for (var i = 0, len = actors.length; i < len; i++) {
2508       func(actors[i]);
2509     }
2510   },
2511   show: function(actors, visible) {
2512     this.doAll(actors, function(actor) {
2513       actor.visible = visible;
2514     });
2515   },
2516   delete: function(actors, visible) {
2517     this.doAll(actors, function(actor) {
2518       actor.delete = visible;
2519     });
2520   },
2521   add: function(actors, actor) {
2522     this.doAll(actors, function(a) {
2523       actor.add(a);
2524     });
2525   },
2526   remove: function(actors, actor) {
2527     this.doAll(actors, function(a) {
2528       actor.remove(a);
2529     });
2530   },
2531   contains: function(actors, actor) {
2532     if (!actor) {
2533       return false;
2534     }
2535     for (var i = 0, len = actors.length; i < len; i++) {
2536       if (actors[i].getId() == actor.getId()) {
2537         return true;
2538       }
2539     }
2540     return false;
2541   }
2542 };
2543
2544
2545 //
2546 // Class for depth adornments
2547 //
2548 function DepthAdornment() {
2549   "use strict";
2550   this.attachedTo = null;
2551   this.actors = []; // array of 5 square attaced around and to back of actor to show depth
2552
2553   for (var i = 0; i < 5; i++) { //
2554
2555     var a = dali.createSolidColorActor([0.5, 0.5, 0.5, 1],
2556                                        false, [0, 0, 0, 1],
2557                                        0);
2558     a.name = "**_dali_adornment";
2559     this.actors.push(a);
2560   }
2561
2562   ActorList.show(this.actors, false);
2563 }
2564
2565 DepthAdornment.prototype.delete = function() {
2566   "use strict";
2567   ActorList.delete(this.actors);
2568   this.actors = [];
2569 };
2570
2571 DepthAdornment.prototype.attach = function(actor) {
2572   "use strict";
2573   var newActor = true;
2574   if (this.attachedTo) {
2575     newActor = (actor.getId() !== this.attachedTo.getId());
2576   }
2577
2578   if (actor && newActor) {
2579     this.unattach(this.attachedTo);
2580
2581     if(!ActorList.contains(this.actors, actor)) {
2582       this.__positionActors(actor);
2583
2584       ActorList.add(this.actors, actor);
2585
2586       ActorList.show(this.actors, true);
2587
2588       this.attachedTo = actor;
2589     }
2590   }
2591 };
2592
2593 DepthAdornment.prototype.unattach = function() {
2594   "use strict";
2595   if (this.attachedTo) {
2596     ActorList.show(this.actors, false);
2597     ActorList.remove(this.actors, this.attachedTo);
2598     this.attachedTo = null;
2599   }
2600 };
2601
2602 DepthAdornment.prototype.reposition = function() {
2603   "use strict";
2604   if (this.attachedTo) {
2605     this.__positionActors(this.attachedTo);
2606   }
2607 };
2608
2609 DepthAdornment.prototype.__positionActors = function(actor) {
2610   "use strict";
2611   var s = actor.size;
2612   s[2] = Math.max(s[2], 20); // pretend the actor is at least 20
2613   var halfw = s[0] / 2;
2614   var halfh = s[1] / 2;
2615   var halfd = s[2] / 2;
2616
2617   this.actors[0].position = [-halfw, 0, -halfd];
2618   this.actors[0].orientation = [0, -90, 0];
2619   this.actors[0].size = [s[2], s[1], 1];
2620
2621   this.actors[1].position = [+halfw, 0, -halfd];
2622   this.actors[1].orientation = [0, 90, 0];
2623   this.actors[1].size = [s[2], s[1], 1];
2624
2625   this.actors[2].position = [0, -halfh, -halfd];
2626   this.actors[2].orientation = [90, 0, 0];
2627   this.actors[2].size = [s[0], s[2], 1];
2628
2629   this.actors[3].position = [0, halfh, -halfd];
2630   this.actors[3].orientation = [-90, 0, 0];
2631   this.actors[3].size = [s[0], s[2], 1];
2632   // back
2633   // this.actors[4].position = [0, 0, -s[2]];
2634   // this.actors[4].orientation = [0, 0, 0];
2635   // this.actors[4].size = s;
2636
2637 };
2638
2639
2640
2641 /**
2642  * Class for cursor adornments when displaying selected actor
2643  */
2644 function Cursors() {
2645   "use strict";
2646   var i;
2647   var a;
2648   this.attachedTo = null;
2649   this.resizers = []; // array of 8 small square resizers
2650   this.lines = []; // array of 4 bounding box lines
2651   this.lineColor = [0.5, 0.5, 0.5, 1];
2652   this.resizerColor = [0, 0, 0, 1];
2653   this.depthAdornments = new DepthAdornment();
2654
2655   for (i = 0; i < 4; i++) { // lines
2656     a = dali.createSolidColorActor(this.lineColor, false, [0, 0, 0, 1], 0);
2657     a.name = "**_dali_adornment";
2658     this.lines.push(a);
2659   }
2660
2661   for(i = 0; i < 8; i++) { // squares
2662     a = dali.createSolidColorActor(this.resizerColor, true, [1, 1, 1, 1], 1);
2663     a.name = "**_dali_adornment";
2664     this.resizers.push(a);
2665     this.resizers[i].size = [10, 10, 1];
2666   }
2667
2668   ActorList.show(this.lines, false);
2669   ActorList.show(this.resizers, false);
2670
2671 }
2672
2673
2674 Cursors.prototype.attach = function(actor) {
2675   "use strict";
2676   if (actor) {
2677
2678     if (this.attachedTo) {
2679       this.unattach(this.attachedTo);
2680     }
2681
2682     this.__positionActors(actor);
2683
2684     ActorList.add(this.lines, actor);
2685     ActorList.add(this.resizers, actor);
2686
2687     ActorList.show(this.lines, true);
2688     ActorList.show(this.resizers, true);
2689
2690     this.depthAdornments.attach(actor);
2691
2692     this.attachedTo = actor;
2693   }
2694 };
2695
2696 Cursors.prototype.unattach = function(actor) {
2697   "use strict";
2698   if (actor && this.attachedTo) {
2699     ActorList.show(this.lines, false);
2700     ActorList.show(this.resizers, false);
2701
2702     ActorList.remove(this.lines, actor);
2703     ActorList.remove(this.resizers, actor);
2704
2705     this.depthAdornments.unattach(actor);
2706
2707     this.attachedTo = null;
2708   }
2709 };
2710
2711 Cursors.prototype.reposition = function() {
2712   "use strict";
2713   if (this.attachedTo) {
2714     this.__positionActors(this.attachedTo);
2715     this.depthAdornments.reposition();
2716   }
2717 };
2718
2719 Cursors.prototype.__positionActors = function(actor) {
2720   "use strict";
2721   var s = actor.size;
2722   var p = actor.position;
2723   var halfw = s[0] / 2;
2724   var halfh = s[1] / 2;
2725
2726   this.lines[0].position = [0 - halfw, 0, 0];
2727   this.lines[0].size = [1, halfh * 2, 1];
2728
2729   this.lines[1].position = [0, 0 - halfh, 0];
2730   this.lines[1].size = [halfw * 2, 1, 1];
2731
2732   this.lines[2].position = [0 + halfw, 0, 0];
2733   this.lines[2].size = [1, halfh * 2, 1];
2734
2735   this.lines[3].position = [0, 0 + halfh, 0];
2736   this.lines[3].size = [halfw * 2, 1, 1];
2737
2738   // drag functions presumes order here is clockwise from top left
2739   var offsetZ = 5;
2740   this.resizers[0].position = [-halfw, +halfh, offsetZ];
2741   this.resizers[1].position = [0, +halfh, offsetZ];
2742   this.resizers[2].position = [+halfw, +halfh, offsetZ];
2743   this.resizers[3].position = [+halfw, 0, offsetZ];
2744
2745   this.resizers[4].position = [+halfw, -halfh, offsetZ];
2746   this.resizers[5].position = [0, -halfh, offsetZ];
2747   this.resizers[6].position = [-halfw, -halfh, offsetZ];
2748   this.resizers[7].position = [-halfw, 0, offsetZ];
2749 };
2750
2751
2752
2753 function App(theEventHandler) {
2754   "use strict";
2755   var self = this;
2756   this.rootRotation = [0, 0, 0]; // in degrees
2757   this.cursors = new Cursors();
2758   // ActorWrapper CreateSolidColorActor(const Vector4 & color, bool border,
2759   //   const Vector4 & borderColor,
2760   //     const unsigned int borderSize)
2761   this.rootLayerIndicator = dali.createSolidColorActor(
2762     [0, 0, 0, 0.0],
2763     true, [0, 0, 0, 1],
2764     1);
2765   this.rootLayerIndicator.name = "**_dali_adornment";
2766
2767   this.rootLayerIndicator.parentOrigin = [0.5, 0.5, 0.5];
2768   this.rootLayerIndicator.anchorPoint = [0.5, 0.5, 0.5];
2769   this.rootLayerIndicator.size = [250, 250, 1];
2770   this.rootLayerIndicator.position = [0, 0, 0];
2771
2772   this.selectedActor = null;
2773   this.selectedActorSize = [0, 0, 0];
2774   this.selectedActorPosition = [0, 0, 0];
2775
2776   this.__handleMouseDrag = function(eventHandler) {
2777     if (self.resizing) {
2778       if (self.selectedActor) {
2779         self.selectedActor.size = [
2780           self.selectedActorSize[0] + eventHandler.dragDx,
2781           self.selectedActorSize[1] + eventHandler.dragDy,
2782           self.selectedActorSize[2]
2783         ];
2784         self.cursors.reposition();
2785       }
2786     } else {
2787       // move the touched actor
2788       if (self.selectedActor) {
2789         if (eventHandler.mouse_buttons === 0) {
2790           self.selectedActor.position = [
2791             self.selectedActorPosition[0] + eventHandler.dragDx,
2792             self.selectedActorPosition[1] + eventHandler.dragDy,
2793             self.selectedActorPosition[2]
2794           ];
2795         } else if (eventHandler.mouse_buttons === 2) {
2796           self.selectedActor.position = [
2797             self.selectedActorPosition[0],
2798             self.selectedActorPosition[1], -(self.selectedActorPosition[2] + eventHandler.dragDy)
2799           ];
2800         }
2801       }
2802     }
2803
2804     // rotate on middle button
2805     if (eventHandler.mouse_buttons === 1) {
2806       self.rootRotation = [eventHandler.mouseDownPosition[1] - eventHandler.mouseY, -(eventHandler.mouseDownPosition[0] - eventHandler.mouseX),
2807                            self.rootRotation[2]
2808                           ];
2809       dali.stage.rootRotationActor.orientation = self.rootRotation;
2810     }
2811
2812   };
2813
2814   this.addActor = function(actor) {
2815     if (eventHandler.touchedActor) {
2816       eventHandler.touchedActor.add(actor);
2817       actor.position = [20,20,0]; // offset so new actor isnt right behind touched
2818     } else {
2819       dali.stage.add(actor);
2820     }
2821
2822     rebuildTree();
2823
2824   };
2825
2826   this.__handleSelect = function(eventHandler) {
2827     if (eventHandler.mouse_buttons === 0) { // left click only selects actor
2828       var actor = eventHandler.touchedActor;
2829       self.selectedActor = actor;
2830       if(actor) {
2831         self.selectedActorPosition = actor.position;
2832         self.selectedActorSize = actor.size;
2833       } else {
2834         self.selectedActorPosition = [0, 0, 0];
2835         self.selectedActorSize = [1, 1, 1];
2836       }
2837       self.cursors.attach(self.selectedActor);
2838       dali.stage.add(self.rootLayerIndicator);
2839       onActorSelected(actor);
2840     }
2841   };
2842
2843   this.__handleDeselect = function(eventHandler) {
2844     self.cursors.unattach(self.selectedActor);
2845     dali.stage.remove(self.rootLayerIndicator);
2846   };
2847
2848   // initialize
2849   eventHandler.register("MouseDrag", this.__handleMouseDrag);
2850   eventHandler.register("Select", this.__handleSelect);
2851   eventHandler.register("Deselect", this.__handleDeselect);
2852
2853   //
2854   // Monkey patch the stage object (to add to root object not the root layer for rotations)
2855   //
2856   dali.stage.rootRotationActor = new dali.Actor();
2857   dali.stage.rootRotationActor.parentOrigin = [0.5, 0.5, 0.5];
2858   dali.stage.rootRotationActor.anchorPoint = [0.5, 0.5, 0.5];
2859   dali.stage.rootRotationActor.name = "app rotation actor";
2860   dali.stage.rootRotationActor.size = [100,100,1];
2861   dali.stage.add(dali.stage.rootRotationActor);
2862
2863   dali.stage.add = function(actor) {
2864     dali.stage.rootRotationActor.add(actor);
2865   };
2866
2867   dali.stage.remove = function(actor) {
2868     dali.stage.rootRotationActor.remove(actor);
2869   };
2870
2871 }
2872
2873 //
2874 // Global
2875 //
2876
2877 var eventHandler = new EventHandler();
2878 var app = new App(eventHandler);
2879 var canvas = document.getElementById("canvas");
2880
2881 function mouseDown(e) {
2882   "use strict";
2883   eventHandler.mouseDown(canvas, e);
2884 }
2885
2886 function mouseUp(e) {
2887   "use strict";
2888   eventHandler.mouseUp(canvas, e);
2889 }
2890
2891 function mouseMove(e) {
2892   "use strict";
2893   eventHandler.mouseMove(canvas, e);
2894 }
2895
2896 function mouseWheel(e) {
2897   "use strict";
2898   eventHandler.mouseWheel(canvas, e);
2899 }
2900
2901 function keyDown(e) {
2902   "use strict";
2903   eventHandler.keyDown(canvas, e);
2904 }
2905
2906 function keyUp(e) {
2907   "use strict";
2908   eventHandler.keyUp(canvas, e);
2909 }
2910
2911 canvas.onmousemove = mouseMove;
2912 canvas.onmousedown = mouseDown;
2913 canvas.onmouseup = mouseUp;
2914 canvas.onwheel = mouseWheel;
2915
2916 canvas.onkeydown = keyDown;
2917 canvas.onkeyup = keyUp;
2918
2919 //
2920 //
2921 //
2922
2923 function runRandomAnimation(actor) {
2924   "use strict";
2925   var a = new dali.Animation(0);
2926   a.setDuration(6);
2927   a.setLooping(true);
2928   a.animateTo(actor, "position", [300 * Math.random() - 150, 300 * Math.random() - 150, 0],
2929               "Linear", 0, 3);
2930   a.animateTo(actor, "position", [0, 0, 0], "Linear", 3, 3);
2931   a.animateTo(actor, "rotation", [0, 0, 1, 720 * Math.random() - 360], "Linear", 0, 3);
2932   a.animateTo(actor, "rotation", [0, 0, 1, 0], "Linear", 3, 3);
2933
2934   a.play();
2935   //    a.delete(); // delete the animtion object but a.Play() keeps it running in Dali
2936   return a;
2937 }
2938
2939
2940 //------------------------------------------------------------------------------
2941 //
2942 // application building helpers (pseudo DSL)
2943 //
2944 //------------------------------------------------------------------------------
2945 var _whenBuilder = { // builder for when() function. mimicks dali builder
2946   paths: {},
2947   styles: {},
2948   templates: {},
2949   propertyBuffers: {},
2950   geometries: {},
2951   imageBuffers: {},
2952   materials: {},
2953   samplers: {},
2954   shaders: {},
2955   renderers: {},
2956   tags: {}
2957 };
2958
2959 function _actorId(a) { // return id from [object|string name|id]
2960   "use strict";
2961   if( typeof a === "object" ) {
2962     return a.getId();
2963   } else if( typeof a === "string" ) {
2964     var child = dali.stage.findChildByName(a);
2965     return child.getId();
2966   } else {
2967     return a;
2968   }
2969 }
2970
2971 /**
2972  * Builder namespace. Usage as singleton "build".
2973  */
2974 dali.Builder = function() {
2975   "use strict";
2976   this.data = _whenBuilder;
2977   this.init();
2978 };
2979
2980 /**
2981  * 
2982  */
2983 dali.Builder.prototype.init = function() {
2984   var imageSize = 0.5; // half quad size
2985   this.propertyBuffer("imageVerts",
2986                        {format: [ ["aPosition", dali.PropertyType.VECTOR3],
2987                                   ["aTexCoord", dali.PropertyType.VECTOR2] ],
2988                         data: { "aPosition": [ [-imageSize, -imageSize, 0.0],
2989                                                [+imageSize, -imageSize, 0.0],
2990                                                [-imageSize, +imageSize, 0.0],
2991                                                [+imageSize, +imageSize, 0.0]
2992                                              ],
2993                                 "aTexCoord": [ [0, 0],
2994                                                [1, 0],
2995                                                [0, 1],
2996                                                [1, 1]
2997                                              ]
2998                               }
2999                        }
3000                       );
3001
3002   this.propertyBuffer("imageIndices",
3003                       { format: [ ["indices", dali.PropertyType.INTEGER]],
3004                         data: { "indices": [0, 3, 1, 0, 2, 3] } } );
3005
3006   this.geometry("imageGeometry", {vertices: ["imageVerts"],
3007                                   indices: "imageIndices",
3008                                   type: "TRIANGLES",
3009                                   requiresSelfDepthTest: false} );
3010
3011   this.shader("imageShader",
3012               {vertex: "\n" +
3013                "attribute mediump vec3 aPosition;\n" +
3014                "attribute mediump vec2 aTexCoord;\n" +
3015                "varying mediump vec2 vTexCoord;\n" +
3016                "uniform mediump vec3 uSize;\n" +
3017                "uniform mediump mat4 uMvpMatrix;\n" +
3018                "\n" +
3019                "void main(void)\n" +
3020                "{\n" +
3021                "  mediump vec4 vertexPosition = vec4(aPosition, 1.0);\n" +
3022                "  vertexPosition.xyz *= uSize;\n" +
3023                "  gl_Position = uMvpMatrix * vertexPosition;\n" +
3024                "  vTexCoord = aTexCoord;\n" +
3025                "}\n" +
3026                "\n" +
3027                "",
3028                fragment:
3029                "precision mediump float;\n" +
3030                "uniform sampler2D sTexture;\n" +
3031                "uniform mediump vec4 uColor;\n" +
3032                "varying mediump vec2 vTexCoord;\n" +
3033                "\n" +
3034                "void main()\n" +
3035                "{\n" +
3036                "  gl_FragColor =  texture2D( sTexture, vTexCoord ) * uColor;\n" +
3037                "}\n" +
3038                "\n" +
3039                "",
3040                hints: "HINTS_NONE"
3041               });
3042
3043   var builtInImages = ["girl1","funnyface","ducks","field"];
3044
3045   var d;
3046   for(var i=0; i < builtInImages.length; i++)
3047   {
3048     var imageName = builtInImages[i];
3049
3050     var samplerName = "sampler_" +  imageName;
3051     this.sampler(samplerName,
3052                  { "minification-filter":0,
3053                    "magnification-filter":0,
3054                    "u-wrap":0,
3055                    "v-wrap":0,
3056                    "affects-transparency":false});
3057
3058     var materialName ="material_" +  imageName;
3059     this.material(materialName,
3060                   {textures:
3061                    [
3062                      { image: imageName,
3063                        uniform: "sTexture",
3064                        sampler: samplerName
3065                      }
3066                    ],
3067                    shader: "imageShader"} );
3068
3069     this.renderer("render_" + imageName,
3070                   {geometry: "imageGeometry",
3071                    material: materialName});
3072
3073   }
3074
3075 }; // init()
3076
3077 /**
3078  * tags an actor
3079  */
3080 dali.Builder.prototype.tag = function(actor, tag) {
3081   // tag an actor (multiple by seperated by space)
3082   "use strict";
3083   var names = tag.split();
3084   var id = _actorId(actor);
3085   for(var i = 0; i < names.length; i++) {
3086     var name = names[i];
3087     if(!(name in _whenBuilder.tags)) {
3088       _whenBuilder.tags[name] = [];
3089     }
3090     var nameIndex = _whenBuilder.tags[name].indexOf(id);
3091     if(nameIndex < 0) {
3092       _whenBuilder.tags[name].push( id );
3093     }
3094   }
3095 };
3096
3097 /**
3098  * unTags an actor
3099  */
3100 dali.Builder.prototype.unTag = function(actor, tag) {
3101   // untag
3102   "use strict";
3103   var names = tag.split();
3104   var id = _actorId(actor);
3105   for(var i = 0; i < names.length; i++) {
3106     var name = names[i];
3107     if( name in _whenBuilder.tags ) {
3108       var nameIndex = _whenBuilder.tags[name].indexOf(id);
3109       if(nameIndex >= 0) {
3110         _whenBuilder.tags[name].splice(nameIndex, 1);
3111       }
3112     }
3113   }
3114 };
3115
3116 /**
3117  * Gets list of actors tagged by 'tag'
3118  */
3119 dali.Builder.prototype.tagged = function(tag) {
3120   // return all tagged
3121   "use strict";
3122   return _whenBuilder.tags[tag];
3123 };
3124
3125 /**
3126  * Returns actorIdArray with actorOrArray removed
3127  */
3128 dali.Builder.prototype.excludeFrom = function(actorIdArray, actorOrArray)
3129 {
3130   // return all except one
3131   "use strict";
3132   var item, id;
3133   var excludes = {};
3134   if("length" in actorOrArray) {
3135     for(item in actorOrArray) {
3136       id = _actorId(item);
3137       excludes[id] = 1;
3138     }
3139   } else {
3140     id = _actorId(actorOrArray);
3141     excludes[id] = 1;
3142   }
3143
3144   var ret = [];
3145   for(item in actorIdArray) {
3146     if( !(item in excludes) ) {
3147       ret.push( item );
3148     }
3149   }
3150   return ret;
3151 };
3152
3153 /**
3154  * 
3155  */
3156 dali.Builder.prototype.path = function (d) {
3157   // Stores paths in builder
3158   // paths({name: {points: [[1,2,3],[4,5,6]], forward:[1,0,0]},
3159   //        other:{points: [[1,2,3],[4,5,6]], forward:[1,0,0]}})
3160   //
3161   "use strict";
3162   for(var name in d) {
3163     var pathData = {point: [], forward: [1, 0, 0]};
3164     pathData = dali.mergeObjects(pathData, d[name]);
3165     var daliPath = new dali.Path();
3166     daliPath.points = pathData.points;
3167     dali.generateControlPoints(daliPath, pathData.curvature); // @todo remove magic number?
3168     _whenBuilder.paths[name] = daliPath;
3169   }
3170 };
3171
3172 /**
3173  * Set style definition
3174  */
3175 dali.Builder.prototype.style = function(name, d) {
3176   // Stores styles in builder
3177   // style(name, {property1:value, prop2,value})
3178   // style(other, {property1:value, prop2,value})
3179   //
3180   "use strict";
3181   _whenBuilder.styles[name] = d;
3182 };
3183
3184 //
3185 //  +------------------+          +---------------+
3186 //  | PropertyBuffer   | *      * | Geometry      |
3187 //  +------------------+ -------- +---------------+
3188 //  | format:          |          | vertex:PBuf   |1      * +-----------+         +------------+
3189 //  |   name:v2,name:v3|          | indices:PBuf  +---------| Renderer  |         | Actor      |
3190 //  | data             |          |               |         +-----------+ *     * +------------+
3191 //  +------------------+          +---------------+       * | geom      +---------| renderer(s)|
3192 //                                                     +----| material  |         |            |
3193 //  +-------------+ *      * +----------+ 1            |    |           |         |            |
3194 //  |Sampler      +----------|Material  +--------------+    +-----------+         +------------+
3195 //  +-------------+          +----------+
3196 //  |uniformName  |        * |sampler(s)|
3197 //  |Image        |       +--|shader    |
3198 //  |Filter/wrap  |       |  |facecull  |
3199 //  +-------------+       |  |blendfunc |
3200 //                        |  +----------+
3201 //  +-----------------+   |
3202 //  |Shader           |   |
3203 //  +-----------------+ 1 |
3204 //  |program:vert,frag|---+
3205 //  |hints            |
3206 //  +-----------------+
3207 //
3208
3209 /**
3210  * Set template defintion
3211  */
3212 dali.Builder.prototype.template = function(name, d) {
3213   // Stores templates in builder
3214   // template("name":{ "type": "ImageActor", property1:value, prop2,value})
3215   // template("other: { "type": "TextView", property1:value, prop2,value})
3216   "use strict";
3217   _whenBuilder.templates[name] = d;
3218
3219 };
3220
3221 /**
3222  * Set style definition
3223  */
3224 dali.Builder.prototype.imageBuffer = function(name, d) {
3225   // stores imageBuffers
3226   // imageBuffers("buffer1", { bufferName: "" }
3227   //                         } )
3228   "use strict";
3229   _whenBuilder.imageBuffers[name] = d;
3230 };
3231
3232 /**
3233  * Set property buffer definition
3234  */
3235 dali.Builder.prototype.propertyBuffer = function(name, d) {
3236   // stores PropertyBuffers
3237   // propertyBuffers("buffer1", { format: [ ["aPosition", dali.PropertyType.VECTOR2],
3238   //                                       ["aTexCoord", dali.PropertyType.VECTOR2].
3239   //                             data: {aPosition: [-0.5,-0.5,],
3240   //                                               [+0.5,-0.5,],
3241   //                                               [-0.5,+0.5,],
3242   //                                               [+0.5,+0.5,],
3243   //                                    aCol:      [0.0, 0.0],
3244   //                                               [1.0, 0.0],
3245   //                                               [0.0, 1.0],
3246   //                                               [1.0, 1.0] }
3247   //                           } )
3248   "use strict";
3249   _whenBuilder.propertyBuffers[name] = d;
3250 };
3251
3252 /**
3253  * Set geometry definition
3254  */
3255 dali.Builder.prototype.geometry = function(name, d) {
3256   // stores geometry meshes
3257   // geometries("mesh1": { vertices: "buffer1",
3258   //                       index: "index1",
3259   //                       type: "TRIANGLES",
3260   //                       requresDepthTest:false } )
3261   "use strict";
3262   _whenBuilder.geometries[name] = d;
3263 };
3264
3265 /**
3266  * Set sample definition
3267  */
3268 dali.Builder.prototype.sampler = function(name, d) {
3269   // stores samplers
3270   // samplers("sampler1", { "minification-filter":0,
3271   //                       "magnification-filter":0,
3272   //                       "u-wrap":0,
3273   //                       "v-wrap":0,
3274   //                       "affects-transparency":false})
3275   "use strict";
3276   _whenBuilder.samplers[name] = d;
3277 };
3278
3279 /**
3280  * Set shader definition
3281  */
3282 dali.Builder.prototype.shader = function(name, d) {
3283   // stores shaders
3284   // shaders("shader1", { vertex:"",
3285   //                     fragment:"",
3286   //                     hints:"NONE"} )
3287   "use strict";
3288   _whenBuilder.shaders[name] = d;
3289 };
3290
3291 /**
3292  * Set material definition
3293  */
3294 dali.Builder.prototype.material = function(name, d) {
3295   // stores materials meshes
3296   // materials({"mat1",{ textures: [
3297   //                       { image: animage,
3298   //                         uniform: "uTexture"
3299   //                         sampler: asampler
3300   //                        }
3301   //                    ],
3302   //                    shader: "shader1",
3303   //                    faceCulling: "BACK",
3304   //                    blend: "AUTO",
3305   //                    blendFunc : {srcFactorRGBA, destFactorRGBA},
3306   //                    blendEquation : "",
3307   //                    mixColor : [1,0,0,1] } )
3308   //
3309   "use strict";
3310   var value; // check required things
3311   value = this.GetRequiredKey(d, "shader");
3312   this.GetRequiredKey(_whenBuilder.shaders, value);  // must already exist
3313
3314   // only support textures so must have textures section
3315   this.GetRequiredKey(d, "textures");
3316
3317   var i;
3318   for(i = 0; i < d.textures.length; i++)
3319   {
3320     if(typeof(d.textures[i]) == "string")
3321     {
3322       // the image must already exist
3323       value = this.GetRequiredKey(d.textures[i], "image");
3324       this.GetRequiredKey(_whenBuilder.imageBuffers, value);
3325     }
3326     else
3327     {
3328     }
3329   }
3330
3331   // value = this.GetRequiredKey(d, "textures");
3332   // this.GetRequiredKey(_whenBuilder.textures, value);
3333   _whenBuilder.materials[name] = d;
3334 };
3335
3336 /**
3337  * Set renderer definition
3338  */
3339 dali.Builder.prototype.renderer = function(name, d) {
3340   // store renderer
3341   // renderers("rend1",  {"geometry": "geom1",
3342   //                     "material": "mat1",
3343   //                     "depth-index"})
3344   "use strict";
3345   var value; // check required things
3346   value = this.GetRequiredKey(d, "geometry");
3347   this.GetRequiredKey(_whenBuilder.geometries, value);  // must already exist
3348   value = this.GetRequiredKey(d, "material");
3349   this.GetRequiredKey(_whenBuilder.materials, value);
3350
3351   _whenBuilder.renderers[name] = d;
3352 };
3353
3354 dali.Builder.prototype.createOrGetDaliPropertyBuffer = function(name) {
3355   "use strict";
3356   consoleAssert(name in _whenBuilder.propertyBuffers, "property buffer not defined:" + name);
3357   var ret;
3358   if("daliObject" in _whenBuilder.propertyBuffers[name]) {
3359     ret = _whenBuilder.propertyBuffers[name].daliObject;
3360   } else {
3361     var data = _whenBuilder.propertyBuffers[name];
3362
3363     ret = dali.createPropertyBuffer(data);
3364
3365     _whenBuilder.propertyBuffers[name].daliObject = ret;
3366   }
3367   return ret;
3368 };
3369
3370 dali.Builder.prototype.createOrGetDaliGeometry = function(name) {
3371   "use strict";
3372   consoleAssert(name in _whenBuilder.geometries, "geometry not defined:" + name);
3373   var ret;
3374   if("daliObject" in _whenBuilder.geometries[name]) {
3375     ret = _whenBuilder.geometries[name].daliObject;
3376   } else {
3377     var data = _whenBuilder.geometries[name];
3378
3379     ret = new dali.Geometry();
3380
3381     for(var i = 0; i < data.vertices.length; i++) {
3382       ret.addVertexBuffer( this.createOrGetDaliPropertyBuffer(data.vertices[i] ) );
3383     }
3384
3385     ret.setIndexBuffer( this.createOrGetDaliPropertyBuffer(data.indices) );
3386
3387     if("requiresSelfDepthTest" in data) {
3388       ret.setRequiresDepthTesting(data.requiresSelfDepthTest);
3389     }
3390
3391     _whenBuilder.geometries[name].daliObject = ret;
3392   }
3393   return ret;
3394 };
3395
3396 dali.Builder.prototype.createOrGetDaliShader = function(name) {
3397   "use strict";
3398   consoleAssert(name in _whenBuilder.shaders, "shader not defined:" + name);
3399   var ret = null;
3400   if("daliObject" in _whenBuilder.shaders[name]) {
3401     ret = _whenBuilder.shaders[name].daliObject;
3402   } else {
3403     var data = _whenBuilder.shaders[name];
3404
3405     ret = new dali.Shader(data.vertex,
3406                           data.fragment,
3407                           uiShaderTab.getDaliShaderHints(data.hints));
3408
3409     _whenBuilder.shaders[name].daliObject = ret;
3410   }
3411
3412   return ret;
3413 };
3414
3415 dali.Builder.prototype.createOrGetDaliImage = function(name) {
3416   "use strict";
3417   if(!(name in _whenBuilder.imageBuffers)) {
3418     _whenBuilder.imageBuffers[name] = {};
3419   }
3420
3421   var ret;
3422   if("daliObject" in _whenBuilder.imageBuffers[name]) {
3423     ret = _whenBuilder.imageBuffers[name].daliObject;
3424   } else {
3425     // get images from the ui buffer
3426     ret = imageFromUiBuffer(name);
3427     _whenBuilder.imageBuffers[name].daliObject = ret;
3428   }
3429   return ret;
3430 };
3431
3432 dali.Builder.prototype.createOrGetDaliSampler = function(name) {
3433   "use strict";
3434   consoleAssert( name in _whenBuilder.samplers, "sampler not defined:" + name);
3435   var ret;
3436   if("daliObject" in _whenBuilder.samplers[name]) {
3437     ret = _whenBuilder.samplers[name].daliObject;
3438   } else {
3439     var data = _whenBuilder.samplers[name];
3440     ret = new dali.Sampler();
3441     _whenBuilder.samplers[name].daliObject = ret;
3442   }
3443   return ret;
3444 };
3445
3446 dali.Builder.prototype.createOrGetDaliMaterial = function(name) {
3447   "use strict";
3448   consoleAssert( name in _whenBuilder.materials, "Material not defined:" + name);
3449   var ret;
3450   if("daliObject" in _whenBuilder.materials[name]) {
3451     ret = _whenBuilder.materials[name].daliObject;
3452   } else {
3453     var data = _whenBuilder.materials[name];
3454
3455     ret = new dali.Material(this.createOrGetDaliShader( data.shader ));
3456
3457     for(var i = 0; i < data.textures.length; i++) {
3458       ret.addTexture( this.createOrGetDaliImage(data.textures[i].image),
3459                       data.textures[i].uniform,
3460                       this.createOrGetDaliSampler( data.textures[i].sampler ) );
3461     }
3462
3463     _whenBuilder.materials[name].daliObject = ret;
3464   }
3465   return ret;
3466 };
3467
3468 dali.Builder.prototype.createOrGetDaliRenderer = function(name) {
3469   "use strict";
3470   consoleAssert( name in _whenBuilder.renderers, "Renderer not defined:" + name);
3471
3472   var ret;
3473   if("daliObject" in _whenBuilder.renderers[name]) {
3474     ret = _whenBuilder.renderers[name].daliObject;
3475   } else {
3476     var data = _whenBuilder.renderers[name];
3477
3478     ret = new dali.Renderer(this.createOrGetDaliGeometry(data.geometry),
3479                             this.createOrGetDaliMaterial(data.material));
3480
3481     _whenBuilder.renderers[name].daliObject = ret;
3482   }
3483   return ret;
3484 };
3485
3486 dali.Builder.prototype.createActorTree = function(dictionary) {
3487   "use strict";
3488   var ret;
3489   var i;
3490   consoleAssert(typeof(dictionary) == "object", "createActorTree needs an object");
3491
3492   if("type" in dictionary) {
3493     if( dictionary.type in dali ) {
3494       ret = new dali[ dictionary.type ]();
3495     } else if( dictionary.type in _whenBuilder.templates ) {
3496       var realType = _whenBuilder.templates[ dictionary.type ].type;
3497       ret = new dali[ realType ]();
3498     } else {
3499       consoleAssert(0, "Cannot find type to create:" + dictionary.type);
3500     }
3501   } else {
3502     consoleAssert("render" in dictionary, "'type' or 'render needed to create dali object");
3503     ret = new dali.Actor();
3504   }
3505
3506   var tags = [];
3507
3508   for(var prop in dictionary) {
3509     if( prop === "actors" ) {
3510       var actors = dictionary[prop];
3511       for(i = 0; i < actors.length; i++) {
3512         ret.add( this.createActorTree( actors[i] ) );
3513       }
3514     } else if( prop === "tag" ) {
3515       tags.push(dictionary.tag);
3516     } else if( prop === "tags" ) {
3517       tags.concat(dictionary.tags);
3518     } else if( prop === "type" ) {
3519       // ignore
3520     } else if( prop === "render") {
3521       var renderer;
3522       if(typeof(dictionary.render) == "string")
3523       {
3524         renderer = this.createOrGetDaliRenderer(dictionary.render);
3525         ret.addRenderer(renderer);
3526       }
3527       else
3528       {
3529         for(i = 0; i < dictionary.render.length; i++) {
3530           renderer = this.createOrGetDaliRenderer(dictionary.render[i]);
3531           ret.addRenderer(renderer);
3532         }
3533       }
3534     } else {
3535       // a property set
3536       ret[prop] = dictionary[prop];
3537     }
3538   }
3539
3540   if(tags) {
3541     for(i = 0; i < tags.length; i++) {
3542       this.tag(ret, tags[i]);
3543     }
3544   }
3545
3546   return ret;
3547 };
3548
3549 /**
3550  * Adds actor defintions to stage.
3551  */
3552 dali.Builder.prototype.stage = function(/* actor definition array */) {
3553   "use strict";
3554   for(var i = 0; i < arguments.length; i++) {
3555     dali.stage.add( this.createActorTree( arguments[i] ) );
3556   }
3557 };
3558
3559 /**
3560  * Adds actor defintions to stage.
3561  */
3562 dali.Builder.prototype.addTo = function(/* toActor, actor_definition_array */) {
3563   "use strict";
3564   consoleAssert(typeof(arguments[0]) == "string", "1st argument must be name");
3565
3566   var i;
3567
3568   for(i = 1; i < arguments.length; i++) {
3569     consoleAssert(typeof(arguments[1]) == "object", "2nd and other arguments must be object");
3570   }
3571
3572   var actor;
3573   if( arguments[0] == "stage" ) {
3574     actor = dali.stage.getRootLayer();
3575   }
3576   else {
3577     actor = dali.stage.getRootLayer().findChildByName( arguments[0] );
3578     consoleAssert(actor, "Cannot find actor:" + arguments[0]);
3579   }
3580
3581   for(i = 1; i < arguments.length; i++) {
3582     dali.stage.add( this.createActorTree( arguments[i] ) );
3583   }
3584 };
3585
3586 /**
3587  * Adds actor defintions to stage.
3588  */
3589 dali.Builder.prototype.GetRequiredKey = function(object, name, caller) {
3590   if( name in object )
3591   {
3592     return object[name];
3593   }
3594   else
3595   {
3596     consoleAssert(0, "Object is missing key:'" + name + "'\n" + JSON.stringify(object));
3597     return false;
3598   }
3599 };
3600
3601 dali.Builder.prototype.image = function(dictionary) {
3602   // image({name:"name"
3603   //
3604   //       })
3605   //
3606   //
3607   "use strict";
3608   var d = {};
3609   var name = this.GetRequiredKey(dictionary, "name");
3610
3611   var shaderName = "imageShader";
3612   if("shader" in dictionary) {
3613     shaderName = dictionary.shader;
3614   }
3615   var samplers = [name + "_sampler"];
3616   if("samplers" in dictionary) {
3617     samplers = dictionary.samplers;
3618   }
3619
3620   var samplername = name + "_sampler";
3621   d = {};
3622   d[samplername] = {};
3623   this.samplers(d);
3624
3625   var matname = name + "_material";
3626   d = {};
3627   d[matname] = {shader: shaderName, textures: [ {image: this.GetRequiredKey(dictionary, "image"),
3628                                                  uniform: "sTexture",
3629                                                  sampler: samplername}]};
3630   this.materials(d);
3631
3632   var rendname = name + "_renderer";
3633   d = {};
3634   d[rendname] = {geometry: "imageGeometry", material: matname};
3635   this.renderers(d);
3636
3637   // store imageBuffers if they are missing for image
3638   // (we're only using image data from browser buffers)
3639   if( !(dictionary.image in _whenBuilder.imageBuffers) ) { // add to _whenBuilder
3640     d = {};
3641     d[dictionary.image] = { bufferName: dictionary.image };
3642     this.imageBuffers(d);
3643   }
3644
3645   dictionary.type = "Actor";
3646   dictionary.renderers = [rendname];
3647
3648   return dictionary;
3649 };
3650
3651 ////////////////////////////////////////////////////////////////////////////////
3652 //
3653 // dali toy Builder singleton
3654 //
3655 //
3656 ////////////////////////////////////////////////////////////////////////////////
3657 var build = new dali.Builder();
3658
3659 ////////////////////////////////////////////////////////////////////////////////
3660 //
3661 //
3662 //
3663 ////////////////////////////////////////////////////////////////////////////////
3664 function _addTypeToDictionaryClosure(actorType) {
3665   "use strict";
3666   return function(dictionary) {
3667     dictionary.type = actorType;
3668     return dictionary;
3669   };
3670 }
3671
3672 // @ todo; why is this global?
3673 var HTML5Image = Image; // html5 also has "Image" which were about to overwrite
3674 var _registry = new dali.TypeRegistry();
3675 for(var _i = 0; _i < _registry.getTypeNameCount(); _i++) {
3676   var _typename = _registry.getTypeName(_i);
3677   this[_typename] = _addTypeToDictionaryClosure(_typename);
3678 }
3679
3680 function _actorArray(actorOrName) {
3681   "use strict";
3682   if(typeof actorOrName === "string") {
3683     return [actorOrName];
3684   } else {
3685     return [actorOrName.name];
3686   }
3687 }
3688
3689 function _actorIdList(a) {
3690   "use strict";
3691   var ret = [];
3692   if("length" in a) {
3693     for(var item in a) {
3694       ret.push( _actorId(item) );
3695     }
3696   } else {
3697     ret.push( _actorId(a) );
3698   }
3699   return ret;
3700 }
3701
3702
3703 function _functionName(fun) {
3704   "use strict";
3705   var ret = fun.toString();
3706   ret = ret.substr("function ".length);
3707   ret = ret.substr(0, ret.indexOf("("));
3708   return ret;
3709 }
3710
3711 function _numberOrRaise(value, errorMessage) {
3712   "use strict";
3713   if(typeof value === "number") {
3714     return value;
3715   } else {
3716     throw errorMessage;
3717   }
3718 }
3719
3720 function _stringOrRaise(value, errorMessage) {
3721   "use strict";
3722   if(typeof value === "string") {
3723     return value;
3724   } else {
3725     throw errorMessage;
3726   }
3727 }
3728
3729 // Animate to
3730 //   to(value)
3731 //   to(value, delay, duration)
3732 //   to(value, delay, duration, interpolation)
3733 // ie
3734 //   to([10,10,10]
3735 //   to([10,10,10], 0,3, "ease_in")),
3736 function to() {
3737   "use strict";
3738   var ret = { animate: "animateTo",
3739               value: null,
3740               delay: 0,
3741               duration: 0,
3742               alpha: "linear"};
3743
3744   ret.value = arguments[0]; // property value
3745   if( arguments.length > 1 ) {
3746     ret.delay = _numberOrRaise(arguments[1], "Delay must be a number");
3747   }
3748   if( arguments.length > 2 ) {
3749     ret.duration = _numberOrRaise(arguments[2], "Duration must be a number");
3750   }
3751   if( arguments.length > 3 ) { // optional
3752     ret.alpha = arguments[3];
3753   }
3754   return ret;
3755 }
3756
3757 // Animate by
3758 //   by(value)
3759 //   by(value, delay, duration)
3760 //   by(value, delay, duration, interpolation)
3761 // ie
3762 //   by([10,10,10]
3763 //   by([10,10,10], 0,3, "ease_in")),
3764 function by() {
3765   "use strict";
3766   var ret = { animate: "animateBy",
3767               value: null,
3768               delay: 0,
3769               duration: 0,
3770               alpha: "linear"};
3771
3772   ret.value = arguments[0]; // property value
3773   if( arguments.length > 1 ) {
3774     ret.delay = _numberOrRaise(arguments[1], "Delay must be a number");
3775   }
3776   if( arguments.length > 2 ) {
3777     ret.duration = _numberOrRaise(arguments[2], "Duration must be a number");
3778   }
3779   if( arguments.length > 3 ) { // optional
3780     ret.alpha = arguments[3];
3781   }
3782   return ret;
3783 }
3784
3785 // Animate between
3786 //   between(fromValue, toValue)
3787 //   between(fromValue, toValue, delay, duration)
3788 //   between(fromValue, toValue, delay, duration, interpolation)
3789 // ie
3790 //   between([10,10,10], [100,10,10]
3791 //   between([10,10,10], [100,10,10], 0,3, "ease_in")),
3792 function between() {
3793   "use strict";
3794   var ret = { animate: "animateBy",
3795               fromValue: null,
3796               toValue: null,
3797               delay: 0,
3798               duration: 0,
3799               alpha: "linear"};
3800
3801   ret.value = arguments[0]; // property value
3802   ret.value = arguments[1]; // property value
3803   if( arguments.length > 2 ) {
3804     ret.delay = _numberOrRaise(arguments[2], "Delay must be a number");
3805   }
3806   if( arguments.length > 3 ) {
3807     ret.duration = _numberOrRaise(arguments[3], "Duration must be a number");
3808   }
3809
3810   if( arguments.length > 4 ) { // optional
3811     ret.alpha = arguments[4];
3812   }
3813   return ret;
3814 }
3815
3816 // Animate path
3817 //   path(pathName)
3818 //   path(pathName, delay, duration)
3819 //   path(pathName, delay, duration, interpolation)
3820 // ie
3821 //   path("path0", 0, 3, "linear")
3822 function path() {
3823   "use strict";
3824   var ret = { animate: "path",
3825               path: null,
3826               forward: [1, 0, 0],
3827               delay: 0,
3828               duration: 0,
3829               alpha: "linear"};
3830
3831   ret.path = arguments[0]; // path
3832   if( arguments.length > 1 ) {
3833     ret.delay = _numberOrRaise(arguments[1], "Delay must be a number");
3834   }
3835   if( arguments.length > 2 ) {
3836     ret.duration = _numberOrRaise(arguments[2], "Duration must be a number");
3837   }
3838
3839   if( arguments.length > 3 ) { // optional
3840     ret.alpha = arguments[3];
3841   }
3842   return ret;
3843 }
3844
3845 // conditional animation
3846 // when("myimage", condition("touch", "inside", 0, 100),
3847 //
3848 function condition(propertyName, conditionType, arg0, arg1)
3849 {
3850   "use strict";
3851   var ret = { actors: [],
3852               property: propertyName,
3853               type: conditionType,
3854               arg0: arg0,
3855               arg1: arg1
3856             };
3857
3858   if(arg1 === undefined) {
3859     ret.arg1 = 0.0; // make a float for the c++ call (ignored if irrelevant)
3860   }
3861
3862   return ret;
3863 }
3864
3865 // set animation
3866 //   set(actorOrListOrNone, signalName, animationDefition)
3867 // ie
3868 //   set("myimage", "size", to([10,10,10], 0,3, "ease_in"),
3869 //                          path(0,3, "ease_in", "path0"))
3870 //   set("size", to([10,10,10], 0,3, "ease_in")),
3871 //               between([0,0,0], [10,10,10], 0,3, "ease_in")))
3872 //   set(tagged("scrollitem), "position", path(0,3, "ease_in", "path0")),
3873 //   set(excludeFrom(tagged("scrollitem"), "myimage"), "position", path(0,3, "ease_in", "path0")),
3874 function set() {
3875   "use strict";
3876   var ret = { action: "set",
3877               actors: [],
3878               property: null,
3879               animation: []
3880             };
3881
3882   var index;
3883   if( arguments.length === 3 ) { // then actor is specified somehow
3884     ret.actors = _actorArray( arguments[0] );
3885     ret.property = _stringOrRaise(arguments[1], "Property must be a string");
3886     index = 2;
3887   } else if( arguments.length === 2 ) { // actor is self (indicated in 'when' call)
3888     ret.property = _stringOrRaise(arguments[0], "Property must be a string");
3889     index = 1;
3890   } else {
3891     throw "set needs 2 or 3 arguments";
3892   }
3893
3894   for(var i = index; i < arguments.length; i++) {
3895     ret.animation.push( arguments[i] );
3896   }
3897
3898   return ret;
3899 }
3900
3901 // set animation
3902 //   call(function, arg0, arg1)
3903 // ie
3904 //   call(func)
3905 //   call(func, 10.0, "enable")
3906 function call() {
3907   "use strict";
3908   var ret = { action: "call",
3909               arguments: [],
3910               func: null
3911             };
3912
3913   ret.func = arguments[0];
3914
3915   for(var i = 1; i < arguments.length; i++) {
3916     ret.arguments.push( arguments[i] );
3917   }
3918
3919   return ret;
3920 }
3921
3922 function then()
3923 {
3924   "use strict";
3925   return [{ action: arguments[0],
3926             parameters: arguments[1]}];
3927 }
3928
3929 function _actorNameList()
3930 {
3931   "use strict";
3932   var names;
3933   if(typeof arguments[0] === "function") {
3934     var lookup = arguments[0]();
3935     names = lookup[0];
3936   } else if(typeof arguments[0] === "object") {
3937     // or it can be the actual dali actor object
3938     names = _actorArray(arguments[0].name);
3939   } else if(typeof arguments[0] === "string") {
3940     // or arg0,arg1 are the actor property
3941     names = _actorArray(arguments[0]);
3942   } else {
3943     return names; // presume already actor name list
3944   }
3945   return names;
3946 }
3947
3948 var _buildDescription = {animations:{}, templates:{}};
3949
3950 function _animation(a) {
3951   if(a) {
3952     return a;
3953   } else {
3954     return new dali.Animation(0);
3955   }
3956 }
3957
3958 // function _makeActionCallback(func, args) {
3959 //   "use strict";
3960 //   return function(){
3961 //     var a;
3962 //     for(var i = 0; i < args.length; i++) {
3963 //       var d = args[i];
3964 //       if( d.action === "set" ) {
3965 //         for(var ai = 0; ai < d.actors.length; ai++) {
3966 //           if( d.property ) {
3967 //             apply(_animation,
3968 //                   d.arguments[0].animate,
3969
3970 //                   anim.push( [d.actors[ai]], d.property,
3971 //           }
3972 //         }
3973 //       }
3974
3975 //   var ret = { action: "set",
3976 //               actors: [],
3977 //               property: null,
3978 //               condition: null,
3979 //               animation: []
3980 //             };
3981
3982
3983 //     func.apply(null, args);
3984 //   };
3985 // }
3986
3987 function loop(on)
3988 {
3989   "use strict";
3990   return { action: "loop",
3991             value: on};
3992 }
3993
3994 function endAction(action)
3995 {
3996   "use strict";
3997   return { action: "endAction",
3998             value: action};
3999 }
4000
4001 function disconnectAction(action)
4002 {
4003   "use strict";
4004   return { action: "disconnectAction",
4005             value: action};
4006 }
4007
4008
4009 function _makeCallback(args) {
4010   "use strict";
4011   return function(){
4012     var a;
4013     var actors = _actorNameList( args[0] );
4014     // args[1] is signal name
4015     for(var i = 2; i < args.length; i++) {
4016       var d = args[i];
4017       if(d.action === "call") {
4018         d.func.apply(null, d.arguments);
4019       } else if(d.action === "loop") {
4020         a = _animation(a);
4021         a.setLooping( d.value );
4022       } else if(d.action === "endAction") {
4023         a = _animation(a);
4024         a.setEndAction( d.value );
4025       } else if(d.action === "disconnectAction") {
4026         a = _animation(a);
4027         a.setDisconnectAction( d.value );
4028       } else if(d.action === "set") {
4029         if( d.actors.length ) {
4030           actors = d.actors;
4031         }
4032         for(var actori = 0; actori < actors.length; actori++) {
4033           var actorName = actors[actori];
4034           var root = dali.stage.getRootLayer();
4035           var actor = root.findChildByName( actorName );
4036           a = _animation(a);
4037           for(var animi = 0; animi < d.animation.length; animi++) {
4038             var anim = d.animation[animi];
4039             var value = anim.value;
4040             if(typeof value === "function") { // can be a function
4041               value = value();
4042             }
4043             if(anim.animate === "animateTo") {
4044               a.animateTo(actor, d.property, value, anim.alpha, anim.delay, anim.duration);
4045             } else if(anim.animate === "animateBy") {
4046               a.animateBy(actor, d.property, value, anim.alpha, anim.delay, anim.duration);
4047             } else if(anim.animate === "animatePath") {
4048               var pathData = anim.path;
4049               var daliPath;
4050               if(typeof pathData === "function") {
4051                 pathData = pathData();
4052               }
4053               if(typeof pathData === "string") {
4054                 if(pathData in _whenBuilder.paths) {
4055                   daliPath = _whenBuilder.paths[pathData];
4056                 } else {
4057                   throw "Path not known";
4058                 }
4059               } else {
4060                 daliPath = new dali.Path();
4061                 daliPath.points = pathData;
4062                 dali.generateControlPoints(daliPath, 0.35); // @todo remove magic number?
4063               }
4064               _animation(a).animatePath(actor, daliPath, anim.forward, anim.alpha, anim.delay, anim.duration);
4065             } else {
4066               throw "";
4067             }
4068           } // for anims
4069         } // for actors
4070       }
4071     }// for args
4072
4073     // animation support?
4074     // else if( d.action === "animate" ) {
4075     // }
4076
4077     // actions support??
4078     // else if( d.action === "then" ) {
4079     //   if( d.actors.length ) {
4080     //     actors = d.actors;
4081     //   }
4082
4083     if(a) {
4084       a.play();
4085     }
4086   }; // closure function
4087 } // _makeCallback
4088
4089
4090 // doNow(<defaultActor>, ...)
4091 //
4092 // doNow("myimage",
4093 //      call(myfunction),
4094 //      call(myfunction, arg1),
4095 //      and("animation-ends"),
4096 //      set("myimage", "size", to([10,10,10]),
4097 //                             to([10,10,10], 0,3, "ease_in")),
4098 //                             path(0,3, "ease_in", "path0")),
4099 //                             between([0,0,0], [10,10,10], 0,3, "ease_in")),
4100 //                             to([0,0,0], 0, 3)
4101 //     set(tagged("scrollitem), path(0,3, "ease_in", "path0")),
4102 //     set(excludeFrom(tagged("scrollitem"), "myimage"), path(0,3, "ease_in", "path0")),
4103 //     endAction("bake"),
4104 //     discardAction("bake"),
4105 //     loop(true),
4106 //     then("myimage", "hide"),
4107 //     then("quit"),
4108 //     then("play", "myanim"),
4109 //     thenOnChild("myimage", "child", "hide"),
4110 //     animate("name"),
4111 //     animateTo("position",
4112 //        )
4113 function doNow(args) {
4114   "use strict";
4115   var actor = args.shift();
4116   args.unshift("");     // signal name
4117   args.unshift(actor);
4118   var cb = _makeCallback.apply(null, args);
4119   cb();
4120 }
4121
4122 function _makeSensibleTouched(func, state) { // dali giving all mouse events on touched signal --- is this correct?? @todo
4123   "use strict";
4124   return function(actor, touch){
4125     var doit = false;
4126     for(var i = 0; i < touch.points.length; i++) {
4127       if(touch.points[i].state === state) {
4128         doit = true;
4129         break;
4130       }
4131     }
4132     if(doit) {
4133       func.apply( null, arguments);
4134     }
4135   };
4136 }
4137
4138 // function _connectToSignal(actors, signalName, func) {
4139 //   "use strict";
4140 //   var root = dali.stage.getRootLayer();
4141 //   var f = func;
4142
4143 //   if( signalName === "touchedDown" ) { // fix as touched signal is really "mouseState"?
4144 //     f = _makeSensibleTouchedDown(func);
4145 //     signalName = "touch";
4146 //   }
4147
4148 //   for(var ai = 0; ai < actors.length; ai++) {
4149 //     var actor = root.findChildByName( actors[ai] );
4150 //     actor.connect( signalName, f );
4151 //   }
4152 // }
4153
4154
4155 // when("myimage", condition("touch", "inside", 0, 100),
4156 // or
4157 // when("myimage", "touch",
4158 //      call(myfunction),
4159 //      call(myfunction, arg1),
4160 //      and("animation-ends"),
4161 //      set("myimage", "size", to([10,10,10]),
4162 //                             to([10,10,10], 0,3, "ease_in")),
4163 //                             path(0,3, "ease_in", "path0")),
4164 //                             between([0,0,0], [10,10,10], 0,3, "ease_in")),
4165 //                             to([0,0,0], 0, 3)
4166 //     set(tagged("scrollitem), path(0,3, "ease_in", "path0")),
4167 //     set(excludeFrom(tagged("scrollitem"), "myimage"), path(0,3, "ease_in", "path0")),
4168 //     endAction("bake"),
4169 //     discardAction("bake"),
4170 //     loop(true),
4171 //     then("myimage", "hide"),
4172 //     then("quit"),
4173 //     then("play", "myanim"),
4174 //     thenOnChild("myimage", "child", "hide"),
4175 //     animate("name"),
4176 //        )
4177 function when() {
4178   "use strict";
4179   var actors, property, index;
4180   var signal = null;
4181   var condition = null;
4182
4183   // arg0 can be an actor lookup function; returning an actor array
4184   actors = _actorNameList(arguments[0]);
4185
4186   if(typeof arguments[1] === "string") {
4187     // if string then its a signal
4188     signal = arguments[1];
4189   } else {
4190     // if object then its a condition
4191     condition = arguments[1];
4192     // actors can be null which means use the actors in when() call
4193     if(condition.actors === null) {
4194       condition.actor = actors[0];
4195     }
4196   }
4197
4198   var root;
4199   var f;
4200   var ai;
4201   var actor;
4202
4203   if(signal) {
4204     // _connectToSignal( actors, signal, _makeCallback(arguments) );
4205     root = dali.stage.getRootLayer();
4206     f = _makeCallback(arguments);
4207
4208     if( signal === "touchedDown" ) { // fix as touched signal is really "mouseState"?
4209       f = _makeSensibleTouched(f, "DOWN");
4210       signal = "touch";
4211     }
4212     if( signal === "touchedUp" ) { // fix as touched signal is really "mouseState"?
4213       f = _makeSensibleTouched(f, "UP");
4214       signal = "touch";
4215     }
4216     if( signal === "touchedMotion" ) { // fix as touched signal is really "mouseState"?
4217       f = _makeSensibleTouched(f, "MOTION");
4218       signal = "touch";
4219     }
4220     if( signal === "touchedLeave" ) { // fix as touched signal is really "mouseState"?
4221       f = _makeSensibleTouched(f, "LEAVE");
4222       signal = "touch";
4223     }
4224     if( signal === "touchedStationary" ) { // fix as touched signal is really "mouseState"?
4225       f = _makeSensibleTouched(f, "STATIONARY");
4226       signal = "touch";
4227     }
4228     if( signal === "touchedInterrupted" ) { // fix as touched signal is really "mouseState"?
4229       f = _makeSensibleTouched(f, "INTERRUPTED");
4230       signal = "touch";
4231     }
4232
4233     for(ai = 0; ai < actors.length; ai++) {
4234       actor = root.findChildByName( actors[ai] );
4235       actor.connect( signal, f );
4236     }
4237   }
4238
4239   if(condition) {
4240     // _connectToCondition( actors, condition, _makeCallback(arguments) );
4241     root = dali.stage.getRootLayer();
4242     f = _makeCallback(arguments);
4243
4244     for(ai = 0; ai < actors.length; ai++) {
4245       actor = root.findChildByName( actors[ai] );
4246       actor.setPropertyNotification(condition.property,
4247                                     condition.type, condition.arg0, condition.arg1,
4248                                     f);
4249     }
4250   }
4251
4252 // when("myimage", condition("touch", "inside", 0, 100),
4253 // or
4254 // when("myimage", "touch",
4255 //       ***
4256 //       dali.ActorWrapper.prototype.connect = function(signalName, callback) {
4257 //     if(d.action === "set") {
4258 //       var animationActors = d.actors;
4259 //       if( animationActors.length === 0 ) {
4260 //         animationActors = actors;
4261 //       }
4262 //       var a = new dali.Animation(0);
4263 // // dali.AnimationWrapper.prototype.animateTo = function(object, propertyName, value, alphaFunction, delay, duration) {
4264 // //dali.AnimationWrapper.prototype.animateBy = function(object, propertyName, value, alphaFunction, delay, duration) {
4265 // //dali.AnimationWrapper.prototype.animatePath = function(object, pathObject, forward, alphaFunction, delay, duration) {
4266 //       for(var ai =0; ai < animationActors.length; ai++) {
4267 //         for(var animi =0; animi < d.animation; animi++) {
4268 //           var animEntry = d.animation[animi];
4269 //           if( d.animate == "animatePath") {
4270 //             a.animatePath(animationActors[ai], animEntry.path, animEntry.forward, animEntry.alpha,
4271 //                           animEntry.delay, animEntry.duration);
4272
4273 //           } else if( d.animate == "animateBetween") {
4274 //             a.animateBetween(animationActors[ai], d.property,
4275 //                              animEntry.fromValue, animEntry.toValue,
4276 //                              animEntry.alpha, animEntry.delay, animEntry.duration);
4277 //           } else {
4278 //             // call animateTo,animateBy,
4279 //             a[animEntry.animate](animationActors[ai], d.property, animEntry.value, animEntry.alpha,
4280 //                                  animEntry.delay, animEntry.duration);
4281 //           }
4282 //         }
4283 //   }
4284
4285   // var animiations = [];
4286
4287   // for(var i = 2; i < arguments.length; i++) {
4288   //   var d = arguments[i];
4289   //   if( d.action === "set" ) {
4290   //     // var ret = { action: "set",
4291   //     //             actors: [],
4292   //     //             property: null,
4293   //     //             condition: null,
4294   //     //             animation: []
4295   //     //           };
4296   //     for(var ai = 0; ai < d.actors.length; ai++) {
4297   //       d.actors[ai]
4298   //     }
4299   //   }
4300
4301   //   for(var j = 0; j < d.length; j++) {
4302   //     if(signal) { // then its signal actions
4303   //       d.name = signal;
4304   //       templates[actorName].signals.push(d[j]);
4305   //     } else { // its property notifications
4306   //       d.condition = condition;
4307   //       d.property = property;
4308   //       templates[actorName].notifications.push(d[j]);
4309
4310   // index = 2;
4311
4312   // // but we could also be specifying a property notification so...
4313   // //
4314   // var condition;
4315   // var value;
4316   // if(typeof arguments[index] === "string") {
4317   //   var lowerCase = arguments[index].toLowerCase();
4318   //   if("insideoutsidegreaterthanlessthan".indexOf(lowerCase)) {
4319   //     property = signal;
4320   //     signal = null;
4321   //     condition = lowerCase;
4322   //     index += 1;
4323   //     value = arguments[index];
4324   //     index += 1;
4325   //     if( condition === "inside" || condition === "outside" ) {
4326   //       assert( value.length === 2, "Inside/Outside condition must specify min,max");
4327   //       assert(typeof value[0] === "number" && typeof value[1] === "number", "Conditions must be numbers");
4328   //     }
4329   //     if(condition === "lessthan" || condition === "greaterthan") {
4330   //       assert(value.length === 1, "LessThan/GreaterThan condition must specify one value");
4331   //       assert(typeof value === "number", "Conditions must be numbers");
4332   //     }
4333   //   }
4334   // }
4335
4336   // // The reset are objects created by the set or call function
4337   // var templates = _buildDescription.templates;
4338
4339   // for( var actorName in actors ) {
4340   //   // the other args come from functions that generate json
4341   //   for(var i = index; i < arguments.length; i++) {
4342   //     var d = arguments[i];
4343   //     for(var j = 0; j < d.length; j++) {
4344   //       if(signal) { // then its signal actions
4345   //         d.name = signal;
4346   //         templates[actorName].signals.push(d[j]);
4347   //       } else { // its property notifications
4348   //         d.condition = condition;
4349   //         d.property = property;
4350   //         templates[actorName].notifications.push(d[j]);
4351   //       }
4352   //     }
4353   //   }
4354   // }
4355
4356 } // when()
4357
4358
4359 // function animation() {
4360 //   "use strict";
4361
4362 //   var name = arguments[0];
4363 //   var anim = {};
4364 //   for(var i = 1; i < arguments.length; i++) {
4365 //     var d = arguments[i];
4366
4367 //     if(d.length === undefined) {  // then array from set
4368
4369 //     } else {
4370 //       extend( anim, d );
4371 //     }
4372 //   }
4373
4374 // }
4375
4376
4377 //
4378 // pseudo dali DSL
4379 //
4380
4381 // stage(
4382 //  layer({
4383 //    width: 400,
4384 //    tag: "scroll"
4385 //    actors:[
4386 //            image({filename:"animage,
4387 //                   name: "myimage",
4388 //                   tag: "scrollitem",
4389 //                   width: 200,
4390 //                   height: 100}),
4391 //            text({text:"sometext,
4392 //                  tag: "scrollitem",
4393 //                  width:10})
4394 //           ]
4395 //  )
4396 // )
4397
4398 // when("myimage", condition("touch", "inside", 0, 100),
4399 // or
4400 // when("myimage", "touch",
4401 //      call(myfunction),
4402 //      call(myfunction, arg1),
4403 //      and("animation-ends"),
4404 //      set("myimage", "size", to([10,10,10]),
4405 //                             to([10,10,10], 0,3, "ease_in")),
4406 //                             path(0,3, "ease_in", "path0")),
4407 //                             between([0,0,0], [10,10,10], 0,3, "ease_in")),
4408 //                             to([0,0,0], 0, 3)
4409 //     set(tagged("scrollitem), path(0,3, "ease_in", "path0")),
4410 //     set(excludeFrom(tagged("scrollitem"), "myimage"), path(0,3, "ease_in", "path0")),
4411 //     then("myimage", "hide"),
4412 //     then("quit"),
4413 //     then("play", "myanim"),
4414 //     thenOnChild("myimage", "child", "hide"),
4415 //     animate("name"),
4416 //        )
4417
4418 // constraints?
4419 // on("myimage", "position", between(0, 100),
4420
4421
4422
4423 //------------------------------------------------------------------------------
4424 // test helper functions
4425 //------------------------------------------------------------------------------
4426
4427 function clear() {
4428   var root = dali.stage.rootRotationActor;
4429   var children = root.getChildren();
4430
4431   for (var i = 0, len = children.length; i < len; i++) {
4432     root.remove(children[i]);
4433     children[i].delete(); // delete the wrapper
4434   }
4435   //  root.delete(); // wrapper
4436 }
4437
4438 function square(color, size) {
4439   var a = dali.createSolidColorActor(color, 0, [0, 0, 0, 1], 0);
4440   a.size = size;
4441   return a;
4442 }
4443
4444 function threeSquares() {
4445   var root = dali.stage.rootRotationActor;
4446
4447   var a = square([1, 0, 0, 1], [200, 200, 0]);
4448   a.name = "red";
4449   a.position = [-100, 0, -20];
4450   root.add(a);
4451   a.delete();
4452
4453   a = square([0, 1, 0, 1], [200, 200, 0]);
4454   a.name = "green";
4455   a.position = [0, -100, -10];
4456   root.add(a);
4457   a.delete();
4458
4459   a = square([0, 0, 1, 1], [200, 200, 0]);
4460   a.name = "blue";
4461   a.position = [0, -100, 0];
4462   root.add(a);
4463   a.delete();
4464
4465   //  root.delete();
4466 }
4467
4468 function threeSquares2() {
4469   var root = dali.stage.rootRotationActor;
4470
4471   var red = square([1, 0, 0, 1], [200, 200, 0]);
4472   red.name = "red";
4473   red.position = [-100, 0, 20];
4474   red.size = [10, 10, 0];
4475   root.add(red);
4476
4477   var green = square([0, 1, 0, 1], [200, 200, 0]);
4478   green.name = "green";
4479   green.position = [0, -100, 0];
4480   green.orientation = [0, 0, 20];
4481   green.size = [200, 200, 0];
4482
4483   var blue = square([0, 0, 1, 1], [200, 200, 0]);
4484   blue.name = "blue";
4485   blue.position = [0, 0, 10];
4486   blue.parentOrigin = [0, 0, 0];
4487   blue.size = [100, 100, 0];
4488   green.add(blue);
4489   root.add(green);
4490
4491   red.delete(); // wrapper
4492   green.delete(); // wrapper
4493   blue.delete(); // wrapper
4494
4495   //  root.delete();
4496 }
4497
4498 function collectByName(collection) {
4499   var root = dali.stage.rootRotationActor;
4500   if (collection === undefined) {
4501     collection = {};
4502   }
4503   var op = function(actor) {
4504     if (actor.name) {
4505       collection[actor.name] = actor;
4506     }
4507     return true;
4508   };
4509
4510   dali.debug.depthVisit(root, op, true);
4511
4512   return collection;
4513 }
4514
4515
4516 function first() {
4517   return dali.stage.getRenderTaskList().getTask(0);
4518 }
4519
4520 function second() {
4521   return dali.stage.getRenderTaskList().getTask(1);
4522 }
4523
4524 function third() {
4525   return dali.stage.getRenderTaskList().getTask(2);
4526 }
4527
4528 function firstCamera() {
4529   return dali.stage.getRenderTaskList().getTask(0).getCameraActor();
4530 }
4531
4532 function secondCamera() {
4533   return dali.stage.getRenderTaskList().getTask(1).getCameraActor();
4534 }
4535
4536 function thirdCamera() {
4537   return dali.stage.getRenderTaskList().getTask(2).getCameraActor();
4538 }
4539
4540 function resize(w, h) {
4541   dali.setCanvasSize(w, h);
4542 }
4543
4544 function compareProperties(a1, a2) {
4545   var props1 = a1.getProperties();
4546   var props2 = a2.getProperties();
4547   var props = new Set();
4548   for (var i = 0, len = props1.size(); i < len; i++) {
4549     props.add(props1.get(i));
4550   }
4551
4552   for (i = 0, len = props2.size(); i < len; i++) {
4553     var n = props2.get(i);
4554     if (!props.has(n)) {
4555       console.log("A1 missing :" + n);
4556     }
4557   }
4558
4559   var doit = function(item) {
4560     var v1 = a1[item]; // a1.getProperty(item);
4561     var v2 = a2[item]; // a2.getProperty(item);
4562
4563     var isSame;
4564
4565     if (Array.isArray(v1)) {
4566       isSame = (v1.length === v2.length) && v1.every(function(element, index) {
4567         return element === v2[index];
4568       });
4569     } else {
4570       isSame = v1 === v2;
4571     }
4572
4573     if (!isSame) {
4574       console.log(item + ": A1= " + v1 + " A2= " + v2);
4575     }
4576   };
4577
4578   props.forEach(doit);
4579 }
4580
4581 var EPSILON = 0.005;
4582
4583 function compareArrays(a, b) {
4584   "use strict";
4585   if (Array.isArray(a) && Array.isArray(b)) {
4586     if (a.length === b.length) {
4587       for (var i = 0, len = a.length; i < len; i++) {
4588         if (Array.isArray(a[i])) {
4589           if (Array.isArray(b[i])) {
4590             if (!compareArrays(a[i], b[i])) {
4591               return false;
4592             }
4593           } else {
4594             return false;
4595           }
4596         } else {
4597           if (typeof (a[i]) === "number") {
4598             if (typeof (b[i]) !== "number") {
4599               return false;
4600             } else {
4601               if (Math.abs(a[i]) > Math.abs(b[i]) + EPSILON ||
4602                   Math.abs(a[i]) < Math.abs(b[i]) - EPSILON) {
4603                 return false;
4604               }
4605             }
4606           } else {
4607             if (a[i] !== b[i]) {
4608               return false;
4609             }
4610           }
4611         }
4612       }
4613       return true;
4614     }
4615   }
4616   return false;
4617 }
4618
4619 function countAllProperties() {
4620   var count = 0;
4621   var tr = new dali.TypeRegistry();
4622   var names = tr.getTypeNames();
4623   for (var i = 0, len = names.size(); i < len; i++) {
4624     var ti = tr.getTypeInfo(names.get(i));
4625     var props = ti.getProperties();
4626     count += props.size();
4627   }
4628   return count;
4629 }
4630
4631 function native2ascii(str) {
4632   "use strict";
4633   // really this function allows only GLSL permittable chars
4634   var out = "";
4635   for (var i = 0; i < str.length; i++) {
4636     if ( 0x20 <= str.charCodeAt(i) && str.charCodeAt(i) <= 0x7E) {
4637       // normal characters
4638       out += str.charAt(i);
4639     } else if( 0x9 <= str.charCodeAt(i) && str.charCodeAt(i) <= 0xD) {
4640       // new lines and tabs
4641       out += str.charAt(i);
4642     }
4643   }
4644   return out;
4645 }
4646
4647
4648 var getGL = function() {
4649   return canvas.getContext("webgl");
4650 };
4651
4652 var getAnimation = function() {
4653   "use strict";
4654   return animationList[animationSelectionIndex].animation;
4655 };
4656
4657 var getActor = function() {
4658   "use strict";
4659   return eventHandler.touchedActor;
4660 };
4661
4662
4663 //------------------------------------------------------------------------------
4664 // Unit test class
4665 //------------------------------------------------------------------------------
4666 function Test() {
4667   "use strict";
4668 }
4669
4670 Test.prototype.hierarchy = function() {
4671   "use strict";
4672   console.log("test_hierarchy...");
4673
4674   // function onTouched(actor) {
4675   //   // console.log("touched " + actor.$$.ptr + " " + actor.position);
4676   //   eventHandler.onTouched(actor);
4677   // }
4678
4679   var actor = new dali.Actor();
4680   actor.parentOrigin = [0.5, 0.5, 0.5];
4681   actor.anchorPoint = [0.5, 0.5, 0.5];
4682   actor.text = "actor";
4683   actor.name = actor.text;
4684   actor.size = [100, 100, 1];
4685   actor.position = [0, 0, 10];
4686   dali.stage.add(actor);
4687
4688   var hello = new dali.Actor();
4689   // hello.connect("touch", onTouched);
4690   hello.text = "hello";
4691   hello.name = hello.text;
4692   actor.add(hello);
4693
4694   var hellochild = new dali.Actor();
4695   // hellochild.connect("touch", onTouched);
4696   hellochild.text = "hello-child";
4697   hellochild.name = hellochild.text;
4698   hello.add(hellochild);
4699
4700   var hellochild2 = new dali.Actor();
4701   // hellochild2.connect("touch", onTouched);
4702   hellochild2.text = "hello-child2";
4703   hellochild2.name = hellochild2.text;
4704   hello.add(hellochild2);
4705
4706   var hellochildchild = new dali.Actor();
4707   // hellochildchild.connect("touch", onTouched);
4708   hellochildchild.text = "hello-child-child1";
4709   hellochildchild.name = "hello-child-child1";
4710   hellochildchild.name = hellochildchild.text;
4711   hellochild.add(hellochildchild);
4712
4713
4714   var depthfirst = actor.findAllChildren();
4715
4716   assert(actor.getChildCount() === 1);
4717   // assert(actor.getChildAt(0).text === "hello");
4718   // assert(actor.findChildByName("hello-child-child1").text = "hello-child-child1");
4719   // assert(hello.getParent().text === "actor");
4720   // assert(depthfirst[depthfirst.length - 1].text === "hello-child2");
4721
4722   var directChildren = actor.directChildren();
4723
4724   assert(directChildren.length === 1);
4725   assert(directChildren[0].getId() === hello.getId());
4726
4727   actor.position = [100, 100, 0];
4728
4729   var root = dali.stage.rootRotationActor;
4730
4731   actor.remove(hello);
4732   assert(actor.getChildCount() === 0);
4733
4734   actor.add(hello);
4735   assert(actor.getChildCount() === 1);
4736
4737   var rootLayerCount = root.getChildCount();
4738   dali.stage.remove(actor); // check these don't assert
4739   assert(root.getChildCount() === rootLayerCount - 1);
4740
4741   dali.stage.add(actor);
4742   assert(root.getChildCount() === rootLayerCount);
4743
4744   assert(root.findChildByName("none") === null);
4745
4746   // actor.connect("touch", onTouched);
4747
4748   // var inserted = new dali.TextActor(); // TextActor no more RIP
4749   // inserted.parentOrigin = [0.5, 0.5, 0.5];
4750   // inserted.anchorPoint = [0.5, 0.5, 0.5];
4751   // inserted.text = "inserted";
4752   // inserted.name = inserted.text;
4753   // inserted.size = [100, 100, 1];
4754   // inserted.position = [0, 0, 50];
4755   // actor.insert(1, inserted);
4756   // assert(actor.getChildAt(1).text === "inserted");
4757
4758   clear();
4759   console.log("  -> ok test_hierarchy");
4760 };
4761
4762 Test.prototype.registerProperty = function() {
4763   "use strict";
4764   console.log("test_registerPropery...");
4765   var s = dali.stage;
4766   var root = s.rootRotationActor;
4767
4768   var another = new dali.Actor();
4769   another.parentOrigin = [0.5, 0.5, 0.5];
4770   another.anchorPoint = [0.5, 0.5, 0.5];
4771   another.text = "peppa";
4772   another.name = another.text;
4773   another.size = [100, 100, 1];
4774   another.position = [-50, 100, 0];
4775   root.add(another);
4776
4777   var c = root.getChildAt(root.getChildCount() - 1);
4778   //var n = c.getChildCount();
4779   var p = c.getParent();
4780   assert(p.getId() == root.getId());
4781
4782   var matrix = c.worldMatrix;
4783
4784   assert(matrix.length === 16);
4785
4786   // todo - no longer supported (?)
4787   // another.registerProperty("data_output", true);
4788   // assert(another.getPropertyTypeFromName("data_output") === "BOOLEAN");
4789   // assert(another.data_output === true);
4790   // another.data_output = false;
4791   // assert(another.data_output === false);
4792   // dali.__updateOnce();
4793   // another.data_output = 2.5;
4794   // assert(another.data_output === 2.5);
4795   // assert(another.getPropertyTypeFromName("data_output") === "FLOAT");
4796
4797   clear();
4798   console.log("  -> ok test_registerPropery");
4799 };
4800
4801 Test.prototype.js_math = function() {
4802   console.log("test_js_math...");
4803   assert(dali.vectorLength([1, 2, 3, 4]) === Math.sqrt(1 * 1 + 2 * 2 + 3 * 3));
4804   assert(dali.vectorLengthSquared(dali.normalize([0, 0, 0, 1])) === 0);
4805
4806   // for(var f=0; f < 6; f+=1)
4807   // {
4808   var f = 2;
4809   assert(1 === dali.vectorLengthSquared(dali.normalize([Math.cos(f) * 10.0,
4810                                                         Math.cos(f + 1.0) * 10.0,
4811                                                         Math.cos(f + 2.0) * 10.0,
4812                                                         1.0
4813                                                        ])));
4814
4815   function assertArray(a, b, epsilon) {
4816     assert(a.length === b.length);
4817     for (var i = 0, len = a.length; i < len; ++i) {
4818       assert(a[i] > b[i] - epsilon && a[i] < b[i] + epsilon);
4819     }
4820   }
4821
4822   assertArray(dali.axisAngleToQuaternion([1.0, 2.0, 3.0, Math.PI / 3.0, Math.PI / 2.0]), [0.189, 0.378, 0.567, 0.707], 0.001);
4823
4824   assertArray(dali.quaternionToAxisAngle([1.1, 3.4, 2.7, 0.932]), [3.03, 9.38, 7.45, 0.74],
4825               0.01);
4826
4827   assertArray(dali.vectorCross([0, 1, 0], [0, 0, 1]), [1, 0, 0], 0.001);
4828
4829   assertArray(dali.vectorAdd([1, 2, 3], [2, 3, 4], [1, 1, 1]), [4, 6, 8], 0.001);
4830
4831   var mq = dali.vectorAdd(dali.vectorCross([0.045, 0.443, 0.432], [0.612, 0.344, -0.144]),
4832                           dali.vectorByScalar([0.612, 0.344, -0.144], 0.784),
4833                           dali.vectorByScalar([0.045, 0.443, 0.432], 0.697));
4834
4835   assertArray(dali.quatByQuat([0.045, 0.443, 0.432, 0.784], [0.612, 0.344, -0.144, 0.697]), [mq[0], mq[1], mq[2], (0.784 * 0.697) - dali.vectorDot([0.045, 0.443, 0.432], [0.612, 0.344, -0.144])],
4836               0.001);
4837
4838   clear();
4839   console.log("  -> ok test_js_math");
4840 };
4841
4842 Test.prototype.getset = function() {
4843   "use strict";
4844   console.log("test_getset...");
4845   threeSquares();
4846   var col = {};
4847   collectByName(col);
4848   var actor = col.red;
4849   var p = actor.position;
4850   actor.position = [1, 1, 1];
4851   assert(compareArrays(actor.position, [1, 1, 1]));
4852   actor.position = [3, 3, 3];
4853   assert(compareArrays(actor.position, [3, 3, 3]));
4854   actor.position = p;
4855
4856   clear();
4857   console.log("  -> ok test_getset");
4858 };
4859
4860 Test.prototype.animation_spline = function() {
4861   "use strict";
4862   console.log("test_animation_spline...");
4863   threeSquares();
4864   var col = {};
4865   collectByName(col);
4866   var actor = col.red;
4867
4868   var a = new dali.Animation(0);
4869   var path = new dali.Path();
4870
4871   path.points = [
4872     [-150, -50, 0],
4873     [0.0, 70.0, 0.0],
4874     [190.0, -150.0, 0.0]
4875   ];
4876
4877   assert(compareArrays(path.points, [
4878     [-150, -50, 0],
4879     [0.0, 70.0, 0.0],
4880     [190.0, -150.0, 0.0]
4881   ]));
4882
4883   dali.generateControlPoints(path, 0.35);
4884
4885   assert(compareArrays(path.controlPoints, [
4886     [-97.5, -8, 0],
4887     [-66.94940948486328, 76.16658020019531, 0],
4888     [101.31224060058594, 60.66832733154297, 0],
4889     [123.5, -73, 0]
4890   ]));
4891
4892   a.setDuration(3);
4893   a.animatePath(actor, path, [1, 0, 0], dali.AlphaFunction.LINEAR, 0, 3);
4894   a.play();
4895
4896   function checkPos() {
4897     assert(actor.position = path.points[2]);
4898     clear();
4899     actor.delete();
4900     path.delete();
4901     a.delete();
4902     console.log("  -> ok test_animation_spline");
4903   }
4904
4905   window.setTimeout(checkPos, 4000);
4906 };
4907
4908 Test.prototype.animation = function() {
4909   "use strict";
4910   console.log("test_animation...");
4911   threeSquares();
4912   var col = {};
4913   collectByName(col);
4914   var actor = col.red;
4915
4916   var a = new dali.Animation(0);
4917   a.setDuration(3);
4918   a.animateTo(actor, "position", [20, 0, 0], dali.AlphaFunction.LINEAR, 0, 3);
4919   a.play();
4920
4921   function checkAnimateBetween() {
4922     assert(actor.position = [0, 0, -30]);
4923     clear();
4924     a.delete();
4925     actor.delete();
4926
4927     console.log("  -> ok test_animation");
4928   }
4929
4930   function checkAnimateBy() {
4931     assert(actor.position = [120, 100, 0]);
4932
4933     a.clear();
4934     a.animateBetween(actor,
4935                      "position", [ [ 0,  [10,20,30] ],
4936                                    [ 1.0,[0, 0, -30] ] ],
4937                      "linear",
4938                      0,
4939                      3,
4940                      "linear");
4941     a.play();
4942     window.setTimeout(checkAnimateBetween, 4000);
4943   }
4944
4945   function checkAnimateTo() {
4946     assert(actor.position = [20, 0, 0]);
4947     actor.position = [100, 100, 0];
4948
4949     a.clear(); // var a = new dali.Animation(0);
4950     a.setDuration(3);
4951     a.animateBy(actor, "position", [20, 0, 0], dali.AlphaFunction.LINEAR, 0, 3);
4952     a.play();
4953
4954     window.setTimeout(checkAnimateBy, 4000);
4955   }
4956
4957   window.setTimeout(checkAnimateTo, 4000);
4958 };
4959
4960 Test.prototype.onePane = function() {
4961   var w = dali.canvas.width;
4962   var h = dali.canvas.height;
4963   var col = dali.getClearColor(0);
4964   dali.onePane();
4965   dali.setFrontView(0, 0, 0, w, h);
4966   dali.setClearColor(0, col);
4967 };
4968
4969 Test.prototype.threePane = function() {
4970   var w = dali.canvas.width;
4971   var h = dali.canvas.height;
4972   dali.threePane();
4973   dali.setClearColor(0, [0.4, 0, 0, 1]);
4974   dali.setClearColor(1, [0, 0.4, 0, 1]);
4975   dali.setClearColor(2, [0, 0, 0.4, 1]);
4976   dali.setFrontView(0, 0, 0, w / 2 - 5, h);
4977   dali.setTopView(1, w / 2, 0, w / 2, h / 2 - 5);
4978   dali.setRightView(2, w / 2, h / 2 + 5, w / 2, h / 2 - 5);
4979 };
4980
4981 Test.prototype.twoPane = function() {
4982   var w = dali.canvas.width;
4983   var h = dali.canvas.height;
4984   dali.twoPane();
4985   dali.setFrontView(0, 0, 0, w / 2 - 10, h);
4986   dali.setTopView(1, 210, 0, w / 2 - 10, h);
4987   dali.setClearColor(0, [0.4, 0, 0, 1]);
4988   dali.setClearColor(1, [0, 0.4, 0, 1]);
4989 };
4990
4991 Test.prototype.views = function() {
4992   "use strict";
4993   console.log("test_views");
4994
4995   var w = dali.canvas.width;
4996   var h = dali.canvas.height;
4997   var col = dali.getClearColor(0);
4998   console.log(col);
4999
5000   function one() {
5001     dali.onePane();
5002     dali.setFrontView(0, 0, 0, w, h);
5003     dali.setClearColor(0, col);
5004   }
5005
5006   function three() {
5007     dali.threePane();
5008     dali.setClearColor(0, [0.4, 0, 0, 1]);
5009     dali.setClearColor(1, [0, 0.4, 0, 1]);
5010     dali.setClearColor(2, [0, 0, 0.4, 1]);
5011     dali.setFrontView(0, 0, 0, w / 2 - 5, h);
5012     dali.setTopView(1, w / 2, 0, w / 2, h / 2 - 5);
5013     dali.setRightView(2, w / 2, h / 2 + 5, w / 2, h / 2 - 5);
5014
5015     window.setTimeout(one, 1000);
5016   }
5017
5018   function two() {
5019     dali.twoPane();
5020     dali.setFrontView(0, 0, 0, w / 2 - 10, h);
5021     dali.setTopView(1, 210, 0, w / 2 - 10, h);
5022     dali.setClearColor(0, [0.4, 0, 0, 1]);
5023     dali.setClearColor(1, [0, 0.4, 0, 1]);
5024
5025     window.setTimeout(three, 1000);
5026   }
5027
5028   one();
5029
5030   window.setTimeout(two, 1000);
5031 };
5032
5033 Test.prototype.blinking = function() {
5034   "use strict";
5035   var layer = new dali.Layer();
5036   layer.name = "frameLayer";
5037   dali.stage.add(layer);
5038
5039   var a = dali.createSolidColorActor([0.5, 0.5, 0.5, 1],
5040                                      false, [0, 0, 0, 1],
5041                                      0);
5042   a.size = [100,100,1];
5043
5044   layer.add(a);
5045
5046   var camera = firstCamera();
5047
5048   camera.position = [ camera.position[0]+10, camera.position[1]+20, camera.position[2] + 10 ];
5049
5050   layer.delete();   // wrapper
5051   a.delete();       // wrapper
5052   camera.delete();  // wrapper
5053 };
5054
5055 Test.prototype.uniformMetaData = function() {
5056   for(var i = 0; i < shaderSources.length; i++) {
5057     console.log(dali.uniformMetaData(shaderSources[i].vertex, shaderSources[i].fragment));
5058   }
5059 };
5060
5061 Test.prototype.signals = function() {
5062   "use strict";
5063   console.log("test_signals...");
5064
5065   function onStage() {
5066     console.log("   -> ok test signals");
5067     //eventHandler.onTouched(actor);
5068   }
5069
5070   var actor = new dali.Actor();
5071   actor.parentOrigin = [0.5, 0.5, 0.5];
5072   actor.anchorPoint = [0.5, 0.5, 0.5];
5073   actor.text = "actor";
5074   actor.name = actor.text;
5075   actor.size = [100, 100, 1];
5076   actor.position = [0, 0, 10];
5077
5078   actor.connect("on-stage", onStage);
5079
5080   dali.stage.add(actor);
5081 };
5082
5083 Test.prototype.shaderInfo = function() {
5084   "use strict";
5085   var info = new dali.ShaderInfo();
5086
5087   var vertex;
5088   var fragment;
5089
5090   vertex = "\n" +
5091     "attribute mediump vec3 aPosition;\n" +
5092     "attribute mediump vec2 aTexCoord;\n" +
5093     "varying mediump vec2 vTexCoord;\n" +
5094     "uniform mediump vec3 uSize;\n" +
5095     "// uniform mediump vec3 unusedUniform;\n" +
5096     "uniform mediump mat4 uModelView;\n" +
5097     "uniform mediump mat4 uProjection;\n" +
5098     "\n" +
5099     "void main(void)\n" +
5100     "{\n" +
5101     "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
5102     "  gl_Position.xyz *= uSize;\n" +
5103     "  vTexCoord = aTexCoord;\n" +
5104     "}\n";
5105
5106   fragment = "precision mediump float;\n" +
5107     "\n" +
5108     "uniform sampler2D sTexture;\n" +
5109     "uniform mediump vec4 uMyColor; // {min:[0,0,0,0], max:[1,1,1,1]}\n" +
5110     "uniform mediump vec4 uColor;\n" +
5111     "varying mediump vec2 vTexCoord;\n" +
5112     "\n" +
5113     "void main()\n" +
5114     "{\n" +
5115     "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * uMyColor;\n" +
5116     "}\n";
5117
5118   var canvas = document.createElement("canvas");
5119   var meta = info.fromCompilation(canvas.getContext("webgl"), vertex, fragment);
5120
5121   var uniforms = { uSize: 1,
5122                    uModelView: 1,
5123                    uProjection: 1,
5124                    uMyColor: 1,
5125                    uColor: 1
5126                  };
5127
5128   assert(meta.hasError === false);
5129   var name;
5130   var metaUniformName;
5131   var found;
5132
5133   for(name in uniforms) {
5134     found = false;
5135     for(metaUniformName in meta.uniforms) {
5136       if(metaUniformName === name) {
5137         found = true;
5138         break;
5139       }
5140     }
5141     assert(found, "missing:" + name);
5142   }
5143
5144   assert(compareArrays(meta.uniformUISpec.uMyColor.min, [0, 0, 0, 0]));
5145   assert(compareArrays(meta.uniformUISpec.uMyColor.max, [1, 1, 1, 1]));
5146
5147
5148   meta = info.fromRegEx(vertex, fragment);
5149
5150   assert(meta.hasError === false);
5151
5152   for(name in uniforms) {
5153     found = false;
5154     for(metaUniformName in meta.uniforms) {
5155       if(metaUniformName === name) {
5156         found = true;
5157         break;
5158       }
5159     }
5160     assert(found, "missing:" + name);
5161   }
5162
5163   assert(compareArrays(meta.uniformUISpec.uMyColor.min, [0, 0, 0, 0]));
5164   assert(compareArrays(meta.uniformUISpec.uMyColor.max, [1, 1, 1, 1]));
5165
5166   console.log("   -> ok test shaderInfo");
5167 };
5168
5169 //------------------------------------------------------------------------------
5170 // regression test
5171 //------------------------------------------------------------------------------
5172
5173 Test.prototype.regression = function() {
5174   "use strict";
5175   this.hierarchy();
5176   this.registerProperty();
5177   this.js_math();
5178   this.getset();
5179   this.animation();
5180   this.animation_spline();
5181   // this.shadereffect1();
5182   this.views();
5183   this.signals();
5184   this.shaderInfo();
5185 };
5186
5187 Test.prototype.remote_execution = function() {
5188   "use strict";
5189   this.regression();
5190 };
5191
5192 Test.prototype.stacking = function() {
5193   "use strict";
5194
5195   eventHandler.selectActor( dali.stage.rootRotationActor );
5196
5197   var a = dali.createSolidColorActor([1.0, 0.0, 0.0, 1.0],
5198                                      false, [0, 0, 0, 1],
5199                                      0);
5200   app.addActor(a);
5201
5202   eventHandler.selectActor( a );
5203
5204   var b = dali.createSolidColorActor([0.0, 0.0, 1.0, 1.0],
5205                                      false, [0, 0, 0, 1],
5206                                      0);
5207   app.addActor(b);
5208
5209   a.sizeWidth = a.sizeHeight = 100;
5210   b.sizeWidth = b.sizeHeight = 50;
5211
5212   b.sizeWidth = 150;
5213
5214   return [a, b];
5215 };
5216
5217
5218 var runTest = function(functionName) {
5219   "use strict";
5220
5221   clear();
5222
5223   dali.stage.setBackgroundColor([0.3, 0.3, 0.3, 1]);
5224
5225   var test = dali[functionName]();
5226
5227   if( test )
5228   {
5229     if( !test.complete() )
5230     {
5231       function check() {
5232         if( !test.complete() ) {
5233           window.setTimeout(checkPos, 500);
5234         } else {
5235           console.log("test success");
5236         }
5237       }
5238     }
5239   }
5240
5241 };
5242
5243 //------------------------------------------------------------------------------
5244 // scratch
5245 //------------------------------------------------------------------------------
5246 function animateShaderEffect2(actor) {
5247   "use strict";
5248   var shader = new dali.ShaderEffect({
5249     vertex: shaderSource2.vertex,
5250     fragment: shaderSource2.fragment
5251   });
5252
5253   actor.setShaderEffect(shader);
5254
5255   var final = [5, 5, 5, 1];
5256
5257   var a = new dali.Animation(0);
5258   a.setDuration(3);
5259   a.setLooping(true);
5260   a.animateTo(shader, "weight", final, dali.AlphaFunction.LINEAR, 0, 3);
5261
5262   a.play();
5263
5264   a.delete();
5265
5266 }
5267
5268
5269 var testfile = { // output from clara.io "Threejs scene output"
5270   "metadata": {
5271     "version": 4.3, // This isnt as its documented on threejs website
5272     "type": "Object", // and the general format looks more like format V3.
5273     "generator": "ObjectExporter"
5274   },
5275   "geometries": [{
5276     "uuid": "2f167add-e571-47c2-9da2-6f0e45cc1119",
5277     "type": "Geometry",
5278     "data": {
5279       "vertices": [
5280         0.5,
5281         0.5,
5282         0.5,
5283         0.5,
5284         0.5, -0.5,
5285         0.5, -0.5,
5286         0.5,
5287         0.5, -0.5, -0.5, -0.5,
5288         0.5, -0.5, -0.5,
5289         0.5,
5290         0.5, -0.5, -0.5, -0.5, -0.5, -0.5,
5291         0.5
5292       ],
5293       "normals": [
5294         1,
5295         0,
5296         0, -1,
5297         0,
5298         0,
5299         0,
5300         1,
5301         0,
5302         0, -1,
5303         0,
5304         0,
5305         0,
5306         1,
5307         0,
5308         0, -1
5309       ],
5310       "uvs": [
5311         [
5312           0,
5313           1,
5314           0,
5315           0,
5316           1,
5317           0,
5318           1,
5319           1
5320         ]
5321       ],
5322       "faces": [
5323         56,
5324
5325         0,
5326         2,
5327         3,
5328
5329         0,
5330         1,
5331         2,
5332
5333         0,
5334         0,
5335         0,
5336
5337         0,
5338
5339         56,
5340         0,
5341         3,
5342         1,
5343         0,
5344         2,
5345         3,
5346         0,
5347         0,
5348         0,
5349         0,
5350         56,
5351         4,
5352         6,
5353         7,
5354         0,
5355         1,
5356         2,
5357         1,
5358         1,
5359         1,
5360         1,
5361         56,
5362         4,
5363         7,
5364         5,
5365         0,
5366         2,
5367         3,
5368         1,
5369         1,
5370         1,
5371         1,
5372         56,
5373         4,
5374         5,
5375         0,
5376         0,
5377         1,
5378         2,
5379         2,
5380         2,
5381         2,
5382         2,
5383         56,
5384         4,
5385         0,
5386         1,
5387         0,
5388         2,
5389         3,
5390         2,
5391         2,
5392         2,
5393         2,
5394         56,
5395         7,
5396         6,
5397         3,
5398         0,
5399         1,
5400         2,
5401         3,
5402         3,
5403         3,
5404         3,
5405         56,
5406         7,
5407         3,
5408         2,
5409         0,
5410         2,
5411         3,
5412         3,
5413         3,
5414         3,
5415         3,
5416         56,
5417         5,
5418         7,
5419         2,
5420         0,
5421         1,
5422         2,
5423         4,
5424         4,
5425         4,
5426         4,
5427         56,
5428         5,
5429         2,
5430         0,
5431         0,
5432         2,
5433         3,
5434         4,
5435         4,
5436         4,
5437         4,
5438         56,
5439         1,
5440         3,
5441         6,
5442         0,
5443         1,
5444         2,
5445         5,
5446         5,
5447         5,
5448         5,
5449         56,
5450         1,
5451         6,
5452         4,
5453         0,
5454         2,
5455         3,
5456         5,
5457         5,
5458         5,
5459         5
5460       ]
5461     }
5462   }],
5463   "materials": [{
5464     "uuid": "14D499F1-27EF-45BF-A457-FD24DAB11205",
5465     "type": "MeshPhongMaterial",
5466     "color": 11579568,
5467     "ambient": 11579568,
5468     "emissive": 0,
5469     "specular": 0,
5470     "shininess": 50,
5471     "opacity": 1,
5472     "transparent": false,
5473     "wireframe": false
5474   }],
5475   "object": {
5476     "uuid": "BFEFB48D-0E6E-46A6-8568-5E258BA17078",
5477     "type": "Scene",
5478     "matrix": [
5479       1,
5480       0,
5481       0,
5482       0,
5483       0,
5484       1,
5485       0,
5486       0,
5487       0,
5488       0,
5489       1,
5490       0,
5491       0,
5492       0,
5493       0,
5494       1
5495     ],
5496     "children": [{
5497       "uuid": "aa901bec-9e47-4b3b-bf3c-4efb0fe5d298",
5498       "name": "Box",
5499       "type": "Mesh",
5500       "geometry": "2f167add-e571-47c2-9da2-6f0e45cc1119",
5501       "material": "14D499F1-27EF-45BF-A457-FD24DAB11205",
5502       "castShadow": true,
5503       "receiveShadow": true,
5504       "matrix": [
5505         1,
5506         0,
5507         0,
5508         0,
5509         0,
5510         1,
5511         0,
5512         0,
5513         0,
5514         0,
5515         1,
5516         0,
5517         0,
5518         0,
5519         0,
5520         1
5521       ]
5522     }]
5523   }
5524 };
5525
5526
5527
5528 //
5529 //
5530 // Event/widget setup
5531 //
5532 //
5533
5534 //------------------------------------------------------------------------------
5535 //
5536 // Helper functions
5537 //
5538 //------------------------------------------------------------------------------
5539 function rebuildDropdown(dropdownElement, db, dbStoreName, optionalItemDataFunc) {
5540   "use strict";
5541   removeAllChildren(dropdownElement);
5542
5543   var func = optionalItemDataFunc;
5544   if( !func ) {
5545     func = function(name) {
5546       return [null, name];
5547     };
5548   }
5549
5550   var li;
5551   var a;
5552   var names = db.getKeys(dbStoreName);
5553
5554   for(var i = 0; i < names.length; i++) {
5555     li = document.createElement("li");
5556     var hrefText = func(names[i]);
5557     if( hrefText[0] ) {
5558       a = document.createElement("a");
5559       a.href = hrefText[0];
5560       a.text = hrefText[1];
5561     } else {
5562       a = document.createElement("p");
5563       a.textContent = hrefText[1];
5564     }
5565     li.appendChild(a);
5566     dropdownElement.appendChild(li);
5567   }
5568 }
5569
5570
5571 //------------------------------------------------------------------------------
5572 //
5573 // UI General
5574 //
5575 //------------------------------------------------------------------------------
5576 function UIApp() {
5577   "use strict";
5578   var self = this;
5579
5580   self.modalQuestionYesFunction = null;
5581   self.modalQuestionNoFunction = null;
5582
5583   var _modalQuestionYes = function() {
5584     if(self.modalQuestionYesFunction) {
5585       self.modalQuestionYesFunction();
5586     }
5587     self.modalQuestionYesFunction = null;
5588     self.modalQuestionNoFunction = null;
5589   };
5590
5591   var _modalQuestionNo = function() {
5592     if(self.modalQuestionNo) {
5593       self.modalQuestionNo();
5594     }
5595     self.modalQuestionYesFunction = null;
5596     self.modalQuestionNoFunction = null;
5597   };
5598
5599   var _modalInputOk = function() {
5600     if(self.modalInputOkFunction) {
5601       var input = $("#modalInputText")[0];
5602       self.modalInputOkFunction(input.value);
5603     }
5604     self.modalInputOkFunction = null;
5605     self.modalInputCancelFunction = null;
5606   };
5607
5608   var _modalInputCancel = function() {
5609     if(self.modalInputCancel) {
5610       self.modalInputCancel();
5611     }
5612     self.modalInputOkFunction = null;
5613     self.modalInputCancelFunction = null;
5614   };
5615
5616   $("#modalQuestionYes")[0].addEventListener("click", _modalQuestionYes);
5617   $("#modalQuestionNo")[0].addEventListener("click", _modalQuestionNo);
5618
5619   self.modalInputYesFunction = null;
5620   self.modalInputNoFunction = null;
5621
5622   $("#modalInputOk")[0].addEventListener("click", _modalInputOk);
5623   $("#modalInputCancel")[0].addEventListener("click", _modalInputCancel);
5624
5625 }
5626
5627 UIApp.prototype.messageBoxHTML = function(innerHtmlText) {
5628   "use strict";
5629   var modalBody = $("#modalCodeInfoBody")[0];
5630   removeAllChildren(modalBody);
5631   modalBody.innerHTML = innerHtmlText;
5632   $("#modalCodeInfo").modal("show");
5633 };
5634
5635 UIApp.prototype.messageBox = function(message) {
5636   "use strict";
5637   this.messageBoxHTML("<p>" + message + "</p>");
5638 };
5639
5640 UIApp.prototype.questionBox = function(message, yesFunction, noFunction) {
5641   "use strict";
5642   var modalBody = $("#modalQuestionBody")[0];
5643   removeAllChildren(modalBody);
5644   modalBody.innerHTML = "<p>" + message + "</p>";
5645
5646   this.modalQuestionYesFunction = yesFunction;
5647   this.modalQuestionNoFunction = noFunction;
5648
5649   $("#modalQuestion").modal("show");
5650 };
5651
5652 UIApp.prototype.codeInformationBox = function(code) {
5653   "use strict";
5654   var modalBody = $("#modalCodeInfoBody")[0];
5655   removeAllChildren(modalBody);
5656   modalBody.innerHTML = "<pre>" + code + "</pre>";
5657   $("#modalCodeInfo").modal("show");
5658 };
5659
5660 UIApp.prototype.inputbox = function(message, okFunction, cancelFunction) {
5661   "use strict";
5662   var modalBody = $("#modalInputBody")[0];
5663   removeAllChildren(modalBody);
5664   modalBody.innerHTML = "<p>" + message + "</p>";
5665
5666   this.modalInputOkFunction = okFunction;
5667   this.modalInputCancelFunction = cancelFunction;
5668
5669   $("#modalInput").modal("show");
5670 };
5671
5672 UIApp.prototype.getTypedBuffer = function(file, callback) {
5673   "use strict";
5674   if (!file) {
5675     return;
5676   }
5677   var reader = new FileReader();
5678   reader._theFilename = file.name;
5679   reader.onload = function(// e
5680   ) {
5681     var uint8View = new Uint8Array(reader.result); // convert ArrayBuffer into a typed array?
5682     callback(file.name, uint8View);
5683   };
5684
5685   reader.readAsArrayBuffer(file);
5686 };
5687
5688
5689 //------------------------------------------------------------------------------
5690 //
5691 // Javascript UI Tab
5692 //
5693 //------------------------------------------------------------------------------
5694 function UIJavascriptTab() {
5695   "use strict";
5696   var self = this;
5697   self.bufferPrepend = "Buffer Name:";
5698
5699   this.addNewBuffer = function() {
5700     var alreadyExists = function() {
5701       self.addNewBuffer();
5702     };
5703
5704     var inputOk = function(name) {
5705       var data = database.readJavascript(name);
5706       if(data) {
5707         uiApp.messageBox("Name already exsists", alreadyExists);
5708       } else {
5709         var newData = {name: name, source: ""};
5710         database.writeJavascript(newData);
5711         self.rebuildDropdown(database);
5712       }
5713     };
5714
5715     uiApp.inputbox("BufferName?", inputOk);
5716
5717   };
5718
5719   this.renameBuffer = function() {
5720     var writeOK = function() {
5721       var openRequest = database.open();
5722
5723       openRequest.onsuccess = function(event) {
5724         var db = event.target.result;
5725         self.rebuildDropdown(database);
5726         db.close();
5727       };
5728     };
5729
5730     var inputOk = function(name) {
5731       var data = uiJavascriptTab.getData();
5732       data.name = name;
5733       database.writeJavascript(data, writeOK);
5734     };
5735
5736     uiApp.inputbox("BufferName?", inputOk);
5737
5738   };
5739
5740   this.loadJavascript = function(name) {
5741     var data = database.readJavascript(name);
5742
5743     // save current
5744     var currentData = self.getData();
5745     if(currentData) {
5746       database.writeJavascript(currentData);
5747     }
5748
5749     self.setData(data);
5750   };
5751
5752   ace.require("ace/ext/language_tools");
5753   var editor = ace.edit("editorJavascript");
5754
5755   var _thisFunctions = [];
5756   for(var attr in this) {
5757     if( !(attr.startsWith("_") || attr.startsWith("dynCall") || attr.startsWith("invoke") ) ) {
5758       if( typeof this[attr] === "function") {
5759         _thisFunctions.push( attr );
5760       }
5761     }
5762   }
5763
5764   var myCompleter = {
5765     getCompletions: function(theEditor, session, pos, prefix, callback) {
5766       var wordlist = [];
5767       if(prefix === "dali.") {
5768         for(attr in dali) {
5769           if( !(attr.startsWith("_") || attr.startsWith("dynCall") || attr.startsWith("invoke") ) ) {
5770             if( typeof dali[attr] === "function") {
5771               wordlist.push( attr );
5772             }
5773           }
5774         }
5775       } else {
5776         wordlist = _thisFunctions;
5777       }
5778       callback(null, wordlist.map(function(word) {
5779         return {
5780           caption: word,
5781           value: word,
5782           meta: "static"
5783         };
5784       }));
5785     }
5786   };
5787
5788   editor.completers = [ myCompleter ];
5789
5790   editor.setOptions({
5791     enableBasicAutocompletion: true,
5792     enableSnippets: true,
5793     enableLiveAutocompletion: true
5794   });
5795
5796   document.getElementById("btnJavascriptSourceJson").addEventListener(
5797     "click",
5798     function(/*e*/) {
5799       self.showModalJSON();
5800     });
5801
5802   document.getElementById("btnJavascriptClearRun").addEventListener(
5803     "click",
5804     function(/*e*/) {
5805       self.clearStageAndEval();
5806     });
5807
5808   document.getElementById("btnJavascriptRun").addEventListener(
5809     "click",
5810     function(/*e*/) {
5811       self.eval();
5812     });
5813
5814   document.getElementById("btnJavascriptAddBuffer").addEventListener(
5815     "click",
5816     function(/*e*/) {
5817       self.addNewBuffer();
5818     });
5819
5820   document.getElementById("btnJavascriptRenameBuffer").addEventListener(
5821     "click",
5822     function(/*e*/) {
5823       self.renameBuffer();
5824     });
5825
5826   this.currentName = undefined;
5827
5828   var names = database.readJavascriptNames();
5829   if(names.length) {
5830     self.loadJavascript(names[0]); // load first javascript buffer
5831   }
5832
5833 }
5834
5835 UIJavascriptTab.prototype.getData = function() {
5836   "use strict";
5837   var e = ace.edit("editorJavascript");
5838   var ascii = native2ascii(e.getSession().getValue());
5839
5840   if(this.currentName !== undefined) {
5841     return { name: this.currentName,
5842              source: ascii };
5843   } else {
5844     return undefined;
5845   }
5846 };
5847
5848 UIJavascriptTab.prototype.setData = function(data) {
5849   "use strict";
5850   this.currentName = data.name;
5851   // set new
5852   var editor = ace.edit("editorJavascript");
5853   editor.getSession().setValue(data.source);
5854
5855   $("#textJavascriptName").html(this.bufferPrepend + data.name);
5856
5857 };
5858
5859 UIJavascriptTab.prototype.showModalJSON = function() {
5860   "use strict";
5861   var e = ace.edit("editorJavascript");
5862   var ascii = native2ascii(e.getSession().getValue());
5863
5864   var lines = ascii.split("\n");
5865
5866   var data = "{source:";
5867
5868   for(var i = 0; i < lines.length; i++) {
5869     data += "\"" + lines[i].replace(/"/g, "\\\"") + "\\n\" +\n";
5870   }
5871
5872   data += "\n\"\"}";
5873
5874   // data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
5875
5876   // data = data.replace(/"/g, "\\\""); // for loops are interpreted by browser as tags and dont print?
5877
5878   // data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
5879
5880   uiApp.codeInformationBox( data );
5881
5882 };
5883
5884 UIJavascriptTab.prototype.clearStageAndEval = function() {
5885   "use strict";
5886   var e = ace.edit("editorJavascript");
5887   var ascii = native2ascii(e.getSession().getValue());
5888   clear();
5889   // as of ecma5 an indirect call like this is in global scope
5890   var globalEval = eval;
5891   globalEval(ascii);
5892 };
5893
5894 UIJavascriptTab.prototype.eval = function() {
5895   "use strict";
5896   var e = ace.edit("editorJavascript");
5897   var ascii = native2ascii(e.getSession().getValue());
5898   // as of ecma5 an indirect call like this is in global scope
5899   var globalEval = eval;
5900   globalEval(ascii);
5901 };
5902
5903 UIJavascriptTab.prototype.rebuildDropdown = function(db) {
5904   "use strict";
5905   rebuildDropdown( document.getElementById("javascriptDropDown"),
5906                    db,
5907                    "javascript",
5908                    function(name) {
5909                      return ["javascript:uiJavascriptTab.loadJavascript(\"" + name + "\")",
5910                              name];
5911                    }
5912                  );
5913 };
5914
5915
5916 //------------------------------------------------------------------------------
5917 //
5918 // Image UI Tab
5919 //
5920 //------------------------------------------------------------------------------
5921
5922 /**
5923  * Get or create a dali image from the image buffer.
5924  *
5925  * Global function for use in javascript buffers or the console.
5926  * @param {string} shader buffer name
5927  * @return  {Object} dali.Image
5928  */
5929 function imageFromUiBuffer(name) {
5930   "use strict";
5931   var img = uiImageTab.getDaliImage(name);
5932   assert(img, "Could not find image:" + name);
5933   return img;
5934 }
5935
5936
5937 /**
5938  * Manages UI image tab.
5939  *
5940  * @constructor
5941  */
5942 function UIImageTab() {
5943   "use strict";
5944   var self = this;
5945   this.imagesCreated = {}; // dali shader objects
5946
5947   /********** methods **********/
5948   this.getBufferImageRGB = function(file, callback) {
5949     if (!file) {
5950       return;
5951     }
5952
5953     var img = new HTML5Image(); // the renamed Image()
5954
5955     var objectUrl = window.URL.createObjectURL(file);
5956
5957     img.onload = function( //e
5958     ) {
5959       var imageCanvas = document.createElement("canvas");
5960       imageCanvas.width = img.width; // naturalWidth;
5961       imageCanvas.height = img.height; // naturalHeight;
5962       var context = imageCanvas.getContext("2d");
5963       context.drawImage(img, 0, 0 );
5964       var imageData = context.getImageData(0, 0, img.naturalWidth, img.naturalHeight); // <-ImageData
5965       callback(file.name, imageData);
5966       window.URL.revokeObjectURL(objectUrl);
5967     };
5968
5969     img.src = objectUrl;
5970
5971   };
5972
5973
5974   /**
5975    * Add new image data
5976    *
5977    * @param {object} ImageData object
5978    */
5979   this.addNewBuffer = function(imageData) {
5980     var alreadyExists = function() {
5981       self.addNewBuffer(imageData);
5982     };
5983
5984     var inputOk = function(name) {
5985       var oldData = database.readImage(name);
5986       if(oldData) {
5987         uiApp.messageBox("Name already exsists", alreadyExists);
5988       } else {
5989         database.writeImage(name, imageData);
5990         self.rebuildDropdown(database);
5991       }
5992     };
5993
5994     uiApp.inputbox("BufferName?", inputOk);
5995   };
5996
5997   this.renameBuffer = function() {
5998     var inputOk = function(name) {
5999       var data = uiJavascriptTab.getData();
6000       data.name = name;
6001       database.writeJavascript(data);
6002       self.rebuildDropdown(database);
6003     };
6004
6005     uiApp.inputbox("BufferName?", inputOk);
6006   };
6007
6008   /**
6009    * Load image into the UI Image tab. (used for dynamically generated html dropdowns)
6010    *
6011    * @param {string} name of image buffer
6012    */
6013   this.loadImage = function(name) {
6014     self.setData( database.readImage(name) );
6015   };
6016
6017   /********** init **********/
6018
6019   document.getElementById("btnImageAddBuffer").addEventListener(
6020     "change",
6021     function() {
6022       var fileInput = document.getElementById("btnImageAddBuffer");
6023       var file = fileInput.files[0];
6024       self.getBufferImageRGB(
6025         file,
6026         function(name, typedBuffer) {
6027           self.addNewBuffer(typedBuffer);
6028         });
6029     });
6030
6031
6032   document.getElementById("btnImageRenameBuffer").addEventListener(
6033     "click",
6034     function(/*e*/) {
6035       self.renameBuffer();
6036     });
6037
6038   var names = database.readImageNames();
6039   if(names.length) {
6040     // load first image buffer
6041     self.setData( database.readImage(names[0]) );
6042   }
6043
6044 }
6045
6046 /**
6047  * Get or create a dali image from the image buffer.
6048  *
6049  * @return  {Object} dali.Image
6050  */
6051 UIImageTab.prototype.getDaliImage = function(name) {
6052   "use strict";
6053   if(name in this.imagesCreated) {
6054     return this.imagesCreated[name];
6055   } else {
6056     var imageData = database.readImage(name);
6057     var uint8array = new Uint8Array(imageData.data);
6058     var image = new dali.BufferImage(uint8array, imageData.width, imageData.height, dali.PixelFormat.RGBA8888);
6059     this.imagesCreated[name] = image;
6060     return image;
6061   }
6062 };
6063
6064 UIImageTab.prototype.rebuildDropdown = function(db) {
6065   "use strict";
6066   rebuildDropdown( document.getElementById("imageDropDown"),
6067                    db,
6068                    "images",
6069                    function(name) {
6070                      return ["javascript:uiImageTab.loadImage(\"" + name + "\")",
6071                              name];
6072                    }
6073                  );
6074 };
6075
6076 UIImageTab.prototype.setData = function(data) {
6077   "use strict";
6078   var imageViewCanvas = document.getElementById("imageViewCanvas"); // createElement("canvas");
6079   imageViewCanvas.width = data.width; // naturalWidth;
6080   imageViewCanvas.height = data.height; // naturalHeight;
6081   var context = imageViewCanvas.getContext("2d");
6082   context.putImageData( data, 0, 0 );
6083
6084 };
6085
6086 //------------------------------------------------------------------------------
6087 //
6088 // Shader UI Tab
6089 //
6090 //------------------------------------------------------------------------------
6091 /**
6092  * Get or create a dali shader from the shader buffer.
6093  *
6094  * Global function for use in javascript buffers or the console.
6095  * @param {string} shader buffer name
6096  * @return  {Object} dali.Shader
6097  */
6098 function shaderFromUiBuffer(name) {
6099   "use strict";
6100   var shader = uiShaderTab.getDaliShader(name);
6101   assert(shader, "Could not find/compile shader:" + name);
6102   return shader;
6103 }
6104
6105 function shaderInfoFromUiBuffer(name) {
6106   "use strict";
6107   return uiShaderTab.getShaderInfo(name);
6108 }
6109
6110 /**
6111  * Manage shader UI tab events.
6112  * Holds dali shader objects created from shader buffers.
6113  *
6114  * @constructor
6115  * @return {Object} UIShaderTab
6116  */
6117 function UIShaderTab() {
6118   "use strict";
6119   var self = this;
6120   this.bufferPrepend = "Buffer Name:";
6121   this.inhibitCheckAndUpdateShader = false;
6122
6123   this.shadersCreated = {}; // dali shader objects
6124   document.getElementById("btnShaderAddBuffer").addEventListener(
6125     "click",
6126     function(/*e*/) {
6127       self.addNewBuffer();
6128     });
6129
6130   document.getElementById("btnShaderRenameBuffer").addEventListener(
6131     "click",
6132     function(/*e*/) {
6133       self.renameBuffer();
6134     });
6135
6136   document.getElementById("btnShaderSourceJSON").addEventListener(
6137     "click",
6138     function(/*e*/) {
6139       self.showModalJSON();
6140     });
6141
6142   document.getElementById("btnShaderSourceC").addEventListener(
6143     "click",
6144     function(/*e*/) {
6145       self.showModalC();
6146     });
6147
6148   document.getElementById("btnShaderSourceJS").addEventListener(
6149     "click",
6150     function(/*e*/) {
6151       self.showModalJS();
6152     });
6153
6154
6155   this.addNewBuffer = function() {
6156     var alreadyExists = function() {
6157       self.addNewBuffer();
6158     };
6159
6160     var inputOk = function(name) {
6161       var data = database.readJavascript(name);
6162       if(data) {
6163         uiApp.messageBox("Name already exsists", alreadyExists);
6164       } else {
6165         var newData = {name: name, fragment: "", vertex: "", hints: ""};
6166         database.writeShader(newData);
6167         self.rebuildDropDown(database);
6168       }
6169     };
6170
6171     uiApp.inputbox("BufferName?", inputOk);
6172
6173   };
6174
6175   this.renameBuffer = function() {
6176     var inputOk = function(name) {
6177       var data = self.getData();
6178       data.name = name;
6179       database.writeShader(data);
6180       $("#textShaderName").html(self.bufferPrepend + name);
6181       self.rebuildDropdown(database);
6182     };
6183
6184     uiApp.inputbox("BufferName?", inputOk);
6185   };
6186
6187   this.loadShader = function(name) {
6188
6189     var data = database.readShader(name);
6190
6191     // save current
6192     var currentData = self.getData();
6193     if(currentData) {
6194       database.writeShader(currentData);
6195     }
6196
6197     // so that we can change vertex & fragment as an atomic operation
6198     self.inhibitCheckAndUpdateShader = true;
6199
6200     // otherwise this will trigger a checkAndUpdateShader() after
6201     // we've only changed the vertex shader (ie with mismatching fragment shader)
6202     self.setData(data);
6203
6204     self.inhibitCheckAndUpdateShader = false;
6205
6206     self.checkAndUpdateShader();
6207
6208   };
6209
6210   /**
6211    * Set the UI tab data of vertex/fragment strings.
6212    *
6213    * @param {Object} shader data object
6214    */
6215   this.setData = function(options) {
6216     var e;
6217     var vertex = "";
6218     var fragment = "";
6219     var hints = "";
6220
6221     vertex = options.vertex;
6222     fragment = options.fragment;
6223     hints = options.hints;
6224
6225     $("#requiresSelfDepthTest").prop("checked", (hints.search("requiresSelfDepthTest") >= 0));
6226     $("#outputIsTransparent").prop("checked", (hints.search("outputIsTransparent") >= 0));
6227     $("#outputIsOpaque").prop("checked", (hints.search("outputIsOpaque") >= 0));
6228     $("#modifiesGeometry").prop("checked", (hints.search("modifiesGeometry") >= 0));
6229
6230     // do this after setting up the checkboxes as it will trigger storing the checkbox state
6231     // in the actorIdToShaderSet map
6232     e = ace.edit("editorVertex");
6233     e.getSession().setValue(vertex);
6234
6235     e = ace.edit("editorFragment");
6236     e.getSession().setValue(fragment);
6237
6238     $("#textShaderName").html(self.bufferPrepend + options.name);
6239
6240   };
6241
6242   var shaderTab = $("#tab2primary")[0];
6243   var lastClassName = shaderTab.className;
6244   window.setInterval( function() {
6245     var className = shaderTab.className;
6246     if (className !== lastClassName) {
6247       //
6248       // an attempt to get the editboxes to display the correct content.
6249       // when you setValue() the content and they aren't visible then
6250       // they dont update properly until you click in the box
6251       //
6252       var e = ace.edit("editorVertex");
6253       e.setShowInvisibles(true);
6254       e.setShowInvisibles(false);
6255
6256       e = ace.edit("editorFragment");
6257       e.setShowInvisibles(true);
6258       e.setShowInvisibles(false);
6259       lastClassName = className;
6260     }
6261   }, 1);
6262
6263   var names = database.readShaderNames();
6264   if(names.length) {
6265     // load first image buffer
6266     self.setData( database.readShader(names[0]) );
6267   }
6268
6269   var editor = ace.edit("editorVertex");
6270   editor.getSession().addEventListener("change", function() {
6271     self.checkAndUpdateShader();
6272   });
6273
6274   editor = ace.edit("editorFragment");
6275   editor.getSession().addEventListener("change", function() {
6276     self.checkAndUpdateShader();
6277   });
6278
6279 }
6280
6281 /**
6282  * Get or create a dali shader from the shader buffer.
6283  *
6284  * @return  {Object} dali.Shader
6285  */
6286 UIShaderTab.prototype.getDaliShader = function(name) {
6287   "use strict";
6288   if(name in this.shadersCreated) {
6289     return this.shadersCreated[name].daliShader;
6290   } else {
6291     var ret = null;
6292     var data = database.readShader(name);
6293
6294     if(this.isCompilable(data)) {
6295       var daliShader = new dali.Shader(data.vertex,
6296                                        data.fragment,
6297                                        this.getDaliShaderHints(data.hints));
6298
6299       var shaderInfo = new dali.ShaderInfo();
6300       var info = shaderInfo.fromCompilation( canvas.getContext("webgl"),
6301                                              data.vertex,
6302                                              data.fragment );
6303
6304       for(name in info.uniformUISpec) {
6305         var metaData = info.uniformUISpec[name];
6306         if("default" in metaData) {
6307           // could provide automatic defaults
6308           daliShader.registerAnimatedProperty(name, metaData.default);
6309         }
6310       }
6311
6312       if(daliShader) {
6313         this.shadersCreated[name] = data;
6314         this.shadersCreated[name].daliShader = daliShader;
6315       }
6316       ret = daliShader;
6317     } else {
6318       console.log("Requested shader could not be compiled:" + name);
6319     }
6320
6321     return ret;
6322   }
6323 };
6324
6325 /**
6326  * Get info for a shader. See getInfo()
6327  *
6328  * @return  {Object} dali.Shader
6329  */
6330
6331 UIShaderTab.prototype.getShaderInfo = function(name) {
6332   "use strict";
6333   var data = database.readShader(name);
6334   return this.getInfo(data);
6335 };
6336
6337 /**
6338  * Rebuild UI tab drop down selection.
6339  *
6340  * @param {Object} Database
6341  */
6342 UIShaderTab.prototype.rebuildDropdown = function(db) {
6343   "use strict";
6344   rebuildDropdown( document.getElementById("shaderDropDown"),
6345                    db,
6346                    "shaders",
6347                    function(name) {
6348                      return ["javascript:uiShaderTab.loadShader(\"" + name + "\")",
6349                              name];
6350                    }
6351                  );
6352 };
6353
6354
6355 /**
6356  * Get the UI tab data with vertex/fragment strings.
6357  *
6358  * @return {Object} shader data object
6359  */
6360 UIShaderTab.prototype.getData = function() {
6361   "use strict";
6362   var e = ace.edit("editorVertex");
6363   var ret = {};
6364   ret.name = $("#textShaderName").text().substr(this.bufferPrepend.length);
6365   ret.vertex = native2ascii(e.getSession().getValue());
6366   e = ace.edit("editorFragment");
6367   ret.fragment = native2ascii(e.getSession().getValue());
6368
6369   ret.hints = "";
6370   if( $("#requiresSelfDepthTest")[0].checked ) {
6371     ret.hints += " requiresSelfDepthTest";
6372   }
6373   if( $("#outputIsTransparent")[0].checked ) {
6374     ret.hints += " outputIsTransparent";
6375   }
6376   if( $("#outputIsOpaque")[0].checked ) {
6377     ret.hints += " outputIsOpaque";
6378   }
6379   if( $("#modifiesGeometry")[0].checked ) {
6380     ret.hints += " modifiesGeometry";
6381   }
6382
6383   return ret;
6384 };
6385
6386 /**
6387  * Get dali shader hints from hints string.
6388  *
6389  * @param {string} hints string (space separated)
6390  * @return  {integer} or'd hints to pass to Dali
6391  */
6392 UIShaderTab.prototype.getDaliShaderHints = function(hintsString) {
6393   "use strict";
6394   var ret = 0;
6395
6396   if(hintsString.search("requiresSelfDepthTest") >= 0) {
6397     ret += dali.ShaderHints.REQUIRES_SELF_DEPTH_TEST;
6398   }
6399   if(hintsString.search("outputIsTransparent") >= 0) {
6400     ret += dali.ShaderHints.OUTPUT_IS_TRANSPARENT;
6401   }
6402   if(hintsString.search("outputIsOpaque") >= 0) {
6403     ret += dali.ShaderHints.OUTPUT_IS_OPAQUE;
6404   }
6405   if(hintsString.search("modifiesGeometry") >= 0) {
6406     ret += dali.ShaderHints.MODIFIES_GEOMETRY;
6407   }
6408   return ret;
6409 };
6410
6411 /**
6412  * Get information on a shader
6413  * If hasError==true then attributes etc will be empty. ie it must compile.
6414  *
6415  * Compile the shader with webGL. Query webGL for meta data.
6416  *
6417  * @param {object} data object. {vertex:"", fragment:""}
6418  * @return  {object} info metadata object
6419  *  // var info = {
6420  *  //   attributes: [],
6421  *  //   uniforms: [],
6422  *  //   attributeCount: 0,
6423  *  //   uniformCount: 0,
6424  *  //   hasError: false,    // compiles without error
6425  *  //   vertexError: "",
6426  *  //   fragmentError: "",
6427  *  //   linkError: ""
6428  *  // };
6429  */
6430
6431
6432 // uniform vec3 uMe; // gui:number, min:0, max:1, default: 0.5
6433 // uniform vec3 uMe; // gui:slider, min:0, max:1, default: 0.5
6434 // uniform vec3 uMe; // gui:color, min:[0,0,0,0] max:[1,1,1,1], default: [0,0,0,1]
6435
6436 UIShaderTab.prototype.getInfo = function(data) {
6437   "use strict";
6438
6439   var canvas = document.getElementById("canvas");
6440
6441   var info = new dali.ShaderInfo();
6442
6443   return info.fromCompilation(canvas.getContext("webgl"),
6444                               data.vertex,
6445                               data.fragment);
6446 };
6447
6448 /**
6449  * Check a shader can compile. Shader given as data object with vertex/fragment buffers.
6450  *
6451  * Compile the shader with webGL as a preprocess step to giving it to Dali.
6452  *
6453  * @param {string} shader buffer name
6454  * @return  {Boolean} true if the shader compiles ok.
6455  */
6456 UIShaderTab.prototype.isCompilable = function(data) {
6457   "use strict";
6458   var info = this.getInfo(data);
6459   return !info.hasError;
6460 };
6461
6462
6463 /**
6464  * Check the shader in the UI tab can compile and if so update the saved dali.Shader object.
6465  * (Does not create the dali.Shader object)
6466  *
6467  * For use on an event for continuous shader checking.
6468  *
6469  * @param {string} shader buffer name
6470  * @return  {Object} dali.Shader
6471  */
6472 UIShaderTab.prototype.checkAndUpdateShader = function() {
6473   "use strict";
6474   if(this.inhibitCheckAndUpdateShader) {
6475     return;
6476   }
6477
6478   var options = this.getData();
6479
6480   var info = this.getInfo(options);
6481
6482   if(!info.hasError) {
6483     if( options.name in this.shadersCreated ) {
6484       if("daliShader" in this.shadersCreated[options.name]) {
6485         // setting shader.program= doesn't seem to recompile the shader?
6486         // this.shadersCreated[options.name].daliShader.delete(); no delete; could be held elsewhere
6487         delete this.shadersCreated[options.name];
6488       }
6489     }
6490   }
6491
6492   var vertexPrepend = "";
6493   var fragmentPrepend = "";
6494
6495   var errors = "";
6496   var count;
6497   var editor;
6498   var description;
6499   var col;
6500   var line;
6501   var i;
6502
6503   var textShaderErrors = $("#textShaderErrors");
6504
6505   textShaderErrors.value = "";
6506
6507   editor = ace.edit("editorVertex");
6508   if (info.hasError && info.vertexError) {
6509     editor.getSession().setOption("useWorker", false);
6510     textShaderErrors.value = "VERTEX:\n" + info.vertexError;
6511     errors = info.vertexError.split("\n");
6512     count = vertexPrepend.split("\n").length;
6513     for(i = 0; i < errors.length; i++) {
6514       if(errors[i]) {
6515         description = errors[i].split(":");
6516         col = Number(description[1]);
6517         try {
6518           line = Number(description[2]);
6519         } catch(e) {
6520           line = "unknown";
6521         }
6522         editor.getSession().setAnnotations([{row: line - count, column: col, text: errors[i], type: "error"}]);
6523       }
6524     }
6525   } else {
6526     editor.getSession().setOption("useWorker", true);
6527     editor.getSession().setAnnotations([]);
6528   }
6529
6530   editor = ace.edit("editorFragment");
6531   if (info.hasError && info.fragmentError) {
6532     editor.getSession().setOption("useWorker", false);
6533     textShaderErrors.value += "FRAGMENT:\n" + info.fragmentError;
6534     errors = info.fragmentError.split("\n");
6535     count = fragmentPrepend.split("\n").length;
6536     for(i = 0; i < errors.length; i++) {
6537       if(errors[i]) {
6538         description = errors[i].split(":");
6539         col = Number(description[1]);
6540         try {
6541           line = Number(description[2]);
6542         } catch(e) {
6543           line = "unknown";
6544         }
6545         editor.getSession().setAnnotations([{row: line - count, column: col, text: errors[i], type: "error"}]);
6546       }
6547     }
6548   } else {
6549     editor.getSession().setOption("useWorker", true);
6550     editor.getSession().setAnnotations([]);
6551   }
6552
6553   if(!info.hasError) {
6554     database.writeShader(options);
6555   }
6556
6557 };
6558
6559
6560 UIShaderTab.prototype.showModalC = function() {
6561   "use strict";
6562   var i;
6563   var info = this.getData();
6564
6565   var data = "#define MAKE_STRING(A)#A\n\n" +
6566         "std::string vertexShader = MAKE_STRING(\n";
6567
6568   var lines = info.vertex.split("\n");
6569   for(i = 0; i < lines.length; i++) {
6570     data += lines[i] + "\n";
6571   }
6572   data += ");\n\n";
6573
6574   data += "std::string fragShader = MAKE_STRING(\n";
6575
6576   lines = info.fragment.split("\n");
6577   for(i = 0; i < lines.length; i++) {
6578     data += lines[i] + "\n";
6579   }
6580   data += ");\n\n";
6581
6582   data += "ShaderEffect shaderEffect;\n" +
6583     "shaderEffect = ShaderEffect::New( vertexShader, fragmentShader,\n" +
6584     "                                ShaderEffect::ShaderHint( " + info.hints + " ) )\n";
6585
6586   data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
6587
6588   uiApp.codeInformationBox( data );
6589
6590   // data = data.replace(/</g, "&lt;");
6591   // data = data.replace(/>/g, "&gt;");
6592
6593   // var myWindow = window.open("data:text/html," + encodeURIComponent(data));
6594   // //                             "_blank");  // , "width=00,height=100");
6595   // myWindow.focus();
6596
6597 };
6598
6599 UIShaderTab.prototype.showModalJS = function() {
6600   "use strict";
6601   var i;
6602   var info = this.getData();
6603
6604   var data = "var shaderOptions = {vertex:\n";
6605
6606   var lines = info.vertex.split("\n");
6607   for(i = 0; i < lines.length; i++) {
6608     data += "                     \"" + lines[i] + "\\n\" +\n";
6609   }
6610   data += "                     \"\",\n";
6611
6612   data += "                     fragment:\n";
6613   lines = info.fragment.split("\n");
6614   for(i = 0; i < lines.length; i++) {
6615     data += "                     \"" + lines[i] + "\\n\" +\n";
6616   }
6617   data += "                     \"\",\n";
6618
6619   data += "                     geometryType: \"" + info.geometryType + "\",\n";
6620   data += "                     geometryHints: \"" + info.geometryHints + "\"\n";
6621   data += "                     };\n";
6622
6623   data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
6624   // data = data.replace(/</g, "&lt;");
6625   // data = data.replace(/>/g, "&gt;");
6626
6627   // var myWindow = window.open("data:text/html," + encodeURIComponent(data));
6628   // //                             "_blank");  // , "width=00,height=100");
6629   // myWindow.focus();
6630
6631   var modalBody = $("#modalCodeInfoBody")[0];
6632   removeAllChildren(modalBody);
6633   modalBody.innerHTML = "<code><pre>" + data + "</pre></code>";
6634   $("#modalCodeInfo").modal("show");
6635
6636 };
6637
6638 UIShaderTab.prototype.showModalJSON = function() {
6639   "use strict";
6640   var info = this.getData();
6641
6642   var hints = ""; // tbd
6643
6644   var vertex = info.vertex.replace(/\n/g, "\\n");
6645   var fragment = info.fragment.replace(/\n/g, "\\n");
6646
6647   var data = "{\"shader-effects\": {\n" +
6648         "  \"" + "effect" + "\": {\n" +
6649         "    \"program\": {\n" +
6650         "    \"vertexPrefix\": \"\",\n" +
6651         "    \"vertex\": \"" + vertex + "\",\n" +
6652         "    \"fragmentPrefix\": \"\",\n" +
6653         "    \"fragment\": \"" + fragment + "\"\n" +
6654         "    },\n" +
6655         "    \"geometry-hints\": \"" + hints + "\",\n" +
6656         "    \"grid-density\": \"" + "0" + "\",\n" +
6657         "    \"image\": {\n" +
6658         "      \"filename\": \"\"\n" +
6659         "    }\n" +
6660         "  }\n" +
6661         " }\n" +
6662         "}\n";
6663
6664   data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
6665
6666   uiApp.codeInformationBox( data );
6667
6668 };
6669
6670 document.getElementById("btnRewriteDatabase").addEventListener("click", function(// e
6671 ) {
6672   "use strict";
6673
6674   database.delete(
6675     function() {
6676       consoleLogSuccess("database.delete")();
6677       window.setTimeout(function () {
6678         window.location.reload(true); // forces a reload from the server
6679       }, 500);
6680     },
6681     consoleLogErrorEvent, // fail
6682     consoleLogErrorEvent // blocked
6683   );
6684
6685 });
6686
6687
6688 window.setTimeout(initDB, 1000);
6689
6690
6691 function updateStatistics(eventHandler){
6692   "use strict";
6693
6694   var elem = $("#statistics")[0];
6695
6696   var actor = eventHandler.touchedActor;
6697
6698   var usedRootLayer = false;
6699
6700   if(!actor) {
6701     usedRootLayer = true;
6702     actor = dali.stage.getRootLayer();
6703   }
6704
6705   var rt = dali.stage.getRenderTaskList().getTask(0);
6706
6707   var xy;
6708   try {
6709     xy = dali.screenToLocal(eventHandler.mouseX, eventHandler.mouseY,
6710                             actor, rt);
6711   } catch(err) {
6712     xy = [0, 0];
6713   }
6714
6715   var screenxy = dali.worldToScreen(actor.position, rt);
6716
6717   var name = "Actor";
6718
6719   if(usedRootLayer) {
6720     name = "Root Actor";
6721   }
6722
6723   var prec = 3;
6724   var px = "none";
6725   var py = "none";
6726   if(eventHandler.mouseDownPosition) {
6727     px = eventHandler.mouseDownPosition[0].toFixed(prec);
6728     py = eventHandler.mouseDownPosition[1].toFixed(prec);
6729   }
6730
6731   elem.innerHTML = name + " (" + actor.getId() + ") '" + actor.name + "'" + "<br>" +
6732     "Screen:" + eventHandler.mouseX.toFixed(prec) + "," + eventHandler.mouseY.toFixed(prec) + "<br>" +
6733     name + " Screen To Local:" + xy[0].toFixed(prec) + "," + xy[1].toFixed(prec) + "<br>" +
6734     name + " To Screen:" + screenxy[0].toFixed(prec) + "," + screenxy[1].toFixed(prec) + "<br>" +
6735     name + " Drag dx/dy:" + eventHandler.dragDx.toFixed(prec) + "," + eventHandler.dragDy.toFixed(prec) + "<br>" +
6736     name + " pos:" + actor.position + "<br>"+
6737     name + " pos:" + px + "," + py + "<br>";
6738
6739   if(usedRootLayer) { // dont delete eventHandler object
6740     actor.delete(); // wrapper
6741   }
6742
6743   rt.delete(); // wrapper
6744
6745 }
6746
6747
6748 $(".btn-toggle").click(function() {
6749   "use strict";
6750   $(this).find(".btn").toggleClass("active");
6751
6752   if($(this).find(".btn-primary").size() > 0) {
6753     $(this).find(".btn").toggleClass("btn-primary");
6754   }
6755
6756   $(this).find(".btn").toggleClass("btn-default");
6757
6758   if(this.id === "loop") {
6759     var looping = $(this).find("#loopOn").hasClass("active");
6760     animationList[animationSelectionIndex].looping = looping;
6761     animationList[animationSelectionIndex].dirtyData = true;
6762   }
6763
6764   if(this.id === "endAction") {
6765     var bake = $(this).find("#endBake").hasClass("active");
6766     if(bake) {
6767       animationList[animationSelectionIndex].endAction = "Bake";
6768     } else {
6769       animationList[animationSelectionIndex].endAction = "Discard";
6770     }
6771     animationList[animationSelectionIndex].dirtyData = true;
6772   }
6773
6774 });
6775
6776 //------------------------------------------------------------------------------
6777 //
6778 // Database; access to browser indexed db
6779 //
6780 //------------------------------------------------------------------------------
6781 function Database() {
6782   "use strict";
6783   this.currentVersion = 1;
6784   this.name = "dalitoy";
6785   this.data = {};
6786   var self = this;
6787
6788   this.copyDBStore = function(db, dbStoreName, andClose) {
6789     var tr = db.transaction([dbStoreName], "readonly");
6790     var store = tr.objectStore(dbStoreName);
6791     var cursor = store.openCursor();
6792     self.data[dbStoreName] = {};
6793     cursor.onsuccess = function(e) {
6794       var res = e.target.result; // another cursor
6795       if(res) {
6796         self.data[dbStoreName][res.key] = res.value;
6797         res.continue();
6798       } else {
6799         if(andClose) {
6800           db.close();
6801         }
6802       }
6803     };
6804     cursor.onerror = consoleLogErrorEvent;
6805   };
6806
6807   this.initializeData = function(db) {
6808     self.copyDBStore(db, "javascript");
6809     self.copyDBStore(db, "images");
6810     self.copyDBStore(db, "shaders", true); // true to close db (last copy)
6811   };
6812
6813   this.init();
6814 }
6815
6816 Database.prototype.open = function() {
6817   "use strict";
6818   return window.indexedDB.open(this.name, this.currentVersion);
6819 };
6820
6821 Database.prototype.delete = function(onsuccess, onerror, onblocked) {
6822   "use strict";
6823   var req = window.indexedDB.deleteDatabase(this.name);
6824   req.onsuccess = onsuccess;
6825   req.onerror = onerror;
6826   req.onblocked = onblocked;
6827 };
6828
6829
6830 Database.prototype.upgrade = function(db, oldVersion) {
6831   // force upgrade
6832   "use strict";
6833   if (oldVersion < 1) {
6834     // Version 1 is the first version of the database.
6835     var store = db.createObjectStore("shaders", {keyPath: "name"});
6836     var i;
6837     for(i = 0; i < shaderSources.length; i++) {
6838       store.put( shaderSources[i] );
6839     }
6840
6841     store = db.createObjectStore("javascript", {keyPath: "name"});
6842     for(i = 0; i < javascriptSources.length; i++) {
6843       store.put( javascriptSources[i] );
6844     }
6845
6846     store = db.createObjectStore("images");
6847
6848     // default images in html page
6849     store.put( getStockImageData(1), "girl1" );
6850     store.put( getStockImageData(2), "funnyface" );
6851     store.put( getStockImageData(3), "ducks" );
6852     store.put( getStockImageData(4), "field" );
6853   }
6854 };
6855
6856 Database.prototype.init = function() {
6857   "use strict";
6858   var self = this;
6859
6860   if("indexedDB" in window) {
6861     var openRequest = this.open();
6862
6863     openRequest.onupgradeneeded = function(event) {
6864       var db = event.target.result;
6865       database.upgrade(db, event.oldVersion);
6866       //self.initializeData(db);
6867     };
6868
6869     openRequest.onsuccess = function(event) {
6870       var db = event.target.result;
6871       self.initializeData(db);
6872     };
6873
6874     openRequest.onerror = consoleLogErrorEvent;
6875
6876   }
6877
6878 };
6879
6880 Database.prototype.initTabs = function(jstab, imagetab, shadertab) {
6881   "use strict";
6882   jstab.rebuildDropdown(this);
6883   imagetab.rebuildDropdown(this);
6884   shadertab.rebuildDropdown(this);
6885 };
6886
6887 Database.prototype.writeJavascript = function(data, callback) {
6888   "use strict";
6889
6890   this.data.javascript[data.name] = data;
6891
6892   var openRequest = this.open();
6893   var self = this;
6894   openRequest.onsuccess = function(event) {
6895     var db = event.target.result;
6896     var tr = db.transaction(["javascript"], "readwrite");
6897     var store = tr.objectStore("javascript");
6898
6899     var ob = store.put(data);
6900     self.data.javascript[data.name] = data;
6901
6902     ob.onsuccess = callback;
6903     // ob.onerror = errorCallback;
6904     ob.onerror = consoleLogErrorEvent;
6905
6906     db.close();
6907   };
6908
6909   openRequest.onerror = consoleLogErrorEvent;
6910
6911 };
6912
6913 Database.prototype.readJavascript = function(name) {
6914   "use strict";
6915   return this.data.javascript[name];
6916 };
6917
6918 Database.prototype.readJavascriptNames = function() {
6919   "use strict";
6920   return this.getKeys("javascript");
6921 };
6922
6923 Database.prototype.readKeys = function(dbStoreName, callback) {
6924   "use strict";
6925
6926   var openRequest = database.open();
6927
6928   openRequest.onsuccess = function(event) {
6929     var db = event.target.result;
6930     var tr = db.transaction([dbStoreName], "readonly");
6931     var store = tr.objectStore(dbStoreName);
6932     var cursor = store.openCursor();
6933     var keys = [];
6934     cursor.onsuccess = function(e) {
6935       var res = e.target.result; // another cursor
6936       if(res) {
6937         keys.push(res.key);
6938         res.continue();
6939       } else {
6940         callback(keys);
6941       }
6942     };
6943     cursor.onerror = consoleLogErrorEvent;
6944     db.close();
6945   };
6946
6947 };
6948
6949 Database.prototype.getKeys = function(dbStoreName) {
6950   "use strict";
6951   var l = [];
6952   var o = this.data[dbStoreName];
6953   for(var name in o) {
6954     l.push(name);
6955   }
6956   return l;
6957 };
6958
6959 Database.prototype.writeShader = function(data) {
6960   "use strict";
6961   assert(data.name);
6962
6963   this.data.shaders[data.name] = data;
6964
6965   // write the indexDB too
6966   var openRequest = this.open();
6967
6968   openRequest.onsuccess = function(event) {
6969     var db = event.target.result;
6970     var tr = db.transaction(["shaders"], "readwrite");
6971     var store = tr.objectStore("shaders");
6972
6973     var ob = store.put(data);
6974
6975     //ob.onsuccess = callback;
6976     ob.onerror = consoleLogErrorEvent;
6977
6978     db.close();
6979   };
6980
6981   openRequest.onerror = consoleLogErrorEvent;
6982
6983 };
6984
6985 Database.prototype.readShader = function(name) {
6986   "use strict";
6987   return this.data.shaders[name];
6988 };
6989
6990 Database.prototype.readShaderNames = function() {
6991   "use strict";
6992   return this.getKeys("shaders");
6993 };
6994
6995 Database.prototype.readObjectStore = function(objectStoreName, recordName, callback, errorCallback) {
6996   "use strict";
6997   var openRequest = window.indexedDB.open(this.name, this.currentVersion);
6998
6999   openRequest.onsuccess = function(event) {
7000     var db = event.target.result;
7001
7002     var transaction = db.transaction([objectStoreName], "readonly");
7003     var objectStore = transaction.objectStore(objectStoreName);
7004
7005     //x is some value
7006     var ob = objectStore.get(recordName);
7007
7008     ob.onsuccess = function(e) {
7009       // read with undefined is still a success (should probably do this with cursor?)
7010       if(e.target.result) {
7011         callback(e.target.result);
7012       } else {
7013         errorCallback();
7014       }
7015     };
7016
7017     ob.onerror = errorCallback;
7018
7019     db.close();
7020   };
7021
7022   openRequest.onerror = errorCallback;
7023
7024 };
7025
7026 Database.prototype.writeImage = function(name, data) {
7027   "use strict";
7028
7029   this.data.images[name] = data;
7030
7031   var openRequest = this.open();
7032
7033   openRequest.onsuccess = function(event) {
7034     var db = event.target.result;
7035     var tr = db.transaction(["images"], "readwrite");
7036     var store = tr.objectStore("images");
7037
7038     var ob = store.put(data, name);
7039
7040     //ob.onsuccess = callback;
7041     ob.onerror = consoleLogErrorEvent;
7042
7043     db.close();
7044   };
7045
7046   openRequest.onerror = consoleLogErrorEvent;
7047
7048 };
7049
7050 Database.prototype.readImage = function(name) {
7051   "use strict";
7052   return this.data.images[name];
7053 };
7054
7055 Database.prototype.readImageNames = function() {
7056   "use strict";
7057   return this.getKeys("images");
7058 };
7059
7060 //------------------------------------------------------------------------------
7061 //
7062 // app init functions
7063 //
7064 //------------------------------------------------------------------------------
7065 function initDB() {
7066   "use strict";
7067   database = new Database();
7068   window.setTimeout(init, 500);
7069 }
7070
7071 function init() {
7072   "use strict";
7073
7074   // var root = dali.stage.getRootLayer();
7075   // root.name = "*" + root.name; // * at start means non selectable by convention
7076   // root.delete(); // wrapper
7077
7078   // database = new Database();
7079
7080   test = new Test();
7081
7082   uiApp = new UIApp();
7083
7084   uiJavascriptTab = new UIJavascriptTab();
7085
7086   uiImageTab = new UIImageTab();
7087
7088   uiShaderTab = new UIShaderTab();
7089
7090   database.initTabs(uiJavascriptTab, uiImageTab, uiShaderTab);
7091
7092   $("a[rel=popover]").tooltip();
7093
7094   Object.defineProperty(dali, "shader", {
7095     enumerable: true,
7096     configurable: false,
7097     get: function() {
7098       return getShader();
7099     }
7100   });
7101
7102   Object.defineProperty(dali, "actor", {
7103     enumerable: true,
7104     configurable: false,
7105     get: function() {
7106       return getActor();
7107     }
7108   });
7109
7110   Object.defineProperty(dali, "animation", {
7111     enumerable: true,
7112     configurable: false,
7113     get: function() {
7114       return getAnimation();
7115     }
7116   });
7117
7118   eventHandler.handlersMouseMove.push(updateStatistics);
7119
7120 }
7121
7122 ////////////////////////////////////////////////////////////////////////////////////////////////////
7123
7124 dali.postRenderFunction = undefined;