/**
* @namespace Loader
* @memberof SQR
*
* @description Utility to load different types of files (and also some WebRTC related stuff, see below)
*/
SQR.Loader = {
/**
* @method load
* @memberof SQR.Loader
*
* @description Load a text file and return it's contents in the callback.
*/
loadText: function(path, callback){
var request = new XMLHttpRequest();
request.open("GET", path);
var onReadystatechange = function(){
if (request.readyState == 4) {
request.removeEventListener('readystatechange', onReadystatechange);
callback(request.responseText, path);
}
}
request.addEventListener('readystatechange', onReadystatechange);
request.send();
},
/**
* @method loadJSON
* @memberof SQR.Loader
*
* @description Load a JSON file and return it's contents in the callback.
* This function will parse the JSON data for you and return an Object.
*/
loadJSON: function(path, callback){
SQR.Loader.loadText(path, function(text) {
callback(JSON.parse(text), path);
});
},
/**
* @method loadImage
* @memberof SQR.Loader
*
* @description Load an image file and return it's contents in the callback
* as Image object.
*/
loadImage: function(path, callback, errorCallback){
var img = new Image();
img.crossOrigin = "Anonymous";
if(callback) {
var onload = function() {
img.removeEventListener('load', onload);
callback(img, path);
}
img.addEventListener('load', onload);
}
if(errorCallback) {
var onerror = function() {
img.src = '';
img.removeEventListener('error', onerror);
errorCallback(null, path);
return false;
}
img.addEventListener('error', onerror);
}
img.src = path;
return img;
},
/**
* @method loadWebcam
* @memberof SQR.Loader
*
* @description Initiate user stream (webcam).
*/
loadWebcam: function(callback, options) {
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
if(!navigator.getUserMedia) {
console.error('> SQR.Loader - getUserMedia not supported');
callback();
}
options = options || {
audio: false,
video: {
// mandatory: { minWidth: 1920, minHeight: 1080 }
}
};
var onVideo = function(stream) {
video.srcObject = stream;
video.onloadedmetadata = () => { stream.play(); };
// video.play();
video.addEventListener('canplaythrough', videoReady, false);
}
var videoReady = function() {
callback(video, 'webcam');
}
var video = document.createElement('video');
video.autoplay = true;
navigator.getUserMedia(options, onVideo, function(e) {
console.error('> SQR.Loader - getUserMedia error ', e);
});
},
/**
* @method loadVideo
* @memberof SQR.Loader
*
* @description Preload a video so that it can be used as a texture (typically)
*/
loadVideo: function(path, callback) {
var videoReady = function() {
callback(video, path);
}
var video = document.createElement('video');
video.autoplay = true;
video.addEventListener('canplaythrough', videoReady, false);
var p = path;
if(!video.canPlayType('video/mp4')) {
p = p.replace('mp4', 'webm');
}
video.src = p;
},
/**
* @method loadAssets
* @memberof SQR.Loader
*
* @description Load multiple assets of type:
* <ul>
* <li>text, including GLSL code</li>
* <li>JSON, including model, geometry, scene. etc...</li>
* <li>image (jpg, gif, png), video (mp4, webm)</li>
* <li>webcam (it will initiate the webcam,
* ask user for permisions, and return a ready to use stream)</li>
* </ul>
*
* Each file will be availabke from the asset object passed to the callback
* under it's name, ex. assets['normal2color.glsl']
* It's also possible ot specify an alias. Instead of a String,
* use an Array, where [0] is the path, and [1] is the alias.
*
* @example
SQR.Loader.loadAssets([
['some-image.jpg', 'image'],
['some-video.mp4', 'video'],
['a-shader.glsl', 'shader'],
'another-shader.glsl',
'webcam' // special case, but useful :)
], function(assets) {
var image = assets['image'];
});
*
* @param {object} paths - list of file paths (with optinal aliases) to load, as in example below.
* @param {function} callback - called when all the files are loaded.
* The assets are passed as argument as in the example below.
* @param {function} progressCallback - called each time when on of the files is loaded
*/
loadAssets: function(paths, callback, progressCallback, options) {
options = options || {};
var toLoad = paths.length;
var assets = {};
if(toLoad == 0) {
if(progressCallback) progressCallback(1, 1);
callback();
return;
}
var aliases = {}, includes = {};
var onShader = function(asset, p) {
SQR.GLSLInclude = SQR.GLSLInclude || {};
SQR.GLSLInclude[aliases[p]] = asset;
onAsset(asset, p);
}
var onAsset = function(asset, p) {
assets[aliases[p]] = asset;
toLoad--;
if(progressCallback) {
progressCallback(toLoad, paths.length);
}
if(toLoad == 0) {
callback(assets);
}
}
for(var i = 0; i < toLoad; i++) {
var p = paths[i];
var hasAlias = typeof(p) != 'string';
var file = hasAlias ? p[0] : p;
var alias = hasAlias ? p[1] : p;
var fileType = file.substring(file.lastIndexOf('.') + 1).toLowerCase();
aliases[file] = alias;
switch(fileType) {
case 'glsl':
SQR.Loader.loadText(file, onShader);
break;
case 'png':
case 'jpg':
case 'jpeg':
case 'gif':
SQR.Loader.loadImage(file, onAsset);
break;
case 'json':
case 'js':
SQR.Loader.loadJSON(file, onAsset);
break;
case 'mp4':
case 'webm':
SQR.Loader.loadVideo(file, onAsset);
break;
case 'webcam':
SQR.Loader.loadWebcam(onAsset);
break;
default:
console.warn("SQR.Loader / Unknown asset type: " + file);
break;
}
}
}
};