Sample for video view control
[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(\"touched\", 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("touched", "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, touchEvent){
4125     var doit = false;
4126     for(var i = 0; i < touchEvent.points.length; i++) {
4127       if(touchEvent.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 = "touched";
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("touched", "inside", 0, 100),
4156 // or
4157 // when("myimage", "touched",
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 = "touched";
4211     }
4212     if( signal === "touchedUp" ) { // fix as touched signal is really "mouseState"?
4213       f = _makeSensibleTouched(f, "Up");
4214       signal = "touched";
4215     }
4216     if( signal === "touchedMotion" ) { // fix as touched signal is really "mouseState"?
4217       f = _makeSensibleTouched(f, "Motion");
4218       signal = "touched";
4219     }
4220     if( signal === "touchedLeave" ) { // fix as touched signal is really "mouseState"?
4221       f = _makeSensibleTouched(f, "Leave");
4222       signal = "touched";
4223     }
4224     if( signal === "touchedStationary" ) { // fix as touched signal is really "mouseState"?
4225       f = _makeSensibleTouched(f, "Stationary");
4226       signal = "touched";
4227     }
4228     if( signal === "touchedInterrupted" ) { // fix as touched signal is really "mouseState"?
4229       f = _makeSensibleTouched(f, "Interrupted");
4230       signal = "touched";
4231     }
4232     if( signal === "touchedLast" ) { // fix as touched signal is really "mouseState"?
4233       f = _makeSensibleTouched(f, "Last");
4234       signal = "touched";
4235     }
4236
4237     for(ai = 0; ai < actors.length; ai++) {
4238       actor = root.findChildByName( actors[ai] );
4239       actor.connect( signal, f );
4240     }
4241   }
4242
4243   if(condition) {
4244     // _connectToCondition( actors, condition, _makeCallback(arguments) );
4245     root = dali.stage.getRootLayer();
4246     f = _makeCallback(arguments);
4247
4248     for(ai = 0; ai < actors.length; ai++) {
4249       actor = root.findChildByName( actors[ai] );
4250       actor.setPropertyNotification(condition.property,
4251                                     condition.type, condition.arg0, condition.arg1,
4252                                     f);
4253     }
4254   }
4255
4256 // when("myimage", condition("touched", "inside", 0, 100),
4257 // or
4258 // when("myimage", "touched",
4259 //       ***
4260 //       dali.ActorWrapper.prototype.connect = function(signalName, callback) {
4261 //     if(d.action === "set") {
4262 //       var animationActors = d.actors;
4263 //       if( animationActors.length === 0 ) {
4264 //         animationActors = actors;
4265 //       }
4266 //       var a = new dali.Animation(0);
4267 // // dali.AnimationWrapper.prototype.animateTo = function(object, propertyName, value, alphaFunction, delay, duration) {
4268 // //dali.AnimationWrapper.prototype.animateBy = function(object, propertyName, value, alphaFunction, delay, duration) {
4269 // //dali.AnimationWrapper.prototype.animatePath = function(object, pathObject, forward, alphaFunction, delay, duration) {
4270 //       for(var ai =0; ai < animationActors.length; ai++) {
4271 //         for(var animi =0; animi < d.animation; animi++) {
4272 //           var animEntry = d.animation[animi];
4273 //           if( d.animate == "animatePath") {
4274 //             a.animatePath(animationActors[ai], animEntry.path, animEntry.forward, animEntry.alpha,
4275 //                           animEntry.delay, animEntry.duration);
4276
4277 //           } else if( d.animate == "animateBetween") {
4278 //             a.animateBetween(animationActors[ai], d.property,
4279 //                              animEntry.fromValue, animEntry.toValue,
4280 //                              animEntry.alpha, animEntry.delay, animEntry.duration);
4281 //           } else {
4282 //             // call animateTo,animateBy,
4283 //             a[animEntry.animate](animationActors[ai], d.property, animEntry.value, animEntry.alpha,
4284 //                                  animEntry.delay, animEntry.duration);
4285 //           }
4286 //         }
4287 //   }
4288
4289   // var animiations = [];
4290
4291   // for(var i = 2; i < arguments.length; i++) {
4292   //   var d = arguments[i];
4293   //   if( d.action === "set" ) {
4294   //     // var ret = { action: "set",
4295   //     //             actors: [],
4296   //     //             property: null,
4297   //     //             condition: null,
4298   //     //             animation: []
4299   //     //           };
4300   //     for(var ai = 0; ai < d.actors.length; ai++) {
4301   //       d.actors[ai]
4302   //     }
4303   //   }
4304
4305   //   for(var j = 0; j < d.length; j++) {
4306   //     if(signal) { // then its signal actions
4307   //       d.name = signal;
4308   //       templates[actorName].signals.push(d[j]);
4309   //     } else { // its property notifications
4310   //       d.condition = condition;
4311   //       d.property = property;
4312   //       templates[actorName].notifications.push(d[j]);
4313
4314   // index = 2;
4315
4316   // // but we could also be specifying a property notification so...
4317   // //
4318   // var condition;
4319   // var value;
4320   // if(typeof arguments[index] === "string") {
4321   //   var lowerCase = arguments[index].toLowerCase();
4322   //   if("insideoutsidegreaterthanlessthan".indexOf(lowerCase)) {
4323   //     property = signal;
4324   //     signal = null;
4325   //     condition = lowerCase;
4326   //     index += 1;
4327   //     value = arguments[index];
4328   //     index += 1;
4329   //     if( condition === "inside" || condition === "outside" ) {
4330   //       assert( value.length === 2, "Inside/Outside condition must specify min,max");
4331   //       assert(typeof value[0] === "number" && typeof value[1] === "number", "Conditions must be numbers");
4332   //     }
4333   //     if(condition === "lessthan" || condition === "greaterthan") {
4334   //       assert(value.length === 1, "LessThan/GreaterThan condition must specify one value");
4335   //       assert(typeof value === "number", "Conditions must be numbers");
4336   //     }
4337   //   }
4338   // }
4339
4340   // // The reset are objects created by the set or call function
4341   // var templates = _buildDescription.templates;
4342
4343   // for( var actorName in actors ) {
4344   //   // the other args come from functions that generate json
4345   //   for(var i = index; i < arguments.length; i++) {
4346   //     var d = arguments[i];
4347   //     for(var j = 0; j < d.length; j++) {
4348   //       if(signal) { // then its signal actions
4349   //         d.name = signal;
4350   //         templates[actorName].signals.push(d[j]);
4351   //       } else { // its property notifications
4352   //         d.condition = condition;
4353   //         d.property = property;
4354   //         templates[actorName].notifications.push(d[j]);
4355   //       }
4356   //     }
4357   //   }
4358   // }
4359
4360 } // when()
4361
4362
4363 // function animation() {
4364 //   "use strict";
4365
4366 //   var name = arguments[0];
4367 //   var anim = {};
4368 //   for(var i = 1; i < arguments.length; i++) {
4369 //     var d = arguments[i];
4370
4371 //     if(d.length === undefined) {  // then array from set
4372
4373 //     } else {
4374 //       extend( anim, d );
4375 //     }
4376 //   }
4377
4378 // }
4379
4380
4381 //
4382 // pseudo dali DSL
4383 //
4384
4385 // stage(
4386 //  layer({
4387 //    width: 400,
4388 //    tag: "scroll"
4389 //    actors:[
4390 //            image({filename:"animage,
4391 //                   name: "myimage",
4392 //                   tag: "scrollitem",
4393 //                   width: 200,
4394 //                   height: 100}),
4395 //            text({text:"sometext,
4396 //                  tag: "scrollitem",
4397 //                  width:10})
4398 //           ]
4399 //  )
4400 // )
4401
4402 // when("myimage", condition("touched", "inside", 0, 100),
4403 // or
4404 // when("myimage", "touched",
4405 //      call(myfunction),
4406 //      call(myfunction, arg1),
4407 //      and("animation-ends"),
4408 //      set("myimage", "size", to([10,10,10]),
4409 //                             to([10,10,10], 0,3, "ease_in")),
4410 //                             path(0,3, "ease_in", "path0")),
4411 //                             between([0,0,0], [10,10,10], 0,3, "ease_in")),
4412 //                             to([0,0,0], 0, 3)
4413 //     set(tagged("scrollitem), path(0,3, "ease_in", "path0")),
4414 //     set(excludeFrom(tagged("scrollitem"), "myimage"), path(0,3, "ease_in", "path0")),
4415 //     then("myimage", "hide"),
4416 //     then("quit"),
4417 //     then("play", "myanim"),
4418 //     thenOnChild("myimage", "child", "hide"),
4419 //     animate("name"),
4420 //        )
4421
4422 // constraints?
4423 // on("myimage", "position", between(0, 100),
4424
4425
4426
4427 //------------------------------------------------------------------------------
4428 // test helper functions
4429 //------------------------------------------------------------------------------
4430
4431 function clear() {
4432   var root = dali.stage.rootRotationActor;
4433   var children = root.getChildren();
4434
4435   for (var i = 0, len = children.length; i < len; i++) {
4436     root.remove(children[i]);
4437     children[i].delete(); // delete the wrapper
4438   }
4439   //  root.delete(); // wrapper
4440 }
4441
4442 function square(color, size) {
4443   var a = dali.createSolidColorActor(color, 0, [0, 0, 0, 1], 0);
4444   a.size = size;
4445   return a;
4446 }
4447
4448 function threeSquares() {
4449   var root = dali.stage.rootRotationActor;
4450
4451   var a = square([1, 0, 0, 1], [200, 200, 0]);
4452   a.name = "red";
4453   a.position = [-100, 0, -20];
4454   root.add(a);
4455   a.delete();
4456
4457   a = square([0, 1, 0, 1], [200, 200, 0]);
4458   a.name = "green";
4459   a.position = [0, -100, -10];
4460   root.add(a);
4461   a.delete();
4462
4463   a = square([0, 0, 1, 1], [200, 200, 0]);
4464   a.name = "blue";
4465   a.position = [0, -100, 0];
4466   root.add(a);
4467   a.delete();
4468
4469   //  root.delete();
4470 }
4471
4472 function threeSquares2() {
4473   var root = dali.stage.rootRotationActor;
4474
4475   var red = square([1, 0, 0, 1], [200, 200, 0]);
4476   red.name = "red";
4477   red.position = [-100, 0, 20];
4478   red.size = [10, 10, 0];
4479   root.add(red);
4480
4481   var green = square([0, 1, 0, 1], [200, 200, 0]);
4482   green.name = "green";
4483   green.position = [0, -100, 0];
4484   green.orientation = [0, 0, 20];
4485   green.size = [200, 200, 0];
4486
4487   var blue = square([0, 0, 1, 1], [200, 200, 0]);
4488   blue.name = "blue";
4489   blue.position = [0, 0, 10];
4490   blue.parentOrigin = [0, 0, 0];
4491   blue.size = [100, 100, 0];
4492   green.add(blue);
4493   root.add(green);
4494
4495   red.delete(); // wrapper
4496   green.delete(); // wrapper
4497   blue.delete(); // wrapper
4498
4499   //  root.delete();
4500 }
4501
4502 function collectByName(collection) {
4503   var root = dali.stage.rootRotationActor;
4504   if (collection === undefined) {
4505     collection = {};
4506   }
4507   var op = function(actor) {
4508     if (actor.name) {
4509       collection[actor.name] = actor;
4510     }
4511     return true;
4512   };
4513
4514   dali.debug.depthVisit(root, op, true);
4515
4516   return collection;
4517 }
4518
4519
4520 function first() {
4521   return dali.stage.getRenderTaskList().getTask(0);
4522 }
4523
4524 function second() {
4525   return dali.stage.getRenderTaskList().getTask(1);
4526 }
4527
4528 function third() {
4529   return dali.stage.getRenderTaskList().getTask(2);
4530 }
4531
4532 function firstCamera() {
4533   return dali.stage.getRenderTaskList().getTask(0).getCameraActor();
4534 }
4535
4536 function secondCamera() {
4537   return dali.stage.getRenderTaskList().getTask(1).getCameraActor();
4538 }
4539
4540 function thirdCamera() {
4541   return dali.stage.getRenderTaskList().getTask(2).getCameraActor();
4542 }
4543
4544 function resize(w, h) {
4545   dali.setCanvasSize(w, h);
4546 }
4547
4548 function compareProperties(a1, a2) {
4549   var props1 = a1.getProperties();
4550   var props2 = a2.getProperties();
4551   var props = new Set();
4552   for (var i = 0, len = props1.size(); i < len; i++) {
4553     props.add(props1.get(i));
4554   }
4555
4556   for (i = 0, len = props2.size(); i < len; i++) {
4557     var n = props2.get(i);
4558     if (!props.has(n)) {
4559       console.log("A1 missing :" + n);
4560     }
4561   }
4562
4563   var doit = function(item) {
4564     var v1 = a1[item]; // a1.getProperty(item);
4565     var v2 = a2[item]; // a2.getProperty(item);
4566
4567     var isSame;
4568
4569     if (Array.isArray(v1)) {
4570       isSame = (v1.length === v2.length) && v1.every(function(element, index) {
4571         return element === v2[index];
4572       });
4573     } else {
4574       isSame = v1 === v2;
4575     }
4576
4577     if (!isSame) {
4578       console.log(item + ": A1= " + v1 + " A2= " + v2);
4579     }
4580   };
4581
4582   props.forEach(doit);
4583 }
4584
4585 var EPSILON = 0.005;
4586
4587 function compareArrays(a, b) {
4588   "use strict";
4589   if (Array.isArray(a) && Array.isArray(b)) {
4590     if (a.length === b.length) {
4591       for (var i = 0, len = a.length; i < len; i++) {
4592         if (Array.isArray(a[i])) {
4593           if (Array.isArray(b[i])) {
4594             if (!compareArrays(a[i], b[i])) {
4595               return false;
4596             }
4597           } else {
4598             return false;
4599           }
4600         } else {
4601           if (typeof (a[i]) === "number") {
4602             if (typeof (b[i]) !== "number") {
4603               return false;
4604             } else {
4605               if (Math.abs(a[i]) > Math.abs(b[i]) + EPSILON ||
4606                   Math.abs(a[i]) < Math.abs(b[i]) - EPSILON) {
4607                 return false;
4608               }
4609             }
4610           } else {
4611             if (a[i] !== b[i]) {
4612               return false;
4613             }
4614           }
4615         }
4616       }
4617       return true;
4618     }
4619   }
4620   return false;
4621 }
4622
4623 function countAllProperties() {
4624   var count = 0;
4625   var tr = new dali.TypeRegistry();
4626   var names = tr.getTypeNames();
4627   for (var i = 0, len = names.size(); i < len; i++) {
4628     var ti = tr.getTypeInfo(names.get(i));
4629     var props = ti.getProperties();
4630     count += props.size();
4631   }
4632   return count;
4633 }
4634
4635 function native2ascii(str) {
4636   "use strict";
4637   // really this function allows only GLSL permittable chars
4638   var out = "";
4639   for (var i = 0; i < str.length; i++) {
4640     if ( 0x20 <= str.charCodeAt(i) && str.charCodeAt(i) <= 0x7E) {
4641       // normal characters
4642       out += str.charAt(i);
4643     } else if( 0x9 <= str.charCodeAt(i) && str.charCodeAt(i) <= 0xD) {
4644       // new lines and tabs
4645       out += str.charAt(i);
4646     }
4647   }
4648   return out;
4649 }
4650
4651
4652 var getGL = function() {
4653   return canvas.getContext("webgl");
4654 };
4655
4656 var getAnimation = function() {
4657   "use strict";
4658   return animationList[animationSelectionIndex].animation;
4659 };
4660
4661 var getActor = function() {
4662   "use strict";
4663   return eventHandler.touchedActor;
4664 };
4665
4666
4667 //------------------------------------------------------------------------------
4668 // Unit test class
4669 //------------------------------------------------------------------------------
4670 function Test() {
4671   "use strict";
4672 }
4673
4674 Test.prototype.hierarchy = function() {
4675   "use strict";
4676   console.log("test_hierarchy...");
4677
4678   // function onTouched(actor) {
4679   //   // console.log("touched " + actor.$$.ptr + " " + actor.position);
4680   //   eventHandler.onTouched(actor);
4681   // }
4682
4683   var actor = new dali.Actor();
4684   actor.parentOrigin = [0.5, 0.5, 0.5];
4685   actor.anchorPoint = [0.5, 0.5, 0.5];
4686   actor.text = "actor";
4687   actor.name = actor.text;
4688   actor.size = [100, 100, 1];
4689   actor.position = [0, 0, 10];
4690   dali.stage.add(actor);
4691
4692   var hello = new dali.Actor();
4693   // hello.connect("touched", onTouched);
4694   hello.text = "hello";
4695   hello.name = hello.text;
4696   actor.add(hello);
4697
4698   var hellochild = new dali.Actor();
4699   // hellochild.connect("touched", onTouched);
4700   hellochild.text = "hello-child";
4701   hellochild.name = hellochild.text;
4702   hello.add(hellochild);
4703
4704   var hellochild2 = new dali.Actor();
4705   // hellochild2.connect("touched", onTouched);
4706   hellochild2.text = "hello-child2";
4707   hellochild2.name = hellochild2.text;
4708   hello.add(hellochild2);
4709
4710   var hellochildchild = new dali.Actor();
4711   // hellochildchild.connect("touched", onTouched);
4712   hellochildchild.text = "hello-child-child1";
4713   hellochildchild.name = "hello-child-child1";
4714   hellochildchild.name = hellochildchild.text;
4715   hellochild.add(hellochildchild);
4716
4717
4718   var depthfirst = actor.findAllChildren();
4719
4720   assert(actor.getChildCount() === 1);
4721   // assert(actor.getChildAt(0).text === "hello");
4722   // assert(actor.findChildByName("hello-child-child1").text = "hello-child-child1");
4723   // assert(hello.getParent().text === "actor");
4724   // assert(depthfirst[depthfirst.length - 1].text === "hello-child2");
4725
4726   var directChildren = actor.directChildren();
4727
4728   assert(directChildren.length === 1);
4729   assert(directChildren[0].getId() === hello.getId());
4730
4731   actor.position = [100, 100, 0];
4732
4733   var root = dali.stage.rootRotationActor;
4734
4735   actor.remove(hello);
4736   assert(actor.getChildCount() === 0);
4737
4738   actor.add(hello);
4739   assert(actor.getChildCount() === 1);
4740
4741   var rootLayerCount = root.getChildCount();
4742   dali.stage.remove(actor); // check these don't assert
4743   assert(root.getChildCount() === rootLayerCount - 1);
4744
4745   dali.stage.add(actor);
4746   assert(root.getChildCount() === rootLayerCount);
4747
4748   assert(root.findChildByName("none") === null);
4749
4750   // actor.connect("touched", onTouched);
4751
4752   // var inserted = new dali.TextActor(); // TextActor no more RIP
4753   // inserted.parentOrigin = [0.5, 0.5, 0.5];
4754   // inserted.anchorPoint = [0.5, 0.5, 0.5];
4755   // inserted.text = "inserted";
4756   // inserted.name = inserted.text;
4757   // inserted.size = [100, 100, 1];
4758   // inserted.position = [0, 0, 50];
4759   // actor.insert(1, inserted);
4760   // assert(actor.getChildAt(1).text === "inserted");
4761
4762   clear();
4763   console.log("  -> ok test_hierarchy");
4764 };
4765
4766 Test.prototype.registerProperty = function() {
4767   "use strict";
4768   console.log("test_registerPropery...");
4769   var s = dali.stage;
4770   var root = s.rootRotationActor;
4771
4772   var another = new dali.Actor();
4773   another.parentOrigin = [0.5, 0.5, 0.5];
4774   another.anchorPoint = [0.5, 0.5, 0.5];
4775   another.text = "peppa";
4776   another.name = another.text;
4777   another.size = [100, 100, 1];
4778   another.position = [-50, 100, 0];
4779   root.add(another);
4780
4781   var c = root.getChildAt(root.getChildCount() - 1);
4782   //var n = c.getChildCount();
4783   var p = c.getParent();
4784   assert(p.getId() == root.getId());
4785
4786   var matrix = c.worldMatrix;
4787
4788   assert(matrix.length === 16);
4789
4790   // todo - no longer supported (?)
4791   // another.registerProperty("data_output", true);
4792   // assert(another.getPropertyTypeFromName("data_output") === "BOOLEAN");
4793   // assert(another.data_output === true);
4794   // another.data_output = false;
4795   // assert(another.data_output === false);
4796   // dali.__updateOnce();
4797   // another.data_output = 2.5;
4798   // assert(another.data_output === 2.5);
4799   // assert(another.getPropertyTypeFromName("data_output") === "FLOAT");
4800
4801   clear();
4802   console.log("  -> ok test_registerPropery");
4803 };
4804
4805 Test.prototype.js_math = function() {
4806   console.log("test_js_math...");
4807   assert(dali.vectorLength([1, 2, 3, 4]) === Math.sqrt(1 * 1 + 2 * 2 + 3 * 3));
4808   assert(dali.vectorLengthSquared(dali.normalize([0, 0, 0, 1])) === 0);
4809
4810   // for(var f=0; f < 6; f+=1)
4811   // {
4812   var f = 2;
4813   assert(1 === dali.vectorLengthSquared(dali.normalize([Math.cos(f) * 10.0,
4814                                                         Math.cos(f + 1.0) * 10.0,
4815                                                         Math.cos(f + 2.0) * 10.0,
4816                                                         1.0
4817                                                        ])));
4818
4819   function assertArray(a, b, epsilon) {
4820     assert(a.length === b.length);
4821     for (var i = 0, len = a.length; i < len; ++i) {
4822       assert(a[i] > b[i] - epsilon && a[i] < b[i] + epsilon);
4823     }
4824   }
4825
4826   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);
4827
4828   assertArray(dali.quaternionToAxisAngle([1.1, 3.4, 2.7, 0.932]), [3.03, 9.38, 7.45, 0.74],
4829               0.01);
4830
4831   assertArray(dali.vectorCross([0, 1, 0], [0, 0, 1]), [1, 0, 0], 0.001);
4832
4833   assertArray(dali.vectorAdd([1, 2, 3], [2, 3, 4], [1, 1, 1]), [4, 6, 8], 0.001);
4834
4835   var mq = dali.vectorAdd(dali.vectorCross([0.045, 0.443, 0.432], [0.612, 0.344, -0.144]),
4836                           dali.vectorByScalar([0.612, 0.344, -0.144], 0.784),
4837                           dali.vectorByScalar([0.045, 0.443, 0.432], 0.697));
4838
4839   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])],
4840               0.001);
4841
4842   clear();
4843   console.log("  -> ok test_js_math");
4844 };
4845
4846 Test.prototype.getset = function() {
4847   "use strict";
4848   console.log("test_getset...");
4849   threeSquares();
4850   var col = {};
4851   collectByName(col);
4852   var actor = col.red;
4853   var p = actor.position;
4854   actor.position = [1, 1, 1];
4855   assert(compareArrays(actor.position, [1, 1, 1]));
4856   actor.position = [3, 3, 3];
4857   assert(compareArrays(actor.position, [3, 3, 3]));
4858   actor.position = p;
4859
4860   clear();
4861   console.log("  -> ok test_getset");
4862 };
4863
4864 Test.prototype.animation_spline = function() {
4865   "use strict";
4866   console.log("test_animation_spline...");
4867   threeSquares();
4868   var col = {};
4869   collectByName(col);
4870   var actor = col.red;
4871
4872   var a = new dali.Animation(0);
4873   var path = new dali.Path();
4874
4875   path.points = [
4876     [-150, -50, 0],
4877     [0.0, 70.0, 0.0],
4878     [190.0, -150.0, 0.0]
4879   ];
4880
4881   assert(compareArrays(path.points, [
4882     [-150, -50, 0],
4883     [0.0, 70.0, 0.0],
4884     [190.0, -150.0, 0.0]
4885   ]));
4886
4887   dali.generateControlPoints(path, 0.35);
4888
4889   assert(compareArrays(path.controlPoints, [
4890     [-97.5, -8, 0],
4891     [-66.94940948486328, 76.16658020019531, 0],
4892     [101.31224060058594, 60.66832733154297, 0],
4893     [123.5, -73, 0]
4894   ]));
4895
4896   a.setDuration(3);
4897   a.animatePath(actor, path, [1, 0, 0], dali.AlphaFunction.LINEAR, 0, 3);
4898   a.play();
4899
4900   function checkPos() {
4901     assert(actor.position = path.points[2]);
4902     clear();
4903     actor.delete();
4904     path.delete();
4905     a.delete();
4906     console.log("  -> ok test_animation_spline");
4907   }
4908
4909   window.setTimeout(checkPos, 4000);
4910 };
4911
4912 Test.prototype.animation = function() {
4913   "use strict";
4914   console.log("test_animation...");
4915   threeSquares();
4916   var col = {};
4917   collectByName(col);
4918   var actor = col.red;
4919
4920   var a = new dali.Animation(0);
4921   a.setDuration(3);
4922   a.animateTo(actor, "position", [20, 0, 0], dali.AlphaFunction.LINEAR, 0, 3);
4923   a.play();
4924
4925   function checkAnimateBetween() {
4926     assert(actor.position = [0, 0, -30]);
4927     clear();
4928     a.delete();
4929     actor.delete();
4930
4931     console.log("  -> ok test_animation");
4932   }
4933
4934   function checkAnimateBy() {
4935     assert(actor.position = [120, 100, 0]);
4936
4937     a.clear();
4938     a.animateBetween(actor,
4939                      "position", [ [ 0,  [10,20,30] ],
4940                                    [ 1.0,[0, 0, -30] ] ],
4941                      "linear",
4942                      0,
4943                      3,
4944                      "linear");
4945     a.play();
4946     window.setTimeout(checkAnimateBetween, 4000);
4947   }
4948
4949   function checkAnimateTo() {
4950     assert(actor.position = [20, 0, 0]);
4951     actor.position = [100, 100, 0];
4952
4953     a.clear(); // var a = new dali.Animation(0);
4954     a.setDuration(3);
4955     a.animateBy(actor, "position", [20, 0, 0], dali.AlphaFunction.LINEAR, 0, 3);
4956     a.play();
4957
4958     window.setTimeout(checkAnimateBy, 4000);
4959   }
4960
4961   window.setTimeout(checkAnimateTo, 4000);
4962 };
4963
4964 Test.prototype.onePane = function() {
4965   var w = dali.canvas.width;
4966   var h = dali.canvas.height;
4967   var col = dali.getClearColor(0);
4968   dali.onePane();
4969   dali.setFrontView(0, 0, 0, w, h);
4970   dali.setClearColor(0, col);
4971 };
4972
4973 Test.prototype.threePane = function() {
4974   var w = dali.canvas.width;
4975   var h = dali.canvas.height;
4976   dali.threePane();
4977   dali.setClearColor(0, [0.4, 0, 0, 1]);
4978   dali.setClearColor(1, [0, 0.4, 0, 1]);
4979   dali.setClearColor(2, [0, 0, 0.4, 1]);
4980   dali.setFrontView(0, 0, 0, w / 2 - 5, h);
4981   dali.setTopView(1, w / 2, 0, w / 2, h / 2 - 5);
4982   dali.setRightView(2, w / 2, h / 2 + 5, w / 2, h / 2 - 5);
4983 };
4984
4985 Test.prototype.twoPane = function() {
4986   var w = dali.canvas.width;
4987   var h = dali.canvas.height;
4988   dali.twoPane();
4989   dali.setFrontView(0, 0, 0, w / 2 - 10, h);
4990   dali.setTopView(1, 210, 0, w / 2 - 10, h);
4991   dali.setClearColor(0, [0.4, 0, 0, 1]);
4992   dali.setClearColor(1, [0, 0.4, 0, 1]);
4993 };
4994
4995 Test.prototype.views = function() {
4996   "use strict";
4997   console.log("test_views");
4998
4999   var w = dali.canvas.width;
5000   var h = dali.canvas.height;
5001   var col = dali.getClearColor(0);
5002   console.log(col);
5003
5004   function one() {
5005     dali.onePane();
5006     dali.setFrontView(0, 0, 0, w, h);
5007     dali.setClearColor(0, col);
5008   }
5009
5010   function three() {
5011     dali.threePane();
5012     dali.setClearColor(0, [0.4, 0, 0, 1]);
5013     dali.setClearColor(1, [0, 0.4, 0, 1]);
5014     dali.setClearColor(2, [0, 0, 0.4, 1]);
5015     dali.setFrontView(0, 0, 0, w / 2 - 5, h);
5016     dali.setTopView(1, w / 2, 0, w / 2, h / 2 - 5);
5017     dali.setRightView(2, w / 2, h / 2 + 5, w / 2, h / 2 - 5);
5018
5019     window.setTimeout(one, 1000);
5020   }
5021
5022   function two() {
5023     dali.twoPane();
5024     dali.setFrontView(0, 0, 0, w / 2 - 10, h);
5025     dali.setTopView(1, 210, 0, w / 2 - 10, h);
5026     dali.setClearColor(0, [0.4, 0, 0, 1]);
5027     dali.setClearColor(1, [0, 0.4, 0, 1]);
5028
5029     window.setTimeout(three, 1000);
5030   }
5031
5032   one();
5033
5034   window.setTimeout(two, 1000);
5035 };
5036
5037 Test.prototype.blinking = function() {
5038   "use strict";
5039   var layer = new dali.Layer();
5040   layer.name = "frameLayer";
5041   dali.stage.add(layer);
5042
5043   var a = dali.createSolidColorActor([0.5, 0.5, 0.5, 1],
5044                                      false, [0, 0, 0, 1],
5045                                      0);
5046   a.size = [100,100,1];
5047
5048   layer.add(a);
5049
5050   var camera = firstCamera();
5051
5052   camera.position = [ camera.position[0]+10, camera.position[1]+20, camera.position[2] + 10 ];
5053
5054   layer.delete();   // wrapper
5055   a.delete();       // wrapper
5056   camera.delete();  // wrapper
5057 };
5058
5059 Test.prototype.uniformMetaData = function() {
5060   for(var i = 0; i < shaderSources.length; i++) {
5061     console.log(dali.uniformMetaData(shaderSources[i].vertex, shaderSources[i].fragment));
5062   }
5063 };
5064
5065 Test.prototype.signals = function() {
5066   "use strict";
5067   console.log("test_signals...");
5068
5069   function onStage() {
5070     console.log("   -> ok test signals");
5071     //eventHandler.onTouched(actor);
5072   }
5073
5074   var actor = new dali.Actor();
5075   actor.parentOrigin = [0.5, 0.5, 0.5];
5076   actor.anchorPoint = [0.5, 0.5, 0.5];
5077   actor.text = "actor";
5078   actor.name = actor.text;
5079   actor.size = [100, 100, 1];
5080   actor.position = [0, 0, 10];
5081
5082   actor.connect("on-stage", onStage);
5083
5084   dali.stage.add(actor);
5085 };
5086
5087 Test.prototype.shaderInfo = function() {
5088   "use strict";
5089   var info = new dali.ShaderInfo();
5090
5091   var vertex;
5092   var fragment;
5093
5094   vertex = "\n" +
5095     "attribute mediump vec3 aPosition;\n" +
5096     "attribute mediump vec2 aTexCoord;\n" +
5097     "varying mediump vec2 vTexCoord;\n" +
5098     "uniform mediump vec3 uSize;\n" +
5099     "// uniform mediump vec3 unusedUniform;\n" +
5100     "uniform mediump mat4 uModelView;\n" +
5101     "uniform mediump mat4 uProjection;\n" +
5102     "\n" +
5103     "void main(void)\n" +
5104     "{\n" +
5105     "  gl_Position = uProjection * uModelView * vec4(aPosition, 1.0);\n" +
5106     "  gl_Position.xyz *= uSize;\n" +
5107     "  vTexCoord = aTexCoord;\n" +
5108     "}\n";
5109
5110   fragment = "precision mediump float;\n" +
5111     "\n" +
5112     "uniform sampler2D sTexture;\n" +
5113     "uniform mediump vec4 uMyColor; // {min:[0,0,0,0], max:[1,1,1,1]}\n" +
5114     "uniform mediump vec4 uColor;\n" +
5115     "varying mediump vec2 vTexCoord;\n" +
5116     "\n" +
5117     "void main()\n" +
5118     "{\n" +
5119     "  gl_FragColor = texture2D( sTexture, vTexCoord ) * uColor * uMyColor;\n" +
5120     "}\n";
5121
5122   var canvas = document.createElement("canvas");
5123   var meta = info.fromCompilation(canvas.getContext("webgl"), vertex, fragment);
5124
5125   var uniforms = { uSize: 1,
5126                    uModelView: 1,
5127                    uProjection: 1,
5128                    uMyColor: 1,
5129                    uColor: 1
5130                  };
5131
5132   assert(meta.hasError === false);
5133   var name;
5134   var metaUniformName;
5135   var found;
5136
5137   for(name in uniforms) {
5138     found = false;
5139     for(metaUniformName in meta.uniforms) {
5140       if(metaUniformName === name) {
5141         found = true;
5142         break;
5143       }
5144     }
5145     assert(found, "missing:" + name);
5146   }
5147
5148   assert(compareArrays(meta.uniformUISpec.uMyColor.min, [0, 0, 0, 0]));
5149   assert(compareArrays(meta.uniformUISpec.uMyColor.max, [1, 1, 1, 1]));
5150
5151
5152   meta = info.fromRegEx(vertex, fragment);
5153
5154   assert(meta.hasError === false);
5155
5156   for(name in uniforms) {
5157     found = false;
5158     for(metaUniformName in meta.uniforms) {
5159       if(metaUniformName === name) {
5160         found = true;
5161         break;
5162       }
5163     }
5164     assert(found, "missing:" + name);
5165   }
5166
5167   assert(compareArrays(meta.uniformUISpec.uMyColor.min, [0, 0, 0, 0]));
5168   assert(compareArrays(meta.uniformUISpec.uMyColor.max, [1, 1, 1, 1]));
5169
5170   console.log("   -> ok test shaderInfo");
5171 };
5172
5173 //------------------------------------------------------------------------------
5174 // regression test
5175 //------------------------------------------------------------------------------
5176
5177 Test.prototype.regression = function() {
5178   "use strict";
5179   this.hierarchy();
5180   this.registerProperty();
5181   this.js_math();
5182   this.getset();
5183   this.animation();
5184   this.animation_spline();
5185   // this.shadereffect1();
5186   this.views();
5187   this.signals();
5188   this.shaderInfo();
5189 };
5190
5191 Test.prototype.remote_execution = function() {
5192   "use strict";
5193   this.regression();
5194 };
5195
5196 Test.prototype.stacking = function() {
5197   "use strict";
5198
5199   eventHandler.selectActor( dali.stage.rootRotationActor );
5200
5201   var a = dali.createSolidColorActor([1.0, 0.0, 0.0, 1.0],
5202                                      false, [0, 0, 0, 1],
5203                                      0);
5204   app.addActor(a);
5205
5206   eventHandler.selectActor( a );
5207
5208   var b = dali.createSolidColorActor([0.0, 0.0, 1.0, 1.0],
5209                                      false, [0, 0, 0, 1],
5210                                      0);
5211   app.addActor(b);
5212
5213   a.sizeWidth = a.sizeHeight = 100;
5214   b.sizeWidth = b.sizeHeight = 50;
5215
5216   b.sizeWidth = 150;
5217
5218   return [a, b];
5219 };
5220
5221
5222 var runTest = function(functionName) {
5223   "use strict";
5224
5225   clear();
5226
5227   dali.stage.setBackgroundColor([0.3, 0.3, 0.3, 1]);
5228
5229   var test = dali[functionName]();
5230
5231   if( test )
5232   {
5233     if( !test.complete() )
5234     {
5235       function check() {
5236         if( !test.complete() ) {
5237           window.setTimeout(checkPos, 500);
5238         } else {
5239           console.log("test success");
5240         }
5241       }
5242     }
5243   }
5244
5245 };
5246
5247 //------------------------------------------------------------------------------
5248 // scratch
5249 //------------------------------------------------------------------------------
5250 function animateShaderEffect2(actor) {
5251   "use strict";
5252   var shader = new dali.ShaderEffect({
5253     vertex: shaderSource2.vertex,
5254     fragment: shaderSource2.fragment
5255   });
5256
5257   actor.setShaderEffect(shader);
5258
5259   var final = [5, 5, 5, 1];
5260
5261   var a = new dali.Animation(0);
5262   a.setDuration(3);
5263   a.setLooping(true);
5264   a.animateTo(shader, "weight", final, dali.AlphaFunction.LINEAR, 0, 3);
5265
5266   a.play();
5267
5268   a.delete();
5269
5270 }
5271
5272
5273 var testfile = { // output from clara.io "Threejs scene output"
5274   "metadata": {
5275     "version": 4.3, // This isnt as its documented on threejs website
5276     "type": "Object", // and the general format looks more like format V3.
5277     "generator": "ObjectExporter"
5278   },
5279   "geometries": [{
5280     "uuid": "2f167add-e571-47c2-9da2-6f0e45cc1119",
5281     "type": "Geometry",
5282     "data": {
5283       "vertices": [
5284         0.5,
5285         0.5,
5286         0.5,
5287         0.5,
5288         0.5, -0.5,
5289         0.5, -0.5,
5290         0.5,
5291         0.5, -0.5, -0.5, -0.5,
5292         0.5, -0.5, -0.5,
5293         0.5,
5294         0.5, -0.5, -0.5, -0.5, -0.5, -0.5,
5295         0.5
5296       ],
5297       "normals": [
5298         1,
5299         0,
5300         0, -1,
5301         0,
5302         0,
5303         0,
5304         1,
5305         0,
5306         0, -1,
5307         0,
5308         0,
5309         0,
5310         1,
5311         0,
5312         0, -1
5313       ],
5314       "uvs": [
5315         [
5316           0,
5317           1,
5318           0,
5319           0,
5320           1,
5321           0,
5322           1,
5323           1
5324         ]
5325       ],
5326       "faces": [
5327         56,
5328
5329         0,
5330         2,
5331         3,
5332
5333         0,
5334         1,
5335         2,
5336
5337         0,
5338         0,
5339         0,
5340
5341         0,
5342
5343         56,
5344         0,
5345         3,
5346         1,
5347         0,
5348         2,
5349         3,
5350         0,
5351         0,
5352         0,
5353         0,
5354         56,
5355         4,
5356         6,
5357         7,
5358         0,
5359         1,
5360         2,
5361         1,
5362         1,
5363         1,
5364         1,
5365         56,
5366         4,
5367         7,
5368         5,
5369         0,
5370         2,
5371         3,
5372         1,
5373         1,
5374         1,
5375         1,
5376         56,
5377         4,
5378         5,
5379         0,
5380         0,
5381         1,
5382         2,
5383         2,
5384         2,
5385         2,
5386         2,
5387         56,
5388         4,
5389         0,
5390         1,
5391         0,
5392         2,
5393         3,
5394         2,
5395         2,
5396         2,
5397         2,
5398         56,
5399         7,
5400         6,
5401         3,
5402         0,
5403         1,
5404         2,
5405         3,
5406         3,
5407         3,
5408         3,
5409         56,
5410         7,
5411         3,
5412         2,
5413         0,
5414         2,
5415         3,
5416         3,
5417         3,
5418         3,
5419         3,
5420         56,
5421         5,
5422         7,
5423         2,
5424         0,
5425         1,
5426         2,
5427         4,
5428         4,
5429         4,
5430         4,
5431         56,
5432         5,
5433         2,
5434         0,
5435         0,
5436         2,
5437         3,
5438         4,
5439         4,
5440         4,
5441         4,
5442         56,
5443         1,
5444         3,
5445         6,
5446         0,
5447         1,
5448         2,
5449         5,
5450         5,
5451         5,
5452         5,
5453         56,
5454         1,
5455         6,
5456         4,
5457         0,
5458         2,
5459         3,
5460         5,
5461         5,
5462         5,
5463         5
5464       ]
5465     }
5466   }],
5467   "materials": [{
5468     "uuid": "14D499F1-27EF-45BF-A457-FD24DAB11205",
5469     "type": "MeshPhongMaterial",
5470     "color": 11579568,
5471     "ambient": 11579568,
5472     "emissive": 0,
5473     "specular": 0,
5474     "shininess": 50,
5475     "opacity": 1,
5476     "transparent": false,
5477     "wireframe": false
5478   }],
5479   "object": {
5480     "uuid": "BFEFB48D-0E6E-46A6-8568-5E258BA17078",
5481     "type": "Scene",
5482     "matrix": [
5483       1,
5484       0,
5485       0,
5486       0,
5487       0,
5488       1,
5489       0,
5490       0,
5491       0,
5492       0,
5493       1,
5494       0,
5495       0,
5496       0,
5497       0,
5498       1
5499     ],
5500     "children": [{
5501       "uuid": "aa901bec-9e47-4b3b-bf3c-4efb0fe5d298",
5502       "name": "Box",
5503       "type": "Mesh",
5504       "geometry": "2f167add-e571-47c2-9da2-6f0e45cc1119",
5505       "material": "14D499F1-27EF-45BF-A457-FD24DAB11205",
5506       "castShadow": true,
5507       "receiveShadow": true,
5508       "matrix": [
5509         1,
5510         0,
5511         0,
5512         0,
5513         0,
5514         1,
5515         0,
5516         0,
5517         0,
5518         0,
5519         1,
5520         0,
5521         0,
5522         0,
5523         0,
5524         1
5525       ]
5526     }]
5527   }
5528 };
5529
5530
5531
5532 //
5533 //
5534 // Event/widget setup
5535 //
5536 //
5537
5538 //------------------------------------------------------------------------------
5539 //
5540 // Helper functions
5541 //
5542 //------------------------------------------------------------------------------
5543 function rebuildDropdown(dropdownElement, db, dbStoreName, optionalItemDataFunc) {
5544   "use strict";
5545   removeAllChildren(dropdownElement);
5546
5547   var func = optionalItemDataFunc;
5548   if( !func ) {
5549     func = function(name) {
5550       return [null, name];
5551     };
5552   }
5553
5554   var li;
5555   var a;
5556   var names = db.getKeys(dbStoreName);
5557
5558   for(var i = 0; i < names.length; i++) {
5559     li = document.createElement("li");
5560     var hrefText = func(names[i]);
5561     if( hrefText[0] ) {
5562       a = document.createElement("a");
5563       a.href = hrefText[0];
5564       a.text = hrefText[1];
5565     } else {
5566       a = document.createElement("p");
5567       a.textContent = hrefText[1];
5568     }
5569     li.appendChild(a);
5570     dropdownElement.appendChild(li);
5571   }
5572 }
5573
5574
5575 //------------------------------------------------------------------------------
5576 //
5577 // UI General
5578 //
5579 //------------------------------------------------------------------------------
5580 function UIApp() {
5581   "use strict";
5582   var self = this;
5583
5584   self.modalQuestionYesFunction = null;
5585   self.modalQuestionNoFunction = null;
5586
5587   var _modalQuestionYes = function() {
5588     if(self.modalQuestionYesFunction) {
5589       self.modalQuestionYesFunction();
5590     }
5591     self.modalQuestionYesFunction = null;
5592     self.modalQuestionNoFunction = null;
5593   };
5594
5595   var _modalQuestionNo = function() {
5596     if(self.modalQuestionNo) {
5597       self.modalQuestionNo();
5598     }
5599     self.modalQuestionYesFunction = null;
5600     self.modalQuestionNoFunction = null;
5601   };
5602
5603   var _modalInputOk = function() {
5604     if(self.modalInputOkFunction) {
5605       var input = $("#modalInputText")[0];
5606       self.modalInputOkFunction(input.value);
5607     }
5608     self.modalInputOkFunction = null;
5609     self.modalInputCancelFunction = null;
5610   };
5611
5612   var _modalInputCancel = function() {
5613     if(self.modalInputCancel) {
5614       self.modalInputCancel();
5615     }
5616     self.modalInputOkFunction = null;
5617     self.modalInputCancelFunction = null;
5618   };
5619
5620   $("#modalQuestionYes")[0].addEventListener("click", _modalQuestionYes);
5621   $("#modalQuestionNo")[0].addEventListener("click", _modalQuestionNo);
5622
5623   self.modalInputYesFunction = null;
5624   self.modalInputNoFunction = null;
5625
5626   $("#modalInputOk")[0].addEventListener("click", _modalInputOk);
5627   $("#modalInputCancel")[0].addEventListener("click", _modalInputCancel);
5628
5629 }
5630
5631 UIApp.prototype.messageBoxHTML = function(innerHtmlText) {
5632   "use strict";
5633   var modalBody = $("#modalCodeInfoBody")[0];
5634   removeAllChildren(modalBody);
5635   modalBody.innerHTML = innerHtmlText;
5636   $("#modalCodeInfo").modal("show");
5637 };
5638
5639 UIApp.prototype.messageBox = function(message) {
5640   "use strict";
5641   this.messageBoxHTML("<p>" + message + "</p>");
5642 };
5643
5644 UIApp.prototype.questionBox = function(message, yesFunction, noFunction) {
5645   "use strict";
5646   var modalBody = $("#modalQuestionBody")[0];
5647   removeAllChildren(modalBody);
5648   modalBody.innerHTML = "<p>" + message + "</p>";
5649
5650   this.modalQuestionYesFunction = yesFunction;
5651   this.modalQuestionNoFunction = noFunction;
5652
5653   $("#modalQuestion").modal("show");
5654 };
5655
5656 UIApp.prototype.codeInformationBox = function(code) {
5657   "use strict";
5658   var modalBody = $("#modalCodeInfoBody")[0];
5659   removeAllChildren(modalBody);
5660   modalBody.innerHTML = "<pre>" + code + "</pre>";
5661   $("#modalCodeInfo").modal("show");
5662 };
5663
5664 UIApp.prototype.inputbox = function(message, okFunction, cancelFunction) {
5665   "use strict";
5666   var modalBody = $("#modalInputBody")[0];
5667   removeAllChildren(modalBody);
5668   modalBody.innerHTML = "<p>" + message + "</p>";
5669
5670   this.modalInputOkFunction = okFunction;
5671   this.modalInputCancelFunction = cancelFunction;
5672
5673   $("#modalInput").modal("show");
5674 };
5675
5676 UIApp.prototype.getTypedBuffer = function(file, callback) {
5677   "use strict";
5678   if (!file) {
5679     return;
5680   }
5681   var reader = new FileReader();
5682   reader._theFilename = file.name;
5683   reader.onload = function(// e
5684   ) {
5685     var uint8View = new Uint8Array(reader.result); // convert ArrayBuffer into a typed array?
5686     callback(file.name, uint8View);
5687   };
5688
5689   reader.readAsArrayBuffer(file);
5690 };
5691
5692
5693 //------------------------------------------------------------------------------
5694 //
5695 // Javascript UI Tab
5696 //
5697 //------------------------------------------------------------------------------
5698 function UIJavascriptTab() {
5699   "use strict";
5700   var self = this;
5701   self.bufferPrepend = "Buffer Name:";
5702
5703   this.addNewBuffer = function() {
5704     var alreadyExists = function() {
5705       self.addNewBuffer();
5706     };
5707
5708     var inputOk = function(name) {
5709       var data = database.readJavascript(name);
5710       if(data) {
5711         uiApp.messageBox("Name already exsists", alreadyExists);
5712       } else {
5713         var newData = {name: name, source: ""};
5714         database.writeJavascript(newData);
5715         self.rebuildDropdown(database);
5716       }
5717     };
5718
5719     uiApp.inputbox("BufferName?", inputOk);
5720
5721   };
5722
5723   this.renameBuffer = function() {
5724     var writeOK = function() {
5725       var openRequest = database.open();
5726
5727       openRequest.onsuccess = function(event) {
5728         var db = event.target.result;
5729         self.rebuildDropdown(database);
5730         db.close();
5731       };
5732     };
5733
5734     var inputOk = function(name) {
5735       var data = uiJavascriptTab.getData();
5736       data.name = name;
5737       database.writeJavascript(data, writeOK);
5738     };
5739
5740     uiApp.inputbox("BufferName?", inputOk);
5741
5742   };
5743
5744   this.loadJavascript = function(name) {
5745     var data = database.readJavascript(name);
5746
5747     // save current
5748     var currentData = self.getData();
5749     if(currentData) {
5750       database.writeJavascript(currentData);
5751     }
5752
5753     self.setData(data);
5754   };
5755
5756   ace.require("ace/ext/language_tools");
5757   var editor = ace.edit("editorJavascript");
5758
5759   var _thisFunctions = [];
5760   for(var attr in this) {
5761     if( !(attr.startsWith("_") || attr.startsWith("dynCall") || attr.startsWith("invoke") ) ) {
5762       if( typeof this[attr] === "function") {
5763         _thisFunctions.push( attr );
5764       }
5765     }
5766   }
5767
5768   var myCompleter = {
5769     getCompletions: function(theEditor, session, pos, prefix, callback) {
5770       var wordlist = [];
5771       if(prefix === "dali.") {
5772         for(attr in dali) {
5773           if( !(attr.startsWith("_") || attr.startsWith("dynCall") || attr.startsWith("invoke") ) ) {
5774             if( typeof dali[attr] === "function") {
5775               wordlist.push( attr );
5776             }
5777           }
5778         }
5779       } else {
5780         wordlist = _thisFunctions;
5781       }
5782       callback(null, wordlist.map(function(word) {
5783         return {
5784           caption: word,
5785           value: word,
5786           meta: "static"
5787         };
5788       }));
5789     }
5790   };
5791
5792   editor.completers = [ myCompleter ];
5793
5794   editor.setOptions({
5795     enableBasicAutocompletion: true,
5796     enableSnippets: true,
5797     enableLiveAutocompletion: true
5798   });
5799
5800   document.getElementById("btnJavascriptSourceJson").addEventListener(
5801     "click",
5802     function(/*e*/) {
5803       self.showModalJSON();
5804     });
5805
5806   document.getElementById("btnJavascriptClearRun").addEventListener(
5807     "click",
5808     function(/*e*/) {
5809       self.clearStageAndEval();
5810     });
5811
5812   document.getElementById("btnJavascriptRun").addEventListener(
5813     "click",
5814     function(/*e*/) {
5815       self.eval();
5816     });
5817
5818   document.getElementById("btnJavascriptAddBuffer").addEventListener(
5819     "click",
5820     function(/*e*/) {
5821       self.addNewBuffer();
5822     });
5823
5824   document.getElementById("btnJavascriptRenameBuffer").addEventListener(
5825     "click",
5826     function(/*e*/) {
5827       self.renameBuffer();
5828     });
5829
5830   this.currentName = undefined;
5831
5832   var names = database.readJavascriptNames();
5833   if(names.length) {
5834     self.loadJavascript(names[0]); // load first javascript buffer
5835   }
5836
5837 }
5838
5839 UIJavascriptTab.prototype.getData = function() {
5840   "use strict";
5841   var e = ace.edit("editorJavascript");
5842   var ascii = native2ascii(e.getSession().getValue());
5843
5844   if(this.currentName !== undefined) {
5845     return { name: this.currentName,
5846              source: ascii };
5847   } else {
5848     return undefined;
5849   }
5850 };
5851
5852 UIJavascriptTab.prototype.setData = function(data) {
5853   "use strict";
5854   this.currentName = data.name;
5855   // set new
5856   var editor = ace.edit("editorJavascript");
5857   editor.getSession().setValue(data.source);
5858
5859   $("#textJavascriptName").html(this.bufferPrepend + data.name);
5860
5861 };
5862
5863 UIJavascriptTab.prototype.showModalJSON = function() {
5864   "use strict";
5865   var e = ace.edit("editorJavascript");
5866   var ascii = native2ascii(e.getSession().getValue());
5867
5868   var lines = ascii.split("\n");
5869
5870   var data = "{source:";
5871
5872   for(var i = 0; i < lines.length; i++) {
5873     data += "\"" + lines[i].replace(/"/g, "\\\"") + "\\n\" +\n";
5874   }
5875
5876   data += "\n\"\"}";
5877
5878   // data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
5879
5880   // data = data.replace(/"/g, "\\\""); // for loops are interpreted by browser as tags and dont print?
5881
5882   // data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
5883
5884   uiApp.codeInformationBox( data );
5885
5886 };
5887
5888 UIJavascriptTab.prototype.clearStageAndEval = function() {
5889   "use strict";
5890   var e = ace.edit("editorJavascript");
5891   var ascii = native2ascii(e.getSession().getValue());
5892   clear();
5893   // as of ecma5 an indirect call like this is in global scope
5894   var globalEval = eval;
5895   globalEval(ascii);
5896 };
5897
5898 UIJavascriptTab.prototype.eval = function() {
5899   "use strict";
5900   var e = ace.edit("editorJavascript");
5901   var ascii = native2ascii(e.getSession().getValue());
5902   // as of ecma5 an indirect call like this is in global scope
5903   var globalEval = eval;
5904   globalEval(ascii);
5905 };
5906
5907 UIJavascriptTab.prototype.rebuildDropdown = function(db) {
5908   "use strict";
5909   rebuildDropdown( document.getElementById("javascriptDropDown"),
5910                    db,
5911                    "javascript",
5912                    function(name) {
5913                      return ["javascript:uiJavascriptTab.loadJavascript(\"" + name + "\")",
5914                              name];
5915                    }
5916                  );
5917 };
5918
5919
5920 //------------------------------------------------------------------------------
5921 //
5922 // Image UI Tab
5923 //
5924 //------------------------------------------------------------------------------
5925
5926 /**
5927  * Get or create a dali image from the image buffer.
5928  *
5929  * Global function for use in javascript buffers or the console.
5930  * @param {string} shader buffer name
5931  * @return  {Object} dali.Image
5932  */
5933 function imageFromUiBuffer(name) {
5934   "use strict";
5935   var img = uiImageTab.getDaliImage(name);
5936   assert(img, "Could not find image:" + name);
5937   return img;
5938 }
5939
5940
5941 /**
5942  * Manages UI image tab.
5943  *
5944  * @constructor
5945  */
5946 function UIImageTab() {
5947   "use strict";
5948   var self = this;
5949   this.imagesCreated = {}; // dali shader objects
5950
5951   /********** methods **********/
5952   this.getBufferImageRGB = function(file, callback) {
5953     if (!file) {
5954       return;
5955     }
5956
5957     var img = new HTML5Image(); // the renamed Image()
5958
5959     var objectUrl = window.URL.createObjectURL(file);
5960
5961     img.onload = function( //e
5962     ) {
5963       var imageCanvas = document.createElement("canvas");
5964       imageCanvas.width = img.width; // naturalWidth;
5965       imageCanvas.height = img.height; // naturalHeight;
5966       var context = imageCanvas.getContext("2d");
5967       context.drawImage(img, 0, 0 );
5968       var imageData = context.getImageData(0, 0, img.naturalWidth, img.naturalHeight); // <-ImageData
5969       callback(file.name, imageData);
5970       window.URL.revokeObjectURL(objectUrl);
5971     };
5972
5973     img.src = objectUrl;
5974
5975   };
5976
5977
5978   /**
5979    * Add new image data
5980    *
5981    * @param {object} ImageData object
5982    */
5983   this.addNewBuffer = function(imageData) {
5984     var alreadyExists = function() {
5985       self.addNewBuffer(imageData);
5986     };
5987
5988     var inputOk = function(name) {
5989       var oldData = database.readImage(name);
5990       if(oldData) {
5991         uiApp.messageBox("Name already exsists", alreadyExists);
5992       } else {
5993         database.writeImage(name, imageData);
5994         self.rebuildDropdown(database);
5995       }
5996     };
5997
5998     uiApp.inputbox("BufferName?", inputOk);
5999   };
6000
6001   this.renameBuffer = function() {
6002     var inputOk = function(name) {
6003       var data = uiJavascriptTab.getData();
6004       data.name = name;
6005       database.writeJavascript(data);
6006       self.rebuildDropdown(database);
6007     };
6008
6009     uiApp.inputbox("BufferName?", inputOk);
6010   };
6011
6012   /**
6013    * Load image into the UI Image tab. (used for dynamically generated html dropdowns)
6014    *
6015    * @param {string} name of image buffer
6016    */
6017   this.loadImage = function(name) {
6018     self.setData( database.readImage(name) );
6019   };
6020
6021   /********** init **********/
6022
6023   document.getElementById("btnImageAddBuffer").addEventListener(
6024     "change",
6025     function() {
6026       var fileInput = document.getElementById("btnImageAddBuffer");
6027       var file = fileInput.files[0];
6028       self.getBufferImageRGB(
6029         file,
6030         function(name, typedBuffer) {
6031           self.addNewBuffer(typedBuffer);
6032         });
6033     });
6034
6035
6036   document.getElementById("btnImageRenameBuffer").addEventListener(
6037     "click",
6038     function(/*e*/) {
6039       self.renameBuffer();
6040     });
6041
6042   var names = database.readImageNames();
6043   if(names.length) {
6044     // load first image buffer
6045     self.setData( database.readImage(names[0]) );
6046   }
6047
6048 }
6049
6050 /**
6051  * Get or create a dali image from the image buffer.
6052  *
6053  * @return  {Object} dali.Image
6054  */
6055 UIImageTab.prototype.getDaliImage = function(name) {
6056   "use strict";
6057   if(name in this.imagesCreated) {
6058     return this.imagesCreated[name];
6059   } else {
6060     var imageData = database.readImage(name);
6061     var uint8array = new Uint8Array(imageData.data);
6062     var image = new dali.BufferImage(uint8array, imageData.width, imageData.height, dali.PixelFormat.RGBA8888);
6063     this.imagesCreated[name] = image;
6064     return image;
6065   }
6066 };
6067
6068 UIImageTab.prototype.rebuildDropdown = function(db) {
6069   "use strict";
6070   rebuildDropdown( document.getElementById("imageDropDown"),
6071                    db,
6072                    "images",
6073                    function(name) {
6074                      return ["javascript:uiImageTab.loadImage(\"" + name + "\")",
6075                              name];
6076                    }
6077                  );
6078 };
6079
6080 UIImageTab.prototype.setData = function(data) {
6081   "use strict";
6082   var imageViewCanvas = document.getElementById("imageViewCanvas"); // createElement("canvas");
6083   imageViewCanvas.width = data.width; // naturalWidth;
6084   imageViewCanvas.height = data.height; // naturalHeight;
6085   var context = imageViewCanvas.getContext("2d");
6086   context.putImageData( data, 0, 0 );
6087
6088 };
6089
6090 //------------------------------------------------------------------------------
6091 //
6092 // Shader UI Tab
6093 //
6094 //------------------------------------------------------------------------------
6095 /**
6096  * Get or create a dali shader from the shader buffer.
6097  *
6098  * Global function for use in javascript buffers or the console.
6099  * @param {string} shader buffer name
6100  * @return  {Object} dali.Shader
6101  */
6102 function shaderFromUiBuffer(name) {
6103   "use strict";
6104   var shader = uiShaderTab.getDaliShader(name);
6105   assert(shader, "Could not find/compile shader:" + name);
6106   return shader;
6107 }
6108
6109 function shaderInfoFromUiBuffer(name) {
6110   "use strict";
6111   return uiShaderTab.getShaderInfo(name);
6112 }
6113
6114 /**
6115  * Manage shader UI tab events.
6116  * Holds dali shader objects created from shader buffers.
6117  *
6118  * @constructor
6119  * @return {Object} UIShaderTab
6120  */
6121 function UIShaderTab() {
6122   "use strict";
6123   var self = this;
6124   this.bufferPrepend = "Buffer Name:";
6125   this.inhibitCheckAndUpdateShader = false;
6126
6127   this.shadersCreated = {}; // dali shader objects
6128   document.getElementById("btnShaderAddBuffer").addEventListener(
6129     "click",
6130     function(/*e*/) {
6131       self.addNewBuffer();
6132     });
6133
6134   document.getElementById("btnShaderRenameBuffer").addEventListener(
6135     "click",
6136     function(/*e*/) {
6137       self.renameBuffer();
6138     });
6139
6140   document.getElementById("btnShaderSourceJSON").addEventListener(
6141     "click",
6142     function(/*e*/) {
6143       self.showModalJSON();
6144     });
6145
6146   document.getElementById("btnShaderSourceC").addEventListener(
6147     "click",
6148     function(/*e*/) {
6149       self.showModalC();
6150     });
6151
6152   document.getElementById("btnShaderSourceJS").addEventListener(
6153     "click",
6154     function(/*e*/) {
6155       self.showModalJS();
6156     });
6157
6158
6159   this.addNewBuffer = function() {
6160     var alreadyExists = function() {
6161       self.addNewBuffer();
6162     };
6163
6164     var inputOk = function(name) {
6165       var data = database.readJavascript(name);
6166       if(data) {
6167         uiApp.messageBox("Name already exsists", alreadyExists);
6168       } else {
6169         var newData = {name: name, fragment: "", vertex: "", hints: ""};
6170         database.writeShader(newData);
6171         self.rebuildDropDown(database);
6172       }
6173     };
6174
6175     uiApp.inputbox("BufferName?", inputOk);
6176
6177   };
6178
6179   this.renameBuffer = function() {
6180     var inputOk = function(name) {
6181       var data = self.getData();
6182       data.name = name;
6183       database.writeShader(data);
6184       $("#textShaderName").html(self.bufferPrepend + name);
6185       self.rebuildDropdown(database);
6186     };
6187
6188     uiApp.inputbox("BufferName?", inputOk);
6189   };
6190
6191   this.loadShader = function(name) {
6192
6193     var data = database.readShader(name);
6194
6195     // save current
6196     var currentData = self.getData();
6197     if(currentData) {
6198       database.writeShader(currentData);
6199     }
6200
6201     // so that we can change vertex & fragment as an atomic operation
6202     self.inhibitCheckAndUpdateShader = true;
6203
6204     // otherwise this will trigger a checkAndUpdateShader() after
6205     // we've only changed the vertex shader (ie with mismatching fragment shader)
6206     self.setData(data);
6207
6208     self.inhibitCheckAndUpdateShader = false;
6209
6210     self.checkAndUpdateShader();
6211
6212   };
6213
6214   /**
6215    * Set the UI tab data of vertex/fragment strings.
6216    *
6217    * @param {Object} shader data object
6218    */
6219   this.setData = function(options) {
6220     var e;
6221     var vertex = "";
6222     var fragment = "";
6223     var hints = "";
6224
6225     vertex = options.vertex;
6226     fragment = options.fragment;
6227     hints = options.hints;
6228
6229     $("#requiresSelfDepthTest").prop("checked", (hints.search("requiresSelfDepthTest") >= 0));
6230     $("#outputIsTransparent").prop("checked", (hints.search("outputIsTransparent") >= 0));
6231     $("#outputIsOpaque").prop("checked", (hints.search("outputIsOpaque") >= 0));
6232     $("#modifiesGeometry").prop("checked", (hints.search("modifiesGeometry") >= 0));
6233
6234     // do this after setting up the checkboxes as it will trigger storing the checkbox state
6235     // in the actorIdToShaderSet map
6236     e = ace.edit("editorVertex");
6237     e.getSession().setValue(vertex);
6238
6239     e = ace.edit("editorFragment");
6240     e.getSession().setValue(fragment);
6241
6242     $("#textShaderName").html(self.bufferPrepend + options.name);
6243
6244   };
6245
6246   var shaderTab = $("#tab2primary")[0];
6247   var lastClassName = shaderTab.className;
6248   window.setInterval( function() {
6249     var className = shaderTab.className;
6250     if (className !== lastClassName) {
6251       //
6252       // an attempt to get the editboxes to display the correct content.
6253       // when you setValue() the content and they aren't visible then
6254       // they dont update properly until you click in the box
6255       //
6256       var e = ace.edit("editorVertex");
6257       e.setShowInvisibles(true);
6258       e.setShowInvisibles(false);
6259
6260       e = ace.edit("editorFragment");
6261       e.setShowInvisibles(true);
6262       e.setShowInvisibles(false);
6263       lastClassName = className;
6264     }
6265   }, 1);
6266
6267   var names = database.readShaderNames();
6268   if(names.length) {
6269     // load first image buffer
6270     self.setData( database.readShader(names[0]) );
6271   }
6272
6273   var editor = ace.edit("editorVertex");
6274   editor.getSession().addEventListener("change", function() {
6275     self.checkAndUpdateShader();
6276   });
6277
6278   editor = ace.edit("editorFragment");
6279   editor.getSession().addEventListener("change", function() {
6280     self.checkAndUpdateShader();
6281   });
6282
6283 }
6284
6285 /**
6286  * Get or create a dali shader from the shader buffer.
6287  *
6288  * @return  {Object} dali.Shader
6289  */
6290 UIShaderTab.prototype.getDaliShader = function(name) {
6291   "use strict";
6292   if(name in this.shadersCreated) {
6293     return this.shadersCreated[name].daliShader;
6294   } else {
6295     var ret = null;
6296     var data = database.readShader(name);
6297
6298     if(this.isCompilable(data)) {
6299       var daliShader = new dali.Shader(data.vertex,
6300                                        data.fragment,
6301                                        this.getDaliShaderHints(data.hints));
6302
6303       var shaderInfo = new dali.ShaderInfo();
6304       var info = shaderInfo.fromCompilation( canvas.getContext("webgl"),
6305                                              data.vertex,
6306                                              data.fragment );
6307
6308       for(name in info.uniformUISpec) {
6309         var metaData = info.uniformUISpec[name];
6310         if("default" in metaData) {
6311           // could provide automatic defaults
6312           daliShader.registerAnimatedProperty(name, metaData.default);
6313         }
6314       }
6315
6316       if(daliShader) {
6317         this.shadersCreated[name] = data;
6318         this.shadersCreated[name].daliShader = daliShader;
6319       }
6320       ret = daliShader;
6321     } else {
6322       console.log("Requested shader could not be compiled:" + name);
6323     }
6324
6325     return ret;
6326   }
6327 };
6328
6329 /**
6330  * Get info for a shader. See getInfo()
6331  *
6332  * @return  {Object} dali.Shader
6333  */
6334
6335 UIShaderTab.prototype.getShaderInfo = function(name) {
6336   "use strict";
6337   var data = database.readShader(name);
6338   return this.getInfo(data);
6339 };
6340
6341 /**
6342  * Rebuild UI tab drop down selection.
6343  *
6344  * @param {Object} Database
6345  */
6346 UIShaderTab.prototype.rebuildDropdown = function(db) {
6347   "use strict";
6348   rebuildDropdown( document.getElementById("shaderDropDown"),
6349                    db,
6350                    "shaders",
6351                    function(name) {
6352                      return ["javascript:uiShaderTab.loadShader(\"" + name + "\")",
6353                              name];
6354                    }
6355                  );
6356 };
6357
6358
6359 /**
6360  * Get the UI tab data with vertex/fragment strings.
6361  *
6362  * @return {Object} shader data object
6363  */
6364 UIShaderTab.prototype.getData = function() {
6365   "use strict";
6366   var e = ace.edit("editorVertex");
6367   var ret = {};
6368   ret.name = $("#textShaderName").text().substr(this.bufferPrepend.length);
6369   ret.vertex = native2ascii(e.getSession().getValue());
6370   e = ace.edit("editorFragment");
6371   ret.fragment = native2ascii(e.getSession().getValue());
6372
6373   ret.hints = "";
6374   if( $("#requiresSelfDepthTest")[0].checked ) {
6375     ret.hints += " requiresSelfDepthTest";
6376   }
6377   if( $("#outputIsTransparent")[0].checked ) {
6378     ret.hints += " outputIsTransparent";
6379   }
6380   if( $("#outputIsOpaque")[0].checked ) {
6381     ret.hints += " outputIsOpaque";
6382   }
6383   if( $("#modifiesGeometry")[0].checked ) {
6384     ret.hints += " modifiesGeometry";
6385   }
6386
6387   return ret;
6388 };
6389
6390 /**
6391  * Get dali shader hints from hints string.
6392  *
6393  * @param {string} hints string (space separated)
6394  * @return  {integer} or'd hints to pass to Dali
6395  */
6396 UIShaderTab.prototype.getDaliShaderHints = function(hintsString) {
6397   "use strict";
6398   var ret = 0;
6399
6400   if(hintsString.search("requiresSelfDepthTest") >= 0) {
6401     ret += dali.ShaderHints.REQUIRES_SELF_DEPTH_TEST;
6402   }
6403   if(hintsString.search("outputIsTransparent") >= 0) {
6404     ret += dali.ShaderHints.OUTPUT_IS_TRANSPARENT;
6405   }
6406   if(hintsString.search("outputIsOpaque") >= 0) {
6407     ret += dali.ShaderHints.OUTPUT_IS_OPAQUE;
6408   }
6409   if(hintsString.search("modifiesGeometry") >= 0) {
6410     ret += dali.ShaderHints.MODIFIES_GEOMETRY;
6411   }
6412   return ret;
6413 };
6414
6415 /**
6416  * Get information on a shader
6417  * If hasError==true then attributes etc will be empty. ie it must compile.
6418  *
6419  * Compile the shader with webGL. Query webGL for meta data.
6420  *
6421  * @param {object} data object. {vertex:"", fragment:""}
6422  * @return  {object} info metadata object
6423  *  // var info = {
6424  *  //   attributes: [],
6425  *  //   uniforms: [],
6426  *  //   attributeCount: 0,
6427  *  //   uniformCount: 0,
6428  *  //   hasError: false,    // compiles without error
6429  *  //   vertexError: "",
6430  *  //   fragmentError: "",
6431  *  //   linkError: ""
6432  *  // };
6433  */
6434
6435
6436 // uniform vec3 uMe; // gui:number, min:0, max:1, default: 0.5
6437 // uniform vec3 uMe; // gui:slider, min:0, max:1, default: 0.5
6438 // uniform vec3 uMe; // gui:color, min:[0,0,0,0] max:[1,1,1,1], default: [0,0,0,1]
6439
6440 UIShaderTab.prototype.getInfo = function(data) {
6441   "use strict";
6442
6443   var canvas = document.getElementById("canvas");
6444
6445   var info = new dali.ShaderInfo();
6446
6447   return info.fromCompilation(canvas.getContext("webgl"),
6448                               data.vertex,
6449                               data.fragment);
6450 };
6451
6452 /**
6453  * Check a shader can compile. Shader given as data object with vertex/fragment buffers.
6454  *
6455  * Compile the shader with webGL as a preprocess step to giving it to Dali.
6456  *
6457  * @param {string} shader buffer name
6458  * @return  {Boolean} true if the shader compiles ok.
6459  */
6460 UIShaderTab.prototype.isCompilable = function(data) {
6461   "use strict";
6462   var info = this.getInfo(data);
6463   return !info.hasError;
6464 };
6465
6466
6467 /**
6468  * Check the shader in the UI tab can compile and if so update the saved dali.Shader object.
6469  * (Does not create the dali.Shader object)
6470  *
6471  * For use on an event for continuous shader checking.
6472  *
6473  * @param {string} shader buffer name
6474  * @return  {Object} dali.Shader
6475  */
6476 UIShaderTab.prototype.checkAndUpdateShader = function() {
6477   "use strict";
6478   if(this.inhibitCheckAndUpdateShader) {
6479     return;
6480   }
6481
6482   var options = this.getData();
6483
6484   var info = this.getInfo(options);
6485
6486   if(!info.hasError) {
6487     if( options.name in this.shadersCreated ) {
6488       if("daliShader" in this.shadersCreated[options.name]) {
6489         // setting shader.program= doesn't seem to recompile the shader?
6490         // this.shadersCreated[options.name].daliShader.delete(); no delete; could be held elsewhere
6491         delete this.shadersCreated[options.name];
6492       }
6493     }
6494   }
6495
6496   var vertexPrepend = "";
6497   var fragmentPrepend = "";
6498
6499   var errors = "";
6500   var count;
6501   var editor;
6502   var description;
6503   var col;
6504   var line;
6505   var i;
6506
6507   var textShaderErrors = $("#textShaderErrors");
6508
6509   textShaderErrors.value = "";
6510
6511   editor = ace.edit("editorVertex");
6512   if (info.hasError && info.vertexError) {
6513     editor.getSession().setOption("useWorker", false);
6514     textShaderErrors.value = "VERTEX:\n" + info.vertexError;
6515     errors = info.vertexError.split("\n");
6516     count = vertexPrepend.split("\n").length;
6517     for(i = 0; i < errors.length; i++) {
6518       if(errors[i]) {
6519         description = errors[i].split(":");
6520         col = Number(description[1]);
6521         try {
6522           line = Number(description[2]);
6523         } catch(e) {
6524           line = "unknown";
6525         }
6526         editor.getSession().setAnnotations([{row: line - count, column: col, text: errors[i], type: "error"}]);
6527       }
6528     }
6529   } else {
6530     editor.getSession().setOption("useWorker", true);
6531     editor.getSession().setAnnotations([]);
6532   }
6533
6534   editor = ace.edit("editorFragment");
6535   if (info.hasError && info.fragmentError) {
6536     editor.getSession().setOption("useWorker", false);
6537     textShaderErrors.value += "FRAGMENT:\n" + info.fragmentError;
6538     errors = info.fragmentError.split("\n");
6539     count = fragmentPrepend.split("\n").length;
6540     for(i = 0; i < errors.length; i++) {
6541       if(errors[i]) {
6542         description = errors[i].split(":");
6543         col = Number(description[1]);
6544         try {
6545           line = Number(description[2]);
6546         } catch(e) {
6547           line = "unknown";
6548         }
6549         editor.getSession().setAnnotations([{row: line - count, column: col, text: errors[i], type: "error"}]);
6550       }
6551     }
6552   } else {
6553     editor.getSession().setOption("useWorker", true);
6554     editor.getSession().setAnnotations([]);
6555   }
6556
6557   if(!info.hasError) {
6558     database.writeShader(options);
6559   }
6560
6561 };
6562
6563
6564 UIShaderTab.prototype.showModalC = function() {
6565   "use strict";
6566   var i;
6567   var info = this.getData();
6568
6569   var data = "#define MAKE_STRING(A)#A\n\n" +
6570         "std::string vertexShader = MAKE_STRING(\n";
6571
6572   var lines = info.vertex.split("\n");
6573   for(i = 0; i < lines.length; i++) {
6574     data += lines[i] + "\n";
6575   }
6576   data += ");\n\n";
6577
6578   data += "std::string fragShader = MAKE_STRING(\n";
6579
6580   lines = info.fragment.split("\n");
6581   for(i = 0; i < lines.length; i++) {
6582     data += lines[i] + "\n";
6583   }
6584   data += ");\n\n";
6585
6586   data += "ShaderEffect shaderEffect;\n" +
6587     "shaderEffect = ShaderEffect::New( vertexShader, fragmentShader,\n" +
6588     "                                ShaderEffect::ShaderHint( " + info.hints + " ) )\n";
6589
6590   data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
6591
6592   uiApp.codeInformationBox( data );
6593
6594   // data = data.replace(/</g, "&lt;");
6595   // data = data.replace(/>/g, "&gt;");
6596
6597   // var myWindow = window.open("data:text/html," + encodeURIComponent(data));
6598   // //                             "_blank");  // , "width=00,height=100");
6599   // myWindow.focus();
6600
6601 };
6602
6603 UIShaderTab.prototype.showModalJS = function() {
6604   "use strict";
6605   var i;
6606   var info = this.getData();
6607
6608   var data = "var shaderOptions = {vertex:\n";
6609
6610   var lines = info.vertex.split("\n");
6611   for(i = 0; i < lines.length; i++) {
6612     data += "                     \"" + lines[i] + "\\n\" +\n";
6613   }
6614   data += "                     \"\",\n";
6615
6616   data += "                     fragment:\n";
6617   lines = info.fragment.split("\n");
6618   for(i = 0; i < lines.length; i++) {
6619     data += "                     \"" + lines[i] + "\\n\" +\n";
6620   }
6621   data += "                     \"\",\n";
6622
6623   data += "                     geometryType: \"" + info.geometryType + "\",\n";
6624   data += "                     geometryHints: \"" + info.geometryHints + "\"\n";
6625   data += "                     };\n";
6626
6627   data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
6628   // data = data.replace(/</g, "&lt;");
6629   // data = data.replace(/>/g, "&gt;");
6630
6631   // var myWindow = window.open("data:text/html," + encodeURIComponent(data));
6632   // //                             "_blank");  // , "width=00,height=100");
6633   // myWindow.focus();
6634
6635   var modalBody = $("#modalCodeInfoBody")[0];
6636   removeAllChildren(modalBody);
6637   modalBody.innerHTML = "<code><pre>" + data + "</pre></code>";
6638   $("#modalCodeInfo").modal("show");
6639
6640 };
6641
6642 UIShaderTab.prototype.showModalJSON = function() {
6643   "use strict";
6644   var info = this.getData();
6645
6646   var hints = ""; // tbd
6647
6648   var vertex = info.vertex.replace(/\n/g, "\\n");
6649   var fragment = info.fragment.replace(/\n/g, "\\n");
6650
6651   var data = "{\"shader-effects\": {\n" +
6652         "  \"" + "effect" + "\": {\n" +
6653         "    \"program\": {\n" +
6654         "    \"vertexPrefix\": \"\",\n" +
6655         "    \"vertex\": \"" + vertex + "\",\n" +
6656         "    \"fragmentPrefix\": \"\",\n" +
6657         "    \"fragment\": \"" + fragment + "\"\n" +
6658         "    },\n" +
6659         "    \"geometry-hints\": \"" + hints + "\",\n" +
6660         "    \"grid-density\": \"" + "0" + "\",\n" +
6661         "    \"image\": {\n" +
6662         "      \"filename\": \"\"\n" +
6663         "    }\n" +
6664         "  }\n" +
6665         " }\n" +
6666         "}\n";
6667
6668   data = data.replace(/<([^ ]*)/g, "< $1"); // for loops are interpreted by browser as tags and dont print?
6669
6670   uiApp.codeInformationBox( data );
6671
6672 };
6673
6674 document.getElementById("btnRewriteDatabase").addEventListener("click", function(// e
6675 ) {
6676   "use strict";
6677
6678   database.delete(
6679     function() {
6680       consoleLogSuccess("database.delete")();
6681       window.setTimeout(function () {
6682         window.location.reload(true); // forces a reload from the server
6683       }, 500);
6684     },
6685     consoleLogErrorEvent, // fail
6686     consoleLogErrorEvent // blocked
6687   );
6688
6689 });
6690
6691
6692 window.setTimeout(initDB, 1000);
6693
6694
6695 function updateStatistics(eventHandler){
6696   "use strict";
6697
6698   var elem = $("#statistics")[0];
6699
6700   var actor = eventHandler.touchedActor;
6701
6702   var usedRootLayer = false;
6703
6704   if(!actor) {
6705     usedRootLayer = true;
6706     actor = dali.stage.getRootLayer();
6707   }
6708
6709   var rt = dali.stage.getRenderTaskList().getTask(0);
6710
6711   var xy;
6712   try {
6713     xy = dali.screenToLocal(eventHandler.mouseX, eventHandler.mouseY,
6714                             actor, rt);
6715   } catch(err) {
6716     xy = [0, 0];
6717   }
6718
6719   var screenxy = dali.worldToScreen(actor.position, rt);
6720
6721   var name = "Actor";
6722
6723   if(usedRootLayer) {
6724     name = "Root Actor";
6725   }
6726
6727   var prec = 3;
6728   var px = "none";
6729   var py = "none";
6730   if(eventHandler.mouseDownPosition) {
6731     px = eventHandler.mouseDownPosition[0].toFixed(prec);
6732     py = eventHandler.mouseDownPosition[1].toFixed(prec);
6733   }
6734
6735   elem.innerHTML = name + " (" + actor.getId() + ") '" + actor.name + "'" + "<br>" +
6736     "Screen:" + eventHandler.mouseX.toFixed(prec) + "," + eventHandler.mouseY.toFixed(prec) + "<br>" +
6737     name + " Screen To Local:" + xy[0].toFixed(prec) + "," + xy[1].toFixed(prec) + "<br>" +
6738     name + " To Screen:" + screenxy[0].toFixed(prec) + "," + screenxy[1].toFixed(prec) + "<br>" +
6739     name + " Drag dx/dy:" + eventHandler.dragDx.toFixed(prec) + "," + eventHandler.dragDy.toFixed(prec) + "<br>" +
6740     name + " pos:" + actor.position + "<br>"+
6741     name + " pos:" + px + "," + py + "<br>";
6742
6743   if(usedRootLayer) { // dont delete eventHandler object
6744     actor.delete(); // wrapper
6745   }
6746
6747   rt.delete(); // wrapper
6748
6749 }
6750
6751
6752 $(".btn-toggle").click(function() {
6753   "use strict";
6754   $(this).find(".btn").toggleClass("active");
6755
6756   if($(this).find(".btn-primary").size() > 0) {
6757     $(this).find(".btn").toggleClass("btn-primary");
6758   }
6759
6760   $(this).find(".btn").toggleClass("btn-default");
6761
6762   if(this.id === "loop") {
6763     var looping = $(this).find("#loopOn").hasClass("active");
6764     animationList[animationSelectionIndex].looping = looping;
6765     animationList[animationSelectionIndex].dirtyData = true;
6766   }
6767
6768   if(this.id === "endAction") {
6769     var bake = $(this).find("#endBake").hasClass("active");
6770     if(bake) {
6771       animationList[animationSelectionIndex].endAction = "Bake";
6772     } else {
6773       animationList[animationSelectionIndex].endAction = "Discard";
6774     }
6775     animationList[animationSelectionIndex].dirtyData = true;
6776   }
6777
6778 });
6779
6780 //------------------------------------------------------------------------------
6781 //
6782 // Database; access to browser indexed db
6783 //
6784 //------------------------------------------------------------------------------
6785 function Database() {
6786   "use strict";
6787   this.currentVersion = 1;
6788   this.name = "dalitoy";
6789   this.data = {};
6790   var self = this;
6791
6792   this.copyDBStore = function(db, dbStoreName, andClose) {
6793     var tr = db.transaction([dbStoreName], "readonly");
6794     var store = tr.objectStore(dbStoreName);
6795     var cursor = store.openCursor();
6796     self.data[dbStoreName] = {};
6797     cursor.onsuccess = function(e) {
6798       var res = e.target.result; // another cursor
6799       if(res) {
6800         self.data[dbStoreName][res.key] = res.value;
6801         res.continue();
6802       } else {
6803         if(andClose) {
6804           db.close();
6805         }
6806       }
6807     };
6808     cursor.onerror = consoleLogErrorEvent;
6809   };
6810
6811   this.initializeData = function(db) {
6812     self.copyDBStore(db, "javascript");
6813     self.copyDBStore(db, "images");
6814     self.copyDBStore(db, "shaders", true); // true to close db (last copy)
6815   };
6816
6817   this.init();
6818 }
6819
6820 Database.prototype.open = function() {
6821   "use strict";
6822   return window.indexedDB.open(this.name, this.currentVersion);
6823 };
6824
6825 Database.prototype.delete = function(onsuccess, onerror, onblocked) {
6826   "use strict";
6827   var req = window.indexedDB.deleteDatabase(this.name);
6828   req.onsuccess = onsuccess;
6829   req.onerror = onerror;
6830   req.onblocked = onblocked;
6831 };
6832
6833
6834 Database.prototype.upgrade = function(db, oldVersion) {
6835   // force upgrade
6836   "use strict";
6837   if (oldVersion < 1) {
6838     // Version 1 is the first version of the database.
6839     var store = db.createObjectStore("shaders", {keyPath: "name"});
6840     var i;
6841     for(i = 0; i < shaderSources.length; i++) {
6842       store.put( shaderSources[i] );
6843     }
6844
6845     store = db.createObjectStore("javascript", {keyPath: "name"});
6846     for(i = 0; i < javascriptSources.length; i++) {
6847       store.put( javascriptSources[i] );
6848     }
6849
6850     store = db.createObjectStore("images");
6851
6852     // default images in html page
6853     store.put( getStockImageData(1), "girl1" );
6854     store.put( getStockImageData(2), "funnyface" );
6855     store.put( getStockImageData(3), "ducks" );
6856     store.put( getStockImageData(4), "field" );
6857   }
6858 };
6859
6860 Database.prototype.init = function() {
6861   "use strict";
6862   var self = this;
6863
6864   if("indexedDB" in window) {
6865     var openRequest = this.open();
6866
6867     openRequest.onupgradeneeded = function(event) {
6868       var db = event.target.result;
6869       database.upgrade(db, event.oldVersion);
6870       //self.initializeData(db);
6871     };
6872
6873     openRequest.onsuccess = function(event) {
6874       var db = event.target.result;
6875       self.initializeData(db);
6876     };
6877
6878     openRequest.onerror = consoleLogErrorEvent;
6879
6880   }
6881
6882 };
6883
6884 Database.prototype.initTabs = function(jstab, imagetab, shadertab) {
6885   "use strict";
6886   jstab.rebuildDropdown(this);
6887   imagetab.rebuildDropdown(this);
6888   shadertab.rebuildDropdown(this);
6889 };
6890
6891 Database.prototype.writeJavascript = function(data, callback) {
6892   "use strict";
6893
6894   this.data.javascript[data.name] = data;
6895
6896   var openRequest = this.open();
6897   var self = this;
6898   openRequest.onsuccess = function(event) {
6899     var db = event.target.result;
6900     var tr = db.transaction(["javascript"], "readwrite");
6901     var store = tr.objectStore("javascript");
6902
6903     var ob = store.put(data);
6904     self.data.javascript[data.name] = data;
6905
6906     ob.onsuccess = callback;
6907     // ob.onerror = errorCallback;
6908     ob.onerror = consoleLogErrorEvent;
6909
6910     db.close();
6911   };
6912
6913   openRequest.onerror = consoleLogErrorEvent;
6914
6915 };
6916
6917 Database.prototype.readJavascript = function(name) {
6918   "use strict";
6919   return this.data.javascript[name];
6920 };
6921
6922 Database.prototype.readJavascriptNames = function() {
6923   "use strict";
6924   return this.getKeys("javascript");
6925 };
6926
6927 Database.prototype.readKeys = function(dbStoreName, callback) {
6928   "use strict";
6929
6930   var openRequest = database.open();
6931
6932   openRequest.onsuccess = function(event) {
6933     var db = event.target.result;
6934     var tr = db.transaction([dbStoreName], "readonly");
6935     var store = tr.objectStore(dbStoreName);
6936     var cursor = store.openCursor();
6937     var keys = [];
6938     cursor.onsuccess = function(e) {
6939       var res = e.target.result; // another cursor
6940       if(res) {
6941         keys.push(res.key);
6942         res.continue();
6943       } else {
6944         callback(keys);
6945       }
6946     };
6947     cursor.onerror = consoleLogErrorEvent;
6948     db.close();
6949   };
6950
6951 };
6952
6953 Database.prototype.getKeys = function(dbStoreName) {
6954   "use strict";
6955   var l = [];
6956   var o = this.data[dbStoreName];
6957   for(var name in o) {
6958     l.push(name);
6959   }
6960   return l;
6961 };
6962
6963 Database.prototype.writeShader = function(data) {
6964   "use strict";
6965   assert(data.name);
6966
6967   this.data.shaders[data.name] = data;
6968
6969   // write the indexDB too
6970   var openRequest = this.open();
6971
6972   openRequest.onsuccess = function(event) {
6973     var db = event.target.result;
6974     var tr = db.transaction(["shaders"], "readwrite");
6975     var store = tr.objectStore("shaders");
6976
6977     var ob = store.put(data);
6978
6979     //ob.onsuccess = callback;
6980     ob.onerror = consoleLogErrorEvent;
6981
6982     db.close();
6983   };
6984
6985   openRequest.onerror = consoleLogErrorEvent;
6986
6987 };
6988
6989 Database.prototype.readShader = function(name) {
6990   "use strict";
6991   return this.data.shaders[name];
6992 };
6993
6994 Database.prototype.readShaderNames = function() {
6995   "use strict";
6996   return this.getKeys("shaders");
6997 };
6998
6999 Database.prototype.readObjectStore = function(objectStoreName, recordName, callback, errorCallback) {
7000   "use strict";
7001   var openRequest = window.indexedDB.open(this.name, this.currentVersion);
7002
7003   openRequest.onsuccess = function(event) {
7004     var db = event.target.result;
7005
7006     var transaction = db.transaction([objectStoreName], "readonly");
7007     var objectStore = transaction.objectStore(objectStoreName);
7008
7009     //x is some value
7010     var ob = objectStore.get(recordName);
7011
7012     ob.onsuccess = function(e) {
7013       // read with undefined is still a success (should probably do this with cursor?)
7014       if(e.target.result) {
7015         callback(e.target.result);
7016       } else {
7017         errorCallback();
7018       }
7019     };
7020
7021     ob.onerror = errorCallback;
7022
7023     db.close();
7024   };
7025
7026   openRequest.onerror = errorCallback;
7027
7028 };
7029
7030 Database.prototype.writeImage = function(name, data) {
7031   "use strict";
7032
7033   this.data.images[name] = data;
7034
7035   var openRequest = this.open();
7036
7037   openRequest.onsuccess = function(event) {
7038     var db = event.target.result;
7039     var tr = db.transaction(["images"], "readwrite");
7040     var store = tr.objectStore("images");
7041
7042     var ob = store.put(data, name);
7043
7044     //ob.onsuccess = callback;
7045     ob.onerror = consoleLogErrorEvent;
7046
7047     db.close();
7048   };
7049
7050   openRequest.onerror = consoleLogErrorEvent;
7051
7052 };
7053
7054 Database.prototype.readImage = function(name) {
7055   "use strict";
7056   return this.data.images[name];
7057 };
7058
7059 Database.prototype.readImageNames = function() {
7060   "use strict";
7061   return this.getKeys("images");
7062 };
7063
7064 //------------------------------------------------------------------------------
7065 //
7066 // app init functions
7067 //
7068 //------------------------------------------------------------------------------
7069 function initDB() {
7070   "use strict";
7071   database = new Database();
7072   window.setTimeout(init, 500);
7073 }
7074
7075 function init() {
7076   "use strict";
7077
7078   // var root = dali.stage.getRootLayer();
7079   // root.name = "*" + root.name; // * at start means non selectable by convention
7080   // root.delete(); // wrapper
7081
7082   // database = new Database();
7083
7084   test = new Test();
7085
7086   uiApp = new UIApp();
7087
7088   uiJavascriptTab = new UIJavascriptTab();
7089
7090   uiImageTab = new UIImageTab();
7091
7092   uiShaderTab = new UIShaderTab();
7093
7094   database.initTabs(uiJavascriptTab, uiImageTab, uiShaderTab);
7095
7096   $("a[rel=popover]").tooltip();
7097
7098   Object.defineProperty(dali, "shader", {
7099     enumerable: true,
7100     configurable: false,
7101     get: function() {
7102       return getShader();
7103     }
7104   });
7105
7106   Object.defineProperty(dali, "actor", {
7107     enumerable: true,
7108     configurable: false,
7109     get: function() {
7110       return getActor();
7111     }
7112   });
7113
7114   Object.defineProperty(dali, "animation", {
7115     enumerable: true,
7116     configurable: false,
7117     get: function() {
7118       return getAnimation();
7119     }
7120   });
7121
7122   eventHandler.handlersMouseMove.push(updateStatistics);
7123
7124 }
7125
7126 ////////////////////////////////////////////////////////////////////////////////////////////////////
7127
7128 dali.postRenderFunction = undefined;