API Docs for:
Show:

File: ../src/formats.js

///@INFO: BASE
/**
* Formats is the class where all the info about what is every format, how to parse it, etc, is located
*
* @class LS.Formats
* @param{String} id the id (otherwise a random one is computed)
* @constructor
*/
LS.Formats = {

	//all the supported file formats and their parsers
	supported: {},

	safe_parsing: false, //catch exceptions during parsing
	merge_smoothgroups: false,

	/**
	* Tells the system info about this file format
	* Info should contain fields like type:"image", resource: "Mesh|Texture", format: "text|binary", parse: function, native: true|false
	* 
	* @method addFormat
	*/
	addSupportedFormat: function( extensions, info )
	{
		if( extensions.constructor === String )
			extensions = extensions.split(",");

		for(var i = 0; i < extensions.length; ++i)
		{
			var extension = extensions[i].toLowerCase();
			if( this.supported[ extension ] )
				console.warn("There is already another parser associated to this extension: " + extension);
			this.supported[ extension ] = info;
		}
	},

	/**
	* Parse some data and returns the resulting resource
	* 
	* @method parse
	* @param {string} filename
	* @param {*} data could be a string, binary, arraybuffer, xml...
	* @param {Object} options how the file should be parsed
	* @return {*} the final resource, could be a Texture, a Mesh, or an object
	*/
	parse: function( filename, data, options)
	{
		options = options || {};
		var info = this.getFileFormatInfo( filename );
		if(!info) //unsupported extension
			return null;

		if(options.extension)
			info.extension = options.extension; //force a format
		else
			info.extension = LS.ResourcesManager.getExtension( filename );

		var format = this.supported[ info.extension ];
		if(!format || !format.parse)
		{
			console.error("Parser Error: No parser found for " + info.extension + " format");
			return null;
		}

		var result = null;
		if(!this.safe_parsing)
			result = format.parse( data, options, filename );
		else
			try
			{
				result = format.parse( data, options, filename );
			}
			catch (err)
			{
				console.error("Error parsing content", err );
				return null;
			}
		if(result)
			result.name = filename;
		return result;
	},

	//Returns info about a resource according to its filename
	TEXT_FORMAT: "text",
	JSON_FORMAT: "json",
	XML_FORMAT: "xml",
	BINARY_FORMAT: "binary",

	MESH_DATA: "MESH",
	IMAGE_DATA: "IMAGE",
	NONATIVE_IMAGE_DATA: "NONATIVE_IMAGE",
	SCENE_DATA: "SCENE",
	GENERIC_DATA: "GENERIC",
	
	getFileFormatInfo: function( filename )
	{
		var extension = filename.substr( filename.lastIndexOf(".") + 1).toLowerCase();
		return this.supported[ extension ];
	},

	guessType: function( filename )
	{
		if(!filename)
			return null;

		var ext = LS.RM.getExtension( filename ).toLowerCase();
		var info = this.supported[ ext ];
		if(!info)
			return null;
		return info.resource;
	},

	//Helpers ******************************

	//gets raw image information {width,height,pixels:ArrayBuffer} and create a dataurl to use in images
	convertToDataURL: function( img_data )
	{
		var canvas = document.createElement("canvas");
		canvas.width = img_data.width;
		canvas.height = img_data.height;
		//document.body.appendChild(canvas);
		var ctx = canvas.getContext("2d");
		var pixelsData = ctx.createImageData(img_data.width, img_data.height);
		var num_pixels = canvas.width * canvas.height;

		//flip and copy the pixels
		if(img_data.bytesPerPixel == 3)
		{
			for(var i = 0; i < canvas.width; ++i)
				for(var j = 0; j < canvas.height; ++j)
				{
					var pos = j*canvas.width*4 + i*4;
					var pos2 = (canvas.height - j - 1)*canvas.width*3 + i*3;
					pixelsData.data[pos+2] = img_data.pixels[pos2];
					pixelsData.data[pos+1] = img_data.pixels[pos2+1];
					pixelsData.data[pos+0] = img_data.pixels[pos2+2];
					pixelsData.data[pos+3] = 255;
				}
		}
		else {
			for(var i = 0; i < canvas.width; ++i)
				for(var j = 0; j < canvas.height; ++j)
				{
					var pos = j*canvas.width*4 + i*4;
					var pos2 = (canvas.height - j - 1)*canvas.width*4 + i*4;
					pixelsData.data[pos+0] = img_data.pixels[pos2+2];
					pixelsData.data[pos+1] = img_data.pixels[pos2+1];
					pixelsData.data[pos+2] = img_data.pixels[pos2+0];
					pixelsData.data[pos+3] = img_data.pixels[pos2+3];
				}
		}

		ctx.putImageData(pixelsData,0,0);
		img_data.dataurl = canvas.toDataURL("image/png");
		return img_data.dataurl;
	},

	/* extract important Mesh info from vertices (center, radius, bouding box) */
	computeMeshBounding: function(vertices)
	{
		//compute AABB and useful info
		var min = [vertices[0],vertices[1],vertices[2]];
		var max = [vertices[0],vertices[1],vertices[2]];
		for(var i = 0; i < vertices.length; i += 3)
		{
			var v = [vertices[i],vertices[i+1],vertices[i+2]];
			if (v[0] < min[0]) min[0] = v[0];
			else if (v[0] > max[0]) max[0] = v[0];
			if (v[1] < min[1]) min[1] = v[1];
			else if (v[1] > max[1]) max[1] = v[1];
			if (v[2] < min[2]) min[2] = v[2];
			else if (v[2] > max[2]) max[2] = v[2];
		}

		var center = [(min[0] + max[0]) * 0.5,(min[1] + max[1]) * 0.5, (min[2] + max[2]) * 0.5];
		var halfsize = [ min[0] - center[0], min[1] - center[1], min[2] - center[2]];
		return BBox.setCenterHalfsize( BBox.create(), center, halfsize );
	}
};

//native formats do not need parser
LS.Formats.addSupportedFormat( "png,jpg,jpeg,webp,bmp,gif", { "native": true, dataType: "arraybuffer", resource: "Texture", "resourceClass": GL.Texture, has_preview: true, type: "image" } );
LS.Formats.addSupportedFormat( "wbin", { dataType: "arraybuffer" } );
LS.Formats.addSupportedFormat( "json,js,txt,html,css,csv", { dataType: "text" } );
LS.Formats.addSupportedFormat( "glsl", { dataType: "text", resource: "ShaderCode", "resourceClass": LS.ShaderCode  } );
LS.Formats.addSupportedFormat( "zip", { dataType: "arraybuffer" } );
WBin.classes = LS.Classes; //WBin need to know which classes are accesible to be instantiated right from the WBin data info, in case the class is not a global class


//parsers usually need this
//takes an string an returns a Uint8Array typed array containing that string
function stringToTypedArray(str, fixed_length)
{
	var r = new Uint8Array( fixed_length ? fixed_length : str.length);
	for(var i = 0; i < str.length; i++)
		r[i] = str.charCodeAt(i);
	return r;
}

//takes a typed array with ASCII codes and returns the string
function typedArrayToString(typed_array, same_size)
{
	var r = "";
	for(var i = 0; i < typed_array.length; i++)
		if (typed_array[i] == 0 && !same_size)
			break;
		else
			r += String.fromCharCode( typed_array[i] );
	return r;
}