A lot of cleaning, and compilation of the js code

This commit is contained in:
Thomas FORGIONE
2015-05-22 16:59:33 +02:00
parent fe34290802
commit a6a6c3521c
45 changed files with 100 additions and 41 deletions

237
js/three/DDSLoader.js Normal file
View File

@@ -0,0 +1,237 @@
/*
* @author mrdoob / http://mrdoob.com/
*/
THREE.DDSLoader = function () {
this._parser = THREE.DDSLoader.parse;
};
THREE.DDSLoader.prototype = Object.create( THREE.CompressedTextureLoader.prototype );
THREE.DDSLoader.prototype.constructor = THREE.DDSLoader;
THREE.DDSLoader.parse = function ( 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;
function fourCCToInt32( value ) {
return value.charCodeAt(0) +
(value.charCodeAt(1) << 8) +
(value.charCodeAt(2) << 16) +
(value.charCodeAt(3) << 24);
}
function int32ToFourCC( value ) {
return String.fromCharCode(
value & 0xff,
(value >> 8) & 0xff,
(value >> 16) & 0xff,
(value >> 24) & 0xff
);
}
function loadARGBMip( buffer, dataOffset, width, height ) {
var dataLength = width * height * 4;
var srcBuffer = new Uint8Array( buffer, dataOffset, dataLength );
var byteArray = new Uint8Array( dataLength );
var dst = 0;
var src = 0;
for ( var y = 0; y < height; y ++ ) {
for ( var x = 0; x < width; x ++ ) {
var b = srcBuffer[src]; src ++;
var g = srcBuffer[src]; src ++;
var r = srcBuffer[src]; src ++;
var a = srcBuffer[src]; src ++;
byteArray[dst] = r; dst ++; //r
byteArray[dst] = g; dst ++; //g
byteArray[dst] = b; dst ++; //b
byteArray[dst] = a; dst ++; //a
}
}
return byteArray;
}
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;
var off_RGBBitCount = 22;
var off_RBitMask = 23;
var off_GBitMask = 24;
var off_BBitMask = 25;
var off_ABitMask = 26;
var off_caps = 27;
var off_caps2 = 28;
var off_caps3 = 29;
var off_caps4 = 30;
// Parse header
var header = new Int32Array( buffer, 0, headerLengthInt );
if ( header[ off_magic ] !== DDS_MAGIC ) {
console.error( 'THREE.DDSLoader.parse: Invalid magic number in DDS header.' );
return dds;
}
if ( ! header[ off_pfFlags ] & DDPF_FOURCC ) {
console.error( 'THREE.DDSLoader.parse: Unsupported format, must contain a FourCC code.' );
return dds;
}
var blockBytes;
var fourCC = header[ off_pfFourCC ];
var isRGBAUncompressed = false;
switch ( fourCC ) {
case FOURCC_DXT1:
blockBytes = 8;
dds.format = THREE.RGB_S3TC_DXT1_Format;
break;
case FOURCC_DXT3:
blockBytes = 16;
dds.format = THREE.RGBA_S3TC_DXT3_Format;
break;
case FOURCC_DXT5:
blockBytes = 16;
dds.format = THREE.RGBA_S3TC_DXT5_Format;
break;
default:
if ( header[off_RGBBitCount] == 32
&& header[off_RBitMask]&0xff0000
&& header[off_GBitMask]&0xff00
&& header[off_BBitMask]&0xff
&& header[off_ABitMask]&0xff000000 ) {
isRGBAUncompressed = true;
blockBytes = 64;
dds.format = THREE.RGBAFormat;
} else {
console.error( 'THREE.DDSLoader.parse: Unsupported FourCC code ', int32ToFourCC( fourCC ) );
return dds;
}
}
dds.mipmapCount = 1;
if ( header[ off_flags ] & DDSD_MIPMAPCOUNT && loadMipmaps !== false ) {
dds.mipmapCount = Math.max( 1, header[ off_mipmapCount ] );
}
//TODO: Verify that all faces of the cubemap are present with DDSCAPS2_CUBEMAP_POSITIVEX, etc.
dds.isCubemap = header[ off_caps2 ] & DDSCAPS2_CUBEMAP ? true : false;
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;
var faces = dds.isCubemap ? 6 : 1;
for ( var face = 0; face < faces; face ++ ) {
for ( var i = 0; i < dds.mipmapCount; i ++ ) {
if ( isRGBAUncompressed ) {
var byteArray = loadARGBMip( buffer, dataOffset, width, height );
var dataLength = byteArray.length;
} else {
var dataLength = Math.max( 4, width ) / 4 * Math.max( 4, height ) / 4 * blockBytes;
var byteArray = new Uint8Array( buffer, dataOffset, dataLength );
}
var mipmap = { "data": byteArray, "width": width, "height": height };
dds.mipmaps.push( mipmap );
dataOffset += dataLength;
width = Math.max( width * 0.5, 1 );
height = Math.max( height * 0.5, 1 );
}
width = dds.width;
height = dds.height;
}
return dds;
};

441
js/three/MTLLoader.js Normal file
View File

@@ -0,0 +1,441 @@
/**
* Loads a Wavefront .mtl file specifying materials
*
* @author angelxuanchang
*/
THREE.MTLLoader = function( baseUrl, options, crossOrigin ) {
this.baseUrl = baseUrl;
this.options = options;
this.crossOrigin = crossOrigin;
};
THREE.MTLLoader.prototype = {
constructor: THREE.MTLLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.XHRLoader();
loader.setCrossOrigin( this.crossOrigin );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
/**
* Parses loaded MTL file
* @param text - Content of MTL file
* @return {THREE.MTLLoader.MaterialCreator}
*/
parse: function ( text ) {
var lines = text.split( "\n" );
var info = {};
var delimiter_pattern = /\s+/;
var materialsInfo = {};
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
line = line.trim();
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
// Blank line or comment ignore
continue;
}
var pos = line.indexOf( ' ' );
var key = ( pos >= 0 ) ? line.substring( 0, pos ) : line;
key = key.toLowerCase();
var value = ( pos >= 0 ) ? line.substring( pos + 1 ) : "";
value = value.trim();
if ( key === "newmtl" ) {
// New material
info = { name: value };
materialsInfo[ value ] = info;
} else if ( info ) {
if ( key === "ka" || key === "kd" || key === "ks" ) {
var ss = value.split( delimiter_pattern, 3 );
info[ key ] = [ parseFloat( ss[0] ), parseFloat( ss[1] ), parseFloat( ss[2] ) ];
} else {
info[ key ] = value;
}
}
}
var materialCreator = new THREE.MTLLoader.MaterialCreator( this.baseUrl, this.options );
materialCreator.crossOrigin = this.crossOrigin
materialCreator.setMaterials( materialsInfo );
return materialCreator;
}
};
/**
* Create a new THREE-MTLLoader.MaterialCreator
* @param baseUrl - Url relative to which textures are loaded
* @param options - Set of options on how to construct the materials
* side: Which side to apply the material
* THREE.FrontSide (default), THREE.BackSide, THREE.DoubleSide
* wrap: What type of wrapping to apply for textures
* THREE.RepeatWrapping (default), THREE.ClampToEdgeWrapping, THREE.MirroredRepeatWrapping
* normalizeRGB: RGBs need to be normalized to 0-1 from 0-255
* Default: false, assumed to be already normalized
* ignoreZeroRGBs: Ignore values of RGBs (Ka,Kd,Ks) that are all 0's
* Default: false
* invertTransparency: If transparency need to be inverted (inversion is needed if d = 0 is fully opaque)
* Default: false (d = 1 is fully opaque)
* @constructor
*/
THREE.MTLLoader.MaterialCreator = function( baseUrl, options ) {
this.baseUrl = baseUrl;
this.options = options;
this.materialsInfo = {};
this.materials = {};
this.materialsArray = [];
this.nameLookup = {};
this.side = ( this.options && this.options.side ) ? this.options.side : THREE.FrontSide;
this.wrap = ( this.options && this.options.wrap ) ? this.options.wrap : THREE.RepeatWrapping;
};
THREE.MTLLoader.MaterialCreator.prototype = {
constructor: THREE.MTLLoader.MaterialCreator,
setMaterials: function( materialsInfo ) {
this.materialsInfo = this.convert( materialsInfo );
this.materials = {};
this.materialsArray = [];
this.nameLookup = {};
},
convert: function( materialsInfo ) {
if ( !this.options ) return materialsInfo;
var converted = {};
for ( var mn in materialsInfo ) {
// Convert materials info into normalized form based on options
var mat = materialsInfo[ mn ];
var covmat = {};
converted[ mn ] = covmat;
for ( var prop in mat ) {
var save = true;
var value = mat[ prop ];
var lprop = prop.toLowerCase();
switch ( lprop ) {
case 'kd':
case 'ka':
case 'ks':
// Diffuse color (color under white light) using RGB values
if ( this.options && this.options.normalizeRGB ) {
value = [ value[ 0 ] / 255, value[ 1 ] / 255, value[ 2 ] / 255 ];
}
if ( this.options && this.options.ignoreZeroRGBs ) {
if ( value[ 0 ] === 0 && value[ 1 ] === 0 && value[ 1 ] === 0 ) {
// ignore
save = false;
}
}
break;
case 'd':
// According to MTL format (http://paulbourke.net/dataformats/mtl/):
// d is dissolve for current material
// factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
if ( this.options && this.options.invertTransparency ) {
value = 1 - value;
}
break;
default:
break;
}
if ( save ) {
covmat[ lprop ] = value;
}
}
}
return converted;
},
preload: function () {
for ( var mn in this.materialsInfo ) {
this.create( mn );
}
},
getIndex: function( materialName ) {
return this.nameLookup[ materialName ];
},
getAsArray: function() {
var index = 0;
for ( var mn in this.materialsInfo ) {
this.materialsArray[ index ] = this.create( mn );
this.nameLookup[ mn ] = index;
index ++;
}
return this.materialsArray;
},
create: function ( materialName ) {
if ( this.materials[ materialName ] === undefined ) {
this.createMaterial_( materialName );
}
return this.materials[ materialName ];
},
createMaterial_: function ( materialName ) {
// Create material
var mat = this.materialsInfo[ materialName ];
var params = {
name: materialName,
side: this.side
};
for ( var prop in mat ) {
var value = mat[ prop ];
switch ( prop.toLowerCase() ) {
// Ns is material specular exponent
case 'kd':
// Diffuse color (color under white light) using RGB values
params[ 'diffuse' ] = new THREE.Color().fromArray( value );
break;
case 'ka':
// Ambient color (color under shadow) using RGB values
break;
case 'ks':
// Specular color (color when light is reflected from shiny surface) using RGB values
params[ 'specular' ] = new THREE.Color().fromArray( value );
break;
case 'map_kd':
// Diffuse texture map
params[ 'map' ] = this.loadTexture( this.baseUrl + value );
params[ 'map' ].wrapS = this.wrap;
params[ 'map' ].wrapT = this.wrap;
break;
case 'ns':
// The specular exponent (defines the focus of the specular highlight)
// A high exponent results in a tight, concentrated highlight. Ns values normally range from 0 to 1000.
params['shininess'] = value;
break;
case 'd':
// According to MTL format (http://paulbourke.net/dataformats/mtl/):
// d is dissolve for current material
// factor of 1.0 is fully opaque, a factor of 0 is fully dissolved (completely transparent)
if ( value < 1 ) {
params['transparent'] = true;
params['opacity'] = value;
}
break;
case 'map_bump':
case 'bump':
// Bump texture map
if ( params[ 'bumpMap' ] ) break; // Avoid loading twice.
params[ 'bumpMap' ] = this.loadTexture( this.baseUrl + value );
params[ 'bumpMap' ].wrapS = this.wrap;
params[ 'bumpMap' ].wrapT = this.wrap;
break;
default:
break;
}
}
if ( params[ 'diffuse' ] ) {
params[ 'color' ] = params[ 'diffuse' ];
}
this.materials[ materialName ] = new THREE.MeshPhongMaterial( params );
return this.materials[ materialName ];
},
loadTexture: function ( url, mapping, onLoad, onError ) {
var texture;
var loader = THREE.Loader.Handlers.get( url );
if ( loader !== null ) {
texture = loader.load( url, onLoad );
} else {
texture = new THREE.Texture();
loader = new THREE.ImageLoader();
loader.crossOrigin = this.crossOrigin;
loader.load( url, function ( image ) {
texture.image = THREE.MTLLoader.ensurePowerOfTwo_( image );
texture.needsUpdate = true;
if ( onLoad ) onLoad( texture );
} );
}
if ( mapping !== undefined ) texture.mapping = mapping;
return texture;
}
};
THREE.MTLLoader.ensurePowerOfTwo_ = function ( image ) {
if ( ! THREE.Math.isPowerOfTwo( image.width ) || ! THREE.Math.isPowerOfTwo( image.height ) ) {
var canvas = document.createElement( "canvas" );
canvas.width = THREE.MTLLoader.nextHighestPowerOfTwo_( image.width );
canvas.height = THREE.MTLLoader.nextHighestPowerOfTwo_( image.height );
var ctx = canvas.getContext("2d");
ctx.drawImage( image, 0, 0, image.width, image.height, 0, 0, canvas.width, canvas.height );
return canvas;
}
return image;
};
THREE.MTLLoader.nextHighestPowerOfTwo_ = function( x ) {
-- x;
for ( var i = 1; i < 32; i <<= 1 ) {
x = x | x >> i;
}
return x + 1;
};
THREE.EventDispatcher.prototype.apply( THREE.MTLLoader.prototype );

372
js/three/OBJLoader.js Normal file
View File

@@ -0,0 +1,372 @@
/**
* @author mrdoob / http://mrdoob.com/
*/
THREE.OBJLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.OBJLoader.prototype = {
constructor: THREE.OBJLoader,
load: function ( url, onLoad, onProgress, onError ) {
var scope = this;
var loader = new THREE.XHRLoader( scope.manager );
loader.setCrossOrigin( this.crossOrigin );
loader.load( url, function ( text ) {
onLoad( scope.parse( text ) );
}, onProgress, onError );
},
parse: function ( text ) {
console.time( 'OBJLoader' );
var object, objects = [];
var geometry, material;
function parseVertexIndex( value ) {
var index = parseInt( value );
return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3;
}
function parseNormalIndex( value ) {
var index = parseInt( value );
return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3;
}
function parseUVIndex( value ) {
var index = parseInt( value );
return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2;
}
function addVertex( a, b, c ) {
geometry.vertices.push(
vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ],
vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ],
vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ]
);
}
function addNormal( a, b, c ) {
geometry.normals.push(
normals[ a ], normals[ a + 1 ], normals[ a + 2 ],
normals[ b ], normals[ b + 1 ], normals[ b + 2 ],
normals[ c ], normals[ c + 1 ], normals[ c + 2 ]
);
}
function addUV( a, b, c ) {
geometry.uvs.push(
uvs[ a ], uvs[ a + 1 ],
uvs[ b ], uvs[ b + 1 ],
uvs[ c ], uvs[ c + 1 ]
);
}
function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
var ia = parseVertexIndex( a );
var ib = parseVertexIndex( b );
var ic = parseVertexIndex( c );
var id;
if ( d === undefined ) {
addVertex( ia, ib, ic );
} else {
id = parseVertexIndex( d );
addVertex( ia, ib, id );
addVertex( ib, ic, id );
}
if ( ua !== undefined ) {
ia = parseUVIndex( ua );
ib = parseUVIndex( ub );
ic = parseUVIndex( uc );
if ( d === undefined ) {
addUV( ia, ib, ic );
} else {
id = parseUVIndex( ud );
addUV( ia, ib, id );
addUV( ib, ic, id );
}
}
if ( na !== undefined ) {
ia = parseNormalIndex( na );
ib = parseNormalIndex( nb );
ic = parseNormalIndex( nc );
if ( d === undefined ) {
addNormal( ia, ib, ic );
} else {
id = parseNormalIndex( nd );
addNormal( ia, ib, id );
addNormal( ib, ic, id );
}
}
}
// create mesh if no objects in text
if ( /^o /gm.test( text ) === false ) {
geometry = {
vertices: [],
normals: [],
uvs: []
};
material = {
name: ''
};
object = {
name: '',
geometry: geometry,
material: material
};
objects.push( object );
}
var vertices = [];
var normals = [];
var uvs = [];
// v float float float
var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// vn float float float
var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// vt float float
var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
// f vertex vertex vertex ...
var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/;
// f vertex/uv vertex/uv vertex/uv ...
var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/;
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/;
// f vertex//normal vertex//normal vertex//normal ...
var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/
//
var lines = text.split( '\n' );
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
line = line.trim();
var result;
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
continue;
} else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
vertices.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
} else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
normals.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
);
} else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
// ["vt 0.1 0.2", "0.1", "0.2"]
uvs.push(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] )
);
} else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
// ["f 1 2 3", "1", "2", "3", undefined]
addFace(
result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
);
} else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
addFace(
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
} else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
addFace(
result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ],
result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ],
result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ]
);
} else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
addFace(
result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
undefined, undefined, undefined, undefined,
result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
);
} else if ( /^o /.test( line ) ) {
geometry = {
vertices: [],
normals: [],
uvs: []
};
material = {
name: ''
};
object = {
name: line.substring( 2 ).trim(),
geometry: geometry,
material: material
};
objects.push( object )
} else if ( /^g /.test( line ) ) {
// group
} else if ( /^usemtl /.test( line ) ) {
// material
material.name = line.substring( 7 ).trim();
} else if ( /^mtllib /.test( line ) ) {
// mtl file
} else if ( /^s /.test( line ) ) {
// smooth shading
} else {
// console.log( "THREE.OBJLoader: Unhandled line " + line );
}
}
var container = new THREE.Object3D();
for ( var i = 0, l = objects.length; i < l; i ++ ) {
object = objects[ i ];
geometry = object.geometry;
var buffergeometry = new THREE.BufferGeometry();
buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
if ( geometry.normals.length > 0 ) {
buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
}
if ( geometry.uvs.length > 0 ) {
buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
}
material = new THREE.MeshLambertMaterial();
material.name = object.material.name;
var mesh = new THREE.Mesh( buffergeometry, material );
mesh.name = object.name;
container.add( mesh );
}
console.timeEnd( 'OBJLoader' );
return container;
}
};

365
js/three/OBJMTLLoader.js Normal file
View File

@@ -0,0 +1,365 @@
/**
* Loads a Wavefront .obj file with materials
*
* @author mrdoob / http://mrdoob.com/
* @author angelxuanchang
*/
THREE.OBJMTLLoader = function ( manager ) {
this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
};
THREE.OBJMTLLoader.prototype = {
constructor: THREE.OBJMTLLoader,
load: function ( url, mtlurl, onLoad, onProgress, onError ) {
var scope = this;
var mtlLoader = new THREE.MTLLoader( url.substr( 0, url.lastIndexOf( "/" ) + 1 ) );
mtlLoader.crossOrigin = scope.crossOrigin;
mtlLoader.load( mtlurl, function ( materials ) {
var materialsCreator = materials;
materialsCreator.preload();
var loader = new THREE.XHRLoader( scope.manager );
loader.setCrossOrigin( scope.crossOrigin );
loader.load( url, function ( text ) {
var object = scope.parse( text );
object.traverse( function ( object ) {
if ( object instanceof THREE.Mesh ) {
if ( object.material.name ) {
var material = materialsCreator.create( object.material.name );
if ( material ) object.material = material;
}
}
} );
onLoad( object );
}, onProgress, onError );
}, onProgress, onError );
},
/**
* Parses loaded .obj file
* @param data - content of .obj file
* @param mtllibCallback - callback to handle mtllib declaration (optional)
* @return {THREE.Object3D} - Object3D (with default material)
*/
parse: function ( data, mtllibCallback ) {
function vector( x, y, z ) {
return new THREE.Vector3( x, y, z );
}
function uv( u, v ) {
return new THREE.Vector2( u, v );
}
function face3( a, b, c, normals ) {
return new THREE.Face3( a, b, c, normals );
}
var face_offset = 0;
function meshN( meshName, materialName ) {
if ( vertices.length > 0 ) {
geometry.vertices = vertices;
geometry.mergeVertices();
geometry.computeFaceNormals();
geometry.computeBoundingSphere();
object.add( mesh );
geometry = new THREE.Geometry();
mesh = new THREE.Mesh( geometry, material );
}
if ( meshName !== undefined ) mesh.name = meshName;
if ( materialName !== undefined ) {
material = new THREE.MeshLambertMaterial();
material.name = materialName;
mesh.material = material;
}
}
var group = new THREE.Group();
var object = group;
var geometry = new THREE.Geometry();
var material = new THREE.MeshLambertMaterial();
var mesh = new THREE.Mesh( geometry, material );
var vertices = [];
var normals = [];
var uvs = [];
function add_face( a, b, c, normals_inds ) {
if ( normals_inds === undefined ) {
geometry.faces.push( face3(
parseInt( a ) - (face_offset + 1),
parseInt( b ) - (face_offset + 1),
parseInt( c ) - (face_offset + 1)
) );
} else {
geometry.faces.push( face3(
parseInt( a ) - (face_offset + 1),
parseInt( b ) - (face_offset + 1),
parseInt( c ) - (face_offset + 1),
[
normals[ parseInt( normals_inds[ 0 ] ) - 1 ].clone(),
normals[ parseInt( normals_inds[ 1 ] ) - 1 ].clone(),
normals[ parseInt( normals_inds[ 2 ] ) - 1 ].clone()
]
) );
}
}
function add_uvs( a, b, c ) {
geometry.faceVertexUvs[ 0 ].push( [
uvs[ parseInt( a ) - 1 ].clone(),
uvs[ parseInt( b ) - 1 ].clone(),
uvs[ parseInt( c ) - 1 ].clone()
] );
}
function handle_face_line(faces, uvs, normals_inds) {
if ( faces[ 3 ] === undefined ) {
add_face( faces[ 0 ], faces[ 1 ], faces[ 2 ], normals_inds );
if (!(uvs === undefined) && uvs.length > 0) {
add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 2 ] );
}
} else {
if (!(normals_inds === undefined) && normals_inds.length > 0) {
add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ], [ normals_inds[ 0 ], normals_inds[ 1 ], normals_inds[ 3 ] ]);
add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ], [ normals_inds[ 1 ], normals_inds[ 2 ], normals_inds[ 3 ] ]);
} else {
add_face( faces[ 0 ], faces[ 1 ], faces[ 3 ]);
add_face( faces[ 1 ], faces[ 2 ], faces[ 3 ]);
}
if (!(uvs === undefined) && uvs.length > 0) {
add_uvs( uvs[ 0 ], uvs[ 1 ], uvs[ 3 ] );
add_uvs( uvs[ 1 ], uvs[ 2 ], uvs[ 3 ] );
}
}
}
// v float float float
var vertex_pattern = /v( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/;
// vn float float float
var normal_pattern = /vn( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/;
// vt float float
var uv_pattern = /vt( +[\d|\.|\+|\-|e]+)( +[\d|\.|\+|\-|e]+)/;
// f vertex vertex vertex ...
var face_pattern1 = /f( +\d+)( +\d+)( +\d+)( +\d+)?/;
// f vertex/uv vertex/uv vertex/uv ...
var face_pattern2 = /f( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))( +(\d+)\/(\d+))?/;
// f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
var face_pattern3 = /f( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))( +(\d+)\/(\d+)\/(\d+))?/;
// f vertex//normal vertex//normal vertex//normal ...
var face_pattern4 = /f( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))( +(\d+)\/\/(\d+))?/
//
var lines = data.split( "\n" );
for ( var i = 0; i < lines.length; i ++ ) {
var line = lines[ i ];
line = line.trim();
var result;
if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
continue;
} else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
// ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
vertices.push( vector(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
) );
} else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
// ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
normals.push( vector(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] ),
parseFloat( result[ 3 ] )
) );
} else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
// ["vt 0.1 0.2", "0.1", "0.2"]
uvs.push( uv(
parseFloat( result[ 1 ] ),
parseFloat( result[ 2 ] )
) );
} else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
// ["f 1 2 3", "1", "2", "3", undefined]
handle_face_line([ result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ] ]);
} else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
// ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
handle_face_line(
[ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces
[ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //uv
);
} else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
// ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
handle_face_line(
[ result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ] ], //faces
[ result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ] ], //uv
[ result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ] ] //normal
);
} else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
// ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
handle_face_line(
[ result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ] ], //faces
[ ], //uv
[ result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ] ] //normal
);
} else if ( /^o /.test( line ) ) {
// object
meshN();
face_offset = face_offset + vertices.length;
vertices = [];
object = new THREE.Object3D();
object.name = line.substring( 2 ).trim();
group.add( object );
} else if ( /^g /.test( line ) ) {
// group
meshN( line.substring( 2 ).trim(), undefined );
} else if ( /^usemtl /.test( line ) ) {
// material
meshN( undefined, line.substring( 7 ).trim() );
} else if ( /^mtllib /.test( line ) ) {
// mtl file
if ( mtllibCallback ) {
var mtlfile = line.substring( 7 );
mtlfile = mtlfile.trim();
mtllibCallback( mtlfile );
}
} else if ( /^s /.test( line ) ) {
// Smooth shading
} else {
console.log( "THREE.OBJMTLLoader: Unhandled line " + line );
}
}
//Add last object
meshN(undefined, undefined);
return group;
}
};
THREE.EventDispatcher.prototype.apply( THREE.OBJMTLLoader.prototype );

706
js/three/OrbitControls.js Normal file
View File

@@ -0,0 +1,706 @@
/**
* @author qiao / https://github.com/qiao
* @author mrdoob / http://mrdoob.com
* @author alteredq / http://alteredqualia.com/
* @author WestLangley / http://github.com/WestLangley
* @author erich666 / http://erichaines.com
*/
/*global THREE, console */
// This set of controls performs orbiting, dollying (zooming), and panning. It maintains
// the "up" direction as +Y, unlike the TrackballControls. Touch on tablet and phones is
// supported.
//
// Orbit - left mouse / touch: one finger move
// Zoom - middle mouse, or mousewheel / touch: two finger spread or squish
// Pan - right mouse, or arrow keys / touch: three finter swipe
THREE.OrbitControls = function ( object, domElement ) {
this.object = object;
this.domElement = ( domElement !== undefined ) ? domElement : document;
// API
// Set to false to disable this control
this.enabled = true;
// "target" sets the location of focus, where the control orbits around
// and where it pans with respect to.
this.target = new THREE.Vector3();
// center is old, deprecated; use "target" instead
this.center = this.target;
// This option actually enables dollying in and out; left as "zoom" for
// backwards compatibility
this.noZoom = false;
this.zoomSpeed = 1.0;
// Limits to how far you can dolly in and out ( PerspectiveCamera only )
this.minDistance = 0;
this.maxDistance = Infinity;
// Limits to how far you can zoom in and out ( OrthographicCamera only )
this.minZoom = 0;
this.maxZoom = Infinity;
// Set to true to disable this control
this.noRotate = false;
this.rotateSpeed = 1.0;
// Set to true to disable this control
this.noPan = false;
this.keyPanSpeed = 7.0; // pixels moved per arrow key push
// Set to true to automatically rotate around the target
this.autoRotate = false;
this.autoRotateSpeed = 2.0; // 30 seconds per round when fps is 60
// How far you can orbit vertically, upper and lower limits.
// Range is 0 to Math.PI radians.
this.minPolarAngle = 0; // radians
this.maxPolarAngle = Math.PI; // radians
// How far you can orbit horizontally, upper and lower limits.
// If set, must be a sub-interval of the interval [ - Math.PI, Math.PI ].
this.minAzimuthAngle = - Infinity; // radians
this.maxAzimuthAngle = Infinity; // radians
// Set to true to disable use of the keys
this.noKeys = false;
// The four arrow keys
this.keys = { LEFT: 37, UP: 38, RIGHT: 39, BOTTOM: 40 };
// Mouse buttons
this.mouseButtons = { ORBIT: THREE.MOUSE.LEFT, ZOOM: THREE.MOUSE.MIDDLE, PAN: THREE.MOUSE.RIGHT };
////////////
// internals
var scope = this;
var EPS = 0.000001;
var rotateStart = new THREE.Vector2();
var rotateEnd = new THREE.Vector2();
var rotateDelta = new THREE.Vector2();
var panStart = new THREE.Vector2();
var panEnd = new THREE.Vector2();
var panDelta = new THREE.Vector2();
var panOffset = new THREE.Vector3();
var offset = new THREE.Vector3();
var dollyStart = new THREE.Vector2();
var dollyEnd = new THREE.Vector2();
var dollyDelta = new THREE.Vector2();
var theta;
var phi;
var phiDelta = 0;
var thetaDelta = 0;
var scale = 1;
var pan = new THREE.Vector3();
var lastPosition = new THREE.Vector3();
var lastQuaternion = new THREE.Quaternion();
var STATE = { NONE : -1, ROTATE : 0, DOLLY : 1, PAN : 2, TOUCH_ROTATE : 3, TOUCH_DOLLY : 4, TOUCH_PAN : 5 };
var state = STATE.NONE;
// for reset
this.target0 = this.target.clone();
this.position0 = this.object.position.clone();
this.zoom0 = this.object.zoom;
// so camera.up is the orbit axis
var quat = new THREE.Quaternion().setFromUnitVectors( object.up, new THREE.Vector3( 0, 1, 0 ) );
var quatInverse = quat.clone().inverse();
// events
var changeEvent = { type: 'change' };
var startEvent = { type: 'start' };
var endEvent = { type: 'end' };
this.rotateLeft = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
thetaDelta -= angle;
};
this.rotateUp = function ( angle ) {
if ( angle === undefined ) {
angle = getAutoRotationAngle();
}
phiDelta -= angle;
};
// pass in distance in world space to move left
this.panLeft = function ( distance ) {
var te = this.object.matrix.elements;
// get X column of matrix
panOffset.set( te[ 0 ], te[ 1 ], te[ 2 ] );
panOffset.multiplyScalar( - distance );
pan.add( panOffset );
};
// pass in distance in world space to move up
this.panUp = function ( distance ) {
var te = this.object.matrix.elements;
// get Y column of matrix
panOffset.set( te[ 4 ], te[ 5 ], te[ 6 ] );
panOffset.multiplyScalar( distance );
pan.add( panOffset );
};
// pass in x,y of change desired in pixel space,
// right and down are positive
this.pan = function ( deltaX, deltaY ) {
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
if ( scope.object instanceof THREE.PerspectiveCamera ) {
// perspective
var position = scope.object.position;
var offset = position.clone().sub( scope.target );
var targetDistance = offset.length();
// half of the fov is center to top of screen
targetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );
// we actually don't use screenWidth, since perspective camera is fixed to screen height
scope.panLeft( 2 * deltaX * targetDistance / element.clientHeight );
scope.panUp( 2 * deltaY * targetDistance / element.clientHeight );
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
// orthographic
scope.panLeft( deltaX * (scope.object.right - scope.object.left) / element.clientWidth );
scope.panUp( deltaY * (scope.object.top - scope.object.bottom) / element.clientHeight );
} else {
// camera neither orthographic or perspective
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );
}
};
this.dollyIn = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
if ( scope.object instanceof THREE.PerspectiveCamera ) {
scale /= dollyScale;
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom * dollyScale ) );
scope.object.updateProjectionMatrix();
scope.dispatchEvent( changeEvent );
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
}
};
this.dollyOut = function ( dollyScale ) {
if ( dollyScale === undefined ) {
dollyScale = getZoomScale();
}
if ( scope.object instanceof THREE.PerspectiveCamera ) {
scale *= dollyScale;
} else if ( scope.object instanceof THREE.OrthographicCamera ) {
scope.object.zoom = Math.max( this.minZoom, Math.min( this.maxZoom, this.object.zoom / dollyScale ) );
scope.object.updateProjectionMatrix();
scope.dispatchEvent( changeEvent );
} else {
console.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );
}
};
this.update = function () {
var position = this.object.position;
offset.copy( position ).sub( this.target );
// rotate offset to "y-axis-is-up" space
offset.applyQuaternion( quat );
// angle from z-axis around y-axis
theta = Math.atan2( offset.x, offset.z );
// angle from y-axis
phi = Math.atan2( Math.sqrt( offset.x * offset.x + offset.z * offset.z ), offset.y );
if ( this.autoRotate && state === STATE.NONE ) {
this.rotateLeft( getAutoRotationAngle() );
}
theta += thetaDelta;
phi += phiDelta;
// restrict theta to be between desired limits
theta = Math.max( this.minAzimuthAngle, Math.min( this.maxAzimuthAngle, theta ) );
// restrict phi to be between desired limits
phi = Math.max( this.minPolarAngle, Math.min( this.maxPolarAngle, phi ) );
// restrict phi to be betwee EPS and PI-EPS
phi = Math.max( EPS, Math.min( Math.PI - EPS, phi ) );
var radius = offset.length() * scale;
// restrict radius to be between desired limits
radius = Math.max( this.minDistance, Math.min( this.maxDistance, radius ) );
// move target to panned location
this.target.add( pan );
offset.x = radius * Math.sin( phi ) * Math.sin( theta );
offset.y = radius * Math.cos( phi );
offset.z = radius * Math.sin( phi ) * Math.cos( theta );
// rotate offset back to "camera-up-vector-is-up" space
offset.applyQuaternion( quatInverse );
position.copy( this.target ).add( offset );
this.object.lookAt( this.target );
thetaDelta = 0;
phiDelta = 0;
scale = 1;
pan.set( 0, 0, 0 );
// update condition is:
// min(camera displacement, camera rotation in radians)^2 > EPS
// using small-angle approximation cos(x/2) = 1 - x^2 / 8
if ( lastPosition.distanceToSquared( this.object.position ) > EPS
|| 8 * (1 - lastQuaternion.dot(this.object.quaternion)) > EPS ) {
this.dispatchEvent( changeEvent );
lastPosition.copy( this.object.position );
lastQuaternion.copy (this.object.quaternion );
}
};
this.reset = function () {
state = STATE.NONE;
this.target.copy( this.target0 );
this.object.position.copy( this.position0 );
this.object.zoom = this.zoom0;
this.object.updateProjectionMatrix();
this.dispatchEvent( changeEvent );
this.update();
};
this.getPolarAngle = function () {
return phi;
};
this.getAzimuthalAngle = function () {
return theta
};
function getAutoRotationAngle() {
return 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;
}
function getZoomScale() {
return Math.pow( 0.95, scope.zoomSpeed );
}
function onMouseDown( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
if ( event.button === scope.mouseButtons.ORBIT ) {
if ( scope.noRotate === true ) return;
state = STATE.ROTATE;
rotateStart.set( event.clientX, event.clientY );
} else if ( event.button === scope.mouseButtons.ZOOM ) {
if ( scope.noZoom === true ) return;
state = STATE.DOLLY;
dollyStart.set( event.clientX, event.clientY );
} else if ( event.button === scope.mouseButtons.PAN ) {
if ( scope.noPan === true ) return;
state = STATE.PAN;
panStart.set( event.clientX, event.clientY );
}
if ( state !== STATE.NONE ) {
document.addEventListener( 'mousemove', onMouseMove, false );
document.addEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( startEvent );
}
}
function onMouseMove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
if ( state === STATE.ROTATE ) {
if ( scope.noRotate === true ) return;
rotateEnd.set( event.clientX, event.clientY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
} else if ( state === STATE.DOLLY ) {
if ( scope.noZoom === true ) return;
dollyEnd.set( event.clientX, event.clientY );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyIn();
} else if ( dollyDelta.y < 0 ) {
scope.dollyOut();
}
dollyStart.copy( dollyEnd );
} else if ( state === STATE.PAN ) {
if ( scope.noPan === true ) return;
panEnd.set( event.clientX, event.clientY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
}
if ( state !== STATE.NONE ) scope.update();
}
function onMouseUp( /* event */ ) {
if ( scope.enabled === false ) return;
document.removeEventListener( 'mousemove', onMouseMove, false );
document.removeEventListener( 'mouseup', onMouseUp, false );
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
function onMouseWheel( event ) {
if ( scope.enabled === false || scope.noZoom === true || state !== STATE.NONE ) return;
event.preventDefault();
event.stopPropagation();
var delta = 0;
if ( event.wheelDelta !== undefined ) { // WebKit / Opera / Explorer 9
delta = event.wheelDelta;
} else if ( event.detail !== undefined ) { // Firefox
delta = - event.detail;
}
if ( delta > 0 ) {
scope.dollyOut();
} else if ( delta < 0 ) {
scope.dollyIn();
}
scope.update();
scope.dispatchEvent( startEvent );
scope.dispatchEvent( endEvent );
}
function onKeyDown( event ) {
if ( scope.enabled === false || scope.noKeys === true || scope.noPan === true ) return;
switch ( event.keyCode ) {
case scope.keys.UP:
scope.pan( 0, scope.keyPanSpeed );
scope.update();
break;
case scope.keys.BOTTOM:
scope.pan( 0, - scope.keyPanSpeed );
scope.update();
break;
case scope.keys.LEFT:
scope.pan( scope.keyPanSpeed, 0 );
scope.update();
break;
case scope.keys.RIGHT:
scope.pan( - scope.keyPanSpeed, 0 );
scope.update();
break;
}
}
function touchstart( event ) {
if ( scope.enabled === false ) return;
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) return;
state = STATE.TOUCH_ROTATE;
rotateStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) return;
state = STATE.TOUCH_DOLLY;
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyStart.set( 0, distance );
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) return;
state = STATE.TOUCH_PAN;
panStart.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
break;
default:
state = STATE.NONE;
}
if ( state !== STATE.NONE ) scope.dispatchEvent( startEvent );
}
function touchmove( event ) {
if ( scope.enabled === false ) return;
event.preventDefault();
event.stopPropagation();
var element = scope.domElement === document ? scope.domElement.body : scope.domElement;
switch ( event.touches.length ) {
case 1: // one-fingered touch: rotate
if ( scope.noRotate === true ) return;
if ( state !== STATE.TOUCH_ROTATE ) return;
rotateEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
rotateDelta.subVectors( rotateEnd, rotateStart );
// rotating across whole screen goes 360 degrees around
scope.rotateLeft( 2 * Math.PI * rotateDelta.x / element.clientWidth * scope.rotateSpeed );
// rotating up and down along whole screen attempts to go 360, but limited to 180
scope.rotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight * scope.rotateSpeed );
rotateStart.copy( rotateEnd );
scope.update();
break;
case 2: // two-fingered touch: dolly
if ( scope.noZoom === true ) return;
if ( state !== STATE.TOUCH_DOLLY ) return;
var dx = event.touches[ 0 ].pageX - event.touches[ 1 ].pageX;
var dy = event.touches[ 0 ].pageY - event.touches[ 1 ].pageY;
var distance = Math.sqrt( dx * dx + dy * dy );
dollyEnd.set( 0, distance );
dollyDelta.subVectors( dollyEnd, dollyStart );
if ( dollyDelta.y > 0 ) {
scope.dollyOut();
} else if ( dollyDelta.y < 0 ) {
scope.dollyIn();
}
dollyStart.copy( dollyEnd );
scope.update();
break;
case 3: // three-fingered touch: pan
if ( scope.noPan === true ) return;
if ( state !== STATE.TOUCH_PAN ) return;
panEnd.set( event.touches[ 0 ].pageX, event.touches[ 0 ].pageY );
panDelta.subVectors( panEnd, panStart );
scope.pan( panDelta.x, panDelta.y );
panStart.copy( panEnd );
scope.update();
break;
default:
state = STATE.NONE;
}
}
function touchend( /* event */ ) {
if ( scope.enabled === false ) return;
scope.dispatchEvent( endEvent );
state = STATE.NONE;
}
this.domElement.addEventListener( 'contextmenu', function ( event ) { event.preventDefault(); }, false );
this.domElement.addEventListener( 'mousedown', onMouseDown, false );
this.domElement.addEventListener( 'mousewheel', onMouseWheel, false );
this.domElement.addEventListener( 'DOMMouseScroll', onMouseWheel, false ); // firefox
this.domElement.addEventListener( 'touchstart', touchstart, false );
this.domElement.addEventListener( 'touchend', touchend, false );
this.domElement.addEventListener( 'touchmove', touchmove, false );
window.addEventListener( 'keydown', onKeyDown, false );
// force an update at start
this.update();
};
THREE.OrbitControls.prototype = Object.create( THREE.EventDispatcher.prototype );
THREE.OrbitControls.prototype.constructor = THREE.OrbitControls;

6
js/three/stats.min.js vendored Normal file
View File

@@ -0,0 +1,6 @@
// stats.js - http://github.com/mrdoob/stats.js
var Stats=function(){var l=Date.now(),m=l,g=0,n=Infinity,o=0,h=0,p=Infinity,q=0,r=0,s=0,f=document.createElement("div");f.id="stats";f.addEventListener("mousedown",function(b){b.preventDefault();t(++s%2)},!1);f.style.cssText="width:80px;opacity:0.9;cursor:pointer";var a=document.createElement("div");a.id="fps";a.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#002";f.appendChild(a);var i=document.createElement("div");i.id="fpsText";i.style.cssText="color:#0ff;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";
i.innerHTML="FPS";a.appendChild(i);var c=document.createElement("div");c.id="fpsGraph";c.style.cssText="position:relative;width:74px;height:30px;background-color:#0ff";for(a.appendChild(c);74>c.children.length;){var j=document.createElement("span");j.style.cssText="width:1px;height:30px;float:left;background-color:#113";c.appendChild(j)}var d=document.createElement("div");d.id="ms";d.style.cssText="padding:0 0 3px 3px;text-align:left;background-color:#020;display:none";f.appendChild(d);var k=document.createElement("div");
k.id="msText";k.style.cssText="color:#0f0;font-family:Helvetica,Arial,sans-serif;font-size:9px;font-weight:bold;line-height:15px";k.innerHTML="MS";d.appendChild(k);var e=document.createElement("div");e.id="msGraph";e.style.cssText="position:relative;width:74px;height:30px;background-color:#0f0";for(d.appendChild(e);74>e.children.length;)j=document.createElement("span"),j.style.cssText="width:1px;height:30px;float:left;background-color:#131",e.appendChild(j);var t=function(b){s=b;switch(s){case 0:a.style.display=
"block";d.style.display="none";break;case 1:a.style.display="none",d.style.display="block"}};return{REVISION:12,domElement:f,setMode:t,begin:function(){l=Date.now()},end:function(){var b=Date.now();g=b-l;n=Math.min(n,g);o=Math.max(o,g);k.textContent=g+" MS ("+n+"-"+o+")";var a=Math.min(30,30-30*(g/200));e.appendChild(e.firstChild).style.height=a+"px";r++;b>m+1E3&&(h=Math.round(1E3*r/(b-m)),p=Math.min(p,h),q=Math.max(q,h),i.textContent=h+" FPS ("+p+"-"+q+")",a=Math.min(30,30-30*(h/100)),c.appendChild(c.firstChild).style.height=
a+"px",m=b,r=0);return b},update:function(){l=this.end()}}};"object"===typeof module&&(module.exports=Stats);

835
js/three/three.min.js vendored Normal file

File diff suppressed because one or more lines are too long