Dart DocumentationImageUtils

ImageUtils library

Properties

var crossOrigin #

var crossOrigin = 'anonymous'

Functions

dynamic generateDataTexture(width, height, color) #

generateDataTexture( width, height, color ) {

	var size = width * height;
	var data = new Uint8List( 3 * size );

	var r = ( color.r * 255 ).floor();
	var g = ( color.g * 255 ).floor();
	var b = ( color.b * 255 ).floor();

	for ( var i = 0; i < size; i ++ ) {

		data[ i * 3 ] 	  = r;
		data[ i * 3 + 1 ] = g;
		data[ i * 3 + 2 ] = b;

	}

	var texture = new DataTexture( data, width, height, RGBFormat );
	texture.needsUpdate = true;

	return texture;

}

dynamic getNormalMap(image, depth) #

getNormalMap ( image, depth ) {

	// Adapted from http://www.paulbrunt.co.uk/lab/heightnormal/

	var cross = ( a, b ) {

		return [ a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ], a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ], a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ] ];

	};

	var subtract = ( a, b ) {

		return [ a[ 0 ] - b[ 0 ], a[ 1 ] - b[ 1 ], a[ 2 ] - b[ 2 ] ];

	};

	var normalize = ( a ) {

		var l = Math.sqrt( a[ 0 ] * a[ 0 ] + a[ 1 ] * a[ 1 ] + a[ 2 ] * a[ 2 ] );
		return [ a[ 0 ] / l, a[ 1 ] / l, a[ 2 ] / l ];

	};

	depth = depth | 1;

	var width = image.width;
	var height = image.height;

	var canvas = new CanvasElement();;
	canvas.width = width;
	canvas.height = height;

	var context = canvas.context2D;
	context.drawImage( image, 0, 0 );

	var data = context.getImageData( 0, 0, width, height ).data;
	var imageData = context.createImageData( width, height );
	var output = imageData.data;

	for ( var x = 0; x < width; x ++ ) {

		for ( var y = 0; y < height; y ++ ) {

			num ly = y - 1 < 0 ? 0 : y - 1;
			num uy = y + 1 > height - 1 ? height - 1 : y + 1;
			num lx = x - 1 < 0 ? 0 : x - 1;
			num ux = x + 1 > width - 1 ? width - 1 : x + 1;

			var points = [];
			var origin = [ 0, 0, data[ ( y * width + x ) * 4 ] / 255 * depth ];
			points.add( [ - 1, 0, data[ ( y * width + lx ) * 4 ] / 255 * depth ] );
			points.add( [ - 1, - 1, data[ ( ly * width + lx ) * 4 ] / 255 * depth ] );
			points.add( [ 0, - 1, data[ ( ly * width + x ) * 4 ] / 255 * depth ] );
			points.add( [  1, - 1, data[ ( ly * width + ux ) * 4 ] / 255 * depth ] );
			points.add( [ 1, 0, data[ ( y * width + ux ) * 4 ] / 255 * depth ] );
			points.add( [ 1, 1, data[ ( uy * width + ux ) * 4 ] / 255 * depth ] );
			points.add( [ 0, 1, data[ ( uy * width + x ) * 4 ] / 255 * depth ] );
			points.add( [ - 1, 1, data[ ( uy * width + lx ) * 4 ] / 255 * depth ] );

			List<List> normals = [];
			var num_points = points.length;

			for ( var i = 0; i < num_points; i ++ ) {

				var v1 = points[ i ];
				var v2 = points[ ( i + 1 ) % num_points ];
				v1 = subtract( v1, origin );
				v2 = subtract( v2, origin );
				normals.add( normalize( cross( v1, v2 ) ) );

			}

			List<num> normal = [ 0, 0, 0 ];

			for ( var i = 0; i < normals.length; i ++ ) {

				normal[ 0 ] += normals[ i ][ 0 ];
				normal[ 1 ] += normals[ i ][ 1 ];
				normal[ 2 ] += normals[ i ][ 2 ];

			}

			normal[ 0 ] /= normals.length;
			normal[ 1 ] /= normals.length;
			normal[ 2 ] /= normals.length;

			var idx = ( y * width + x ) * 4;

			output[ idx ] = ( ( normal[ 0 ] + 1.0 ) / 2.0 * 255 ).toInt() | 0;
			output[ idx + 1 ] = ( ( normal[ 1 ] + 1.0 ) / 2.0 * 255 ).toInt() | 0;
			output[ idx + 2 ] = ( normal[ 2 ] * 255 ).toInt() | 0;
			output[ idx + 3 ] = 255;

		}

	}

	context.putImageData( imageData, 0, 0 );

	return canvas;

}

dynamic parseDDS(buffer, loadMipmaps) #

parseDDS( buffer, loadMipmaps ) {

 var dds = { "mipmaps": [], "width": 0, "height": 0, "format": null, "mipmapCount": 1 };

 // Adapted from @toji's DDS utils
 //  https://github.com/toji/webgl-texture-utils/blob/master/texture-util/dds.js

 // All values and structures referenced from:
 // http://msdn.microsoft.com/en-us/library/bb943991.aspx/

 var DDS_MAGIC = 0x20534444;

 var DDSD_CAPS = 0x1,
   DDSD_HEIGHT = 0x2,
   DDSD_WIDTH = 0x4,
   DDSD_PITCH = 0x8,
   DDSD_PIXELFORMAT = 0x1000,
   DDSD_MIPMAPCOUNT = 0x20000,
   DDSD_LINEARSIZE = 0x80000,
   DDSD_DEPTH = 0x800000;

 var DDSCAPS_COMPLEX = 0x8,
   DDSCAPS_MIPMAP = 0x400000,
   DDSCAPS_TEXTURE = 0x1000;

 var DDSCAPS2_CUBEMAP = 0x200,
   DDSCAPS2_CUBEMAP_POSITIVEX = 0x400,
   DDSCAPS2_CUBEMAP_NEGATIVEX = 0x800,
   DDSCAPS2_CUBEMAP_POSITIVEY = 0x1000,
   DDSCAPS2_CUBEMAP_NEGATIVEY = 0x2000,
   DDSCAPS2_CUBEMAP_POSITIVEZ = 0x4000,
   DDSCAPS2_CUBEMAP_NEGATIVEZ = 0x8000,
   DDSCAPS2_VOLUME = 0x200000;

 var DDPF_ALPHAPIXELS = 0x1,
   DDPF_ALPHA = 0x2,
   DDPF_FOURCC = 0x4,
   DDPF_RGB = 0x40,
   DDPF_YUV = 0x200,
   DDPF_LUMINANCE = 0x20000;

 fourCCToInt32( value ) {

   return value.charCodeAt(0) +
     (value.charCodeAt(1) << 8) +
     (value.charCodeAt(2) << 16) +
     (value.charCodeAt(3) << 24);

 }

 int32ToFourCC( value ) {

   return new String.fromCharCodes([
     value & 0xff,
     (value >> 8) & 0xff,
     (value >> 16) & 0xff,
     (value >> 24) & 0xff
   ]);
 }

 var FOURCC_DXT1 = fourCCToInt32("DXT1");
 var FOURCC_DXT3 = fourCCToInt32("DXT3");
 var FOURCC_DXT5 = fourCCToInt32("DXT5");

 var headerLengthInt = 31; // The header length in 32 bit ints

 // Offsets into the header array

 var off_magic = 0;

 var off_size = 1;
 var off_flags = 2;
 var off_height = 3;
 var off_width = 4;

 var off_mipmapCount = 7;

 var off_pfFlags = 20;
 var off_pfFourCC = 21;

 // Parse header

 var header = new Int32List.view(buffer, 0, headerLengthInt);

 if ( header[ off_magic ] != DDS_MAGIC ) {
     print( "ImageUtils.parseDDS(): Invalid magic number in DDS header" );
     return dds;
 }

 if ( (header[ off_pfFlags ] & DDPF_FOURCC) == 0 ) {
     print( "ImageUtils.parseDDS(): Unsupported format, must contain a FourCC code" );
     return dds;
 }

 var blockBytes;

 var fourCC = header[ off_pfFourCC ];

 if( fourCC == FOURCC_DXT1 ) {
     blockBytes = 8;
     dds["format"] = RGB_S3TC_DXT1_Format;
 } else if(fourCC == FOURCC_DXT3) {
     blockBytes = 16;
     dds["format"] = RGBA_S3TC_DXT3_Format;
 } else if(fourCC == FOURCC_DXT5) {
     blockBytes = 16;
     dds["format"] = RGBA_S3TC_DXT5_Format;
 } else {
     print( "ImageUtils.parseDDS(): Unsupported FourCC code: ${int32ToFourCC( fourCC )}" );
 }

 dds["mipmapCount"] = 1;

 if ( ( (header[ off_flags ] & DDSD_MIPMAPCOUNT) != 0) && (loadMipmaps != false) ) {
     dds["mipmapCount"] = Math.max( 1, header[ off_mipmapCount ] );
 }

 dds["width"] = header[ off_width ];
 dds["height"] = header[ off_height ];

 var dataOffset = header[ off_size ] + 4;

 // Extract mipmaps buffers

 var width = dds["width"];
 var height = dds["height"];

 for ( var i = 0; i < dds["mipmapCount"]; i ++ ) {

   int dataLength = Math.max( 4, width ) ~/ 4 * Math.max( 4, height ) ~/ 4 * blockBytes;
   var byteArray = new Uint8List.view(buffer, dataOffset, dataLength);

   var mipmap = { "data": byteArray, "width": width, "height": height };
   dds["mipmaps"].add( mipmap );

   dataOffset += dataLength;

   width = Math.max( width * 0.5, 1 );
   height = Math.max( height * 0.5, 1 );

 }

 return dds;

}

Texture loadTextureCube(array, [mapping = null, onLoad]) #

Texture loadTextureCube ( array, [mapping = null, onLoad ]) {

	var i, l;
	l = array.length;
	ImageList images = new ImageList(l);
	var texture = new Texture( images );
	mapping = (mapping == null)? texture.mapping:mapping;

	texture.flipY = false;

	images.loadCount = 0;

	for ( i = 0; i < l; ++ i ) {

		images[ i ] = new ImageElement();
		images[ i ].onLoad.listen((_) {

		  images.loadCount += 1;

			if ( images.loadCount == 6 ) {

				texture.needsUpdate = true;
				if ( onLoad != null ) onLoad();

			}

		});

		images[ i ].crossOrigin = crossOrigin;
		images[ i ].src = array[ i ];

	}

	return texture;

}

Texture loadCompressedTexture(url, {mapping, onLoad, onError}) #

Texture loadCompressedTexture( url, {mapping, onLoad, onError} ) {

 var texture = new CompressedTexture();
 texture.mapping = mapping;

 var request = new HttpRequest();

 request.onLoad.listen( (Event e) {

   var buffer = request.response;
   var dds = parseDDS( buffer, true );

   texture.format = dds["format"];

   texture.mipmaps = dds["mipmaps"];
   texture.image.width = dds["width"];
   texture.image.height = dds["height"];

   // gl.generateMipmap fails for compressed textures
   // mipmaps must be embedded in the DDS file
   // or texture filters must not use mipmapping

   texture.generateMipmaps = false;

   texture.needsUpdate = true;

   if ( onLoad ) onLoad( texture );

 });

 request.onError.listen(onError);

 request.open( 'GET', url, async: true );
 request.responseType = "arraybuffer";
 request.send( null );

 return texture;

}

Texture loadTexture(url, {mapping, onLoad, onError}) #

Texture loadTexture ( url, {mapping, onLoad, onError} ) {

	var image = new ImageElement();
	var texture = new Texture( image, mapping );

	var loader = new ImageLoader();

	loader.addEventListener( 'load',  ( event ) {

		texture.image = event.content;
		texture.needsUpdate = true;

		if ( onLoad != null ) onLoad( texture );

	} );

	loader.addEventListener( 'error',  ( event ) {

		if ( onError != null ) onError( event.message );

	} );

	loader.crossOrigin = crossOrigin;
	loader.load( url, image );

	return texture;

}