- add sources.
[platform/framework/web/crosswalk.git] / src / native_client_sdk / src / gonacl_appengine / static / pnacl-demo-smoothlife / example.js
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 'use strict';
6
7 var naclModule = null;
8 var presets = [
9   [[15.2,32.1,7.6],[3,0.329,0.15,0.321,0.145,0.709,3,2,4,0.269,0.662],[0,"#000000",3,"#f5f5c1",12,"#158a34",68,"#89e681",100]],
10   [[15.2,32.1,5],[3,0.273,0.117,0.288,0.243,0.348,3,2,4,0.269,0.662],[1,"#000000",3,"#f5f5c1",8,"#158a34",17,"#89e681",20]],
11   [[4,12,1],[2,0.115,0.269,0.523,0.34,0.746,3,4,4,0.028,0.147],[0,"#36065e",0,"#c24242",77,"#8a19b0",91,"#ff9900",99,"#f5c816",99]],
12   [[4,12,1],[3,0.12,0.218,0.267,0.365,0.445,3,4,4,0.028,0.147],[0,"#000000",0,"#0f8a84",38,"#f5f5c1",43,"#158a34",70,"#89e681",100]],
13   [[4,12,1],[0,0.09,0.276,0.27,0.365,0.445,1,4,4,0.028,0.147],[0,"#93afd9",11,"#9cf0ff",92,"#edfdff",100]],
14   [[10.4,12,1],[2,0.082,0.302,0.481,0.35,0.749,2,3,4,0.028,0.147],[0,"#000000",11,"#ffffff",22,"#19a68a",85,"#6b0808",98]],
15   [[7.8,27.2,2.6],[3,0.21,0.714,0.056,0.175,0.838,2,0,2,0.132,0.311],[0,"#0a1340",0,"#ffffff",55,"#4da8a3",83,"#2652ab",99,"#2f1e75",46]],
16   [[4,12,1],[2,0.115,0.269,0.496,0.34,0.767,3,4,4,0.028,0.147],[0,"#b8cfcf",0,"#3f5a5c",77,"#1a330a",91,"#c0e0dc",99]],
17   [[10.6,31.8,1],[1,0.157,0.092,0.256,0.098,0.607,3,4,4,0.015,0.34],[0,"#4d3e3e",0,"#9a1ac9",77,"#aaf09e",100]],
18 ];
19
20 /**
21  * A helper function to abbreviate getElementById.
22  *
23  * @param {string} elementId The id to get.
24  * @return {Element}
25  */
26 function $(elementId) {
27   return document.getElementById(elementId);
28 }
29
30 /**
31  * MIME type for PNaCl
32  *
33  * @return {string} MIME type
34  */
35 function PNaClmimeType() {
36   return 'application/x-pnacl';
37 }
38
39 /**
40  * Check if the browser supports PNaCl.
41  *
42  * @return {bool}
43  */
44 function browserSupportsPNaCl() {
45   var mimetype = PNaClmimeType();
46   return navigator.mimeTypes[mimetype] !== undefined;
47 }
48
49 /**
50  * Get the URL for Google Cloud Storage.
51  *
52  * @param {string} name The relative path to the file.
53  * @return {string}
54  */
55 function getDataURL(name) {
56   var revision = 231964;
57   var baseUrl = 'http://commondatastorage.googleapis.com/gonacl/demos/publish/';
58   return baseUrl + revision + '/smoothlife/' + name;
59 }
60
61 /**
62  * Create the Native Client <embed> element as a child of the DOM element
63  * named "listener".
64  *
65  * @param {string} name The name of the example.
66  * @param {number} width The width to create the plugin.
67  * @param {number} height The height to create the plugin.
68  * @param {Object} attrs Dictionary of attributes to set on the module.
69  */
70 function createNaClModule(name, width, height, attrs) {
71   var moduleEl = document.createElement('embed');
72   moduleEl.setAttribute('name', 'nacl_module');
73   moduleEl.setAttribute('id', 'nacl_module');
74   moduleEl.setAttribute('width', width);
75   moduleEl.setAttribute('height', height);
76   moduleEl.setAttribute('path', '');
77   moduleEl.setAttribute('src', getDataURL(name + '.nmf'));
78   moduleEl.setAttribute('type', PNaClmimeType());
79
80   // Add any optional arguments
81   if (attrs) {
82     for (var key in attrs) {
83       moduleEl.setAttribute(key, attrs[key]);
84     }
85   }
86
87   // The <EMBED> element is wrapped inside a <DIV>, which has both a 'load'
88   // and a 'message' event listener attached.  This wrapping method is used
89   // instead of attaching the event listeners directly to the <EMBED> element
90   // to ensure that the listeners are active before the NaCl module 'load'
91   // event fires.
92   var listenerDiv = $('listener');
93   listenerDiv.appendChild(moduleEl);
94 }
95
96 /**
97  * Add the default event listeners to the element with id "listener".
98  */
99 function attachDefaultListeners() {
100   var listenerDiv = $('listener');
101   listenerDiv.addEventListener('load', moduleDidLoad, true);
102   listenerDiv.addEventListener('error', moduleLoadError, true);
103   listenerDiv.addEventListener('progress', moduleLoadProgress, true);
104   listenerDiv.addEventListener('message', handleMessage, true);
105   listenerDiv.addEventListener('crash', handleCrash, true);
106   attachListeners();
107 }
108
109 /**
110  * Called when the Browser can not communicate with the Module
111  *
112  * This event listener is registered in attachDefaultListeners above.
113  *
114  * @param {Object} event
115  */
116 function handleCrash(event) {
117   if (naclModule.exitStatus == -1) {
118     updateStatus('CRASHED');
119   } else {
120     updateStatus('EXITED [' + naclModule.exitStatus + ']');
121   }
122 }
123
124 /**
125  * Called when the NaCl module is loaded.
126  *
127  * This event listener is registered in attachDefaultListeners above.
128  */
129 function moduleDidLoad() {
130   var bar = $('progress');
131   bar.value = 100;
132   bar.max = 100;
133   naclModule = $('nacl_module');
134   hideStatus();
135   loadPreset(0);
136 }
137
138 /**
139  * Hide the status field and progress bar.
140  */
141 function hideStatus() {
142   $('statusField').style.display = 'none';
143   $('progress').style.display = 'none';
144 }
145
146 /**
147  * Called when the plugin fails to load.
148  *
149  * @param {Object} event
150  */
151 function moduleLoadError(event) {
152   updateStatus('Load failed.');
153 }
154
155 /**
156  * Called when the plugin reports progress events.
157  *
158  * @param {Object} event
159  */
160 function moduleLoadProgress(event) {
161   $('progress').style.display = 'block';
162
163   var loadPercent = 0.0;
164   var bar = $('progress');
165   bar.max = 100;
166   if (event.lengthComputable && event.total > 0) {
167     loadPercent = event.loaded / event.total * 100.0;
168   } else {
169     // The total length is not yet known.
170     loadPercent = -1.0;
171   }
172   bar.value = loadPercent;
173 }
174
175 /**
176  * If the element with id 'statusField' exists, then set its HTML to the status
177  * message as well.
178  *
179  * @param {string} opt_message The message to set.
180  */
181 function updateStatus(opt_message) {
182   var statusField = $('statusField');
183   if (statusField) {
184     statusField.style.display = 'block';
185     statusField.textContent = opt_message;
186   }
187 }
188
189 /**
190  * Add event listeners after the NaCl module has loaded.  These listeners will
191  * forward messages to the NaCl module via postMessage()
192  */
193 function attachListeners() {
194   $('preset').addEventListener('change', loadSelectedPreset);
195   $('reset').addEventListener('click', loadSelectedPreset);
196   $('clear').addEventListener('click', function() { clear(0); });
197   $('splat').addEventListener('click', function() { splat(); });
198   $('brushSizeRange').addEventListener('change', function() {
199     var radius = parseFloat(this.value);
200     setBrushSize(radius, 1.0);
201     $('brushSize').textContent = radius.toFixed(1);
202   });
203 }
204
205 function loadSelectedPreset() {
206   loadPreset($('preset').value);
207 }
208
209 function loadPreset(index) {
210   var preset = presets[index];
211
212   clear(0);
213   setKernel.apply(null, preset[0]);
214   setSmoother.apply(null, preset[1]);
215   setPalette.apply(null, preset[2]);
216   splat();
217 }
218
219 function clear(color) {
220   naclModule.postMessage({cmd: 'clear', color: color});
221 }
222
223 function setKernel(discRadius, ringRadius, blendRadius) {
224   naclModule.postMessage({
225     cmd: 'setKernel',
226     discRadius: discRadius,
227     ringRadius: ringRadius,
228     blendRadius: blendRadius});
229 }
230
231 function setSmoother(type, dt, b1, d1, b2, d2, mode, sigmoid, mix, sn, sm) {
232   naclModule.postMessage({
233     cmd: 'setSmoother',
234     type: type, dt: dt,
235     b1: b1, d1: d1, b2: b2, d2: d2,
236     mode: mode, sigmoid: sigmoid, mix: mix,
237     sn: sn, sm: sm});
238 }
239
240 function setPalette() {
241   var repeating = arguments[0] !== 0;
242   var colors = []
243   var stops = []
244   for (var i = 1; i < arguments.length; i += 2) {
245     colors.push(arguments[i]);
246     stops.push(arguments[i + 1]);
247   }
248   naclModule.postMessage({
249     cmd: 'setPalette',
250     repeating: repeating,
251     colors: colors,
252     stops: stops});
253 }
254
255 function splat() {
256   naclModule.postMessage({cmd: 'splat'});
257 }
258
259 function setBrushSize(radius, color) {
260   naclModule.postMessage({cmd: 'setBrush', radius: radius, color: color});
261 }
262
263
264 /**
265  * Handle a message coming from the NaCl module.
266  * @param {Object} message_event
267  */
268 function handleMessage(message_event) {
269   // Update FPS
270   $('fps').textContent = message_event.data.toFixed(1);
271 }
272
273 /**
274  * Listen for the DOM content to be loaded. This event is fired when parsing of
275  * the page's document has finished.
276  */
277 document.addEventListener('DOMContentLoaded', function() {
278   updateStatus('Loading...');
279   if (!browserSupportsPNaCl()) {
280     updateStatus('Browser does not support PNaCl or PNaCl is disabled');
281   } else if (naclModule == null) {
282     createNaClModule('smoothnacl', 512, 512);
283     attachDefaultListeners();
284   } else {
285     // It's possible that the Native Client module onload event fired
286     // before the page's onload event.  In this case, the status message
287     // will reflect 'SUCCESS', but won't be displayed.  This call will
288     // display the current message.
289     updateStatus('Waiting.');
290   }
291 });