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; }