├── 64.png ├── README.md ├── arcontroller.js ├── index.html └── lib ├── awe-jsartoolkit-dependencies.js ├── awe-loader-min.js ├── awe-loader.js ├── awe-standard-dependencies.js ├── awe-standard-object_clicked.js ├── awe-standard-window_resized.js ├── awe-standard.js ├── awe-v8.js ├── awe.geo_ar.js ├── awe.marker_ar.js └── underscore-min.js /64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sitepoint-editors/ARLIFXController/7152e8e40b5a28ef4735cee0257e53a65c954b9c/64.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | AR LIFX Controller 2 | ======== 3 | 4 | An augmented reality controller to control LIFX lightbulbs using awe.js, the browser and IFTTT. 5 | 6 | If you make something neat from this code, please do let me know! I'm on Twitter at @thatpatrickguy, or you can find me at http://www.patrickcatanzariti.com. 7 | 8 | PatCat 9 | -------------------------------------------------------------------------------- /arcontroller.js: -------------------------------------------------------------------------------- 1 | window.addEventListener('load', function() { 2 | var menu_open = false; 3 | 4 | window.awe.init({ 5 | device_type: awe.AUTO_DETECT_DEVICE_TYPE, 6 | settings: { 7 | container_id: 'container', 8 | fps: 30, 9 | default_camera_position: { x:0, y:0, z:0 }, 10 | default_lights: [{ 11 | id: 'point_light', 12 | type: 'point', 13 | color: 0xFFFFFF 14 | }] 15 | }, 16 | ready: function() { 17 | awe.util.require([ 18 | { 19 | capabilities: ['gum','webgl'], 20 | files: [ 21 | ['lib/awe-standard-dependencies.js', 'lib/awe-standard.js'], 22 | 'lib/awe-standard-window_resized.js', 23 | 'lib/awe-standard-object_clicked.js', 24 | 'lib/awe-jsartoolkit-dependencies.js', 25 | 'lib/awe.marker_ar.js' 26 | ], 27 | success: function() { 28 | window.awe.setup_scene(); 29 | 30 | // Points of Interest 31 | awe.pois.add({id: 'marker', position: {x: 0, y: 0, z: 10000}, visible: false}); 32 | 33 | // Projections 34 | awe.projections.add({ 35 | id: 'wormhole', 36 | geometry: {shape: 'plane', height: 400, width: 400}, 37 | position: {x: 0, y: 0, z: 0}, 38 | rotation: {x: 90, z: 45}, 39 | material: { 40 | type: 'phong', 41 | color: 0x000000 42 | } 43 | }, {poi_id: 'marker'}); 44 | 45 | awe.projections.add({ 46 | id: 'ar_button_one', 47 | geometry: {shape: 'cube', x: 60, y: 30, z: 5}, 48 | rotation: {y: 45}, 49 | position: {x: -5, y: -31, z: -5}, 50 | material: { 51 | type: 'phong', 52 | color: 0xFF0000 53 | } 54 | }, {poi_id: 'marker'}); 55 | 56 | awe.projections.add({ 57 | id: 'ar_button_two', 58 | geometry: {shape: 'cube', x: 60, y: 30, z: 5}, 59 | rotation: {y: 45}, 60 | position: {x: -5, y: -31, z: -5}, 61 | material: { 62 | type: 'phong', 63 | color: 0xFF6600 64 | } 65 | }, {poi_id: 'marker'}); 66 | 67 | awe.projections.add({ 68 | id: 'ar_button_three', 69 | geometry: {shape: 'cube', x: 110, y: 30, z: 5}, 70 | rotation: {y: 45}, 71 | position: {x: -5, y: -31, z: -5}, 72 | material: { 73 | type: 'phong', 74 | color: 0xFFFF00 75 | } 76 | }, {poi_id: 'marker'}); 77 | 78 | awe.projections.add({ 79 | id: 'ar_button_four', 80 | geometry: {shape: 'cube', x: 150, y: 30, z: 5}, 81 | rotation: {y: 45}, 82 | position: {x: -5, y: -31, z: -5}, 83 | material: { 84 | type: 'phong', 85 | color: 0xFFFFFF 86 | } 87 | }, {poi_id: 'marker'}); 88 | 89 | awe.projections.add({ 90 | id: 'ar_button_five', 91 | geometry: {shape: 'cube', x: 180, y: 30, z: 5}, 92 | rotation: {y: 45}, 93 | position: {x: -5, y: -31, z: -5}, 94 | material: { 95 | type: 'phong', 96 | color: 0x00FF00 97 | } 98 | }, {poi_id: 'marker'}); 99 | 100 | awe.projections.add({ 101 | id: 'ar_button_six', 102 | geometry: {shape: 'cube', x: 150, y: 30, z: 5}, 103 | rotation: {y: 45}, 104 | position: {x: -5, y: -31, z: -5}, 105 | material: { 106 | type: 'phong', 107 | color: 0x0080FF 108 | } 109 | }, {poi_id: 'marker'}); 110 | 111 | awe.projections.add({ 112 | id: 'ar_button_seven', 113 | geometry: {shape: 'cube', x: 100, y: 30, z: 5}, 114 | rotation: {y: 45}, 115 | position: {x: -5, y: -31, z: -5}, 116 | material: { 117 | type: 'phong', 118 | color: 0x8000FF 119 | } 120 | }, {poi_id: 'marker'}); 121 | 122 | awe.events.add([{ 123 | id: 'ar_tracking_marker', 124 | device_types: { 125 | pc: 1, 126 | android: 1 127 | }, 128 | register: function(handler) { 129 | window.addEventListener('ar_tracking_marker', handler, false); 130 | }, 131 | unregister: function(handler) { 132 | window.removeEventListener('ar_tracking_marker', handler, false); 133 | }, 134 | handler: function(event) { 135 | if (event.detail) { 136 | if (event.detail['64']) { 137 | awe.pois.update({ 138 | data: { 139 | visible: true, 140 | position: {x: 0, y: 0, z: 0}, 141 | matrix: event.detail['64'].transform 142 | }, 143 | where: { 144 | id: 'marker' 145 | } 146 | }); 147 | awe.projections.update({ 148 | data: { 149 | visible: true 150 | }, 151 | where: { 152 | id: 'wormhole' 153 | } 154 | }); 155 | } else if (menu_open) { 156 | awe.projections.update({ 157 | data: { 158 | visible: false 159 | }, 160 | where: { 161 | id: 'wormhole' 162 | } 163 | }); 164 | } 165 | else { 166 | awe.pois.update({ 167 | data: { 168 | visible: false 169 | }, 170 | where: { 171 | id: 'marker' 172 | } 173 | }); 174 | } 175 | awe.scene_needs_rendering = 1; 176 | } 177 | } 178 | }]); 179 | 180 | window.addEventListener('object_clicked', function(e) { 181 | switch (e.detail.projection_id) { 182 | case 'wormhole': 183 | if (!menu_open) { 184 | awe.projections.update({ 185 | data: { 186 | animation: { 187 | duration: 1 188 | }, 189 | position: {y: 35} 190 | }, 191 | where: {id: 'ar_button_one'} 192 | }); 193 | 194 | awe.projections.update({ 195 | data: { 196 | animation: { 197 | duration: 1 198 | }, 199 | position: {y: 70} 200 | }, 201 | where: {id: 'ar_button_two'} 202 | }); 203 | 204 | awe.projections.update({ 205 | data: { 206 | animation: { 207 | duration: 1 208 | }, 209 | position: {y: 105} 210 | }, 211 | where: {id: 'ar_button_three'} 212 | }); 213 | 214 | awe.projections.update({ 215 | data: { 216 | animation: { 217 | duration: 1 218 | }, 219 | position: {y: 140} 220 | }, 221 | where: {id: 'ar_button_four'} 222 | }); 223 | 224 | awe.projections.update({ 225 | data: { 226 | animation: { 227 | duration: 1 228 | }, 229 | position: {y: 175} 230 | }, 231 | where: {id: 'ar_button_five'} 232 | }); 233 | 234 | awe.projections.update({ 235 | data: { 236 | animation: { 237 | duration: 1 238 | }, 239 | position: {y: 210} 240 | }, 241 | where: {id: 'ar_button_six'} 242 | }); 243 | 244 | awe.projections.update({ 245 | data: { 246 | animation: { 247 | duration: 1 248 | }, 249 | position: {y: 245} 250 | }, 251 | where: {id: 'ar_button_seven'} 252 | }); 253 | } else { 254 | awe.projections.update({ 255 | data: { 256 | animation: { 257 | duration: 1 258 | }, 259 | position: {y: -31} 260 | }, 261 | where: {id: 'ar_button_one'} 262 | }); 263 | 264 | awe.projections.update({ 265 | data: { 266 | animation: { 267 | duration: 1 268 | }, 269 | position: {y: -31} 270 | }, 271 | where: {id: 'ar_button_two'} 272 | }); 273 | 274 | awe.projections.update({ 275 | data: { 276 | animation: { 277 | duration: 1 278 | }, 279 | position: {y: -31} 280 | }, 281 | where: {id: 'ar_button_three'} 282 | }); 283 | 284 | awe.projections.update({ 285 | data: { 286 | animation: { 287 | duration: 1 288 | }, 289 | position: {y: -31} 290 | }, 291 | where: {id: 'ar_button_four'} 292 | }); 293 | 294 | awe.projections.update({ 295 | data: { 296 | animation: { 297 | duration: 1 298 | }, 299 | position: {y: -31} 300 | }, 301 | where: {id: 'ar_button_five'} 302 | }); 303 | 304 | awe.projections.update({ 305 | data: { 306 | animation: { 307 | duration: 1 308 | }, 309 | position: {y: -31} 310 | }, 311 | where: {id: 'ar_button_six'} 312 | }); 313 | 314 | awe.projections.update({ 315 | data: { 316 | animation: { 317 | duration: 1 318 | }, 319 | position: {y: -31} 320 | }, 321 | where: {id: 'ar_button_seven'} 322 | }); 323 | } 324 | 325 | menu_open = !menu_open; 326 | break; 327 | case 'ar_button_one': 328 | case 'ar_button_two': 329 | case 'ar_button_three': 330 | case 'ar_button_four': 331 | case 'ar_button_five': 332 | case 'ar_button_six': 333 | case 'ar_button_seven': 334 | var request = new XMLHttpRequest(); 335 | request.open('GET', 'http://maker.ifttt.com/trigger/'+e.detail.projection_id+'/with/key/yourkeyhere', true); 336 | 337 | request.onload = function() { 338 | if (request.status >= 200 && request.status < 400) { 339 | var data = JSON.parse(request.responseText); 340 | console.log(data); 341 | } 342 | }; 343 | 344 | request.send(); 345 | break; 346 | } 347 | }, false); 348 | } // success() 349 | }, 350 | { 351 | capabilities: [], 352 | success: function() { 353 | document.body.innerHTML = '

Try this demo in the latest version of Chrome or Firefox on a PC or Android device

'; 354 | } 355 | } 356 | ]); // awe.util.require() 357 | } // ready() 358 | }); // window.awe.init() 359 | }); // load -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | AR LIFX Controller 5 | 6 | 7 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /lib/awe-loader-min.js: -------------------------------------------------------------------------------- 1 | /* MIT License */var V8_CONFIG={default_id_field:"id",default_output_format:"js",debug:false,};function awe_v8(){var ID_FIELD="id";try{if(V8_CONFIG.default_id_field!==undefined){ID_FIELD=V8_CONFIG.default_id_field;}} 2 | catch(e){} 3 | var OUTPUT_FORMAT="js";try{if(V8_CONFIG.default_output_format!==undefined){OUTPUT_FORMAT=V8_CONFIG.default_output_format;}} 4 | catch(e){} 5 | var awe_v8_object=new awe_v8_template();var _return=function(return_flag,return_values,errors,output_format){if(output_format===undefined){output_format=OUTPUT_FORMAT;} 6 | if(output_format=="soapjr"){var return_object={HEAD:{},BODY:[]};if(return_flag){if(typeof(return_values)==="object"&&return_values.length!==undefined){return_object.BODY=return_values;} 7 | else{return_object.BODY=[return_values];} 8 | return_object.HEAD.result=1;return return_object;} 9 | else{return_object.HEAD.result=0;if(errors!==undefined&&Object.keys(errors).length){for(var i in errors){if(Object.keys(errors[i]).length){return_object.HEAD.errors[i]=errors[i];}}} 10 | return return_object;}} 11 | else{if(return_flag){return return_values;} 12 | else{return undefined;}}};function _add(data,io,errors){if(io==undefined){throw"io undefined";} 13 | if(data[io[ID_FIELD]]!==undefined){errors.BODY[ID_FIELD]={code:500,message:ID_FIELD+" already exists ("+io[ID_FIELD]+")",};throw ID_FIELD+" already exists ("+io[ID_FIELD]+")";} 14 | else{data[io[ID_FIELD]]=io;return io[ID_FIELD];}};function awe_v8_template(){var data={};if(V8_CONFIG.debug!==undefined){this.debug=V8_CONFIG.debug;} 15 | else{this.debug=false;} 16 | if(V8_CONFIG.debug_verbose!==undefined){this.debug_verbose=V8_CONFIG.debug;} 17 | else{this.debug_verbose=0;} 18 | this.get_data=function(){return data;} 19 | this.constructor.prototype.list=function(BODY,HEAD){if(BODY===undefined){BODY={};} 20 | if(HEAD===undefined){HEAD={};} 21 | var return_values=[];var return_flag=true;var errors={HEAD:{},BODY:{}};var output_format=undefined;if(HEAD!==undefined&&HEAD.output_format!==undefined){output_format=HEAD.output_format;} 22 | try{var page=0;var limit=undefined;var order_by=ID_FIELD;var order_type="alphabetic";var order_direction="asc";var data_array=[];for(var i in data){data_array.push(data[i]);} 23 | if(HEAD!==undefined){if(HEAD.page!==undefined&&typeof(HEAD.page)=="number"){page=HEAD.page-1;} 24 | if(HEAD.limit!==undefined&&typeof(HEAD.limit)=="number"){limit=HEAD.limit;} 25 | if(HEAD.order_by!==undefined&&typeof(HEAD.order_by)=="string"){order_by=HEAD.order_by;} 26 | if(HEAD.order_type!==undefined&&HEAD.order_type=="numeric"){order_type="numeric";} 27 | if(HEAD.order_direction!==undefined&&HEAD.order_direction=="desc"){order_direction="desc";}} 28 | var sort_function=function(A,B){var a=undefined;var b=undefined;if(order_type=="alphabetic"){if(A[order_by]!==undefined&&typeof(A[order_by])=="string"){a=A[order_by].toLowerCase();} 29 | if(B[order_by]!==undefined&&typeof(B[order_by])=="string"){b=B[order_by].toLowerCase();} 30 | if(order_direction=="asc"){if(a==undefined&&b!==undefined){return 0;} 31 | else if(a==undefined){return 1;} 32 | else if(b==undefined){return-1} 33 | else{if(ab){return 1;} 35 | else{return 0;}}} 36 | else{if(a==undefined&&b!==undefined){return 0;} 37 | else if(a==undefined){return-1;} 38 | else if(b==undefined){return 1} 39 | else{if(a>b){return-1;} 40 | else if(a0)){for(var i in BODY){var a=_add(data,BODY[i],errors);if(a){return_values.push(a);} 68 | else{throw"add failed";}}} 69 | else{var a=_add(data,BODY,errors) 70 | if(a){return_values.push(a);} 71 | else{throw"add failed";}}} 72 | catch(e){this.error_handler(e);return_flag=false;} 73 | if(return_values.length==0){return _return(return_flag,{},errors,output_format);} 74 | else if(return_values.length==1){return _return(return_flag,{id:return_values[0]},errors,output_format);} 75 | else{return _return(return_flag,{id:return_values},errors,output_format);}};this.constructor.prototype.view=function(BODY,HEAD){if(BODY==undefined){BODY={};} 76 | if(HEAD==undefined){HEAD={};} 77 | var return_value=undefined;var return_flag=true;var errors={HEAD:{},BODY:{}};var output_format=undefined;if(HEAD!==undefined&&HEAD.output_format!==undefined){output_format=HEAD.output_format;} 78 | try{if(typeof(BODY)=="string"&&data[BODY]!==undefined){return data[BODY].hasOwnProperty('value')?data[BODY].value:data[BODY];} 79 | else if(BODY!==undefined&&BODY.id!==undefined&&data[BODY.id]){return_value=data[BODY.id].hasOwnProperty('value')?data[BODY.id].value:data[BODY.id];} 80 | else{errors.BODY.id={code:500,message:BODY.id+" does not exist",};throw BODY.id+" does not exist";}} 81 | catch(e){this.error_handler(e);return_flag=false;} 82 | return _return(return_flag,return_value,errors);};this.constructor.prototype.update=function(BODY,HEAD){if(BODY==undefined){BODY={};} 83 | if(HEAD==undefined){HEAD={};} 84 | var return_values=HEAD.fields_updated||[];var return_flag=true;var errors={HEAD:{},BODY:{}};var output_format=undefined;if(HEAD!==undefined&&HEAD.output_format!==undefined){output_format=HEAD.output_format;} 85 | try{if(BODY==undefined){errors.BODY={code:500,message:"missing BODY object",};throw"missing BODY object";} 86 | if(BODY.data==undefined){errors.BODY.data={code:500,message:"missing 'data' clause in BODY object",};throw"missing 'data' clause in BODY object";} 87 | if(BODY.where==undefined){errors.BODY.where={code:500,message:"missing 'where' clause in BODY object",};throw"missing 'where' clause in BODY object";} 88 | if(BODY.where[ID_FIELD]!==undefined){if(HEAD.strict){if(data[BODY.where[ID_FIELD]]==undefined){errors.BODY[BODY.where[ID_FIELD]]={code:500,message:ID_FIELD+" doesn't exist ("+BODY.where[ID_FIELD]+")",};throw ID_FIELD+" doesn't exist ("+BODY.where[ID_FIELD]+")";}} 89 | for(var i in BODY.data){if(i!=ID_FIELD){if(!data[BODY.where[ID_FIELD]]){data[BODY.where[ID_FIELD]]={};data[BODY.where[ID_FIELD]][ID_FIELD]=BODY.where[ID_FIELD];} 90 | data[BODY.where[ID_FIELD]][i]=BODY.data[i];return_values.push(i);}}} 91 | else{errors.BODY.where={code:500,message:"where."+ID_FIELD+" required",};throw"where."+ID_FIELD+" required";}} 92 | catch(e){this.error_handler(e);return_flag=false;} 93 | return _return(return_flag,{fields_updated:return_values},errors,output_format);};this.constructor.prototype.delete=function(BODY,HEAD){if(BODY==undefined){BODY={};} 94 | if(HEAD==undefined){HEAD={};} 95 | var return_values=[];var return_flag=true;var errors={HEAD:{},BODY:{}};var output_format=undefined;if(HEAD!==undefined&&HEAD.output_format!==undefined){output_format=HEAD.output_format;} 96 | try{if(BODY!==undefined&&typeof(BODY.id)=="string"||typeof(BODY.id)=="number"){if(BODY!==undefined&&data[BODY.id]!==undefined){delete(data[BODY.id]);return_values.push(BODY.id);} 97 | else{errors.BODY.id={code:500,message:BODY.id+" does not exist",};throw BODY.id+" does not exist";}} 98 | else{for(var id in BODY.id){if(BODY.id[id]!==undefined&&data[BODY.id[id]]!==undefined){delete(data[BODY.id[id]]);return_values.push(BODY.id[id]);} 99 | else{errors.BODY[BODY.id[id]]={code:500,message:BODY.id[id]+" does not exist"};throw BODY.id[id]+" does not exist";}}}} 100 | catch(e){this.error_handler(e);return_flag=false;} 101 | if(return_values.length==0){return _return(return_flag,{},errors,output_format);} 102 | else if(return_values.length==1){return _return(return_flag,{id:return_values[0]},errors,output_format);} 103 | else{return _return(return_flag,{id:return_values},errors,output_format);}};this.constructor.prototype.report=function(BODY,HEAD){if(BODY==undefined){BODY={};} 104 | if(HEAD==undefined){HEAD={};} 105 | var return_value={count:0,fields:{},};var return_flag=true;var errors={HEAD:{},BODY:{}};var output_format=undefined;if(HEAD!==undefined&&HEAD.output_format!==undefined){output_format=HEAD.output_format;} 106 | try{if(data==undefined){errors.HEAD.data={code:500,message:"internal data invalid"};throw"internal data invalid";} 107 | for(var i in data){for(var k in data[i]){if(return_value.fields[k]==undefined){return_value.fields[k]=1;} 108 | else{return_value.fields[k]++;}} 109 | return_value.count++;}} 110 | catch(e){this.error_handler(e);return_flag=false;} 111 | return _return(return_flag,return_value,errors,output_format);};this.constructor.prototype.error_handler=function(e,debug){if(debug||this.debug){if(e.code&&e.message){console.log("ERROR: "+e.code);console.log(e.message);} 112 | else{console.log("ERROR");console.log(e);} 113 | if(this.debug_verbose>0){console.log("CALLER");console.log(arguments.callee.caller);} 114 | if(this.debug_verbose>2){console.log(arguments.callee.caller.toString());}}};this.constructor.prototype.toString=function(){return'awe_v8_object'};return this;};return awe_v8_object;} 115 | (function(window){var this_awe;var _audio_context;if(!window.awe){function awe(){var initialized=false;this.constructor.prototype.capabilities=new awe_v8();this.constructor.prototype.settings=new awe_v8();this.settings.add([{id:'debug',value:false,},{id:'geo',value:{get_location:false,}},{id:'auto_start',value:false,},{id:'renderer',value:'webgl',},{id:'start_video_stream',value:false,},{id:'fps',value:60,},{id:'default_lights',value:[{id:'spot_light',type:'spot',color:0xFFFFFF,intensity:3,distance:1000,position:{x:0,y:300,z:100},target:{x:0,y:0,z:100},cast_shadow:true,},],},]);this.constructor.prototype.events=new awe_v8();this.constructor.prototype.events.add=function(BODY,HEAD){if(!BODY){BODY={};} 116 | if(!HEAD){HEAD={};} 117 | try{var result=this.constructor.prototype.add.call(this,BODY,HEAD);if(Array.isArray(result.id)){for(var i in result.id){var event_handler=this.constructor.prototype.view.call(this,result.id[i]);if(event_handler){if(!event_handler.device_types||Object.keys(event_handler.device_types).length==0||event_handler.device_types[this_awe.device_type()]){event_handler.register(event_handler.handler);}}}} 118 | else{var event_handler=this.constructor.prototype.view.call(this,result.id);if(!event_handler.device_types||Object.keys(event_handler.device_types).length==0||event_handler.device_types[this_awe.device_type()]){event_handler.register(event_handler.handler);}}} 119 | catch(e){this.error_handler(e);} 120 | return result;} 121 | this.constructor.prototype.events.delete=function(BODY,HEAD){if(!BODY){BODY={};} 122 | if(!HEAD){HEAD={};} 123 | if(typeof BODY=='string'||typeof BODY=='number'){event_handler=this_awe.events.view(BODY);BODY={id:BODY};} 124 | else if(BODY.id){event_handler=this_awe.events.view(BODY.id);} 125 | if(event_handler){event_handler.unregister(event_handler.handler);} 126 | return this.constructor.prototype.delete.call(this,BODY,HEAD);} 127 | this.constructor.prototype.pois=new awe_v8();this.constructor.prototype.plugins=new awe_v8();this.constructor.prototype.plugins.add=function(BODY,HEAD){if(!BODY){BODY={};} 128 | if(!HEAD){HEAD={};} 129 | try{var result=this.constructor.prototype.add.call(this,BODY,HEAD);if(initialized){if(Array.isArray(result.id)){for(var i in result.id){var plugin=this.constructor.prototype.view.call(this,result.id[i]);if(plugin.auto_register===undefined||plugin.auto_register===true){plugin.register(plugin.data);}}} 130 | else{var plugin=this.constructor.prototype.view.call(this,result.id);if(plugin.auto_register===undefined||plugin.auto_register===true){plugin.register(plugin.data);}}}} 131 | catch(e){this.error_handler(e);} 132 | return result;} 133 | this.constructor.prototype.plugins.delete=function(BODY,HEAD){if(!BODY){BODY={};} 134 | if(!HEAD){HEAD={};} 135 | if(typeof BODY=='string'||typeof BODY=='number'){plugin=this_awe.plugins.view(BODY);BODY={id:BODY};} 136 | else if(BODY.id){plugin=this_awe.plugins.view(BODY.id);} 137 | if(plugin){plugin.unregister(plugin.data);} 138 | return this.constructor.prototype.delete.call(this,BODY,HEAD);} 139 | this.constructor.prototype.error_handler=function(e,debug){if(debug||this.debug){if(e.code&&e.message){console.log('ERROR: '+e.code);console.log(e.message);} 140 | else{console.log('ERROR');console.log(e);} 141 | if(this.debug_verbose>0){console.log('CALLER');console.log(arguments.callee.caller);} 142 | if(this.debug_verbose>2){console.log(arguments.callee.caller.toString());}}};this.constructor.prototype.init=function(io){if(initialized){console.log('awe was already initialized.');return;} 143 | if(!io){io={};} 144 | if(io.settings){for(var key in io.settings){try{if(this_awe.settings.view(key)!==undefined){this_awe.settings.update({data:{value:io.settings[key],},where:{id:key,}});} 145 | else{this_awe.settings.add({id:key,value:io.settings[key],});}} 146 | catch(e){}}} 147 | if(this_awe.settings.view('debug')){this.debug=this_awe.settings.view('debug');} 148 | else{this.debug=true;} 149 | if(this_awe.settings.view('debug_verbose')){this.debug_verbose=this_awe.settings.view('debug_verbose');} 150 | else{this.debug_verbose=1;} 151 | if(io.device_type!==undefined){if(io.device_type===true){var device_type='unsupported';var ua=navigator.userAgent;if(ua.match(/ipad/i)){device_type='ipad';} 152 | else if(ua.match(/iphone/i)){device_type='iphone';} 153 | else if(ua.match(/android/i)){device_type='android';} 154 | else if(ua.match(/(win|os x|linux)/i)){device_type='pc';} 155 | this_awe.settings.update({data:{value:device_type},where:{id:'device_type'}});} 156 | else{this_awe.settings.update({data:{value:io.device_type,},where:{id:'device_type',}});}} 157 | this_awe.detect_capabilities(function(){var plugins=this_awe.plugins.list();for(var i in plugins){plugins[i].register(plugins[i]);} 158 | if(io.ready){try{io.ready();} 159 | catch(e){}} 160 | var event=new CustomEvent('awe_ready');window.dispatchEvent(event);if(this_awe.settings.view('auto_start')){this_awe.setup_scene();} 161 | initialized=true;});};this.constructor.prototype.detect_capabilities=function(done){var io={},asynch_count=3,defaults={ajax:false,geo:false,lat:undefined,lon:undefined,gyro:false,motion:false,audio:false,gum:false,webgl:false,css3d:false,storage:false,sockets:false};var finished=function(){asynch_count--;if(asynch_count===0){var io_array=[];for(prop in io){io_array.push({id:prop,value:io[prop]});} 162 | this_awe.capabilities.add(io_array);if(done&&typeof(done)=='function'){done();}}};for(prop in defaults){if(!io[prop]){io[prop]=defaults[prop];}} 163 | if(!!window.XMLHttpRequest||!!window.XMLHttpRequest2){io.ajax=true;} 164 | if(!!navigator.geolocation){io.geo=true;if(this_awe.settings.view('geo')){if(this_awe.settings.view('geo.get_location')){navigator.geolocation.getCurrentPosition(function(position){this_awe.capabilities.update({data:{value:position.coords.latitude},where:{id:'lat'}});this_awe.capabilities.update({data:{value:position.coords.longitude},where:{id:'lon'}});});}}} 165 | if(!!window.DeviceOrientationEvent){var s1=function(e){if(e.alpha!==null){io.gyro=true;} 166 | window.removeEventListener('deviceorientation',s1,true);finished();} 167 | window.addEventListener('deviceorientation',s1,true);if(this_awe.device_type()=='pc'){setTimeout(function(){if(!io.gyro){finished();}},5000);}} 168 | else{finished();} 169 | if(!!window.DeviceMotionEvent){var s2=function(e){if(e.acceleration!==null){io.motion=true;} 170 | window.removeEventListener('devicemotion',s2,true);finished();} 171 | window.addEventListener('devicemotion',s2,true);if(this_awe.device_type()=='pc'){setTimeout(function(){if(!io.motion){finished();}},5000);}} 172 | else{finished();} 173 | if(this_awe.util.get_user_media){io.gum=true;} 174 | if(!!window.AudioContext){_audio_context=new AudioContext();} 175 | else if(!!window.webkitAudioContext){_audio_context=new webkitAudioContext();} 176 | if(_audio_context){io.audio=true;this_awe.util.audio_context=_audio_context;} 177 | if(!!document.createElement('canvas').getContext('experimental-webgl')||!!document.createElement('canvas').getContext('webgl')){io.webgl=true;} 178 | var tmp_div=document.createElement('div');if(tmp_div.style.WebkitTransformStyle){tmp_div.style.WebkitTransformStyle='preserve-3d';if(tmp_div.style.WebkitTransformStyle=='preserve-3d'){io.css3d=true;}} 179 | else if(tmp_div.style.transformStyle){tmp_div.style.transformStyle='preserve-3d';if(tmp_div.style.transformStyle=='preserve-3d'){io.css3d=true;}} 180 | if(!!window.localStorage){io.storage=true;} 181 | if(!!window.WebSocket||!!window.MozWebSocket||!!window.WebkitWebSocket||!!window.OWebSocket||!!window.msWebSocket||!!window.KhtmlWebSocket){io.sockets=true;} 182 | finished();};this.constructor.prototype.device_type=function(){var device_type;try{device_type=this.settings.view('device_type');} 183 | catch(e){};return device_type;};this.constructor.prototype.ready=function(){return initialized;} 184 | return this;};function _reset_load_file_queue(){return{error_called:false,success_called:false,queue:[],status:{},};} 185 | var _load_file_queue=_reset_load_file_queue();function _require(io){_load_file_queue=_reset_load_file_queue();if(Array.isArray(io)){for(var obj in io){if(io[obj].capabilities&&io[obj].files){if(!io[obj].success||typeof io[obj].success!=='function'){io[obj].success=function(){}} 186 | if(!io[obj].error||typeof io[obj].error!=='function'){io[obj].error=function(){console.log('required scripts load failed');}} 187 | if(Array.isArray(io[obj].capabilities)){var requirements_valid=true;for(var test in io[obj].capabilities){if(!this_awe.capabilities.view(io[obj].capabilities[test])){requirements_valid=false;}} 188 | if(requirements_valid){if(Array.isArray(io[obj].files)){_load_file_queue.queue=io[obj].files;_load_file_queue.success=io[obj].success;_load_file_queue.error=io[obj].error;_process_load_file_queue();} 189 | else{_load_file('script',{src:io[obj].files},io[obj].success,io[obj].error);} 190 | break;}} 191 | else{throw'require is not an array';}}}}} 192 | function _process_load_file_queue(){var is_loading=_is_loading();if(is_loading.failed){if(!_load_file_queue.error_called){_load_file_queue.error_called=true;try{_load_file_queue.error();} 193 | catch(e){} 194 | _load_file_queue=_reset_load_file_queue();} 195 | return;} 196 | else if(!is_loading.loading){if(Array.isArray(_load_file_queue.queue)&&_load_file_queue.queue.length>0){if(Array.isArray(_load_file_queue.queue[0])){for(var f in _load_file_queue.queue[0]){var file=_load_file_queue.queue[0][f];_load_file_queue.status[file]=0 197 | _load_file('script',{src:file},function(e){var file=this.getAttribute("src");_load_file_queue.status[file]=1;_process_load_file_queue();},function(e){var file=this.getAttribute("src");_load_file_queue.status[file]=-1;_process_load_file_queue();});} 198 | _load_file_queue.queue.splice(0,1);} 199 | else{var file=_load_file_queue.queue[0];_load_file_queue.queue.splice(0,1);_load_file_queue.status[file]=0;_load_file('script',{src:file},function(e){var file=this.getAttribute("src");_load_file_queue.status[file]=1;_process_load_file_queue();},function(e){var file=this.getAttribute("src");_load_file_queue.status[file]=-1;_process_load_file_queue();});} 200 | var is_loading=_is_loading();if(is_loading.failed){if(!_load_file_queue.error_called){_load_file_queue.error_called=true;try{_load_file_queue.error();} 201 | catch(e){} 202 | _load_file_queue=_reset_load_file_queue();}}} 203 | else{if(!_load_file_queue.success_called){_load_file_queue.success_called=true;try{_load_file_queue.success();} 204 | catch(e){} 205 | _load_file_queue=_reset_load_file_queue();}}}} 206 | function _is_loading(){var loading=false;var failed=false;for(var f in _load_file_queue.status){if(_load_file_queue.status[f]==-1){failed=true;} 207 | else if(_load_file_queue.status[f]==0){loading=true;;}} 208 | return{loading:loading,failed:failed};} 209 | function _load_file(type,attributes,success,error){try{var file=document.createElement(type);for(var i in attributes){file.setAttribute(i,attributes[i]);} 210 | if(success&&typeof(success)=='function'){file.onload=success;} 211 | if(error&&typeof(error)=='function'){file.onerror=error;} 212 | document.querySelector('head').appendChild(file);} 213 | catch(e){};} 214 | var _get_user_media=undefined,_connect_stream_to_src=function(){};if(navigator.getUserMedia){_get_user_media=navigator.getUserMedia.bind(navigator);_connect_stream_to_src=function(media_stream,media_element){media_element.srcObject=media_stream;media_element.play();};} 215 | else if(navigator.mozGetUserMedia){_get_user_media=navigator.mozGetUserMedia.bind(navigator);_connect_stream_to_src=function(media_stream,media_element){media_element.mozSrcObject=media_stream;media_element.play();};} 216 | else if(navigator.webkitGetUserMedia){_get_user_media=navigator.webkitGetUserMedia.bind(navigator);_connect_stream_to_src=function(media_stream,media_element){media_element.src=webkitURL.createObjectURL(media_stream);media_element.play();};} 217 | function _clean_object(object,list_of_keys){var keys={};for(var key in list_of_keys){keys[list_of_keys[key]]=1;} 218 | for(var key in object){if(!keys[key]){delete object[key];}} 219 | return object;} 220 | var util={require:_require,get_user_media:_get_user_media,connect_stream_to_src:_connect_stream_to_src,clean_object:_clean_object,};window.awe=new awe();this_awe=window.awe;this_awe.util=util;this_awe.AUTO_DETECT_DEVICE_TYPE=true;}})(window); -------------------------------------------------------------------------------- /lib/awe-loader.js: -------------------------------------------------------------------------------- 1 | // BEGIN FILE: awe_v8.js 2 | // See: https://github.com/buildar/awe.js/blob/master/awe_v8.js 3 | /* 4 | 5 | The MIT License 6 | 7 | Copyright (c) 2013 Rob Manson, http://buildAR.com. All rights reserved. 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in 17 | all copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 25 | THE SOFTWARE. 26 | 27 | 28 | What is awe_v8.js? 29 | ------------------ 30 | 31 | It's a simple datastore template that makes it easy to store, manage and 32 | extend collections of javascript object in a consistent way. 33 | 34 | Trust me, it's funkier than that sounds! 8) 35 | 36 | 37 | Why is it called awe_v8? 38 | ------------------------ 39 | 40 | Each datastore by default is designed to support a standard set of "8 verbs". 41 | 42 | - search 43 | - list 44 | - add 45 | - view 46 | - edit 47 | - update 48 | - delete 49 | - report 50 | 51 | Through the magical process of simplification this translates in a subset of 52 | "6 implemented methods". 53 | 54 | - list 55 | - add 56 | - view 57 | - update 58 | - delete 59 | - report 60 | 61 | search and edit are simply UIs that drive one of these 6 methods. 62 | 63 | e.g. edit -> update or search -> list 64 | 65 | 66 | How are errors handled? 67 | ----------------------- 68 | 69 | In simple js mode a method call either returns undefined for an error or 70 | either an object or an array of 0 or more objects. 71 | 72 | 73 | How do you use awe_v8? 74 | ---------------------- 75 | 76 | // create a awe_v8 datastore 77 | var my_datastore = new awe_v8(); 78 | 79 | // add one object to your datastore 80 | console.log("add an object (return new id)"); 81 | my_datastore.add({ 82 | id: "test", 83 | some_data: "blah" 84 | }); 85 | 86 | // add multiple objects to your datastore in one go 87 | console.log("add several objects (return new ids)"); 88 | my_datastore.add([ 89 | { 90 | id: "test2", 91 | some_data: "blahdeblah" 92 | }, 93 | { 94 | new_param: 99, 95 | id: "test3", 96 | some_data: "hrmok" 97 | }, 98 | ]); 99 | 100 | // list all objects currently in your datastore 101 | console.log("list all objects (return all objects)"); 102 | my_datastore.list(); 103 | 104 | // list all objects in SOAPjr format (see separate documentation for SOAPjr API) 105 | console.log("list all objects (return all objects in SOAPjr)"); 106 | my_datastore.list({}, { output_format:"soapjr" }); 107 | 108 | // view one object 109 | console.log("view an object (return one object)"); 110 | my_datastore.view("test"); // simple 111 | my_datastore.view({ id: "test" }); // clear 112 | my_datastore.view({ id: "test" }, { output_format:"js" }); // explicit 113 | 114 | // update one object 115 | console.log("update an object (return updated fields)"); 116 | my_datastore.update({ 117 | data: { 118 | new_param: 34, 119 | some_data: "new_data", 120 | }, 121 | where: { 122 | id: "test", 123 | } 124 | }); 125 | 126 | // search for objects that fuzzy match a pattern 127 | console.log("list fuzzy matches (return roughly matching objects)"); 128 | my_datastore.list({ id: "test" }, { limit: 10 }); 129 | 130 | // search for objects that exactly match a pattern 131 | console.log("list exact matches (return exactly matching objects)"); 132 | my_datastore.list({ exact: { id: "test2" } }); 133 | 134 | // delete one object 135 | console.log("delete an object (return deleted ids)"); 136 | my_datastore.delete({ id: "test2" }); 137 | 138 | // report metadata about this datastore 139 | console.log("report overview info (return a summary)"); 140 | my_datastore.report(); 141 | 142 | */ 143 | 144 | // override this to customise how you want your awe_v8 template to behave 145 | var V8_CONFIG = { 146 | default_id_field: "id", 147 | default_output_format: "js", 148 | debug: false, 149 | }; 150 | 151 | // below here is the template awe_v8 object implementation 152 | function awe_v8() { 153 | var ID_FIELD = "id"; 154 | try { 155 | if (V8_CONFIG.default_id_field !== undefined) { 156 | ID_FIELD = V8_CONFIG.default_id_field; 157 | } 158 | } 159 | catch(e) { /* TODO */ } 160 | var OUTPUT_FORMAT = "js"; 161 | try { 162 | if (V8_CONFIG.default_output_format !== undefined) { 163 | OUTPUT_FORMAT = V8_CONFIG.default_output_format; 164 | } 165 | } 166 | catch(e) { /* TODO */ } 167 | var awe_v8_object = new awe_v8_template(); 168 | var _return = function(return_flag, return_values, errors, output_format) { 169 | if (output_format === undefined) { 170 | output_format = OUTPUT_FORMAT; 171 | } 172 | if (output_format == "soapjr") { 173 | var return_object = { 174 | HEAD: {}, 175 | BODY: [] 176 | }; 177 | if (return_flag) { 178 | if (typeof(return_values) === "object" && return_values.length !== undefined) { 179 | return_object.BODY = return_values; 180 | } 181 | else { 182 | return_object.BODY = [return_values]; 183 | } 184 | return_object.HEAD.result = 1; 185 | return return_object; 186 | } 187 | else { 188 | return_object.HEAD.result = 0; 189 | if (errors !== undefined && Object.keys(errors).length) { 190 | for (var i in errors) { 191 | if (Object.keys(errors[i]).length) { 192 | 193 | return_object.HEAD.errors[i] = errors[i]; 194 | } 195 | } 196 | } 197 | return return_object; 198 | } 199 | } 200 | else { 201 | if (return_flag) { 202 | return return_values; 203 | } 204 | else { 205 | return undefined; 206 | } 207 | } 208 | }; 209 | function _add(data, io, errors) { 210 | if (io == undefined) { 211 | throw "io undefined"; 212 | } 213 | if (data[io[ID_FIELD]] !== undefined) { 214 | errors.BODY[ID_FIELD] = { 215 | code: 500, 216 | message: ID_FIELD+" already exists ("+io[ID_FIELD]+")", 217 | }; 218 | throw ID_FIELD+" already exists ("+io[ID_FIELD]+")"; 219 | } 220 | else { 221 | data[io[ID_FIELD]] = io; 222 | return io[ID_FIELD]; 223 | } 224 | }; 225 | function awe_v8_template() { 226 | var data = {}; 227 | if (V8_CONFIG.debug !== undefined) { 228 | this.debug = V8_CONFIG.debug; 229 | } 230 | else { 231 | this.debug = false; 232 | } 233 | if (V8_CONFIG.debug_verbose !== undefined) { 234 | this.debug_verbose = V8_CONFIG.debug; 235 | } 236 | else { 237 | this.debug_verbose = 0; 238 | } 239 | this.get_data = function(){ 240 | return data; 241 | } 242 | 243 | this.constructor.prototype.list = function(BODY, HEAD){ 244 | if (BODY === undefined) { BODY = {}; } 245 | if (HEAD === undefined) { HEAD = {}; } 246 | var return_values = []; 247 | var return_flag = true; 248 | var errors = { HEAD:{}, BODY:{} }; 249 | var output_format = undefined; 250 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 251 | output_format = HEAD.output_format; 252 | } 253 | try { 254 | var page = 0; 255 | var limit = undefined; 256 | var order_by = ID_FIELD; 257 | var order_type = "alphabetic"; 258 | var order_direction = "asc"; 259 | var data_array = []; 260 | for (var i in data) { 261 | data_array.push(data[i]); 262 | } 263 | if (HEAD !== undefined) { 264 | if (HEAD.page !== undefined && typeof(HEAD.page) == "number") { 265 | page = HEAD.page-1; 266 | } 267 | if (HEAD.limit !== undefined && typeof(HEAD.limit) == "number") { 268 | limit = HEAD.limit; 269 | } 270 | if (HEAD.order_by !== undefined && typeof(HEAD.order_by) == "string") { 271 | order_by = HEAD.order_by; 272 | } 273 | if (HEAD.order_type !== undefined && HEAD.order_type == "numeric") { 274 | order_type = "numeric"; 275 | } 276 | if (HEAD.order_direction !== undefined && HEAD.order_direction == "desc") { 277 | order_direction = "desc"; 278 | } 279 | } 280 | var sort_function = function(A, B) { 281 | var a = undefined; 282 | var b = undefined; 283 | if (order_type == "alphabetic") { 284 | if (A[order_by] !== undefined && typeof(A[order_by]) == "string") { 285 | a = A[order_by].toLowerCase(); 286 | } 287 | if (B[order_by] !== undefined && typeof(B[order_by]) == "string") { 288 | b = B[order_by].toLowerCase(); 289 | } 290 | if (order_direction == "asc") { 291 | if (a == undefined && b !== undefined) { 292 | return 0; 293 | } 294 | else if (a == undefined) { 295 | return 1; 296 | } 297 | else if (b == undefined) { 298 | return -1 299 | } 300 | else { 301 | if (a < b) { 302 | return -1; 303 | } 304 | else if (a > b) { 305 | return 1; 306 | } 307 | else { 308 | return 0; 309 | } 310 | } 311 | } 312 | else { 313 | if (a == undefined && b !== undefined) { 314 | return 0; 315 | } 316 | else if (a == undefined) { 317 | return -1; 318 | } 319 | else if (b == undefined) { 320 | return 1 321 | } 322 | else { 323 | if (a > b) { 324 | return -1; 325 | } 326 | else if (a < b) { 327 | return 1; 328 | } 329 | else { 330 | return 0; 331 | } 332 | } 333 | } 334 | } 335 | else { 336 | if (A[order_by] !== undefined && typeof(A[order_by]) == "number") { 337 | a = A[order_by]; 338 | } 339 | if (B[order_by] !== undefined && typeof(B[order_by]) == "number") { 340 | b = B[order_by]; 341 | } 342 | if (order_direction == "asc") { 343 | if (a == undefined && b == undefined) { 344 | return 0 345 | } 346 | else if (a == undefined) { 347 | return 1; 348 | } 349 | else if (b == undefined) { 350 | return -1; 351 | } 352 | else { 353 | return a-b; 354 | } 355 | } 356 | else { 357 | if (a == undefined && b == undefined) { 358 | return 0 359 | } 360 | else if (a == undefined) { 361 | return 1; 362 | } 363 | else if (b == undefined) { 364 | return -1; 365 | } 366 | else { 367 | return b-a; 368 | } 369 | } 370 | } 371 | }; 372 | for (var i in data_array) { 373 | if (BODY == undefined || BODY.length == 0) { 374 | return_values.push(data_array[i]); 375 | } 376 | else if (BODY !== undefined && BODY.exact !== undefined) { 377 | var a = undefined; 378 | var b = undefined; 379 | var match = 0; 380 | for (var m in BODY.exact) { 381 | a = data_array[i][m]; 382 | b = BODY.exact[m]; 383 | if (a == b) { 384 | match = 1; 385 | } 386 | } 387 | if (match) { 388 | return_values.push(data_array[i]); 389 | } 390 | } 391 | else { 392 | var match = 1; 393 | for (var m in BODY) { 394 | if (data_array[i][m] !== undefined && typeof(data_array[i][m]) == "string") { 395 | a = data_array[i][m].toLowerCase(); 396 | } 397 | if (BODY[m] !== undefined && typeof(BODY[m]) == "string") { 398 | b = BODY[m].toLowerCase(); 399 | } 400 | if (a !== undefined && b !== undefined) { 401 | var r = a.match(b); 402 | if (r == undefined) { 403 | match = 0; 404 | } 405 | } 406 | else { 407 | match = 0; 408 | } 409 | } 410 | if (match) { 411 | return_values.push(data_array[i]); 412 | } 413 | } 414 | } 415 | return_values = return_values.sort(sort_function); 416 | if (limit !== undefined) { 417 | var start = limit*page; 418 | var end = limit*(page+1); 419 | return_values = return_values.slice(start,end); 420 | } 421 | } 422 | catch(e) { 423 | this.error_handler(e); 424 | return_flag = false; 425 | } 426 | /* NOTE: commented out to make it more forgiving - maybe move to config 427 | if (!(return_values.length > 0)) { 428 | return_flag = false; 429 | errors.BODY.io = { 430 | code: 500, 431 | message: "object does not exist", 432 | }; 433 | } 434 | */ 435 | return _return(return_flag, return_values, errors, output_format); 436 | }; 437 | 438 | this.constructor.prototype.add = function(BODY, HEAD) { 439 | if (BODY == undefined) { BODY = {}; } 440 | if (HEAD == undefined) { HEAD = {}; } 441 | var return_values = []; 442 | var return_flag = true; 443 | var errors = { HEAD:{}, BODY:{} }; 444 | var output_format = undefined; 445 | if (HEAD !== undefined) { 446 | if (HEAD.output_format !== undefined) { 447 | output_format = HEAD.output_format; 448 | } 449 | if (HEAD.replace_all !== undefined && HEAD.replace_all) { 450 | data = {}; 451 | } 452 | } 453 | try { 454 | /* NOTE: commented out to make it more forgiving - maybe move to config 455 | if (BODY == undefined) { 456 | errors.BODY = { 457 | code: 500, 458 | message: "BODY object invalid (undefined)", 459 | }; 460 | throw "BODY object invalid (undefined)"; 461 | } 462 | */ 463 | if (typeof(BODY) == "string") { 464 | errors.BODY = { 465 | code: 500, 466 | message: "BODY object invalid (string)", 467 | }; 468 | throw "BODY object invalid (string)"; 469 | } 470 | if (typeof(BODY) == "number") { 471 | errors.BODY = { 472 | code: 500, 473 | message: "BODY object invalid (number)", 474 | }; 475 | throw "BODY object invalid (number)"; 476 | } 477 | if ((Array.isArray && Array.isArray(BODY)) || (BODY[ID_FIELD] == undefined && BODY.length > 0)) { 478 | for (var i in BODY) { 479 | var a = _add(data, BODY[i], errors); 480 | if (a) { 481 | return_values.push(a); // if this fails will it still push something? yes, undefined 482 | } 483 | else { 484 | throw "add failed"; 485 | } 486 | } 487 | } 488 | else { 489 | var a = _add(data, BODY, errors) 490 | if (a) { 491 | return_values.push(a); // if this fails will it still push something? yes, undefined 492 | } 493 | else { 494 | throw "add failed"; 495 | } 496 | } 497 | } 498 | catch(e) { 499 | this.error_handler(e); 500 | return_flag = false; 501 | } 502 | if (return_values.length == 0) { 503 | return _return(return_flag, {}, errors, output_format); 504 | } 505 | else if (return_values.length == 1) { 506 | return _return(return_flag, { id: return_values[0] }, errors, output_format); 507 | } 508 | else { 509 | return _return(return_flag, { id: return_values }, errors, output_format); 510 | } 511 | }; 512 | 513 | this.constructor.prototype.view = function(BODY, HEAD) { 514 | if (BODY == undefined) { BODY = {}; } 515 | if (HEAD == undefined) { HEAD = {}; } 516 | var return_value = undefined; 517 | var return_flag = true; 518 | var errors = { HEAD:{}, BODY:{} }; 519 | var output_format = undefined; 520 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 521 | output_format = HEAD.output_format; 522 | } 523 | try { 524 | if (typeof(BODY) == "string" && data[BODY] !== undefined) { 525 | return data[BODY].hasOwnProperty('value') ? data[BODY].value : data[BODY]; 526 | } 527 | else if (BODY !== undefined && BODY.id !== undefined && data[BODY.id]) { 528 | return_value = data[BODY.id].hasOwnProperty('value') ? data[BODY.id].value : data[BODY.id]; 529 | } 530 | else { 531 | errors.BODY.id = { 532 | code: 500, 533 | message: BODY.id+" does not exist", 534 | }; 535 | throw BODY.id+" does not exist"; 536 | } 537 | } 538 | catch(e) { 539 | this.error_handler(e); 540 | return_flag = false; 541 | } 542 | return _return(return_flag, return_value, errors); 543 | }; 544 | 545 | this.constructor.prototype.update = function(BODY, HEAD) { 546 | if (BODY == undefined) { BODY = {}; } 547 | if (HEAD == undefined) { HEAD = {}; } 548 | var return_values = HEAD.fields_updated || []; 549 | var return_flag = true; 550 | var errors = { HEAD:{}, BODY:{} }; 551 | var output_format = undefined; 552 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 553 | output_format = HEAD.output_format; 554 | } 555 | try { 556 | if (BODY == undefined) { 557 | errors.BODY = { 558 | code: 500, 559 | message: "missing BODY object", 560 | }; 561 | throw "missing BODY object"; 562 | } 563 | if (BODY.data == undefined) { 564 | errors.BODY.data = { 565 | code: 500, 566 | message: "missing 'data' clause in BODY object", 567 | }; 568 | throw "missing 'data' clause in BODY object"; 569 | } 570 | if (BODY.where == undefined) { 571 | errors.BODY.where = { 572 | code: 500, 573 | message: "missing 'where' clause in BODY object", 574 | }; 575 | throw "missing 'where' clause in BODY object"; 576 | } 577 | if (BODY.where[ID_FIELD] !== undefined) { 578 | if (HEAD.strict) { 579 | if (data[BODY.where[ID_FIELD]] == undefined) { 580 | errors.BODY[BODY.where[ID_FIELD]] = { 581 | code: 500, 582 | message: ID_FIELD+" doesn't exist ("+BODY.where[ID_FIELD]+")", 583 | }; 584 | throw ID_FIELD+" doesn't exist ("+BODY.where[ID_FIELD]+")"; 585 | } 586 | } 587 | for (var i in BODY.data) { 588 | if (i != ID_FIELD) { 589 | if (!data[BODY.where[ID_FIELD]]) { 590 | data[BODY.where[ID_FIELD]] = {}; 591 | data[BODY.where[ID_FIELD]][ID_FIELD] = BODY.where[ID_FIELD]; 592 | } 593 | data[BODY.where[ID_FIELD]][i] = BODY.data[i]; 594 | return_values.push(i); 595 | } 596 | } 597 | } 598 | else { 599 | errors.BODY.where = { 600 | code: 500, 601 | message: "where."+ID_FIELD+" required", 602 | }; 603 | throw "where."+ID_FIELD+" required"; 604 | } 605 | } 606 | catch(e) { 607 | this.error_handler(e); 608 | return_flag = false; 609 | } 610 | return _return(return_flag, { fields_updated: return_values }, errors, output_format); 611 | }; 612 | 613 | this.constructor.prototype.delete = function(BODY, HEAD) { 614 | if (BODY == undefined) { BODY = {}; } 615 | if (HEAD == undefined) { HEAD = {}; } 616 | var return_values = []; 617 | var return_flag = true; 618 | var errors = { HEAD:{}, BODY:{} }; 619 | var output_format = undefined; 620 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 621 | output_format = HEAD.output_format; 622 | } 623 | try { 624 | if (BODY !== undefined && typeof(BODY.id) == "string" || typeof(BODY.id) == "number") { 625 | if (BODY !== undefined && data[BODY.id] !== undefined) { 626 | delete(data[BODY.id]); 627 | return_values.push(BODY.id); 628 | } 629 | else { 630 | errors.BODY.id = { 631 | code: 500, 632 | message: BODY.id+" does not exist", 633 | }; 634 | throw BODY.id+" does not exist"; 635 | } 636 | } 637 | else { 638 | for (var id in BODY.id) { 639 | if (BODY.id[id] !== undefined && data[BODY.id[id]] !== undefined) { 640 | delete(data[BODY.id[id]]); 641 | return_values.push(BODY.id[id]); 642 | } 643 | else { 644 | errors.BODY[BODY.id[id]] = { 645 | code: 500, 646 | message: BODY.id[id]+" does not exist" 647 | }; 648 | throw BODY.id[id]+" does not exist"; 649 | } 650 | } 651 | } 652 | } 653 | catch(e) { 654 | this.error_handler(e); 655 | return_flag = false; 656 | } 657 | if (return_values.length == 0) { 658 | return _return(return_flag, {}, errors, output_format); 659 | } 660 | else if (return_values.length == 1) { 661 | return _return(return_flag, { id: return_values[0] }, errors, output_format); 662 | } 663 | else { 664 | return _return(return_flag, { id: return_values }, errors, output_format); 665 | } 666 | }; 667 | 668 | this.constructor.prototype.report = function(BODY, HEAD) { 669 | if (BODY == undefined) { BODY = {}; } 670 | if (HEAD == undefined) { HEAD = {}; } 671 | var return_value = { 672 | count: 0, 673 | fields: {}, 674 | }; 675 | var return_flag = true; 676 | var errors = { HEAD:{}, BODY:{} }; 677 | var output_format = undefined; 678 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 679 | output_format = HEAD.output_format; 680 | } 681 | try { 682 | if (data == undefined) { 683 | errors.HEAD.data = { 684 | code: 500, 685 | message: "internal data invalid" 686 | }; 687 | throw "internal data invalid"; 688 | } 689 | for (var i in data) { 690 | for (var k in data[i]) { 691 | if (return_value.fields[k] == undefined) { 692 | return_value.fields[k] = 1; 693 | } 694 | else { 695 | return_value.fields[k]++; 696 | } 697 | } 698 | return_value.count++; 699 | } 700 | } 701 | catch(e) { 702 | this.error_handler(e); 703 | return_flag = false; 704 | } 705 | return _return(return_flag, return_value, errors, output_format); 706 | }; 707 | 708 | 709 | this.constructor.prototype.error_handler = function(e, debug) { 710 | if (debug || this.debug) { 711 | if (e.code && e.message) { 712 | console.log("ERROR: "+e.code); 713 | console.log(e.message); 714 | } 715 | else { 716 | console.log("ERROR"); 717 | console.log(e); 718 | } 719 | if (this.debug_verbose > 0) { 720 | console.log("CALLER"); 721 | console.log(arguments.callee.caller); 722 | } 723 | if (this.debug_verbose > 2) { 724 | console.log(arguments.callee.caller.toString()); 725 | } 726 | } 727 | }; 728 | 729 | this.constructor.prototype.toString = function() { 730 | return 'awe_v8_object' 731 | }; 732 | 733 | return this; 734 | }; 735 | return awe_v8_object; 736 | } 737 | // END FILE: awe_v8.js 738 | 739 | // BEGIN FILE: awe-loader.js file 740 | /* 741 | 742 | The MIT License 743 | 744 | Copyright (c) 2013 Rob Manson & Malgorzata Wierzbicka, http://buildAR.com. 745 | All rights reserved. 746 | 747 | Permission is hereby granted, free of charge, to any person obtaining a copy 748 | of this software and associated documentation files (the "Software"), to deal 749 | in the Software without restriction, including without limitation the rights 750 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 751 | copies of the Software, and to permit persons to whom the Software is 752 | furnished to do so, subject to the following conditions: 753 | 754 | The above copyright notice and this permission notice shall be included in 755 | all copies or substantial portions of the Software. 756 | 757 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 758 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 759 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 760 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 761 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 762 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 763 | THE SOFTWARE. 764 | 765 | */ 766 | 767 | (function(window) { 768 | var this_awe; 769 | var _audio_context; 770 | if (!window.awe) { 771 | function awe() { 772 | var initialized = false; 773 | 774 | this.constructor.prototype.capabilities = new awe_v8(); 775 | 776 | this.constructor.prototype.settings = new awe_v8(); 777 | // set default settings 778 | // NOTE: override this in your code to customize how you want your awe.js app to behave 779 | 780 | this.settings.add([ 781 | { 782 | id: 'debug', 783 | value: false, 784 | }, 785 | { 786 | id: 'geo', 787 | value:{ 788 | get_location: false, 789 | } 790 | }, 791 | { 792 | id: 'auto_start', 793 | value: false, 794 | }, 795 | { 796 | id: 'renderer', 797 | value: 'webgl', 798 | }, 799 | { 800 | id: 'start_video_stream', 801 | value: false, 802 | }, 803 | { 804 | id: 'fps', 805 | value: 60, 806 | }, 807 | { 808 | id: 'default_lights', 809 | value: [ 810 | { 811 | id: 'spot_light', 812 | type: 'spot', 813 | color: 0xFFFFFF, 814 | intensity: 3, 815 | distance: 1000, 816 | position: { x:0, y:300, z:100 }, 817 | target: { x:0, y:0, z:100 }, 818 | cast_shadow: true, 819 | }, 820 | ], 821 | }, 822 | ]); 823 | 824 | this.constructor.prototype.events = new awe_v8(); 825 | this.constructor.prototype.events.add = function(BODY, HEAD) { 826 | if (!BODY) { BODY = {}; } 827 | if (!HEAD) { HEAD = {}; } 828 | try { 829 | var result = this.constructor.prototype.add.call(this, BODY, HEAD); // super 830 | if (Array.isArray(result.id)) { 831 | for (var i in result.id) { 832 | var event_handler = this.constructor.prototype.view.call(this, result.id[i]); 833 | if (event_handler) { 834 | if (!event_handler.device_types || Object.keys(event_handler.device_types).length == 0 || event_handler.device_types[this_awe.device_type()]) { 835 | event_handler.register(event_handler.handler); 836 | } 837 | } 838 | } 839 | } 840 | else { 841 | var event_handler = this.constructor.prototype.view.call(this, result.id); 842 | if (!event_handler.device_types || Object.keys(event_handler.device_types).length == 0 || event_handler.device_types[this_awe.device_type()]) { 843 | event_handler.register(event_handler.handler); 844 | } 845 | } 846 | } 847 | catch(e) { 848 | this.error_handler(e); 849 | } 850 | return result; 851 | } 852 | this.constructor.prototype.events.delete = function(BODY, HEAD) { 853 | if (!BODY) { BODY = {}; } 854 | if (!HEAD) { HEAD = {}; } 855 | 856 | if (typeof BODY == 'string' || typeof BODY == 'number') { 857 | event_handler = this_awe.events.view(BODY); 858 | BODY = { id: BODY }; 859 | } 860 | else if (BODY.id) { 861 | event_handler = this_awe.events.view(BODY.id); 862 | } 863 | if (event_handler) { 864 | event_handler.unregister(event_handler.handler); 865 | } 866 | return this.constructor.prototype.delete.call(this, BODY, HEAD); // super 867 | } 868 | 869 | this.constructor.prototype.pois = new awe_v8(); 870 | 871 | this.constructor.prototype.plugins = new awe_v8(); 872 | this.constructor.prototype.plugins.add = function(BODY, HEAD) { 873 | if (!BODY) { BODY = {}; } 874 | if (!HEAD) { HEAD = {}; } 875 | try { 876 | var result = this.constructor.prototype.add.call(this, BODY, HEAD); // super 877 | if (initialized) { 878 | if (Array.isArray(result.id)) { 879 | for (var i in result.id) { 880 | var plugin = this.constructor.prototype.view.call(this, result.id[i]); 881 | if (plugin.auto_register === undefined || plugin.auto_register === true) { 882 | plugin.register(plugin.data); 883 | } 884 | } 885 | } 886 | else { 887 | var plugin = this.constructor.prototype.view.call(this, result.id); 888 | if (plugin.auto_register === undefined || plugin.auto_register === true) { 889 | plugin.register(plugin.data); 890 | } 891 | } 892 | } 893 | } 894 | catch(e) { 895 | this.error_handler(e); 896 | } 897 | return result; 898 | } 899 | this.constructor.prototype.plugins.delete = function(BODY, HEAD) { 900 | if (!BODY) { BODY = {}; } 901 | if (!HEAD) { HEAD = {}; } 902 | // tear down plugin 903 | if (typeof BODY == 'string' || typeof BODY == 'number') { 904 | plugin = this_awe.plugins.view(BODY); 905 | BODY = { id: BODY }; 906 | } 907 | else if (BODY.id) { 908 | plugin = this_awe.plugins.view(BODY.id); 909 | } 910 | if (plugin) { 911 | plugin.unregister(plugin.data); 912 | } 913 | return this.constructor.prototype.delete.call(this, BODY, HEAD); // super 914 | } 915 | 916 | this.constructor.prototype.error_handler = function(e, debug) { 917 | if (debug || this.debug) { 918 | if (e.code && e.message) { 919 | console.log('ERROR: '+e.code); 920 | console.log(e.message); 921 | } 922 | else { 923 | console.log('ERROR'); 924 | console.log(e); 925 | } 926 | if (this.debug_verbose > 0) { 927 | console.log('CALLER'); 928 | console.log(arguments.callee.caller); 929 | } 930 | if (this.debug_verbose > 2) { 931 | console.log(arguments.callee.caller.toString()); 932 | } 933 | } 934 | }; 935 | 936 | this.constructor.prototype.init = function(io) { 937 | if (initialized) { 938 | console.log('awe was already initialized.'); 939 | return; 940 | } 941 | if (!io) { io = {}; } 942 | 943 | 944 | if (io.settings) { 945 | for (var key in io.settings) { 946 | try { 947 | if (this_awe.settings.view(key) !== undefined) { 948 | this_awe.settings.update({ 949 | data: { 950 | value: io.settings[key], 951 | }, 952 | where: { 953 | id: key, 954 | } 955 | }); 956 | } 957 | else { 958 | this_awe.settings.add({ 959 | id: key, 960 | value: io.settings[key], 961 | }); 962 | } 963 | } 964 | catch(e) { /* TODO */ } 965 | } 966 | } 967 | 968 | if (this_awe.settings.view('debug')) { 969 | this.debug = this_awe.settings.view('debug'); 970 | } 971 | else { 972 | this.debug = true; 973 | } 974 | if (this_awe.settings.view('debug_verbose')) { 975 | this.debug_verbose = this_awe.settings.view('debug_verbose'); 976 | } 977 | else { 978 | this.debug_verbose = 1; 979 | } 980 | 981 | if (io.device_type !== undefined) { 982 | if (io.device_type === true) { 983 | var device_type = 'unsupported'; 984 | var ua = navigator.userAgent; 985 | if (ua.match(/ipad/i)) { 986 | device_type = 'ipad'; 987 | } 988 | else if (ua.match(/iphone/i)) { 989 | device_type = 'iphone'; 990 | } 991 | else if (ua.match(/android/i)) { 992 | device_type = 'android'; 993 | // NOTE: may differentiate more here 994 | } 995 | else if (ua.match(/(win|os x|linux)/i)) { 996 | device_type = 'pc'; 997 | } 998 | this_awe.settings.update({ 999 | data: { 1000 | value: device_type 1001 | }, 1002 | where: { 1003 | id: 'device_type' 1004 | } 1005 | }); 1006 | } 1007 | else { 1008 | this_awe.settings.update({ 1009 | data:{ 1010 | value: io.device_type, 1011 | }, 1012 | where:{ 1013 | id: 'device_type', 1014 | } 1015 | }); 1016 | } 1017 | } 1018 | 1019 | this_awe.detect_capabilities(function() { 1020 | var plugins = this_awe.plugins.list(); 1021 | for (var i in plugins) { 1022 | plugins[i].register(plugins[i]); 1023 | } 1024 | if (io.ready) { 1025 | try { 1026 | io.ready(); 1027 | } 1028 | catch(e) { /* TODO */ } 1029 | } 1030 | var event = new CustomEvent('awe_ready'); 1031 | window.dispatchEvent(event); 1032 | if (this_awe.settings.view('auto_start')) { 1033 | this_awe.setup_scene(); 1034 | } 1035 | initialized = true; 1036 | }); 1037 | }; 1038 | 1039 | this.constructor.prototype.detect_capabilities = function(done) { 1040 | var io = {}, 1041 | asynch_count = 3, 1042 | defaults = { 1043 | ajax : false, // is ajax supported 1044 | geo : false, // is geo supported 1045 | lat: undefined, // only populated once location requested 1046 | lon: undefined, // only populated once location requested 1047 | gyro : false, // is orientation supported 1048 | motion : false, // is motion supported 1049 | audio : false, // is web audio supported 1050 | gum: false, // is camera/microphone access supported 1051 | webgl: false, // is webgl supported 1052 | css3d: false, // is css3d supported 1053 | storage : false, // is local storage supported 1054 | sockets : false // are web sockets supported 1055 | }; 1056 | 1057 | var finished = function() { 1058 | asynch_count--; 1059 | if (asynch_count === 0) { 1060 | var io_array = []; 1061 | for (prop in io) { 1062 | io_array.push({ id:prop, value:io[prop] }); 1063 | } 1064 | this_awe.capabilities.add(io_array); 1065 | if (done && typeof(done) == 'function') { 1066 | done(); 1067 | } 1068 | } 1069 | }; 1070 | 1071 | for (prop in defaults) { 1072 | if (!io[prop]) { 1073 | io[prop] = defaults[prop]; 1074 | } 1075 | } 1076 | 1077 | // services (ajax) enabled 1078 | if (!!window.XMLHttpRequest || !!window.XMLHttpRequest2) { 1079 | io.ajax = true; 1080 | } 1081 | 1082 | // geo enabled 1083 | if (!!navigator.geolocation) { 1084 | io.geo = true; 1085 | if (this_awe.settings.view('geo')) { 1086 | if (this_awe.settings.view('geo.get_location')) { 1087 | navigator.geolocation.getCurrentPosition(function(position) { 1088 | this_awe.capabilities.update({ data: { value: position.coords.latitude }, where: { id: 'lat' } }); 1089 | this_awe.capabilities.update({ data: { value: position.coords.longitude }, where: { id: 'lon' } }); 1090 | }); 1091 | } 1092 | } 1093 | } 1094 | 1095 | // orientation enabled 1096 | if (!!window.DeviceOrientationEvent) { 1097 | var s1 = function(e) { 1098 | if (e.alpha !== null) { 1099 | io.gyro = true; 1100 | } 1101 | window.removeEventListener('deviceorientation', s1, true); 1102 | finished(); 1103 | } 1104 | window.addEventListener('deviceorientation', s1, true); 1105 | // in case event handler never returns - eg. on a pc 1106 | if (this_awe.device_type() == 'pc') { 1107 | setTimeout(function() { 1108 | if (!io.gyro) { 1109 | finished(); 1110 | } 1111 | }, 5000); 1112 | } 1113 | } 1114 | else { 1115 | finished(); 1116 | } 1117 | 1118 | // motion enabled 1119 | if (!!window.DeviceMotionEvent) { 1120 | var s2 = function(e) { 1121 | if (e.acceleration !== null) { 1122 | io.motion = true; 1123 | } 1124 | window.removeEventListener('devicemotion', s2, true); 1125 | finished(); 1126 | } 1127 | window.addEventListener('devicemotion', s2, true); 1128 | // in case event handler never returns - eg. on a pc 1129 | if (this_awe.device_type() == 'pc') { 1130 | setTimeout(function() { 1131 | if (!io.motion) { 1132 | finished(); 1133 | } 1134 | }, 5000); 1135 | } 1136 | } 1137 | else { 1138 | finished(); 1139 | } 1140 | 1141 | // getUserMedia microphone & camera access enabled 1142 | if (this_awe.util.get_user_media) { 1143 | io.gum = true; 1144 | } 1145 | 1146 | // web audio enabled 1147 | if (!!window.AudioContext) { 1148 | _audio_context = new AudioContext(); 1149 | } 1150 | else if (!!window.webkitAudioContext) { 1151 | _audio_context = new webkitAudioContext(); 1152 | } 1153 | if (_audio_context) { 1154 | io.audio = true; 1155 | this_awe.util.audio_context = _audio_context; 1156 | } 1157 | 1158 | // webgl enabled 1159 | if (!!document.createElement('canvas').getContext('experimental-webgl') || !!document.createElement('canvas').getContext('webgl')) { 1160 | io.webgl = true; 1161 | } 1162 | 1163 | var tmp_div = document.createElement('div'); 1164 | if (tmp_div.style.WebkitTransformStyle) { 1165 | tmp_div.style.WebkitTransformStyle = 'preserve-3d'; 1166 | if (tmp_div.style.WebkitTransformStyle == 'preserve-3d') { 1167 | io.css3d = true; 1168 | } 1169 | } 1170 | else if (tmp_div.style.transformStyle) { 1171 | tmp_div.style.transformStyle = 'preserve-3d'; 1172 | if (tmp_div.style.transformStyle == 'preserve-3d') { 1173 | io.css3d = true; 1174 | } 1175 | } 1176 | 1177 | // localstorage enabled 1178 | if (!!window.localStorage) { 1179 | io.storage = true; 1180 | } 1181 | 1182 | // websockets enabled 1183 | if (!!window.WebSocket || !!window.MozWebSocket || !!window.WebkitWebSocket || !!window.OWebSocket || !!window.msWebSocket || !!window.KhtmlWebSocket) { 1184 | io.sockets = true; 1185 | } 1186 | 1187 | finished(); 1188 | }; 1189 | 1190 | this.constructor.prototype.device_type = function() { 1191 | var device_type; 1192 | try { 1193 | device_type = this.settings.view('device_type'); 1194 | } 1195 | catch(e) { /* TODO */ }; 1196 | return device_type; 1197 | }; 1198 | 1199 | this.constructor.prototype.ready = function() { 1200 | return initialized; 1201 | } 1202 | 1203 | return this; 1204 | }; 1205 | 1206 | function _reset_load_file_queue() { 1207 | return { 1208 | error_called: false, 1209 | success_called: false, 1210 | queue: [], 1211 | status: {}, 1212 | }; 1213 | } 1214 | 1215 | var _load_file_queue = _reset_load_file_queue(); 1216 | function _require(io) { 1217 | _load_file_queue = _reset_load_file_queue(); 1218 | if (Array.isArray(io)) { 1219 | for (var obj in io) { 1220 | if (io[obj].capabilities && io[obj].files) { 1221 | if (!io[obj].success || typeof io[obj].success !== 'function') { 1222 | io[obj].success = function() { /* TODO */ } 1223 | } 1224 | if (!io[obj].error || typeof io[obj].error !== 'function') { 1225 | io[obj].error = function() { console.log('required scripts load failed'); } 1226 | } 1227 | if (Array.isArray(io[obj].capabilities)) { 1228 | var requirements_valid = true; 1229 | for (var test in io[obj].capabilities) { 1230 | if (!this_awe.capabilities.view(io[obj].capabilities[test])) { 1231 | requirements_valid = false; 1232 | } 1233 | } 1234 | if (requirements_valid) { 1235 | if (Array.isArray(io[obj].files)) { 1236 | _load_file_queue.queue = io[obj].files; 1237 | _load_file_queue.success = io[obj].success; 1238 | _load_file_queue.error = io[obj].error; 1239 | _process_load_file_queue(); 1240 | } 1241 | else { 1242 | _load_file( 1243 | 'script', 1244 | { src: io[obj].files }, 1245 | io[obj].success, 1246 | io[obj].error 1247 | ); 1248 | } 1249 | break; 1250 | } 1251 | } 1252 | else { 1253 | throw 'require is not an array'; 1254 | } 1255 | } 1256 | } 1257 | } 1258 | } 1259 | 1260 | function _process_load_file_queue() { 1261 | var is_loading = _is_loading(); 1262 | if (is_loading.failed) { 1263 | if (!_load_file_queue.error_called) { 1264 | _load_file_queue.error_called = true; 1265 | try { 1266 | _load_file_queue.error(); 1267 | } 1268 | catch(e) { /* TODO */ } 1269 | _load_file_queue = _reset_load_file_queue(); 1270 | } 1271 | return; 1272 | } 1273 | else if (!is_loading.loading) { 1274 | if (Array.isArray(_load_file_queue.queue) && _load_file_queue.queue.length > 0) { 1275 | if (Array.isArray(_load_file_queue.queue[0])) { 1276 | for (var f in _load_file_queue.queue[0]) { 1277 | var file = _load_file_queue.queue[0][f]; 1278 | _load_file_queue.status[file] = 0 1279 | _load_file( 1280 | 'script', 1281 | { src: file }, 1282 | function(e) { 1283 | var file = this.getAttribute("src"); 1284 | _load_file_queue.status[file] = 1; 1285 | _process_load_file_queue(); 1286 | }, 1287 | function(e) { 1288 | var file = this.getAttribute("src"); 1289 | _load_file_queue.status[file] = -1; 1290 | _process_load_file_queue(); 1291 | } 1292 | ); 1293 | } 1294 | _load_file_queue.queue.splice(0, 1); 1295 | } 1296 | else { 1297 | var file = _load_file_queue.queue[0]; 1298 | _load_file_queue.queue.splice(0, 1); 1299 | _load_file_queue.status[file] = 0; 1300 | _load_file( 1301 | 'script', 1302 | { src: file }, 1303 | function(e) { 1304 | var file = this.getAttribute("src"); 1305 | _load_file_queue.status[file] = 1; 1306 | _process_load_file_queue(); 1307 | }, 1308 | function(e) { 1309 | var file = this.getAttribute("src"); 1310 | _load_file_queue.status[file] = -1; 1311 | _process_load_file_queue(); 1312 | } 1313 | ); 1314 | } 1315 | var is_loading = _is_loading(); 1316 | if (is_loading.failed) { 1317 | if (!_load_file_queue.error_called) { 1318 | _load_file_queue.error_called = true; 1319 | try { 1320 | _load_file_queue.error(); 1321 | } 1322 | catch(e) { /* TODO */ } 1323 | _load_file_queue = _reset_load_file_queue(); 1324 | } 1325 | } 1326 | } 1327 | else { 1328 | if (!_load_file_queue.success_called) { 1329 | _load_file_queue.success_called = true; 1330 | try { 1331 | _load_file_queue.success(); 1332 | } 1333 | catch(e) { /* TODO */ } 1334 | _load_file_queue = _reset_load_file_queue(); 1335 | } 1336 | } 1337 | } 1338 | } 1339 | 1340 | function _is_loading() { 1341 | var loading = false; 1342 | var failed = false; 1343 | for (var f in _load_file_queue.status) { 1344 | if (_load_file_queue.status[f] == -1) { 1345 | failed = true; 1346 | } 1347 | else if (_load_file_queue.status[f] == 0) { 1348 | loading = true;; 1349 | } 1350 | } 1351 | return { loading: loading, failed: failed }; 1352 | } 1353 | 1354 | function _load_file(type, attributes, success, error) { 1355 | try { 1356 | var file = document.createElement(type); 1357 | for (var i in attributes) { 1358 | file.setAttribute(i, attributes[i]); 1359 | } 1360 | if (success && typeof(success) == 'function') { 1361 | file.onload = success; 1362 | } 1363 | if (error && typeof(error) == 'function') { 1364 | file.onerror = error; 1365 | } 1366 | document.querySelector('head').appendChild(file); 1367 | } 1368 | catch(e) { /* TODO */ }; 1369 | } 1370 | 1371 | var _get_user_media = undefined, 1372 | _connect_stream_to_src = function() {}; 1373 | 1374 | if (navigator.getUserMedia) { // WebRTC 1.0 standard compliant browser 1375 | _get_user_media = navigator.getUserMedia.bind(navigator); 1376 | _connect_stream_to_src = function(media_stream, media_element) { 1377 | media_element.srcObject = media_stream; 1378 | media_element.play(); 1379 | }; 1380 | } 1381 | else if (navigator.mozGetUserMedia) { // early firefox webrtc implementation 1382 | _get_user_media = navigator.mozGetUserMedia.bind(navigator); 1383 | _connect_stream_to_src = function(media_stream, media_element) { 1384 | media_element.mozSrcObject = media_stream; 1385 | media_element.play(); 1386 | }; 1387 | } 1388 | else if (navigator.webkitGetUserMedia) { // early webkit webrtc implementation 1389 | _get_user_media = navigator.webkitGetUserMedia.bind(navigator); 1390 | _connect_stream_to_src = function(media_stream, media_element) { 1391 | media_element.src = webkitURL.createObjectURL(media_stream); 1392 | media_element.play(); 1393 | }; 1394 | } 1395 | 1396 | function _clean_object(object, list_of_keys) { 1397 | var keys = {}; 1398 | for (var key in list_of_keys) { 1399 | keys[list_of_keys[key]] = 1; 1400 | } 1401 | for (var key in object) { 1402 | if (!keys[key]) { 1403 | delete object[key]; 1404 | } 1405 | } 1406 | return object; 1407 | } 1408 | 1409 | var util = { 1410 | require: _require, 1411 | get_user_media: _get_user_media, 1412 | connect_stream_to_src: _connect_stream_to_src, 1413 | clean_object: _clean_object, 1414 | }; 1415 | 1416 | window.awe = new awe(); 1417 | this_awe = window.awe; 1418 | this_awe.util = util; 1419 | 1420 | this_awe.AUTO_DETECT_DEVICE_TYPE = true; 1421 | } 1422 | })(window); 1423 | // END FILE: awe-loader.js file 1424 | -------------------------------------------------------------------------------- /lib/awe-standard-object_clicked.js: -------------------------------------------------------------------------------- 1 | (function(awe) { 2 | var mouse = {}; 3 | var projector = new THREE.Projector(); 4 | var ray = new THREE.Raycaster(); 5 | awe.plugins.add([{ 6 | id: 'object_clicked', 7 | auto_register: true, 8 | register: function(){ 9 | awe.events.add([ 10 | { 11 | id: 'click', 12 | register: function(handler) { 13 | window.addEventListener('click', handler, false); 14 | }, 15 | unregister: function(handler){ 16 | window.removeEventListener('click', handler, false); 17 | }, 18 | handler: function(e) { 19 | var click_handling = awe.settings.view("click_handling"); 20 | if (click_handling === undefined || click_handling == true) { 21 | var camera = awe.pov(); 22 | mouse.x = (e.clientX/window.innerWidth) * 2 - 1; 23 | mouse.y = -(e.clientY/window.innerHeight) * 2 + 1; 24 | var mouse_vector = new THREE.Vector3(mouse.x, mouse.y, 1); 25 | projector.unprojectVector(mouse_vector, camera); 26 | var direction = mouse_vector.sub(camera.position).normalize(); 27 | ray.set(camera.position, direction); 28 | var intersects = ray.intersectObjects(awe.projections.list({ type:'clickable' }), true); 29 | if (intersects.length) { 30 | var mesh = _get_clicked_projection(intersects[0].object); 31 | if (mesh && mesh.projection_id) { 32 | intersects[0].projection_id = mesh.projection_id; 33 | var event = new CustomEvent('object_clicked', { detail:intersects[0] }); 34 | window.dispatchEvent(event); 35 | } 36 | } 37 | } 38 | } 39 | } 40 | ]); 41 | }, 42 | unregister: function(){ 43 | awe.events.delete('click'); 44 | } 45 | }]); 46 | function _get_clicked_projection(mesh) { 47 | if (mesh.projection_id == undefined) { 48 | if (mesh.parent == undefined) { 49 | return undefined; 50 | } else { 51 | return _get_clicked_projection(mesh.parent); 52 | } 53 | } else { 54 | return mesh; 55 | } 56 | } 57 | })(window.awe); 58 | -------------------------------------------------------------------------------- /lib/awe-standard-window_resized.js: -------------------------------------------------------------------------------- 1 | (function(awe) { 2 | awe.plugins.add([{ 3 | id: 'window_resized', 4 | auto_register: true, 5 | register: function(){ 6 | awe.events.add([ 7 | { 8 | id: 'resize', 9 | device_types: { 10 | pc: 1 11 | }, 12 | register: function(handler) { 13 | window.addEventListener('resize', handler, false); 14 | }, 15 | unregister: function(handler){ 16 | window.removeEventListener('resize', handler, false); 17 | }, 18 | handler: function(e) { 19 | aspect_ratio = window.innerWidth / window.innerHeight; 20 | awe.pov().aspect = aspect_ratio; 21 | awe.pov().updateProjectionMatrix(); 22 | awe.renderer().setSize(window.innerWidth, window.innerHeight); 23 | awe.scene_needs_rendering = 1; 24 | } 25 | } 26 | ]); 27 | }, 28 | unregister: function(){ 29 | awe.events.delete('resize'); 30 | } 31 | }]); 32 | })(window.awe); 33 | -------------------------------------------------------------------------------- /lib/awe-standard.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | The MIT License 4 | 5 | Copyright (c) 2013 Rob Manson & Malgorzata Wierzbicka, http://buildAR.com. 6 | All rights reserved. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | */ 27 | 28 | (function(window) { 29 | var this_awe; 30 | var _clickable_objects = []; 31 | if (window.awe) { 32 | this_awe = window.awe; 33 | 34 | this_awe.constructor.prototype.renderers = new awe_v8(); 35 | this_awe.constructor.prototype.renderers.add = function(BODY, HEAD) { 36 | if (!BODY) { BODY = {}; } 37 | if (!HEAD) { HEAD = {}; } 38 | if (this_awe.settings.view('renderer')) { 39 | if (this_awe.capabilities.view("webgl") && this_awe.settings.view('renderer') == 'webgl') { 40 | var antialias = this_awe.settings.view('antialias') || true; 41 | var renderer = new THREE.WebGLRenderer({ antialias: antialias }); 42 | var shadows = this_awe.settings.view('shadows') || false; 43 | // spotlight is required to add shadows! 44 | // see https://github.com/mrdoob/three.js/issues/748 45 | if (shadows) { 46 | renderer.shadowMapEnabled = shadows; 47 | var shadow_map_type = this_awe.settings.view('shadow_map_type') || "pcf_soft"; 48 | if (shadow_map_type == "basic") { 49 | renderer.shadowMapType = THREE.BasicShadowMap; 50 | } else if (shadow_map_type == "pcf") { 51 | renderer.shadowMapType = THREE.PCFShadowMap; 52 | } else if (shadow_map_type == "pcf_soft") { 53 | renderer.shadowMapType = THREE.PCFSoftShadowMap; 54 | } else { 55 | throw { code: 500, message: 'shadow_map_type unsupported' }; 56 | } 57 | } 58 | } 59 | else if (this_awe.settings.view('renderer') == 'css3d' || !this_awe.capabilities.view("webgl")) { 60 | if (this_awe.capabilities.view({ id: 'css3d' })) { 61 | var renderer = new THREE.CSS3DRenderer(); 62 | } 63 | else { 64 | throw { code: 500, message: 'three.js css3d renderer creation failed' }; 65 | } 66 | } 67 | if (!renderer) { 68 | throw { code: 500, message: 'three.js renderer creation failed' }; 69 | } 70 | else { 71 | var l = this.constructor.prototype.list().length; 72 | renderer.setSize(window.outerWidth, window.outerHeight); 73 | var awe_canvas = renderer.domElement; 74 | awe_canvas.id = 'awe_canvas-'+l; 75 | if (this_awe.settings.view('canvas_style')) { 76 | try { 77 | for (var i in this_awe.settings.view('canvas_style')) { 78 | awe_canvas.style[i] = this_awe.settings.view('canvas_style')[i]; 79 | } 80 | } 81 | catch(e) { /* TODO */ }; 82 | } 83 | else { 84 | awe_canvas.style.position = 'absolute'; 85 | awe_canvas.style.top = '0px'; 86 | awe_canvas.style.left = '0px'; 87 | awe_canvas.style.width = '100%'; 88 | awe_canvas.style.height = '100%'; 89 | } 90 | if (BODY.container_id && document.getElementById(BODY.container_id)) { 91 | document.getElementById(BODY.container_id).appendChild(awe_canvas); 92 | } 93 | else if (this_awe.settings.view('container_id') && document.getElementById(this_awe.settings.view('container_id'))) { 94 | document.getElementById(this_awe.settings.view('container_id')).appendChild(awe_canvas); 95 | } 96 | else { 97 | document.body.appendChild(awe_canvas); 98 | } 99 | } 100 | } 101 | else { 102 | throw { code: 500, message: 'three.js renderer not defined' }; 103 | } 104 | BODY.value = renderer; 105 | this_awe.scene_needs_rendering = 1; 106 | return this.constructor.prototype.add.call(this, BODY, HEAD); // super 107 | } 108 | 109 | this_awe.constructor.prototype.renderer = function() { 110 | return this_awe.renderers.view({ id: 'default' }); 111 | }; 112 | 113 | this_awe.constructor.prototype.lights = new awe_v8(); 114 | this_awe.constructor.prototype.lights.add = function(BODY, HEAD) { 115 | if (!BODY) { BODY = {}; } 116 | if (!HEAD) { HEAD = {}; } 117 | var id = BODY.id || "light-"+new Date().getTime()+'-'+Math.round(Math.random()*1000); 118 | delete BODY.id; 119 | if (!BODY.color) { 120 | BODY.color = 0x404040; 121 | } 122 | var light = new THREE.AmbientLight(BODY.color); 123 | if (BODY.intensity) { 124 | light.intensity = BODY.intensity; 125 | } 126 | switch (BODY.type) { 127 | case 'area': 128 | light = new THREE.AreaLight(BODY.color); 129 | break; 130 | case 'directional': 131 | light = new THREE.DirectionalLight(BODY.color); 132 | break; 133 | case 'hemisphere': 134 | light = new THREE.HemisphereLight(BODY.color); 135 | if (BODY.ground_color) { 136 | light.groundColor = BODY.ground_color; 137 | } 138 | break; 139 | case 'point': 140 | light = new THREE.PointLight(BODY.color); 141 | if (BODY.distance) { 142 | light.distance = BODY.distance; 143 | } 144 | break; 145 | case 'spot': 146 | light = new THREE.SpotLight(BODY.color); 147 | break; 148 | } 149 | 150 | if (light.position && BODY.position && typeof(BODY.position) == 'object') { 151 | for (var p in BODY.position) { 152 | light.position[p] = BODY.position[p]; 153 | } 154 | } 155 | if (light.target && light.target.position && BODY.target && typeof(BODY.target) == 'object') { 156 | for (var p in BODY.target) { 157 | light.target.position[p] = BODY.target[p]; 158 | } 159 | } 160 | if (BODY.cast_shadow) { 161 | light.castShadow = BODY.cast_shadow; 162 | } 163 | this_awe.scene().add(light); 164 | this_awe.scene_needs_rendering = 1; 165 | return this.constructor.prototype.add.call(this, { id: id, value: light }); // super 166 | } 167 | 168 | this_awe.constructor.prototype.video_streams = new awe_v8(); 169 | this_awe.constructor.prototype.video_streams.add = function(BODY, HEAD) { 170 | if (this_awe.capabilities.view('gum')) { 171 | if (!BODY) { BODY = {}; } 172 | if (!HEAD) { HEAD = {}; } 173 | try { 174 | var self = this, 175 | video_id = 'video_stream-'+(new Date()).getTime(), 176 | width = 640, // TODO should be based on viewport width 177 | height = 480, // TODO should be based on viewport height 178 | video = document.createElement('video'); 179 | 180 | video.setAttribute('id', video_id); 181 | video.setAttribute('autoplay', true); 182 | 183 | BODY.video_element = video; 184 | var result = this.constructor.prototype.add.call(this, BODY, HEAD); // super 185 | 186 | // if many sources try to get the environemt-facing camera 187 | var go = function(video_source_id){ 188 | var options = { 189 | video: true 190 | }; 191 | if (video_source_id) { 192 | options.video = { 193 | optional: [{ facingMode: "environment" }, {sourceId: video_source_id}] 194 | }; 195 | } 196 | this_awe.util.get_user_media(options, 197 | function(stream) { 198 | video.setAttribute('width', '100%'); 199 | video.setAttribute('height', '100%'); 200 | document.body.appendChild(video); 201 | video.style.position = 'absolute'; 202 | video.style.top = '-999em'; 203 | video.style.left = '-999em'; 204 | video.style.height = '100%'; 205 | video.style.width = '100%'; 206 | 207 | BODY.stream = stream; 208 | self.constructor.prototype.update.call(this, {data: {stream: stream}, where: {id: BODY.id}}, HEAD); // super 209 | this_awe.util.connect_stream_to_src(stream, video); 210 | 211 | var event = new CustomEvent('gum_ready'); 212 | window.dispatchEvent(event); 213 | }, 214 | function(e) { 215 | var event = new CustomEvent('gum_error'); 216 | window.dispatchEvent(event); 217 | } 218 | ); 219 | } 220 | 221 | if (window.MediaStreamTrack && window.MediaStreamTrack.getSources) { 222 | MediaStreamTrack.getSources(function(source_infos) { 223 | var selected_source = null; 224 | for (var i = 0; i != source_infos.length; ++i) { 225 | var source_info = source_infos[i]; 226 | if (source_info.kind === 'video') { 227 | if (!selected_source || (source_info.facing && source_info.facing == "environment")) { 228 | selected_source = source_info.id; 229 | } 230 | } 231 | } 232 | go(selected_source); 233 | }); 234 | } 235 | else { 236 | go(); 237 | } 238 | } 239 | catch(e) { 240 | console.log(e); 241 | } 242 | return result; 243 | } 244 | else { 245 | throw { code: 500, message: 'video streams not supported by this browser' }; 246 | } 247 | } 248 | this_awe.constructor.prototype.video_streams.delete = function(BODY, HEAD) { 249 | if (this_awe.capabilities.view('gum')) { 250 | if (!BODY) { BODY = {}; } 251 | if (!HEAD) { HEAD = {}; } 252 | try { 253 | if (typeof BODY == 'string' || typeof BODY == 'number') { 254 | video_stream = this.constructor.prototype.view(BODY); 255 | BODY = { id: BODY }; 256 | } 257 | else if (BODY.id) { 258 | video_stream = this.constructor.prototype.view(BODY.id); 259 | } 260 | if (video_stream && video_stream.stream) { 261 | video_stream.stream.stop() 262 | } 263 | return this.constructor.prototype.delete.call(this, BODY, HEAD); // super 264 | } 265 | catch(e) { 266 | console.log(e); 267 | } 268 | } 269 | }; 270 | 271 | this_awe.constructor.prototype.video_stream = function() { 272 | return this_awe.video_streams.view({ id: 'default' }); 273 | }; 274 | 275 | this_awe.constructor.prototype.scenes = new awe_v8(); 276 | this_awe.constructor.prototype.scenes.add = function(BODY, HEAD) { 277 | if (!BODY) { BODY = {}; } 278 | if (!HEAD) { HEAD = {}; } 279 | var scene = new THREE.Scene(); 280 | BODY.value = scene; 281 | this_awe.scene_needs_rendering = 1; 282 | return this.constructor.prototype.add.call(this, BODY, HEAD); // super 283 | } 284 | 285 | this_awe.constructor.prototype.scene = function() { 286 | return this_awe.scenes.view({ id: 'default' }); 287 | }; 288 | this_awe.constructor.prototype.scene.stringify = function() { 289 | // TODO walk the scene and stringify to JSON 290 | } 291 | 292 | this_awe.constructor.prototype.povs = new awe_v8(); 293 | this_awe.constructor.prototype.povs.add = function(BODY, HEAD) { 294 | if (!BODY) { BODY = {}; } 295 | if (!HEAD) { HEAD = {}; } 296 | var fov = this_awe.settings.view('fov') || 65; // ~fov of ios devices - TODO: should set default based on device_type or ideally camera introspection 297 | var near = this_awe.settings.view('near') || 1; 298 | var far = this_awe.settings.view('far') || 10000; 299 | var renderer = this_awe.renderer(); 300 | var aspect_ratio = renderer.domElement.clientWidth / renderer.domElement.clientHeight; 301 | if (BODY.renderer_id) { 302 | renderer = awe.renderers.view(BODY.renderer_id) || this_awe.renderer(); 303 | if (renderer) { 304 | aspect_ratio = renderer.domElement.clientWidth / renderer.domElement.clientHeight; 305 | } 306 | } 307 | delete(BODY.renderer_id); 308 | 309 | var pov = new THREE.PerspectiveCamera( 310 | fov, 311 | aspect_ratio, 312 | near, 313 | far 314 | ); 315 | if (!this_awe.settings.view('default_camera_position')) { 316 | this_awe.settings.add({ 317 | id: 'default_camera_position', 318 | value: { x:0, y:0, z:0 }, 319 | }); 320 | } 321 | var position = _extend({x:0, y:0, z:0}, this_awe.settings.view('default_camera_position')); 322 | pov.position.set(position.x, position.y, position.z); 323 | pov.lookAt(this_awe.origin); 324 | 325 | pov.constructor.prototype.look_at_projection = function(projection_name) { 326 | var projection = this_awe.projections.view(projection_name); 327 | var origin_position = projection.mesh.parent.position; 328 | var projection_position = projection.mesh.position; 329 | var position = {}; 330 | for (var p in origin_position) { 331 | position[p] = origin_position[p]+projection_position[p]; 332 | } 333 | this.lookAt(position); 334 | _map_audio_listener_to_pov(); 335 | this_awe.scene_needs_rendering = 1; 336 | }; 337 | 338 | pov.constructor.prototype.look_at_poi = function(poi) { 339 | this.lookAt(this_awe.pois.view(poi).origin.mesh.position); 340 | _map_audio_listener_to_pov(); 341 | this_awe.scene_needs_rendering = 1; 342 | }; 343 | 344 | pov.constructor.prototype.look_at = function(position) { 345 | this.lookAt(new THREE.Vector3(position.x, position.y, position.z)); 346 | _map_audio_listener_to_pov(); 347 | this_awe.scene_needs_rendering = 1; 348 | }; 349 | 350 | BODY.value = pov; 351 | this_awe.scene().add(pov); 352 | this_awe.scene_needs_rendering = 1; 353 | 354 | return this.constructor.prototype.add.call(this, BODY, HEAD); // super 355 | } 356 | 357 | this_awe.constructor.prototype.povs.update = function(BODY, HEAD) { 358 | if (!BODY) { BODY = {}; } 359 | if (!HEAD) { HEAD = {}; } 360 | if (BODY.data && BODY.where && BODY.where.id) { 361 | var fields_updated = []; 362 | if (BODY.data.position) { 363 | fields_updated.push('position'); 364 | var position = this_awe.pov().position; 365 | for (var p in BODY.data.position) { 366 | position[p] = BODY.data.position[p]; 367 | } 368 | if (this_awe.capabilities.view("audio")) { 369 | this_awe.util.audio_context.listener.setPosition(position.x, position.y, position.z); 370 | } 371 | } 372 | if (BODY.data.scale) { fields_updated.push('scale'); } 373 | if (BODY.data.rotation) { 374 | fields_updated.push('rotation'); 375 | _map_audio_listener_to_pov(); 376 | } 377 | if (fields_updated.length) { 378 | HEAD.fields_updated = fields_updated; 379 | } 380 | if(BODY.data.animation && parseFloat(BODY.data.animation.duration) > 0) { 381 | _tween(_extend({ 382 | mesh: this_awe.projections.view(BODY.where.id).mesh, // TODO this is a bug so need to refactor tweening to support pov().position 383 | end_state: BODY.data 384 | }, BODY.data.animation)); 385 | } 386 | else { 387 | _update_mesh_io(BODY.data, this_awe.pov()); 388 | } 389 | this_awe.scene_needs_rendering = 1; 390 | } 391 | return this.constructor.prototype.update.call(this, BODY, HEAD); // super 392 | }; 393 | 394 | this_awe.constructor.prototype.pov = function() { 395 | return this_awe.povs.view({ id: 'default' }); 396 | }; 397 | 398 | this_awe.constructor.prototype.pois = new awe_v8(); 399 | this_awe.constructor.prototype.pois.add = function(BODY, HEAD) { 400 | if (!BODY) { BODY = {}; } 401 | if (!HEAD) { HEAD = {}; } 402 | var id = new Date().getTime()+'-'+Math.round(Math.random()*1000); 403 | if (!BODY.id) { 404 | BODY.id = 'poi-'+id; 405 | } 406 | var projections = []; 407 | if (BODY.projections && Array.isArray(BODY.projections)) { 408 | projections = BODY.projections; 409 | delete BODY.projections; 410 | } 411 | var origin_id = 'projection-'+id+'-origin'; 412 | var projection_io = {}; 413 | var result = this.constructor.prototype.add.call(this, BODY, HEAD); // super 414 | var poi = this_awe.pois.view(BODY.id); 415 | this_awe.projections.add({ 416 | id: origin_id, 417 | position: BODY.position || { x: 0, y: 0, z: 0 }, 418 | scale: BODY.scale || { x: 1, y: 1, z: 1 }, 419 | rotation: { x: 0, y: 0, z: 0 }, 420 | geometry: { shape: 'sphere', radius: 0.1 }, 421 | }, { poi_id: BODY.id, is_origin: true }); 422 | poi.origin = this_awe.projections.view(origin_id); 423 | if (!poi.projections) { 424 | poi.projections = []; 425 | } 426 | for (var projection in projections) { 427 | projection_io = projections[projection]; 428 | if (!projection_io.id) { 429 | projection_io.id = 'projection-'+id; 430 | } 431 | this_awe.projections.add(projection_io, { poi_id: BODY.id }); 432 | } 433 | return result; 434 | }; 435 | this_awe.constructor.prototype.pois.update = function(BODY, HEAD) { 436 | if (!BODY) { BODY = {}; } 437 | if (!HEAD) { HEAD = {}; } 438 | if (BODY.data && BODY.where && BODY.where.id) { 439 | var fields_updated = []; 440 | if (BODY.data.position) { fields_updated.push('position'); } 441 | if (BODY.data.scale) { fields_updated.push('scale'); } 442 | if (BODY.data.rotation) { fields_updated.push('rotation'); } 443 | if (fields_updated.length) { 444 | HEAD.fields_updated = fields_updated; 445 | } 446 | if(BODY.data.animation && parseFloat(BODY.data.animation.duration) > 0) { 447 | _tween(_extend({ 448 | mesh: this_awe.pois.view(BODY.where.id).origin.mesh, 449 | end_state: BODY.data 450 | }, BODY.data.animation)); 451 | } 452 | else { 453 | _update_mesh_io(BODY.data, this_awe.pois.view(BODY.where.id).origin.mesh); 454 | this_awe.scene_needs_rendering = 1; 455 | } 456 | } 457 | return this.constructor.prototype.update.call(this, BODY, HEAD); // super 458 | }; 459 | this_awe.constructor.prototype.pois.delete = function(BODY, HEAD) { 460 | if (!BODY) { BODY = {}; } 461 | if (!HEAD) { HEAD = {}; } 462 | var projection; 463 | if (typeof BODY == 'string' || typeof BODY == 'number') { 464 | poi = this_awe.pois.view(BODY); 465 | BODY = { id: BODY }; 466 | } 467 | else if (BODY.id) { 468 | poi = this_awe.pois.view(BODY.id); 469 | } 470 | if (poi.origin.mesh) { 471 | this_awe.scene().remove(poi.origin.mesh); 472 | } 473 | if (poi.projections) { 474 | for (var i in poi.projections) { 475 | this_awe.projections.delete(poi.projections[i]); 476 | } 477 | } 478 | this_awe.scene_needs_rendering = 1; 479 | return this.constructor.prototype.delete.call(this, BODY, HEAD); // super 480 | }; 481 | 482 | this_awe.constructor.prototype.projections = new awe_v8(); 483 | this_awe.constructor.prototype.projections.list = function(BODY, HEAD) { 484 | if (!BODY) { BODY = {}; } 485 | if (!HEAD) { HEAD = {}; } 486 | if (BODY.type && BODY.type === "clickable") { 487 | return _clickable_objects; 488 | } else { 489 | return this.constructor.prototype.list.call(this, BODY, HEAD); // super 490 | } 491 | } 492 | this_awe.constructor.prototype.projections.add = function(BODY, HEAD) { 493 | if (!BODY) { BODY = {}; } 494 | if (!HEAD) { HEAD = {}; } 495 | var geometry, material, mesh, parent; 496 | if (!BODY.id) { 497 | throw 'BODY.id required'; 498 | } 499 | if (this_awe.projections.view(BODY.id)) { 500 | throw 'BODY.id already exists'; 501 | } 502 | if (HEAD.parent && HEAD.parent.object_id && HEAD.parent.object_type && this_awe[HEAD.parent.object_type+'s'] && ''+this_awe[HEAD.parent.object_type+'s'] == 'awe_v8_object') { 503 | try { 504 | parent = this_awe[HEAD.parent.object_type+'s'].view(HEAD.parent.object_id); 505 | } 506 | catch(e) {} 507 | } 508 | else if (HEAD.poi_id) { 509 | parent = this_awe.pois.view(HEAD.poi_id); 510 | } 511 | if (!parent) { 512 | throw 'HEAD.poi_id or HEAD.parent required'; 513 | } 514 | if (!BODY.material) { 515 | BODY.material = {}; 516 | } 517 | if (!BODY.texture) { 518 | BODY.texture = {}; 519 | } 520 | if (BODY.sound) { 521 | if (this_awe.capabilities.view("audio")) { 522 | if (BODY.sound.path == undefined) { 523 | throw "sound path required"; 524 | } 525 | BODY.sound.source = this_awe.util.audio_context.createBufferSource(); 526 | BODY.sound.panner = this_awe.util.audio_context.createPanner(); 527 | BODY.sound.source.connect(BODY.sound.panner); 528 | BODY.sound.panner.connect(this_awe.util.audio_context.destination); 529 | BODY.sound.panner.refDistance = 100; 530 | var position = { x:0, y:0, z:0 }; 531 | if (BODY.position !== undefined) { 532 | for (var p in BODY.position) { 533 | position[p] = BODY.position[p]; 534 | } 535 | } 536 | BODY.sound.panner.setPosition(position.x, position.y, position.z); 537 | this_awe.sounds.add(BODY.sound); 538 | } 539 | } 540 | if (BODY.geometry) { 541 | if (BODY.geometry.shape) { 542 | var shape = _validate_shape(BODY.geometry); 543 | switch(BODY.geometry.shape) { 544 | case 'cube': 545 | geometry = new THREE.CubeGeometry(shape.x, shape.y, shape.z); 546 | break; 547 | case 'sphere': 548 | geometry = new THREE.SphereGeometry(shape.radius, shape.widthSegments, shape.heightSegments, shape.phiStart, shape.phiLength, shape.thetaStart, shape.thetaLength); 549 | break; 550 | case 'cylinder': 551 | geometry = new THREE.CylinderGeometry(shape.radiusTop, shape.radiusBottom, shape.height, shape.radiusSegments, shape.heightSegments, shape.openEnded); 552 | break; 553 | case 'lathe': 554 | geometry = new THREE.LatheGeometry(shape.points, shape.segments, shape.phiStart, shape.phiLength); 555 | break; 556 | case 'octahedron': 557 | geometry = new THREE.OctahedronGeometry(shape.radius, shape.detail); 558 | break; 559 | case 'plane': 560 | geometry = new THREE.PlaneGeometry(shape.width, shape.height, shape.widthSegments, shape.heightSegments) 561 | break; 562 | case 'tetrahedron': 563 | geometry = new THREE.TetrahedronGeometry(shape.radius, shape.detail); 564 | break; 565 | case 'text': 566 | geometry = new THREE.TextGeometry(shape.text, shape.parameters) 567 | break; 568 | case 'torus': 569 | geometry = new THREE.TorusGeometry(shape.radius, shape.tube, shape.radialSegments, shape.tubularSegments, shape.arc); 570 | break; 571 | case 'torusknot': 572 | geometry = new THREE.TorusKnotGeometry(shape.radius, shape.tube, shape.radialSegments, shape.tubularSegments, shape.p, shape.q, shape.heightScale); 573 | break; 574 | case 'tube': 575 | geometry = new THREE.TubeGeometry(shape.path, shape.segments, shape.radius, shape.radiusSegments, shape.closed, shape.debug) 576 | break; 577 | default: 578 | geometry = new THREE.CubeGeometry(10,10,10); 579 | } 580 | if (geometry) { 581 | var texture, material; 582 | if (BODY.texture.path) { 583 | if (BODY.geometry.x) { 584 | BODY.texture.width = BODY.geometry.x; 585 | } 586 | if (BODY.geometry.y) { 587 | BODY.texture.height = BODY.geometry.y; 588 | } 589 | var texture_id = this_awe.textures.add(BODY.texture); 590 | if (BODY.texture.color) { 591 | BODY.material.color = BODY.texture.color; 592 | } 593 | BODY.material.map = this_awe.textures.view(texture_id); 594 | } 595 | var material_id = this_awe.materials.add(BODY.material); 596 | var material = this_awe.materials.view(material_id); 597 | mesh = new THREE.Mesh(geometry, material); 598 | this_awe.scene_needs_rendering = 1; 599 | } 600 | } 601 | else if (BODY.geometry.path) { 602 | var loader; 603 | if (BODY.material.path) { 604 | loader = new THREE.OBJMTLLoader(); 605 | loader.load(BODY.geometry.path, BODY.material.path, function(mesh) { 606 | BODY.mesh = _update_mesh_io(BODY, mesh, true); 607 | if (parent.origin) { 608 | parent.origin.mesh.add(BODY.mesh); 609 | } 610 | else { 611 | parent.add(BODY.mesh); 612 | } 613 | var _clickable_id = _clickable_objects.length; 614 | BODY.mesh.projection_id = BODY.id; 615 | _clickable_objects.push(BODY.mesh); 616 | this_awe.projections.update({ data:{ _clickable_object_id:_clickable_id }, where:{ id:BODY.id } }); 617 | this_awe.scene_needs_rendering = 1; 618 | this_awe.scene_needs_rendering = 1; 619 | var event = new CustomEvent('projection_loaded', { detail: BODY.id }); 620 | window.dispatchEvent(event); 621 | }); 622 | } 623 | else { 624 | loader = new THREE.OBJLoader(); 625 | var texture; 626 | if (BODY.texture.path) { 627 | if (BODY.geometry.x) { 628 | BODY.texture.width = BODY.geometry.x; 629 | } 630 | if (BODY.geometry.y) { 631 | BODY.texture.height = BODY.geometry.y; 632 | } 633 | var texture_id = this_awe.textures.add(BODY.texture); 634 | texture = this_awe.textures.view(texture_id); 635 | } 636 | else { 637 | var texture_id = this_awe.textures.add(); 638 | texture = this_awe.textures.view(texture_id); 639 | } 640 | loader.load(BODY.geometry.path, function (mesh) { 641 | mesh.traverse(function (child) { 642 | if ( child instanceof THREE.Mesh ) { 643 | child.material.map = texture; 644 | } 645 | }); 646 | BODY.mesh = _update_mesh_io(BODY, mesh, true); 647 | if (parent.origin) { 648 | parent.origin.mesh.add(BODY.mesh); 649 | } 650 | else { 651 | parent.add(BODY.mesh); 652 | } 653 | 654 | var _clickable_id = _clickable_objects.length; 655 | BODY.mesh.projection_id = BODY.id; 656 | _clickable_objects.push(BODY.mesh); 657 | this_awe.projections.update({ data:{ _clickable_object_id:_clickable_id }, where:{ id:BODY.id } }); 658 | this_awe.scene_needs_rendering = 1; 659 | var event = new CustomEvent('projection_loaded', { detail: BODY.id }); 660 | window.dispatchEvent(event); 661 | }); 662 | } 663 | return this.constructor.prototype.add.call(this, BODY, HEAD); // super 664 | } 665 | else { 666 | geometry = new THREE.CubeGeometry(10,10,10); 667 | var material_id = this_awe.materials.add(BODY.material); 668 | var material = this_awe.materials.view(material_id); 669 | mesh = new THREE.Mesh(geometry, material); 670 | this_awe.scene_needs_rendering = 1; 671 | } 672 | } 673 | BODY.mesh = _update_mesh_io(BODY, mesh, true); 674 | if (BODY.scale) { 675 | for (var p in BODY.scale) { 676 | BODY.mesh.scale[p] = BODY.scale[p]; 677 | } 678 | } 679 | var result = this.constructor.prototype.add.call(this, BODY, HEAD); // super 680 | var projection = this_awe.projections.view(BODY.id); 681 | if (HEAD.is_origin) { 682 | this_awe.scene().add(BODY.mesh); 683 | } 684 | else { 685 | var _clickable_id = _clickable_objects.length; 686 | BODY.mesh.projection_id = result.id; 687 | _clickable_objects.push(BODY.mesh); 688 | this_awe.projections.update({ data:{ _clickable_object_id:_clickable_id }, where:{ id:result.id } }); 689 | 690 | if (parent.origin) { 691 | parent.origin.mesh.add(BODY.mesh); 692 | } 693 | else { 694 | parent.add(BODY.mesh); 695 | } 696 | } 697 | if (!parent.projections) { 698 | parent.projections = []; 699 | } 700 | parent.projections.push(projection.id); 701 | var event = new CustomEvent('projection_loaded', {detail: BODY.id}); 702 | window.dispatchEvent(event); 703 | return result; 704 | }; 705 | this_awe.constructor.prototype.projections.view = function(BODY, HEAD) { 706 | if (!BODY) { BODY = {}; } 707 | if (!HEAD) { HEAD = {}; } 708 | var projection = this.constructor.prototype.view.call(this, BODY, HEAD); // super 709 | if (projection) { 710 | projection.position = { 711 | x: projection.mesh.position.x, 712 | y: projection.mesh.position.y, 713 | z: projection.mesh.position.z, 714 | }; 715 | projection.scale = { 716 | x: projection.mesh.scale.x, 717 | y: projection.mesh.scale.y, 718 | z: projection.mesh.scale.z, 719 | }; 720 | projection.rotation = { 721 | x: THREE.Math.radToDeg(projection.mesh.rotation.x), 722 | y: THREE.Math.radToDeg(projection.mesh.rotation.y), 723 | z: THREE.Math.radToDeg(projection.mesh.rotation.z), 724 | }; 725 | } 726 | return projection; 727 | }; 728 | this_awe.constructor.prototype.projections.update = function(BODY, HEAD) { 729 | if (!BODY) { BODY = {}; } 730 | if (!HEAD) { HEAD = {}; } 731 | if (BODY.data && BODY.where && BODY.where.id) { 732 | var fields_updated = []; 733 | if (BODY.data.position) { fields_updated.push('position'); } 734 | if (BODY.data.scale) { fields_updated.push('scale'); } 735 | if (BODY.data.rotation) { fields_updated.push('rotation'); } 736 | if (fields_updated.length) { 737 | HEAD.fields_updated = fields_updated; 738 | } 739 | if(BODY.data.animation && parseFloat(BODY.data.animation.duration) > 0) { 740 | _tween(_extend({ 741 | mesh: this_awe.projections.view(BODY.where.id).mesh, 742 | end_state: BODY.data 743 | }, BODY.data.animation)); 744 | } 745 | else { 746 | BODY.mesh = _update_mesh_io(BODY.data, this_awe.projections.view(BODY.where.id).mesh); 747 | } 748 | } 749 | return this.constructor.prototype.update.call(this, BODY, HEAD); // super 750 | }; 751 | this_awe.constructor.prototype.projections.delete = function(BODY, HEAD) { 752 | if (!BODY) { BODY = {}; } 753 | if (!HEAD) { HEAD = {}; } 754 | var projection; 755 | if (typeof BODY == 'string' || typeof BODY == 'number') { 756 | projection = this_awe.projections.view(BODY); 757 | BODY = { id: BODY }; 758 | } 759 | else if (BODY.id) { 760 | projection = this_awe.projections.view(BODY.id); 761 | } 762 | if (projection.mesh) { 763 | this_awe.scene().remove(projection.mesh); 764 | _clickable_objects.splice(projection._clickable_object_id, 1); 765 | this_awe.scene_needs_rendering = 1; 766 | } 767 | return this.constructor.prototype.delete.call(this, BODY, HEAD); // super 768 | }; 769 | 770 | this_awe.constructor.prototype.textures = new awe_v8(); 771 | this_awe.constructor.prototype.textures.add = function(BODY, HEAD) { 772 | if (!BODY) { BODY = {}; } 773 | if (!HEAD) { HEAD = {}; } 774 | var id = "texture-"+new Date().getTime()+'-'+Math.round(Math.random()*1000); 775 | var texture = new THREE.Texture(); 776 | if (BODY.path) { 777 | var path = undefined; 778 | var v = document.createElement('video'); 779 | if (Array.isArray(BODY.path)) { 780 | for (var p in BODY.path) { 781 | var tmp_path = BODY.path[p]; 782 | var suffix = tmp_path.match(/\.(webm|mp4|ogg|ogv)/i); 783 | if (suffix) { 784 | if (suffix[1].toLowerCase() == "ogv") { 785 | suffix[1] = "ogg"; 786 | } 787 | var can_play = v.canPlayType("video/"+suffix[1].toLowerCase()); 788 | if (can_play == "probably" || can_play == "maybe") { 789 | path = BODY.path[p]; 790 | break; 791 | } 792 | } 793 | } 794 | } else if (BODY.path.match(/\.(webm|mp4|ogg|ogv)/i)) { 795 | path = BODY.path; 796 | } 797 | if (path) { 798 | if (BODY.width) { 799 | v.width = BODY.width; 800 | } 801 | else { 802 | v.width = 320; 803 | } 804 | if (BODY.height) { 805 | v.height = BODY.height; 806 | } 807 | else { 808 | v.height = 240; 809 | } 810 | v.src = path; 811 | var autoplay = true; 812 | if (BODY.autoplay !== undefined) { 813 | autoplay = BODY.autoplay; 814 | } 815 | v.autoplay = autoplay; 816 | v.load(); 817 | if (autoplay) { 818 | v.play(); 819 | } 820 | if (BODY.loop !== undefined) { 821 | v.loop = BODY.loop; 822 | } 823 | if (BODY.muted !== undefined) { 824 | v.muted = BODY.muted; 825 | } 826 | 827 | var c = document.createElement('canvas'); 828 | c.width = v.width; 829 | c.height = v.height; 830 | 831 | var cc = c.getContext('2d'); 832 | texture = new THREE.Texture(c); 833 | texture.video = v; 834 | texture.cc = cc; 835 | } 836 | else if (BODY.path.match(/^camerastream$/i)) { 837 | var v = this_awe.video_stream().video_element; 838 | if (BODY.width) { 839 | v.width = BODY.width; 840 | } 841 | else { 842 | v.width = 320; 843 | } 844 | if (BODY.height) { 845 | v.height = BODY.height; 846 | } 847 | else { 848 | v.height = 240; 849 | } 850 | v.autoplay = true; 851 | v.play(); 852 | this_awe.util.connect_stream_to_src(this_awe.video_stream().stream, v); 853 | 854 | var c = document.createElement('canvas'); 855 | c.width = v.width; 856 | c.height = v.height; 857 | 858 | var cc = c.getContext('2d'); 859 | texture = new THREE.Texture(c); 860 | texture.video = v; 861 | texture.cc = cc; 862 | } 863 | else { 864 | texture = THREE.ImageUtils.loadTexture(BODY.path, undefined, function() { 865 | this_awe.scene_needs_rendering = 1; 866 | }); 867 | } 868 | return this.constructor.prototype.add.call(this, { id: id, value: texture }); // super 869 | } 870 | else { 871 | throw { code: 500, message: 'texture.path required' }; 872 | } 873 | } 874 | 875 | this_awe.constructor.prototype.materials = new awe_v8(); 876 | this_awe.constructor.prototype.materials.add = function(BODY, HEAD) { 877 | if (!BODY) { BODY = {}; } 878 | if (!HEAD) { HEAD = {}; } 879 | var id = BODY.id || "material-"+new Date().getTime()+'-'+Math.round(Math.random()*1000); 880 | delete BODY.id; 881 | var type = BODY.type || 'basic'; 882 | delete BODY.type; 883 | if (!BODY.wireframe) { 884 | BODY.wireframe = false; 885 | } 886 | if (!BODY.color) { 887 | BODY.color = 0x404040; 888 | } 889 | var side = THREE.DoubleSide; 890 | if (BODY.side) { 891 | if (BODY.side == "front") { 892 | side = THREE.FrontSide; 893 | } 894 | else if (BODY.side == "back") { 895 | side = THREE.BackSide; 896 | } 897 | delete BODY.side; 898 | } 899 | if (!BODY.overdraw) { 900 | BODY.overdraw = true; 901 | } 902 | var material = new THREE.MeshBasicMaterial(BODY); 903 | switch(type) { 904 | case 'phong': 905 | if (!BODY.shading) { 906 | BODY.shading = THREE.SmoothShading; 907 | } 908 | material = new THREE.MeshPhongMaterial(BODY); 909 | break; 910 | case 'lambert': 911 | material = new THREE.MeshLambertMaterial(BODY); 912 | break; 913 | case 'shader': 914 | material = new THREE.ShaderMaterial(BODY); 915 | break; 916 | case 'sprite': 917 | material = new THREE.SpriteMaterial(BODY); 918 | break; 919 | case 'sprite_canvas': 920 | material = new THREE.SpriteCanvasMaterial(BODY); 921 | break; 922 | } 923 | material.side = side; 924 | return this.constructor.prototype.add.call(this, { id: id, value: material }); // super 925 | } 926 | 927 | this_awe.constructor.prototype.sounds = new awe_v8(); 928 | this_awe.constructor.prototype.sounds.add = function(BODY, HEAD) { 929 | if (this_awe.capabilities.view("audio")) { 930 | if (!BODY) { BODY = {}; } 931 | if (!HEAD) { HEAD = {}; } 932 | var id = BODY.id || "sound-"+new Date().getTime()+'-'+Math.round(Math.random()*1000); 933 | delete BODY.id; 934 | if (BODY.autoplay == undefined) { 935 | BODY.autoplay = true; 936 | } 937 | _load_sound(BODY); 938 | return this.constructor.prototype.add.call(this, { id: id, value: BODY }); // super 939 | } 940 | } 941 | 942 | this_awe.constructor.prototype.tween_functions = new awe_v8(); 943 | this_awe.constructor.prototype.tween_functions.add({ 944 | id: 'linear', 945 | value: function(io) { 946 | return io.step/io.steps_total; 947 | } 948 | }); 949 | 950 | this_awe.constructor.prototype.setup_scene = function(io) { 951 | this.origin = new THREE.Vector3(0,0,0); 952 | this_awe.renderers.add({ id: 'default' }); 953 | this_awe.scenes.add({ id: 'default' }); 954 | this_awe.povs.add({ id: 'default' }); 955 | if (this_awe.settings.view('start_video_stream')) { 956 | this_awe.setup_stream(); 957 | } 958 | var lights = this_awe.lights.list(); 959 | if (!lights.length) { 960 | var default_lights = this_awe.settings.view('default_lights'); 961 | if (default_lights && Array.isArray(default_lights)) { 962 | for (var i=0,l=default_lights.length;i min_ts && count <= max_ts) { 1557 | step = j; 1558 | transform.add(tr); 1559 | } 1560 | } 1561 | transform_data.advancement = max_ts; 1562 | if (!isNaN(step) && step != transform_data.current_step) { 1563 | try { 1564 | var current_transform = _get_mesh_state(mesh); 1565 | var n = transform.data(); 1566 | _update_mesh_io(_extend({}, transform_data.steps[step].transform), mesh); 1567 | this_awe.scene_needs_rendering = 1; 1568 | transform_data.current_step = step; 1569 | // step callback 1570 | if (transform_data.step_callback && typeof(transform_data.step_callback) == 'function') { 1571 | transform_data.step_callback({ 1572 | mesh: mesh, 1573 | step: step, 1574 | steps_total: steps_total 1575 | }); 1576 | } 1577 | } 1578 | catch(e) { 1579 | this_awe.error_handler(e); 1580 | } 1581 | } 1582 | if (step && step == transform_data.steps.length-1) { 1583 | if (!isNaN(transform_data.repeat) && transform_data.repeat > 1) { 1584 | transform_data.repeat--; 1585 | var start_state = _extend({}, transform_data.start_state); 1586 | _update_mesh_io(start_state, mesh); 1587 | transform_data.advancement = 0; 1588 | delete(transform_data.current_step); 1589 | if (transform_data.end_callback && typeof(transform_data.end_callback) == 'function') { 1590 | transform_data.end_callback({ 1591 | mesh: mesh 1592 | }); 1593 | } 1594 | } 1595 | else if (!parseInt(transform_data.persist, 10)) { 1596 | var start_state = _extend({}, transform_data.start_state); 1597 | _update_mesh_io(start_state, mesh); 1598 | _finish_tween(mesh.id); 1599 | } 1600 | else { 1601 | _update_mesh_io(_extend({}, transform_data.end_state), mesh); 1602 | _finish_tween(mesh_id); 1603 | } 1604 | } 1605 | } 1606 | } 1607 | 1608 | this_awe.render(); 1609 | 1610 | requestAnimationFrame(function() { 1611 | _tick(); 1612 | var event = new CustomEvent('tick'); 1613 | window.dispatchEvent(event); 1614 | }); 1615 | } 1616 | catch(e) { 1617 | this_awe.error_handler(e); 1618 | } 1619 | } 1620 | 1621 | this_awe.util.extend = _extend; 1622 | } else { 1623 | throw "awe does not exist"; 1624 | } 1625 | })(window); 1626 | -------------------------------------------------------------------------------- /lib/awe-v8.js: -------------------------------------------------------------------------------- 1 | // BEGIN FILE: awe_v8.js 2 | /* 3 | 4 | The MIT License 5 | 6 | Copyright (c) 2013 Rob Manson, http://buildAR.com. All rights reserved. 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 | THE SOFTWARE. 25 | 26 | 27 | What is awe_v8.js? 28 | ------------------ 29 | 30 | It's a simple datastore template that makes it easy to store, manage and 31 | extend collections of javascript object in a consistent way. 32 | 33 | Trust me, it's funkier than that sounds! 8) 34 | 35 | 36 | Why is it called awe_v8? 37 | ----------------------- 38 | 39 | Each datastore by default is designed to support a standard set of "8 verbs". 40 | 41 | - search 42 | - list 43 | - add 44 | - view 45 | - edit 46 | - update 47 | - delete 48 | - report 49 | 50 | Through the magical process of simplification this translates in a subset of 51 | "6 implemented methods". 52 | 53 | - list 54 | - add 55 | - view 56 | - update 57 | - delete 58 | - report 59 | 60 | search and edit are simply UIs that drive one of these 6 methods. 61 | 62 | e.g. edit -> update or search -> list 63 | 64 | 65 | How are errors handled? 66 | ----------------------- 67 | 68 | In simple js mode a method call either returns undefined for an error or 69 | either an object or an array of 0 or more objects. 70 | 71 | 72 | How do you use awe_v8? 73 | ---------------------- 74 | 75 | // create a awe_v8 datastore 76 | var my_datastore = new awe_v8(); 77 | 78 | // add one object to your datastore 79 | console.log("add an object (return new id)"); 80 | my_datastore.add({ 81 | id: "test", 82 | some_data: "blah" 83 | }); 84 | 85 | // add multiple objects to your datastore in one go 86 | console.log("add several objects (return new ids)"); 87 | my_datastore.add([ 88 | { 89 | id: "test2", 90 | some_data: "blahdeblah" 91 | }, 92 | { 93 | new_param: 99, 94 | id: "test3", 95 | some_data: "hrmok" 96 | }, 97 | ]); 98 | 99 | // list all objects currently in your datastore 100 | console.log("list all objects (return all objects)"); 101 | my_datastore.list(); 102 | 103 | // list all objects in SOAPjr format (see separate documentation for SOAPjr API) 104 | console.log("list all objects (return all objects in SOAPjr)"); 105 | my_datastore.list({}, { output_format:"soapjr" }); 106 | 107 | // view one object 108 | console.log("view an object (return one object)"); 109 | my_datastore.view("test"); // simple 110 | my_datastore.view({ id: "test" }); // clear 111 | my_datastore.view({ id: "test" }, { output_format:"js" }); // explicit 112 | 113 | // update one object 114 | console.log("update an object (return updated fields)"); 115 | my_datastore.update({ 116 | data: { 117 | new_param: 34, 118 | some_data: "new_data", 119 | }, 120 | where: { 121 | id: "test", 122 | } 123 | }); 124 | 125 | // search for objects that fuzzy match a pattern 126 | console.log("list fuzzy matches (return roughly matching objects)"); 127 | my_datastore.list({ id: "test" }, { limit: 10 }); 128 | 129 | // search for objects that exactly match a pattern 130 | console.log("list exact matches (return exactly matching objects)"); 131 | my_datastore.list({ exact: { id: "test2" } }); 132 | 133 | // delete one object 134 | console.log("delete an object (return deleted ids)"); 135 | my_datastore.delete({ id: "test2" }); 136 | 137 | // report metadata about this datastore 138 | console.log("report overview info (return a summary)"); 139 | my_datastore.report(); 140 | 141 | */ 142 | 143 | // override this to customise how you want your awe_v8 template to behave 144 | var V8_CONFIG = { 145 | default_id_field: "id", 146 | default_output_format: "js", 147 | debug: false, 148 | }; 149 | 150 | // below here is the template awe_v8 object implementation 151 | function awe_v8() { 152 | var ID_FIELD = "id"; 153 | try { 154 | if (V8_CONFIG.default_id_field !== undefined) { 155 | ID_FIELD = V8_CONFIG.default_id_field; 156 | } 157 | } 158 | catch(e) { /* TODO */ } 159 | var OUTPUT_FORMAT = "js"; 160 | try { 161 | if (V8_CONFIG.default_output_format !== undefined) { 162 | OUTPUT_FORMAT = V8_CONFIG.default_output_format; 163 | } 164 | } 165 | catch(e) { /* TODO */ } 166 | var awe_v8_object = new awe_v8_template(); 167 | var _return = function(return_flag, return_values, errors, output_format) { 168 | if (output_format === undefined) { 169 | output_format = OUTPUT_FORMAT; 170 | } 171 | if (output_format == "soapjr") { 172 | var return_object = { 173 | HEAD: {}, 174 | BODY: [] 175 | }; 176 | if (return_flag) { 177 | if (typeof(return_values) === "object" && return_values.length !== undefined) { 178 | return_object.BODY = return_values; 179 | } 180 | else { 181 | return_object.BODY = [return_values]; 182 | } 183 | return_object.HEAD.result = 1; 184 | return return_object; 185 | } 186 | else { 187 | return_object.HEAD.result = 0; 188 | if (errors !== undefined && Object.keys(errors).length) { 189 | for (var i in errors) { 190 | if (Object.keys(errors[i]).length) { 191 | 192 | return_object.HEAD.errors[i] = errors[i]; 193 | } 194 | } 195 | } 196 | return return_object; 197 | } 198 | } 199 | else { 200 | if (return_flag) { 201 | return return_values; 202 | } 203 | else { 204 | return undefined; 205 | } 206 | } 207 | }; 208 | function _add(data, io, errors) { 209 | if (io == undefined) { 210 | throw "io undefined"; 211 | } 212 | if (data[io[ID_FIELD]] !== undefined) { 213 | errors.BODY[ID_FIELD] = { 214 | code: 500, 215 | message: ID_FIELD+" already exists ("+io[ID_FIELD]+")", 216 | }; 217 | throw ID_FIELD+" already exists ("+io[ID_FIELD]+")"; 218 | } 219 | else { 220 | data[io[ID_FIELD]] = io; 221 | return io[ID_FIELD]; 222 | } 223 | }; 224 | function awe_v8_template() { 225 | var data = {}; 226 | if (V8_CONFIG.debug !== undefined) { 227 | this.debug = V8_CONFIG.debug; 228 | } 229 | else { 230 | this.debug = false; 231 | } 232 | if (V8_CONFIG.debug_verbose !== undefined) { 233 | this.debug_verbose = V8_CONFIG.debug; 234 | } 235 | else { 236 | this.debug_verbose = 0; 237 | } 238 | this.get_data = function(){ 239 | return data; 240 | } 241 | 242 | this.constructor.prototype.list = function(BODY, HEAD){ 243 | if (BODY === undefined) { BODY = {}; } 244 | if (HEAD === undefined) { HEAD = {}; } 245 | var return_values = []; 246 | var return_flag = true; 247 | var errors = { HEAD:{}, BODY:{} }; 248 | var output_format = undefined; 249 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 250 | output_format = HEAD.output_format; 251 | } 252 | try { 253 | var page = 0; 254 | var limit = undefined; 255 | var order_by = ID_FIELD; 256 | var order_type = "alphabetic"; 257 | var order_direction = "asc"; 258 | var data_array = []; 259 | for (var i in data) { 260 | data_array.push(data[i]); 261 | } 262 | if (HEAD !== undefined) { 263 | if (HEAD.page !== undefined && typeof(HEAD.page) == "number") { 264 | page = HEAD.page-1; 265 | } 266 | if (HEAD.limit !== undefined && typeof(HEAD.limit) == "number") { 267 | limit = HEAD.limit; 268 | } 269 | if (HEAD.order_by !== undefined && typeof(HEAD.order_by) == "string") { 270 | order_by = HEAD.order_by; 271 | } 272 | if (HEAD.order_type !== undefined && HEAD.order_type == "numeric") { 273 | order_type = "numeric"; 274 | } 275 | if (HEAD.order_direction !== undefined && HEAD.order_direction == "desc") { 276 | order_direction = "desc"; 277 | } 278 | } 279 | var sort_function = function(A, B) { 280 | var a = undefined; 281 | var b = undefined; 282 | if (order_type == "alphabetic") { 283 | if (A[order_by] !== undefined && typeof(A[order_by]) == "string") { 284 | a = A[order_by].toLowerCase(); 285 | } 286 | if (B[order_by] !== undefined && typeof(B[order_by]) == "string") { 287 | b = B[order_by].toLowerCase(); 288 | } 289 | if (order_direction == "asc") { 290 | if (a == undefined && b !== undefined) { 291 | return 0; 292 | } 293 | else if (a == undefined) { 294 | return 1; 295 | } 296 | else if (b == undefined) { 297 | return -1 298 | } 299 | else { 300 | if (a < b) { 301 | return -1; 302 | } 303 | else if (a > b) { 304 | return 1; 305 | } 306 | else { 307 | return 0; 308 | } 309 | } 310 | } 311 | else { 312 | if (a == undefined && b !== undefined) { 313 | return 0; 314 | } 315 | else if (a == undefined) { 316 | return -1; 317 | } 318 | else if (b == undefined) { 319 | return 1 320 | } 321 | else { 322 | if (a > b) { 323 | return -1; 324 | } 325 | else if (a < b) { 326 | return 1; 327 | } 328 | else { 329 | return 0; 330 | } 331 | } 332 | } 333 | } 334 | else { 335 | if (A[order_by] !== undefined && typeof(A[order_by]) == "number") { 336 | a = A[order_by]; 337 | } 338 | if (B[order_by] !== undefined && typeof(B[order_by]) == "number") { 339 | b = B[order_by]; 340 | } 341 | if (order_direction == "asc") { 342 | if (a == undefined && b == undefined) { 343 | return 0 344 | } 345 | else if (a == undefined) { 346 | return 1; 347 | } 348 | else if (b == undefined) { 349 | return -1; 350 | } 351 | else { 352 | return a-b; 353 | } 354 | } 355 | else { 356 | if (a == undefined && b == undefined) { 357 | return 0 358 | } 359 | else if (a == undefined) { 360 | return 1; 361 | } 362 | else if (b == undefined) { 363 | return -1; 364 | } 365 | else { 366 | return b-a; 367 | } 368 | } 369 | } 370 | }; 371 | for (var i in data_array) { 372 | if (BODY == undefined || BODY.length == 0) { 373 | return_values.push(data_array[i]); 374 | } 375 | else if (BODY !== undefined && BODY.exact !== undefined) { 376 | var a = undefined; 377 | var b = undefined; 378 | var match = 0; 379 | for (var m in BODY.exact) { 380 | a = data_array[i][m]; 381 | b = BODY.exact[m]; 382 | if (a == b) { 383 | match = 1; 384 | } 385 | } 386 | if (match) { 387 | return_values.push(data_array[i]); 388 | } 389 | } 390 | else { 391 | var match = 1; 392 | for (var m in BODY) { 393 | if (data_array[i][m] !== undefined && typeof(data_array[i][m]) == "string") { 394 | a = data_array[i][m].toLowerCase(); 395 | } 396 | if (BODY[m] !== undefined && typeof(BODY[m]) == "string") { 397 | b = BODY[m].toLowerCase(); 398 | } 399 | if (a !== undefined && b !== undefined) { 400 | var r = a.match(b); 401 | if (r == undefined) { 402 | match = 0; 403 | } 404 | } 405 | else { 406 | match = 0; 407 | } 408 | } 409 | if (match) { 410 | return_values.push(data_array[i]); 411 | } 412 | } 413 | } 414 | return_values = return_values.sort(sort_function); 415 | if (limit !== undefined) { 416 | var start = limit*page; 417 | var end = limit*(page+1); 418 | return_values = return_values.slice(start,end); 419 | } 420 | } 421 | catch(e) { 422 | this.error_handler(e); 423 | return_flag = false; 424 | } 425 | /* NOTE: commented out to make it more forgiving - maybe move to config 426 | if (!(return_values.length > 0)) { 427 | return_flag = false; 428 | errors.BODY.io = { 429 | code: 500, 430 | message: "object does not exist", 431 | }; 432 | } 433 | */ 434 | return _return(return_flag, return_values, errors, output_format); 435 | }; 436 | 437 | this.constructor.prototype.add = function(BODY, HEAD) { 438 | if (BODY == undefined) { BODY = {}; } 439 | if (HEAD == undefined) { HEAD = {}; } 440 | var return_values = []; 441 | var return_flag = true; 442 | var errors = { HEAD:{}, BODY:{} }; 443 | var output_format = undefined; 444 | if (HEAD !== undefined) { 445 | if (HEAD.output_format !== undefined) { 446 | output_format = HEAD.output_format; 447 | } 448 | if (HEAD.replace_all !== undefined && HEAD.replace_all) { 449 | data = {}; 450 | } 451 | } 452 | try { 453 | /* NOTE: commented out to make it more forgiving - maybe move to config 454 | if (BODY == undefined) { 455 | errors.BODY = { 456 | code: 500, 457 | message: "BODY object invalid (undefined)", 458 | }; 459 | throw "BODY object invalid (undefined)"; 460 | } 461 | */ 462 | if (typeof(BODY) == "string") { 463 | errors.BODY = { 464 | code: 500, 465 | message: "BODY object invalid (string)", 466 | }; 467 | throw "BODY object invalid (string)"; 468 | } 469 | if (typeof(BODY) == "number") { 470 | errors.BODY = { 471 | code: 500, 472 | message: "BODY object invalid (number)", 473 | }; 474 | throw "BODY object invalid (number)"; 475 | } 476 | if ((Array.isArray && Array.isArray(BODY)) || (BODY[ID_FIELD] == undefined && BODY.length > 0)) { 477 | for (var i in BODY) { 478 | var a = _add(data, BODY[i], errors); 479 | if (a) { 480 | return_values.push(a); // if this fails will it still push something? yes, undefined 481 | } 482 | else { 483 | throw "add failed"; 484 | } 485 | } 486 | } 487 | else { 488 | var a = _add(data, BODY, errors) 489 | if (a) { 490 | return_values.push(a); // if this fails will it still push something? yes, undefined 491 | } 492 | else { 493 | throw "add failed"; 494 | } 495 | } 496 | } 497 | catch(e) { 498 | this.error_handler(e); 499 | return_flag = false; 500 | } 501 | if (return_values.length == 0) { 502 | return _return(return_flag, {}, errors, output_format); 503 | } 504 | else if (return_values.length == 1) { 505 | return _return(return_flag, { id: return_values[0] }, errors, output_format); 506 | } 507 | else { 508 | return _return(return_flag, { id: return_values }, errors, output_format); 509 | } 510 | }; 511 | 512 | this.constructor.prototype.view = function(BODY, HEAD) { 513 | if (BODY == undefined) { BODY = {}; } 514 | if (HEAD == undefined) { HEAD = {}; } 515 | var return_value = undefined; 516 | var return_flag = true; 517 | var errors = { HEAD:{}, BODY:{} }; 518 | var output_format = undefined; 519 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 520 | output_format = HEAD.output_format; 521 | } 522 | try { 523 | if (typeof(BODY) == "string" && data[BODY] !== undefined) { 524 | return data[BODY].hasOwnProperty('value') ? data[BODY].value : data[BODY]; 525 | } 526 | else if (BODY !== undefined && BODY.id !== undefined && data[BODY.id]) { 527 | return_value = data[BODY.id].hasOwnProperty('value') ? data[BODY.id].value : data[BODY.id]; 528 | } 529 | else { 530 | errors.BODY.id = { 531 | code: 500, 532 | message: BODY.id+" does not exist", 533 | }; 534 | throw BODY.id+" does not exist"; 535 | } 536 | } 537 | catch(e) { 538 | this.error_handler(e); 539 | return_flag = false; 540 | } 541 | return _return(return_flag, return_value, errors); 542 | }; 543 | 544 | this.constructor.prototype.update = function(BODY, HEAD) { 545 | if (BODY == undefined) { BODY = {}; } 546 | if (HEAD == undefined) { HEAD = {}; } 547 | var return_values = HEAD.fields_updated || []; 548 | var return_flag = true; 549 | var errors = { HEAD:{}, BODY:{} }; 550 | var output_format = undefined; 551 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 552 | output_format = HEAD.output_format; 553 | } 554 | try { 555 | if (BODY == undefined) { 556 | errors.BODY = { 557 | code: 500, 558 | message: "missing BODY object", 559 | }; 560 | throw "missing BODY object"; 561 | } 562 | if (BODY.data == undefined) { 563 | errors.BODY.data = { 564 | code: 500, 565 | message: "missing 'data' clause in BODY object", 566 | }; 567 | throw "missing 'data' clause in BODY object"; 568 | } 569 | if (BODY.where == undefined) { 570 | errors.BODY.where = { 571 | code: 500, 572 | message: "missing 'where' clause in BODY object", 573 | }; 574 | throw "missing 'where' clause in BODY object"; 575 | } 576 | if (BODY.where[ID_FIELD] !== undefined) { 577 | if (HEAD.strict) { 578 | if (data[BODY.where[ID_FIELD]] == undefined) { 579 | errors.BODY[BODY.where[ID_FIELD]] = { 580 | code: 500, 581 | message: ID_FIELD+" doesn't exist ("+BODY.where[ID_FIELD]+")", 582 | }; 583 | throw ID_FIELD+" doesn't exist ("+BODY.where[ID_FIELD]+")"; 584 | } 585 | } 586 | for (var i in BODY.data) { 587 | if (i != ID_FIELD) { 588 | if (!data[BODY.where[ID_FIELD]]) { 589 | data[BODY.where[ID_FIELD]] = {}; 590 | data[BODY.where[ID_FIELD]][ID_FIELD] = BODY.where[ID_FIELD]; 591 | } 592 | data[BODY.where[ID_FIELD]][i] = BODY.data[i]; 593 | return_values.push(i); 594 | } 595 | } 596 | } 597 | else { 598 | errors.BODY.where = { 599 | code: 500, 600 | message: "where."+ID_FIELD+" required", 601 | }; 602 | throw "where."+ID_FIELD+" required"; 603 | } 604 | } 605 | catch(e) { 606 | this.error_handler(e); 607 | return_flag = false; 608 | } 609 | return _return(return_flag, { fields_updated: return_values }, errors, output_format); 610 | }; 611 | 612 | this.constructor.prototype.delete = function(BODY, HEAD) { 613 | if (BODY == undefined) { BODY = {}; } 614 | if (HEAD == undefined) { HEAD = {}; } 615 | var return_values = []; 616 | var return_flag = true; 617 | var errors = { HEAD:{}, BODY:{} }; 618 | var output_format = undefined; 619 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 620 | output_format = HEAD.output_format; 621 | } 622 | try { 623 | if (BODY !== undefined && typeof(BODY.id) == "string" || typeof(BODY.id) == "number") { 624 | if (BODY !== undefined && data[BODY.id] !== undefined) { 625 | delete(data[BODY.id]); 626 | return_values.push(BODY.id); 627 | } 628 | else { 629 | errors.BODY.id = { 630 | code: 500, 631 | message: BODY.id+" does not exist", 632 | }; 633 | throw BODY.id+" does not exist"; 634 | } 635 | } 636 | else { 637 | for (var id in BODY.id) { 638 | if (BODY.id[id] !== undefined && data[BODY.id[id]] !== undefined) { 639 | delete(data[BODY.id[id]]); 640 | return_values.push(BODY.id[id]); 641 | } 642 | else { 643 | errors.BODY[BODY.id[id]] = { 644 | code: 500, 645 | message: BODY.id[id]+" does not exist" 646 | }; 647 | throw BODY.id[id]+" does not exist"; 648 | } 649 | } 650 | } 651 | } 652 | catch(e) { 653 | this.error_handler(e); 654 | return_flag = false; 655 | } 656 | if (return_values.length == 0) { 657 | return _return(return_flag, {}, errors, output_format); 658 | } 659 | else if (return_values.length == 1) { 660 | return _return(return_flag, { id: return_values[0] }, errors, output_format); 661 | } 662 | else { 663 | return _return(return_flag, { id: return_values }, errors, output_format); 664 | } 665 | }; 666 | 667 | this.constructor.prototype.report = function(BODY, HEAD) { 668 | if (BODY == undefined) { BODY = {}; } 669 | if (HEAD == undefined) { HEAD = {}; } 670 | var return_value = { 671 | count: 0, 672 | fields: {}, 673 | }; 674 | var return_flag = true; 675 | var errors = { HEAD:{}, BODY:{} }; 676 | var output_format = undefined; 677 | if (HEAD !== undefined && HEAD.output_format !== undefined) { 678 | output_format = HEAD.output_format; 679 | } 680 | try { 681 | if (data == undefined) { 682 | errors.HEAD.data = { 683 | code: 500, 684 | message: "internal data invalid" 685 | }; 686 | throw "internal data invalid"; 687 | } 688 | for (var i in data) { 689 | for (var k in data[i]) { 690 | if (return_value.fields[k] == undefined) { 691 | return_value.fields[k] = 1; 692 | } 693 | else { 694 | return_value.fields[k]++; 695 | } 696 | } 697 | return_value.count++; 698 | } 699 | } 700 | catch(e) { 701 | this.error_handler(e); 702 | return_flag = false; 703 | } 704 | return _return(return_flag, return_value, errors, output_format); 705 | }; 706 | 707 | 708 | this.constructor.prototype.error_handler = function(e, debug) { 709 | if (debug || this.debug) { 710 | if (e.code && e.message) { 711 | console.log("ERROR: "+e.code); 712 | console.log(e.message); 713 | } 714 | else { 715 | console.log("ERROR"); 716 | console.log(e); 717 | } 718 | if (this.debug_verbose > 0) { 719 | console.log("CALLER"); 720 | console.log(arguments.callee.caller); 721 | } 722 | if (this.debug_verbose > 2) { 723 | console.log(arguments.callee.caller.toString()); 724 | } 725 | } 726 | }; 727 | 728 | this.constructor.prototype.toString = function() { 729 | return 'awe_v8_object' 730 | }; 731 | 732 | return this; 733 | }; 734 | return awe_v8_object; 735 | } 736 | // END FILE: awe_v8.js 737 | -------------------------------------------------------------------------------- /lib/awe.geo_ar.js: -------------------------------------------------------------------------------- 1 | (function(awe) { 2 | var container = document.getElementById('container'); 3 | var background_video; 4 | 5 | function resize_video() { 6 | if (background_video) { 7 | var video = awe.video_stream().video_element; 8 | var w = video.videoWidth, 9 | h = video.videoHeight; 10 | var cnt_h = container.clientHeight, 11 | cnt_w = container.clientWidth, 12 | wrapper_aspect_ratio = cnt_w / cnt_h, 13 | video_aspect_ratio = w / h 14 | 15 | // stretch the video to cover the background entirely and center it 16 | if (wrapper_aspect_ratio > video_aspect_ratio) { 17 | background_video.setAttribute('width', cnt_w); 18 | background_video.setAttribute('height', cnt_w / video_aspect_ratio); 19 | background_video.style.marginLeft = (-cnt_w/2)+'px'; 20 | } 21 | else { 22 | background_video.setAttribute('height', cnt_h); 23 | background_video.setAttribute('width', cnt_h * video_aspect_ratio); 24 | background_video.style.marginLeft = (-cnt_h * video_aspect_ratio / 2)+'px'; 25 | } 26 | } 27 | aspectRatio = window.innerWidth / window.innerHeight; 28 | awe.pov().aspect = aspectRatio; 29 | awe.pov().updateProjectionMatrix(); 30 | awe.renderer().setSize(window.innerWidth, window.innerHeight); 31 | awe.scene_needs_rendering = 1; 32 | } 33 | 34 | awe.plugins.add([{ 35 | id: 'geo_ar', 36 | auto_register: true, 37 | register: function(plugin_data){ 38 | // add video stream 39 | awe.setup_stream(); 40 | awe.events.add([ 41 | { 42 | id: 'video_stream', 43 | device_types: { 44 | android: 1, 45 | pc: 1 46 | }, 47 | register: function(handler) { 48 | window.addEventListener('gum_ready', handler, false); 49 | }, 50 | unregister: function(handler){ 51 | window.removeEventListener('gum_ready', handler, false); 52 | }, 53 | handler: function(e) { 54 | var video = awe.video_stream(); 55 | background_video = document.createElement('video'); 56 | background_video.setAttribute('width', window.innerWidth); 57 | background_video.setAttribute('height', window.innerHeight); 58 | background_video.setAttribute('autoplay', 'true'); 59 | background_video.style.position = 'absolute'; 60 | background_video.style.left = '50%'; 61 | background_video.style.marginLeft = (-window.innerWidth/2)+'px'; 62 | background_video.style.top = '0px'; 63 | background_video.style.zIndex = '-1'; 64 | container.appendChild(background_video); 65 | awe.util.connect_stream_to_src(awe.video_stream().stream, background_video); 66 | background_video.addEventListener('play',resize_video, false); 67 | setTimeout(function() { 68 | resize_video(); 69 | }, 1000); 70 | } 71 | } 72 | ]); 73 | 74 | // toDeg() is a Number object extension courtesy http://www.movable-type.co.uk/scripts/latlong.html 75 | if (typeof Number.prototype.toDeg == 'undefined') { 76 | Number.prototype.toDeg = function() { 77 | return this * 180 / Math.PI; 78 | }; 79 | } 80 | if (typeof Number.prototype.toRad == 'undefined') { 81 | Number.prototype.toRad = function() { 82 | return this * Math.PI / 180; 83 | }; 84 | } 85 | 86 | awe.events.add({ 87 | id: 'deviceorientation', 88 | device_types: { 89 | pc: 1, 90 | android: 1 91 | }, 92 | register: function(handler) { 93 | window.addEventListener('deviceorientation', handler, false); 94 | }, 95 | unregister: function(handler){ 96 | window.removeEventListener('deviceorientation', handler, false); 97 | }, 98 | handler: function(e) { 99 | var alpha = e.alpha, 100 | beta = e.beta, 101 | gamma = e.gamma, 102 | x = 0, 103 | y = 0, 104 | z = 0; 105 | 106 | if ((beta > 30 && beta < 150) || // device is generally upright (portrait) 107 | (beta < -30 && beta > -150)) { // device is generally upright but inverted (portrait) 108 | x = beta+90; 109 | y = (alpha+gamma)%360; 110 | z = 180; 111 | } else { // device is generally not-upright (landscape) 112 | if (gamma < 0 && gamma > -90) { // rotation below horizon 113 | x = -gamma-90; 114 | } else { // rotation above horizon 115 | x = 90-gamma; 116 | } 117 | y = (alpha+gamma+180)%360; 118 | } 119 | 120 | awe.povs.update({ 121 | data: { 122 | euler_order: 'YZX', 123 | rotation: { 124 | x: x, 125 | y: y, 126 | z: z, 127 | } 128 | }, 129 | where: { 130 | id: 'default' 131 | } 132 | }); 133 | } 134 | }); 135 | 136 | awe.events.add([ 137 | { 138 | id: 'resize_screen', 139 | device_types: { 140 | pc: 1, 141 | android: 1 142 | }, 143 | register: function(handler) { 144 | window.addEventListener('resize', handler, false); 145 | }, 146 | unregister: function(handler){ 147 | window.removeEventListener('resize', handler, false); 148 | }, 149 | handler: function(e) { 150 | resize_video(); 151 | } 152 | } 153 | ]); 154 | }, 155 | unregister: function(plugin_data){ 156 | awe.events.delete('resize_screen'); 157 | awe.events.delete('deviceorientation'); 158 | awe.events.delete('video_stream'); 159 | } 160 | }]); 161 | })(window.awe); 162 | -------------------------------------------------------------------------------- /lib/awe.marker_ar.js: -------------------------------------------------------------------------------- 1 | (function(awe) { 2 | var threshold = 98; 3 | var width = 640; 4 | var height = 480; 5 | var video = document.createElement('video'); 6 | var last_time = 0; 7 | var tracking_enabled = false, background_video, canvas, ctx, video_stream, detector, raster, param, resultMat, tmp = new Float32Array(16), pov_projection_matrix, pov_projection_matrix2; 8 | 9 | function resize_video() { // jsartoolkit specific resize function 10 | if (awe.device_type() == 'android' && navigator.userAgent.match(/firefox/i)) { 11 | // NOTE: This is borken - not quite sure what firefox is doing here 8/ 12 | var aspect_ratio = window.innerWidth / window.innerHeight, 13 | h, w; 14 | if (window.innerHeight > window.innerWidth) { 15 | w = window.innerWidth; 16 | h = window.innerHeight / aspect_ratio; 17 | } 18 | else { 19 | h = window.innerHeight; 20 | w = window.innerWidth / aspect_ratio; 21 | } 22 | if (background_video) { 23 | background_video.setAttribute('height', h); 24 | background_video.setAttribute('width', w); 25 | background_video.style.left = '0px'; 26 | } 27 | awe.renderer().setSize(w, h); 28 | awe.renderer().domElement.style.left = '0px'; 29 | awe.pov().aspect = aspect_ratio; 30 | } 31 | else { 32 | var aspect_ratio = width / height, 33 | h, w; 34 | if (window.innerHeight > window.innerWidth) { 35 | h = window.innerHeight; 36 | w = h * aspect_ratio; 37 | } 38 | else { 39 | w = window.innerWidth; 40 | h = w / aspect_ratio; 41 | } 42 | if (background_video) { 43 | background_video.setAttribute('height', h); 44 | background_video.setAttribute('width', w); 45 | background_video.style.marginLeft = -w/2 + 'px'; 46 | background_video.style.left = '50%'; 47 | } 48 | awe.renderer().setSize(w, h); 49 | awe.renderer().domElement.style.left = '50%'; 50 | awe.renderer().domElement.style.marginLeft = -w/2 + 'px'; 51 | awe.pov().aspect = aspect_ratio; 52 | } 53 | awe.pov().updateProjectionMatrix(); 54 | if (pov_projection_matrix2) { 55 | awe.pov().projectionMatrix.fromArray(pov_projection_matrix2); 56 | } 57 | awe.scene_needs_rendering = 1; 58 | } 59 | 60 | THREE.Matrix4.prototype.setFromArray = function(m){ 61 | return this.set( 62 | m[0],m[4],m[8],m[12], 63 | m[1],m[5],m[9],m[13], 64 | m[2],m[6],m[10],m[14], 65 | m[3],m[7],m[11],m[15] 66 | ); 67 | }; 68 | 69 | function copy_matrix(src, dst){ 70 | dst[0] = src.m00; 71 | dst[1] = -src.m10; 72 | dst[2] = src.m20; 73 | dst[3] = 0; 74 | dst[4] = src.m02; 75 | dst[5] = -src.m12; 76 | dst[6] = src.m22; 77 | dst[7] = 0; 78 | dst[8] = -src.m01; 79 | dst[9] = src.m11; 80 | dst[10] = -src.m21; 81 | dst[11] = 0; 82 | dst[12] = src.m03; 83 | dst[13] = -src.m13; 84 | dst[14] = src.m23; 85 | dst[15] = 1; 86 | } 87 | 88 | function add_ar_events(){ 89 | awe.events.add([{ 90 | id: 'video_stream', 91 | device_types: { 92 | android: 1, 93 | pc: 1 94 | }, 95 | register: function(handler) { 96 | window.addEventListener('gum_ready', handler, false); 97 | }, 98 | unregister: function(handler){ 99 | window.removeEventListener('gum_ready', handler, false); 100 | }, 101 | handler: function(e) { 102 | canvas = document.createElement('canvas'); 103 | canvas.id = "ar_canvas"; 104 | canvas.width = width/2; 105 | canvas.height = height/2; 106 | canvas.style.display = "none"; 107 | document.body.appendChild(canvas); 108 | ctx = canvas.getContext('2d'); 109 | raster = new NyARRgbRaster_Canvas2D(canvas); 110 | param = new FLARParam(width/2,height/2); 111 | resultMat = new NyARTransMatResult(); 112 | detector = new FLARMultiIdMarkerDetector(param,120); 113 | detector.setContinueMode(true); 114 | param.copyCameraMatrix(tmp,10,10000); 115 | pov_projection_matrix = awe.pov().projectionMatrix.toArray(); 116 | awe.pov().projectionMatrix.setFromArray(tmp); 117 | pov_projection_matrix2 = awe.pov().projectionMatrix.toArray(); 118 | video_stream = awe.video_stream(); 119 | video = video_stream.video_element; 120 | video.width = width; 121 | video.height = height; 122 | background_video = document.createElement('video'); 123 | background_video.setAttribute('width', window.innerWidth); 124 | background_video.setAttribute('height', window.innerHeight); 125 | background_video.setAttribute('autoplay', 'true'); 126 | background_video.style.position = 'absolute'; 127 | background_video.style.left = '0px'; 128 | background_video.style.top = '0px'; 129 | background_video.style.zIndex = '-1'; 130 | container.appendChild(background_video); 131 | awe.util.connect_stream_to_src(video_stream.stream, background_video); 132 | background_video.addEventListener('play', function(){ 133 | resize_video(); 134 | tracking_enabled = true; 135 | }, false); 136 | } 137 | }, 138 | { 139 | id: 'ar_tracking', 140 | device_types: { 141 | pc: 1, 142 | android: 1 143 | }, 144 | register: function(handler) { 145 | window.addEventListener('tick', handler, false); 146 | awe.scene_needs_rendering = 1; 147 | }, 148 | unregister: function(handler){ 149 | window.removeEventListener('tick', handler, false); 150 | }, 151 | handler: function(event) { 152 | if (!tracking_enabled) { 153 | return; 154 | } 155 | var video = video_stream.video_element; 156 | if (!video) { 157 | return; 158 | } 159 | if (video.ended) { video.play(); } 160 | if (video.paused) { return; } 161 | if (window.paused) { return; } 162 | if (video.currentTime == last_time) { return; } 163 | last_time = video.currentTime; 164 | try { 165 | ctx.drawImage(video, 0, 0, width/2, height/2); 166 | } catch(e) { /* TODO */ } 167 | canvas.changed = true; 168 | var detected_count = detector.detectMarkerLite(raster, threshold); 169 | var event_data = {}; 170 | for (var i=0; i=0&&o>i;i+=n){var a=u?u[i]:i;e=r(e,t[a],a,t)}return e}return function(r,e,u,i){e=b(e,i,4);var o=!k(r)&&m.keys(r),a=(o||r).length,c=n>0?0:a-1;return arguments.length<3&&(u=r[o?o[c]:c],c+=n),t(r,e,u,o,c,a)}}function t(n){return function(t,r,e){r=x(r,e);for(var u=O(t),i=n>0?0:u-1;i>=0&&u>i;i+=n)if(r(t[i],i,t))return i;return-1}}function r(n,t,r){return function(e,u,i){var o=0,a=O(e);if("number"==typeof i)n>0?o=i>=0?i:Math.max(i+a,o):a=i>=0?Math.min(i+1,a):i+a+1;else if(r&&i&&a)return i=r(e,u),e[i]===u?i:-1;if(u!==u)return i=t(l.call(e,o,a),m.isNaN),i>=0?i+o:-1;for(i=n>0?o:a-1;i>=0&&a>i;i+=n)if(e[i]===u)return i;return-1}}function e(n,t){var r=I.length,e=n.constructor,u=m.isFunction(e)&&e.prototype||a,i="constructor";for(m.has(n,i)&&!m.contains(t,i)&&t.push(i);r--;)i=I[r],i in n&&n[i]!==u[i]&&!m.contains(t,i)&&t.push(i)}var u=this,i=u._,o=Array.prototype,a=Object.prototype,c=Function.prototype,f=o.push,l=o.slice,s=a.toString,p=a.hasOwnProperty,h=Array.isArray,v=Object.keys,g=c.bind,y=Object.create,d=function(){},m=function(n){return n instanceof m?n:this instanceof m?void(this._wrapped=n):new m(n)};"undefined"!=typeof exports?("undefined"!=typeof module&&module.exports&&(exports=module.exports=m),exports._=m):u._=m,m.VERSION="1.8.3";var b=function(n,t,r){if(t===void 0)return n;switch(null==r?3:r){case 1:return function(r){return n.call(t,r)};case 2:return function(r,e){return n.call(t,r,e)};case 3:return function(r,e,u){return n.call(t,r,e,u)};case 4:return function(r,e,u,i){return n.call(t,r,e,u,i)}}return function(){return n.apply(t,arguments)}},x=function(n,t,r){return null==n?m.identity:m.isFunction(n)?b(n,t,r):m.isObject(n)?m.matcher(n):m.property(n)};m.iteratee=function(n,t){return x(n,t,1/0)};var _=function(n,t){return function(r){var e=arguments.length;if(2>e||null==r)return r;for(var u=1;e>u;u++)for(var i=arguments[u],o=n(i),a=o.length,c=0;a>c;c++){var f=o[c];t&&r[f]!==void 0||(r[f]=i[f])}return r}},j=function(n){if(!m.isObject(n))return{};if(y)return y(n);d.prototype=n;var t=new d;return d.prototype=null,t},w=function(n){return function(t){return null==t?void 0:t[n]}},A=Math.pow(2,53)-1,O=w("length"),k=function(n){var t=O(n);return"number"==typeof t&&t>=0&&A>=t};m.each=m.forEach=function(n,t,r){t=b(t,r);var e,u;if(k(n))for(e=0,u=n.length;u>e;e++)t(n[e],e,n);else{var i=m.keys(n);for(e=0,u=i.length;u>e;e++)t(n[i[e]],i[e],n)}return n},m.map=m.collect=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=Array(u),o=0;u>o;o++){var a=e?e[o]:o;i[o]=t(n[a],a,n)}return i},m.reduce=m.foldl=m.inject=n(1),m.reduceRight=m.foldr=n(-1),m.find=m.detect=function(n,t,r){var e;return e=k(n)?m.findIndex(n,t,r):m.findKey(n,t,r),e!==void 0&&e!==-1?n[e]:void 0},m.filter=m.select=function(n,t,r){var e=[];return t=x(t,r),m.each(n,function(n,r,u){t(n,r,u)&&e.push(n)}),e},m.reject=function(n,t,r){return m.filter(n,m.negate(x(t)),r)},m.every=m.all=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(!t(n[o],o,n))return!1}return!0},m.some=m.any=function(n,t,r){t=x(t,r);for(var e=!k(n)&&m.keys(n),u=(e||n).length,i=0;u>i;i++){var o=e?e[i]:i;if(t(n[o],o,n))return!0}return!1},m.contains=m.includes=m.include=function(n,t,r,e){return k(n)||(n=m.values(n)),("number"!=typeof r||e)&&(r=0),m.indexOf(n,t,r)>=0},m.invoke=function(n,t){var r=l.call(arguments,2),e=m.isFunction(t);return m.map(n,function(n){var u=e?t:n[t];return null==u?u:u.apply(n,r)})},m.pluck=function(n,t){return m.map(n,m.property(t))},m.where=function(n,t){return m.filter(n,m.matcher(t))},m.findWhere=function(n,t){return m.find(n,m.matcher(t))},m.max=function(n,t,r){var e,u,i=-1/0,o=-1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],e>i&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(u>o||u===-1/0&&i===-1/0)&&(i=n,o=u)});return i},m.min=function(n,t,r){var e,u,i=1/0,o=1/0;if(null==t&&null!=n){n=k(n)?n:m.values(n);for(var a=0,c=n.length;c>a;a++)e=n[a],i>e&&(i=e)}else t=x(t,r),m.each(n,function(n,r,e){u=t(n,r,e),(o>u||1/0===u&&1/0===i)&&(i=n,o=u)});return i},m.shuffle=function(n){for(var t,r=k(n)?n:m.values(n),e=r.length,u=Array(e),i=0;e>i;i++)t=m.random(0,i),t!==i&&(u[i]=u[t]),u[t]=r[i];return u},m.sample=function(n,t,r){return null==t||r?(k(n)||(n=m.values(n)),n[m.random(n.length-1)]):m.shuffle(n).slice(0,Math.max(0,t))},m.sortBy=function(n,t,r){return t=x(t,r),m.pluck(m.map(n,function(n,r,e){return{value:n,index:r,criteria:t(n,r,e)}}).sort(function(n,t){var r=n.criteria,e=t.criteria;if(r!==e){if(r>e||r===void 0)return 1;if(e>r||e===void 0)return-1}return n.index-t.index}),"value")};var F=function(n){return function(t,r,e){var u={};return r=x(r,e),m.each(t,function(e,i){var o=r(e,i,t);n(u,e,o)}),u}};m.groupBy=F(function(n,t,r){m.has(n,r)?n[r].push(t):n[r]=[t]}),m.indexBy=F(function(n,t,r){n[r]=t}),m.countBy=F(function(n,t,r){m.has(n,r)?n[r]++:n[r]=1}),m.toArray=function(n){return n?m.isArray(n)?l.call(n):k(n)?m.map(n,m.identity):m.values(n):[]},m.size=function(n){return null==n?0:k(n)?n.length:m.keys(n).length},m.partition=function(n,t,r){t=x(t,r);var e=[],u=[];return m.each(n,function(n,r,i){(t(n,r,i)?e:u).push(n)}),[e,u]},m.first=m.head=m.take=function(n,t,r){return null==n?void 0:null==t||r?n[0]:m.initial(n,n.length-t)},m.initial=function(n,t,r){return l.call(n,0,Math.max(0,n.length-(null==t||r?1:t)))},m.last=function(n,t,r){return null==n?void 0:null==t||r?n[n.length-1]:m.rest(n,Math.max(0,n.length-t))},m.rest=m.tail=m.drop=function(n,t,r){return l.call(n,null==t||r?1:t)},m.compact=function(n){return m.filter(n,m.identity)};var S=function(n,t,r,e){for(var u=[],i=0,o=e||0,a=O(n);a>o;o++){var c=n[o];if(k(c)&&(m.isArray(c)||m.isArguments(c))){t||(c=S(c,t,r));var f=0,l=c.length;for(u.length+=l;l>f;)u[i++]=c[f++]}else r||(u[i++]=c)}return u};m.flatten=function(n,t){return S(n,t,!1)},m.without=function(n){return m.difference(n,l.call(arguments,1))},m.uniq=m.unique=function(n,t,r,e){m.isBoolean(t)||(e=r,r=t,t=!1),null!=r&&(r=x(r,e));for(var u=[],i=[],o=0,a=O(n);a>o;o++){var c=n[o],f=r?r(c,o,n):c;t?(o&&i===f||u.push(c),i=f):r?m.contains(i,f)||(i.push(f),u.push(c)):m.contains(u,c)||u.push(c)}return u},m.union=function(){return m.uniq(S(arguments,!0,!0))},m.intersection=function(n){for(var t=[],r=arguments.length,e=0,u=O(n);u>e;e++){var i=n[e];if(!m.contains(t,i)){for(var o=1;r>o&&m.contains(arguments[o],i);o++);o===r&&t.push(i)}}return t},m.difference=function(n){var t=S(arguments,!0,!0,1);return m.filter(n,function(n){return!m.contains(t,n)})},m.zip=function(){return m.unzip(arguments)},m.unzip=function(n){for(var t=n&&m.max(n,O).length||0,r=Array(t),e=0;t>e;e++)r[e]=m.pluck(n,e);return r},m.object=function(n,t){for(var r={},e=0,u=O(n);u>e;e++)t?r[n[e]]=t[e]:r[n[e][0]]=n[e][1];return r},m.findIndex=t(1),m.findLastIndex=t(-1),m.sortedIndex=function(n,t,r,e){r=x(r,e,1);for(var u=r(t),i=0,o=O(n);o>i;){var a=Math.floor((i+o)/2);r(n[a])i;i++,n+=r)u[i]=n;return u};var E=function(n,t,r,e,u){if(!(e instanceof t))return n.apply(r,u);var i=j(n.prototype),o=n.apply(i,u);return m.isObject(o)?o:i};m.bind=function(n,t){if(g&&n.bind===g)return g.apply(n,l.call(arguments,1));if(!m.isFunction(n))throw new TypeError("Bind must be called on a function");var r=l.call(arguments,2),e=function(){return E(n,e,t,this,r.concat(l.call(arguments)))};return e},m.partial=function(n){var t=l.call(arguments,1),r=function(){for(var e=0,u=t.length,i=Array(u),o=0;u>o;o++)i[o]=t[o]===m?arguments[e++]:t[o];for(;e=e)throw new Error("bindAll must be passed function names");for(t=1;e>t;t++)r=arguments[t],n[r]=m.bind(n[r],n);return n},m.memoize=function(n,t){var r=function(e){var u=r.cache,i=""+(t?t.apply(this,arguments):e);return m.has(u,i)||(u[i]=n.apply(this,arguments)),u[i]};return r.cache={},r},m.delay=function(n,t){var r=l.call(arguments,2);return setTimeout(function(){return n.apply(null,r)},t)},m.defer=m.partial(m.delay,m,1),m.throttle=function(n,t,r){var e,u,i,o=null,a=0;r||(r={});var c=function(){a=r.leading===!1?0:m.now(),o=null,i=n.apply(e,u),o||(e=u=null)};return function(){var f=m.now();a||r.leading!==!1||(a=f);var l=t-(f-a);return e=this,u=arguments,0>=l||l>t?(o&&(clearTimeout(o),o=null),a=f,i=n.apply(e,u),o||(e=u=null)):o||r.trailing===!1||(o=setTimeout(c,l)),i}},m.debounce=function(n,t,r){var e,u,i,o,a,c=function(){var f=m.now()-o;t>f&&f>=0?e=setTimeout(c,t-f):(e=null,r||(a=n.apply(i,u),e||(i=u=null)))};return function(){i=this,u=arguments,o=m.now();var f=r&&!e;return e||(e=setTimeout(c,t)),f&&(a=n.apply(i,u),i=u=null),a}},m.wrap=function(n,t){return m.partial(t,n)},m.negate=function(n){return function(){return!n.apply(this,arguments)}},m.compose=function(){var n=arguments,t=n.length-1;return function(){for(var r=t,e=n[t].apply(this,arguments);r--;)e=n[r].call(this,e);return e}},m.after=function(n,t){return function(){return--n<1?t.apply(this,arguments):void 0}},m.before=function(n,t){var r;return function(){return--n>0&&(r=t.apply(this,arguments)),1>=n&&(t=null),r}},m.once=m.partial(m.before,2);var M=!{toString:null}.propertyIsEnumerable("toString"),I=["valueOf","isPrototypeOf","toString","propertyIsEnumerable","hasOwnProperty","toLocaleString"];m.keys=function(n){if(!m.isObject(n))return[];if(v)return v(n);var t=[];for(var r in n)m.has(n,r)&&t.push(r);return M&&e(n,t),t},m.allKeys=function(n){if(!m.isObject(n))return[];var t=[];for(var r in n)t.push(r);return M&&e(n,t),t},m.values=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=n[t[u]];return e},m.mapObject=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=u.length,o={},a=0;i>a;a++)e=u[a],o[e]=t(n[e],e,n);return o},m.pairs=function(n){for(var t=m.keys(n),r=t.length,e=Array(r),u=0;r>u;u++)e[u]=[t[u],n[t[u]]];return e},m.invert=function(n){for(var t={},r=m.keys(n),e=0,u=r.length;u>e;e++)t[n[r[e]]]=r[e];return t},m.functions=m.methods=function(n){var t=[];for(var r in n)m.isFunction(n[r])&&t.push(r);return t.sort()},m.extend=_(m.allKeys),m.extendOwn=m.assign=_(m.keys),m.findKey=function(n,t,r){t=x(t,r);for(var e,u=m.keys(n),i=0,o=u.length;o>i;i++)if(e=u[i],t(n[e],e,n))return e},m.pick=function(n,t,r){var e,u,i={},o=n;if(null==o)return i;m.isFunction(t)?(u=m.allKeys(o),e=b(t,r)):(u=S(arguments,!1,!1,1),e=function(n,t,r){return t in r},o=Object(o));for(var a=0,c=u.length;c>a;a++){var f=u[a],l=o[f];e(l,f,o)&&(i[f]=l)}return i},m.omit=function(n,t,r){if(m.isFunction(t))t=m.negate(t);else{var e=m.map(S(arguments,!1,!1,1),String);t=function(n,t){return!m.contains(e,t)}}return m.pick(n,t,r)},m.defaults=_(m.allKeys,!0),m.create=function(n,t){var r=j(n);return t&&m.extendOwn(r,t),r},m.clone=function(n){return m.isObject(n)?m.isArray(n)?n.slice():m.extend({},n):n},m.tap=function(n,t){return t(n),n},m.isMatch=function(n,t){var r=m.keys(t),e=r.length;if(null==n)return!e;for(var u=Object(n),i=0;e>i;i++){var o=r[i];if(t[o]!==u[o]||!(o in u))return!1}return!0};var N=function(n,t,r,e){if(n===t)return 0!==n||1/n===1/t;if(null==n||null==t)return n===t;n instanceof m&&(n=n._wrapped),t instanceof m&&(t=t._wrapped);var u=s.call(n);if(u!==s.call(t))return!1;switch(u){case"[object RegExp]":case"[object String]":return""+n==""+t;case"[object Number]":return+n!==+n?+t!==+t:0===+n?1/+n===1/t:+n===+t;case"[object Date]":case"[object Boolean]":return+n===+t}var i="[object Array]"===u;if(!i){if("object"!=typeof n||"object"!=typeof t)return!1;var o=n.constructor,a=t.constructor;if(o!==a&&!(m.isFunction(o)&&o instanceof o&&m.isFunction(a)&&a instanceof a)&&"constructor"in n&&"constructor"in t)return!1}r=r||[],e=e||[];for(var c=r.length;c--;)if(r[c]===n)return e[c]===t;if(r.push(n),e.push(t),i){if(c=n.length,c!==t.length)return!1;for(;c--;)if(!N(n[c],t[c],r,e))return!1}else{var f,l=m.keys(n);if(c=l.length,m.keys(t).length!==c)return!1;for(;c--;)if(f=l[c],!m.has(t,f)||!N(n[f],t[f],r,e))return!1}return r.pop(),e.pop(),!0};m.isEqual=function(n,t){return N(n,t)},m.isEmpty=function(n){return null==n?!0:k(n)&&(m.isArray(n)||m.isString(n)||m.isArguments(n))?0===n.length:0===m.keys(n).length},m.isElement=function(n){return!(!n||1!==n.nodeType)},m.isArray=h||function(n){return"[object Array]"===s.call(n)},m.isObject=function(n){var t=typeof n;return"function"===t||"object"===t&&!!n},m.each(["Arguments","Function","String","Number","Date","RegExp","Error"],function(n){m["is"+n]=function(t){return s.call(t)==="[object "+n+"]"}}),m.isArguments(arguments)||(m.isArguments=function(n){return m.has(n,"callee")}),"function"!=typeof/./&&"object"!=typeof Int8Array&&(m.isFunction=function(n){return"function"==typeof n||!1}),m.isFinite=function(n){return isFinite(n)&&!isNaN(parseFloat(n))},m.isNaN=function(n){return m.isNumber(n)&&n!==+n},m.isBoolean=function(n){return n===!0||n===!1||"[object Boolean]"===s.call(n)},m.isNull=function(n){return null===n},m.isUndefined=function(n){return n===void 0},m.has=function(n,t){return null!=n&&p.call(n,t)},m.noConflict=function(){return u._=i,this},m.identity=function(n){return n},m.constant=function(n){return function(){return n}},m.noop=function(){},m.property=w,m.propertyOf=function(n){return null==n?function(){}:function(t){return n[t]}},m.matcher=m.matches=function(n){return n=m.extendOwn({},n),function(t){return m.isMatch(t,n)}},m.times=function(n,t,r){var e=Array(Math.max(0,n));t=b(t,r,1);for(var u=0;n>u;u++)e[u]=t(u);return e},m.random=function(n,t){return null==t&&(t=n,n=0),n+Math.floor(Math.random()*(t-n+1))},m.now=Date.now||function(){return(new Date).getTime()};var B={"&":"&","<":"<",">":">",'"':""","'":"'","`":"`"},T=m.invert(B),R=function(n){var t=function(t){return n[t]},r="(?:"+m.keys(n).join("|")+")",e=RegExp(r),u=RegExp(r,"g");return function(n){return n=null==n?"":""+n,e.test(n)?n.replace(u,t):n}};m.escape=R(B),m.unescape=R(T),m.result=function(n,t,r){var e=null==n?void 0:n[t];return e===void 0&&(e=r),m.isFunction(e)?e.call(n):e};var q=0;m.uniqueId=function(n){var t=++q+"";return n?n+t:t},m.templateSettings={evaluate:/<%([\s\S]+?)%>/g,interpolate:/<%=([\s\S]+?)%>/g,escape:/<%-([\s\S]+?)%>/g};var K=/(.)^/,z={"'":"'","\\":"\\","\r":"r","\n":"n","\u2028":"u2028","\u2029":"u2029"},D=/\\|'|\r|\n|\u2028|\u2029/g,L=function(n){return"\\"+z[n]};m.template=function(n,t,r){!t&&r&&(t=r),t=m.defaults({},t,m.templateSettings);var e=RegExp([(t.escape||K).source,(t.interpolate||K).source,(t.evaluate||K).source].join("|")+"|$","g"),u=0,i="__p+='";n.replace(e,function(t,r,e,o,a){return i+=n.slice(u,a).replace(D,L),u=a+t.length,r?i+="'+\n((__t=("+r+"))==null?'':_.escape(__t))+\n'":e?i+="'+\n((__t=("+e+"))==null?'':__t)+\n'":o&&(i+="';\n"+o+"\n__p+='"),t}),i+="';\n",t.variable||(i="with(obj||{}){\n"+i+"}\n"),i="var __t,__p='',__j=Array.prototype.join,"+"print=function(){__p+=__j.call(arguments,'');};\n"+i+"return __p;\n";try{var o=new Function(t.variable||"obj","_",i)}catch(a){throw a.source=i,a}var c=function(n){return o.call(this,n,m)},f=t.variable||"obj";return c.source="function("+f+"){\n"+i+"}",c},m.chain=function(n){var t=m(n);return t._chain=!0,t};var P=function(n,t){return n._chain?m(t).chain():t};m.mixin=function(n){m.each(m.functions(n),function(t){var r=m[t]=n[t];m.prototype[t]=function(){var n=[this._wrapped];return f.apply(n,arguments),P(this,r.apply(m,n))}})},m.mixin(m),m.each(["pop","push","reverse","shift","sort","splice","unshift"],function(n){var t=o[n];m.prototype[n]=function(){var r=this._wrapped;return t.apply(r,arguments),"shift"!==n&&"splice"!==n||0!==r.length||delete r[0],P(this,r)}}),m.each(["concat","join","slice"],function(n){var t=o[n];m.prototype[n]=function(){return P(this,t.apply(this._wrapped,arguments))}}),m.prototype.value=function(){return this._wrapped},m.prototype.valueOf=m.prototype.toJSON=m.prototype.value,m.prototype.toString=function(){return""+this._wrapped},"function"==typeof define&&define.amd&&define("underscore",[],function(){return m})}).call(this); 6 | //# sourceMappingURL=underscore-min.map --------------------------------------------------------------------------------