BufferGeometry.js 20.9 KB
Newer Older
1 2 3 4 5 6
/**
 * @author alteredq / http://alteredqualia.com/
 */

THREE.BufferGeometry = function () {

7 8
	this.id = THREE.GeometryIdCount ++;
	this.uuid = THREE.Math.generateUUID();
9

M
Mr.doob 已提交
10
	this.name = '';
11
	this.type = 'BufferGeometry';
M
Mr.doob 已提交
12

13
	this.attributes = {};
14 15
	this.drawcalls = [];
	this.offsets = this.drawcalls; // backwards compatibility
16

17 18 19 20 21 22 23
	this.boundingBox = null;
	this.boundingSphere = null;

};

THREE.BufferGeometry.prototype = {

24
	constructor: THREE.BufferGeometry,
25

M
Mr.doob 已提交
26
	addAttribute: function ( name, attribute ) {
27

28 29
		if ( attribute instanceof THREE.BufferAttribute === false ) {

30
			console.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
31 32 33 34 35 36 37

			this.attributes[ name ] = { array: arguments[ 1 ], itemSize: arguments[ 2 ] };

			return;

		}

M
Mr.doob 已提交
38
		this.attributes[ name ] = attribute;
39

M
Mr.doob 已提交
40 41 42 43
	},

	getAttribute: function ( name ) {

44 45
		return this.attributes[ name ];

46 47
	},

M
Mr.doob 已提交
48 49
	addDrawCall: function ( start, count, indexOffset ) {

50
		this.drawcalls.push( {
M
Mr.doob 已提交
51 52 53

			start: start,
			count: count,
M
Mr.doob 已提交
54
			index: indexOffset !== undefined ? indexOffset : 0
M
Mr.doob 已提交
55 56 57 58 59

		} );

	},

60 61
	applyMatrix: function ( matrix ) {

M
Mr.doob 已提交
62
		var position = this.attributes.position;
63

M
Mr.doob 已提交
64
		if ( position !== undefined ) {
65

66
			matrix.applyToVector3Array( position.array );
M
Mr.doob 已提交
67
			position.needsUpdate = true;
68 69 70

		}

M
Mr.doob 已提交
71
		var normal = this.attributes.normal;
72

M
Mr.doob 已提交
73
		if ( normal !== undefined ) {
74

M
Mr.doob 已提交
75
			var normalMatrix = new THREE.Matrix3().getNormalMatrix( matrix );
76

77
			normalMatrix.applyToVector3Array( normal.array );
M
Mr.doob 已提交
78
			normal.needsUpdate = true;
79 80 81 82 83

		}

	},

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
	fromGeometry: function ( geometry, settings ) {

		settings = settings || { 'vertexColors': THREE.NoColors };

		var vertices = geometry.vertices;
		var faces = geometry.faces;
		var faceVertexUvs = geometry.faceVertexUvs;
		var vertexColors = settings.vertexColors;
		var hasFaceVertexUv = faceVertexUvs[ 0 ].length > 0;
		var hasFaceVertexNormals = faces[ 0 ].vertexNormals.length == 3;

		var positions = new Float32Array( faces.length * 3 * 3 );
		this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ) );

		var normals = new Float32Array( faces.length * 3 * 3 );
		this.addAttribute( 'normal', new THREE.BufferAttribute( normals, 3 ) );

		if ( vertexColors !== THREE.NoColors ) {

			var colors = new Float32Array( faces.length * 3 * 3 );
			this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ) );

		}

		if ( hasFaceVertexUv === true ) {

			var uvs = new Float32Array( faces.length * 3 * 2 );
111
			this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
112 113 114 115 116 117 118 119 120 121 122 123 124 125

		}

		for ( var i = 0, i2 = 0, i3 = 0; i < faces.length; i ++, i2 += 6, i3 += 9 ) {

			var face = faces[ i ];

			var a = vertices[ face.a ];
			var b = vertices[ face.b ];
			var c = vertices[ face.c ];

			positions[ i3     ] = a.x;
			positions[ i3 + 1 ] = a.y;
			positions[ i3 + 2 ] = a.z;
126

127 128 129
			positions[ i3 + 3 ] = b.x;
			positions[ i3 + 4 ] = b.y;
			positions[ i3 + 5 ] = b.z;
130

131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214
			positions[ i3 + 6 ] = c.x;
			positions[ i3 + 7 ] = c.y;
			positions[ i3 + 8 ] = c.z;

			if ( hasFaceVertexNormals === true ) {

				var na = face.vertexNormals[ 0 ];
				var nb = face.vertexNormals[ 1 ];
				var nc = face.vertexNormals[ 2 ];

				normals[ i3     ] = na.x;
				normals[ i3 + 1 ] = na.y;
				normals[ i3 + 2 ] = na.z;

				normals[ i3 + 3 ] = nb.x;
				normals[ i3 + 4 ] = nb.y;
				normals[ i3 + 5 ] = nb.z;

				normals[ i3 + 6 ] = nc.x;
				normals[ i3 + 7 ] = nc.y;
				normals[ i3 + 8 ] = nc.z;

			} else {

				var n = face.normal;

				normals[ i3     ] = n.x;
				normals[ i3 + 1 ] = n.y;
				normals[ i3 + 2 ] = n.z;

				normals[ i3 + 3 ] = n.x;
				normals[ i3 + 4 ] = n.y;
				normals[ i3 + 5 ] = n.z;

				normals[ i3 + 6 ] = n.x;
				normals[ i3 + 7 ] = n.y;
				normals[ i3 + 8 ] = n.z;

			}

			if ( vertexColors === THREE.FaceColors ) {

				var fc = face.color;

				colors[ i3     ] = fc.r;
				colors[ i3 + 1 ] = fc.g;
				colors[ i3 + 2 ] = fc.b;

				colors[ i3 + 3 ] = fc.r;
				colors[ i3 + 4 ] = fc.g;
				colors[ i3 + 5 ] = fc.b;

				colors[ i3 + 6 ] = fc.r;
				colors[ i3 + 7 ] = fc.g;
				colors[ i3 + 8 ] = fc.b;

			} else if ( vertexColors === THREE.VertexColors ) {

				var vca = face.vertexColors[ 0 ];
				var vcb = face.vertexColors[ 1 ];
				var vcc = face.vertexColors[ 2 ];

				colors[ i3     ] = vca.r;
				colors[ i3 + 1 ] = vca.g;
				colors[ i3 + 2 ] = vca.b;

				colors[ i3 + 3 ] = vcb.r;
				colors[ i3 + 4 ] = vcb.g;
				colors[ i3 + 5 ] = vcb.b;

				colors[ i3 + 6 ] = vcc.r;
				colors[ i3 + 7 ] = vcc.g;
				colors[ i3 + 8 ] = vcc.b;

			}

			if ( hasFaceVertexUv === true ) {

				var uva = faceVertexUvs[ 0 ][ i ][ 0 ];
				var uvb = faceVertexUvs[ 0 ][ i ][ 1 ];
				var uvc = faceVertexUvs[ 0 ][ i ][ 2 ];

				uvs[ i2     ] = uva.x;
				uvs[ i2 + 1 ] = uva.y;
215

216 217
				uvs[ i2 + 2 ] = uvb.x;
				uvs[ i2 + 3 ] = uvb.y;
218

219 220 221 222 223 224 225 226 227 228 229 230 231
				uvs[ i2 + 4 ] = uvc.x;
				uvs[ i2 + 5 ] = uvc.y;

			}

		}

		this.computeBoundingSphere()

		return this;

	},

232 233
	computeBoundingBox: function () {

234
		var vector = new THREE.Vector3();
235

236
		return function () {
237

238
			if ( this.boundingBox === null ) {
239

240
				this.boundingBox = new THREE.Box3();
241

242 243
			}

244
			var positions = this.attributes[ 'position' ].array;
245

246
			if ( positions ) {
247

248 249
				var bb = this.boundingBox;
				bb.makeEmpty();
250

251
				for ( var i = 0, il = positions.length; i < il; i += 3 ) {
252

253 254
					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
					bb.expandByPoint( vector );
255 256 257 258 259

				}

			}

260
			if ( positions === undefined || positions.length === 0 ) {
261

262 263
				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );
264

265
			}
266

267
			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
268

269
				console.error( 'THREE.BufferGeometry.computeBoundingBox: Computed min/max have NaN values. The "position" attribute is likely to have NaN values.' );
270

271
			}
272 273 274

		}

275
	}(),
276 277 278

	computeBoundingSphere: function () {

279 280
		var box = new THREE.Box3();
		var vector = new THREE.Vector3();
281

282
		return function () {
283

284
			if ( this.boundingSphere === null ) {
285

286
				this.boundingSphere = new THREE.Sphere();
287

288
			}
289

290
			var positions = this.attributes[ 'position' ].array;
291

292
			if ( positions ) {
293

294 295
				box.makeEmpty();

296
				var center = this.boundingSphere.center;
297

298
				for ( var i = 0, il = positions.length; i < il; i += 3 ) {
299

300
					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
J
Jan Wrobel 已提交
301
					box.expandByPoint( vector );
302 303 304 305 306

				}

				box.center( center );

307
				// hoping to find a boundingSphere with a radius smaller than the
M
Mr.doob 已提交
308
				// boundingSphere of the boundingBox:  sqrt(3) smaller in the best case
309

310 311 312 313 314 315
				var maxRadiusSq = 0;

				for ( var i = 0, il = positions.length; i < il; i += 3 ) {

					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
					maxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( vector ) );
316

317 318 319 320
				}

				this.boundingSphere.radius = Math.sqrt( maxRadiusSq );

321 322
				if ( isNaN( this.boundingSphere.radius ) ) {

M
Mr.doob 已提交
323
					console.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' );
324 325 326

				}

327
			}
328 329 330

		}

331
	}(),
332

333 334 335 336 337 338
	computeFaceNormals: function () {

		// backwards compatibility

	},

339 340
	computeVertexNormals: function () {

341
		if ( this.attributes[ 'position' ] ) {
342 343 344 345

			var i, il;
			var j, jl;

346
			var nVertexElements = this.attributes[ 'position' ].array.length;
347

348
			if ( this.attributes[ 'normal' ] === undefined ) {
349

350
				this.attributes[ 'normal' ] = {
351

352
					itemSize: 3,
353
					array: new Float32Array( nVertexElements )
354 355

				};
356 357 358 359 360

			} else {

				// reset existing normals to zero

361
				for ( i = 0, il = this.attributes[ 'normal' ].array.length; i < il; i ++ ) {
362

363
					this.attributes[ 'normal' ].array[ i ] = 0;
364 365 366 367 368

				}

			}

369 370
			var positions = this.attributes[ 'position' ].array;
			var normals = this.attributes[ 'normal' ].array;
371 372 373 374 375 376 377 378 379 380

			var vA, vB, vC, x, y, z,

			pA = new THREE.Vector3(),
			pB = new THREE.Vector3(),
			pC = new THREE.Vector3(),

			cb = new THREE.Vector3(),
			ab = new THREE.Vector3();

381 382
			// indexed elements

383
			if ( this.attributes[ 'index' ] ) {
384

385
				var indices = this.attributes[ 'index' ].array;
386

387
				var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409

				for ( j = 0, jl = offsets.length; j < jl; ++ j ) {

					var start = offsets[ j ].start;
					var count = offsets[ j ].count;
					var index = offsets[ j ].index;

					for ( i = start, il = start + count; i < il; i += 3 ) {

						vA = index + indices[ i ];
						vB = index + indices[ i + 1 ];
						vC = index + indices[ i + 2 ];

						x = positions[ vA * 3 ];
						y = positions[ vA * 3 + 1 ];
						z = positions[ vA * 3 + 2 ];
						pA.set( x, y, z );

						x = positions[ vB * 3 ];
						y = positions[ vB * 3 + 1 ];
						z = positions[ vB * 3 + 2 ];
						pB.set( x, y, z );
410

411 412 413 414
						x = positions[ vC * 3 ];
						y = positions[ vC * 3 + 1 ];
						z = positions[ vC * 3 + 2 ];
						pC.set( x, y, z );
415

416 417 418
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
419

M
Mr.doob 已提交
420
						normals[ vA * 3     ] += cb.x;
421 422 423
						normals[ vA * 3 + 1 ] += cb.y;
						normals[ vA * 3 + 2 ] += cb.z;

M
Mr.doob 已提交
424
						normals[ vB * 3     ] += cb.x;
425 426 427
						normals[ vB * 3 + 1 ] += cb.y;
						normals[ vB * 3 + 2 ] += cb.z;

M
Mr.doob 已提交
428
						normals[ vC * 3     ] += cb.x;
429 430 431 432 433 434 435 436 437 438
						normals[ vC * 3 + 1 ] += cb.y;
						normals[ vC * 3 + 2 ] += cb.z;

					}

				}

			// non-indexed elements (unconnected triangle soup)

			} else {
439

440
				for ( i = 0, il = positions.length; i < il; i += 9 ) {
441

442 443 444
					x = positions[ i ];
					y = positions[ i + 1 ];
					z = positions[ i + 2 ];
445 446
					pA.set( x, y, z );

447 448 449
					x = positions[ i + 3 ];
					y = positions[ i + 4 ];
					z = positions[ i + 5 ];
450 451
					pB.set( x, y, z );

452 453 454
					x = positions[ i + 6 ];
					y = positions[ i + 7 ];
					z = positions[ i + 8 ];
455 456
					pC.set( x, y, z );

457 458 459
					cb.subVectors( pC, pB );
					ab.subVectors( pA, pB );
					cb.cross( ab );
460

M
Mr.doob 已提交
461
					normals[ i     ] = cb.x;
462 463
					normals[ i + 1 ] = cb.y;
					normals[ i + 2 ] = cb.z;
464

465 466 467
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
468

469 470 471
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
472 473 474 475 476

				}

			}

477
			this.normalizeNormals();
478

479
			this.normalsNeedUpdate = true;
480

481
		}
482

483
	},
484

485 486 487 488 489
	computeTangents: function () {

		// based on http://www.terathon.com/code/tangent.html
		// (per vertex tangents)

490 491 492 493
		if ( this.attributes[ 'index' ] === undefined ||
			 this.attributes[ 'position' ] === undefined ||
			 this.attributes[ 'normal' ] === undefined ||
			 this.attributes[ 'uv' ] === undefined ) {
494

495
			console.warn( 'Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
496 497 498 499
			return;

		}

500 501 502 503
		var indices = this.attributes[ 'index' ].array;
		var positions = this.attributes[ 'position' ].array;
		var normals = this.attributes[ 'normal' ].array;
		var uvs = this.attributes[ 'uv' ].array;
504 505 506

		var nVertices = positions.length / 3;

507
		if ( this.attributes[ 'tangent' ] === undefined ) {
508 509 510

			var nTangentElements = 4 * nVertices;

511
			this.attributes[ 'tangent' ] = {
512 513

				itemSize: 4,
514
				array: new Float32Array( nTangentElements )
515 516 517 518 519

			};

		}

520
		var tangents = this.attributes[ 'tangent' ].array;
521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583

		var tan1 = [], tan2 = [];

		for ( var k = 0; k < nVertices; k ++ ) {

			tan1[ k ] = new THREE.Vector3();
			tan2[ k ] = new THREE.Vector3();

		}

		var xA, yA, zA,
			xB, yB, zB,
			xC, yC, zC,

			uA, vA,
			uB, vB,
			uC, vC,

			x1, x2, y1, y2, z1, z2,
			s1, s2, t1, t2, r;

		var sdir = new THREE.Vector3(), tdir = new THREE.Vector3();

		function handleTriangle( a, b, c ) {

			xA = positions[ a * 3 ];
			yA = positions[ a * 3 + 1 ];
			zA = positions[ a * 3 + 2 ];

			xB = positions[ b * 3 ];
			yB = positions[ b * 3 + 1 ];
			zB = positions[ b * 3 + 2 ];

			xC = positions[ c * 3 ];
			yC = positions[ c * 3 + 1 ];
			zC = positions[ c * 3 + 2 ];

			uA = uvs[ a * 2 ];
			vA = uvs[ a * 2 + 1 ];

			uB = uvs[ b * 2 ];
			vB = uvs[ b * 2 + 1 ];

			uC = uvs[ c * 2 ];
			vC = uvs[ c * 2 + 1 ];

			x1 = xB - xA;
			x2 = xC - xA;

			y1 = yB - yA;
			y2 = yC - yA;

			z1 = zB - zA;
			z2 = zC - zA;

			s1 = uB - uA;
			s2 = uC - uA;

			t1 = vB - vA;
			t2 = vC - vA;

			r = 1.0 / ( s1 * t2 - s2 * t1 );

584 585 586 587 588 589 590 591 592 593 594
			sdir.set(
				( t2 * x1 - t1 * x2 ) * r,
				( t2 * y1 - t1 * y2 ) * r,
				( t2 * z1 - t1 * z2 ) * r
			);

			tdir.set(
				( s1 * x2 - s2 * x1 ) * r,
				( s1 * y2 - s2 * y1 ) * r,
				( s1 * z2 - s2 * z1 ) * r
			);
595

596 597 598
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
599

600 601 602
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646

		}

		var i, il;
		var j, jl;
		var iA, iB, iC;

		var offsets = this.offsets;

		for ( j = 0, jl = offsets.length; j < jl; ++ j ) {

			var start = offsets[ j ].start;
			var count = offsets[ j ].count;
			var index = offsets[ j ].index;

			for ( i = start, il = start + count; i < il; i += 3 ) {

				iA = index + indices[ i ];
				iB = index + indices[ i + 1 ];
				iC = index + indices[ i + 2 ];

				handleTriangle( iA, iB, iC );

			}

		}

		var tmp = new THREE.Vector3(), tmp2 = new THREE.Vector3();
		var n = new THREE.Vector3(), n2 = new THREE.Vector3();
		var w, t, test;

		function handleVertex( v ) {

			n.x = normals[ v * 3 ];
			n.y = normals[ v * 3 + 1 ];
			n.z = normals[ v * 3 + 2 ];

			n2.copy( n );

			t = tan1[ v ];

			// Gram-Schmidt orthogonalize

			tmp.copy( t );
647
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
648 649 650

			// Calculate handedness

651
			tmp2.crossVectors( n2, t );
652
			test = tmp2.dot( tan2[ v ] );
653
			w = ( test < 0.0 ) ? - 1.0 : 1.0;
654

M
Mr.doob 已提交
655
			tangents[ v * 4     ] = tmp.x;
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;

		}

		for ( j = 0, jl = offsets.length; j < jl; ++ j ) {

			var start = offsets[ j ].start;
			var count = offsets[ j ].count;
			var index = offsets[ j ].index;

			for ( i = start, il = start + count; i < il; i += 3 ) {

				iA = index + indices[ i ];
				iB = index + indices[ i + 1 ];
				iC = index + indices[ i + 2 ];

				handleVertex( iA );
				handleVertex( iB );
				handleVertex( iC );

			}

		}

682 683
	},

684 685 686 687 688 689 690
	/*
		computeOffsets
		Compute the draw offset for large models by chunking the index buffer into chunks of 65k addressable vertices.
		This method will effectively rewrite the index buffer and remap all attributes to match the new indices.
		WARNING: This method will also expand the vertex count to prevent sprawled triangles across draw offsets.
		indexBufferSize - Defaults to 65535, but allows for larger or smaller chunks.
	*/
691
	computeOffsets: function ( indexBufferSize ) {
692 693

		var size = indexBufferSize;
694
		if ( indexBufferSize === undefined )
695 696 697 698
			size = 65535; //WebGL limits type of index buffer values to 16-bit.

		var s = Date.now();

699 700
		var indices = this.attributes[ 'index' ].array;
		var vertices = this.attributes[ 'position' ].array;
701

702 703
		var verticesCount = ( vertices.length / 3 );
		var facesCount = ( indices.length / 3 );
704 705 706 707 708 709 710 711 712 713 714 715

		/*
		console.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
		console.log("Faces to process: "+(indices.length/3));
		console.log("Reordering "+verticesCount+" vertices.");
		*/

		var sortedIndices = new Uint16Array( indices.length ); //16-bit buffers
		var indexPtr = 0;
		var vertexPtr = 0;

		var offsets = [ { start:0, count:0, index:0 } ];
716
		var offset = offsets[ 0 ];
717 718 719

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
720
		var faceVertices = new Int32Array( 6 );
721 722
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
723
		for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
724 725 726 727 728

		/*
			Traverse every face and reorder vertices in the proper offsets of 65k.
			We can have more than 65k entries in the index buffer per offset, but only reference 65k values.
		*/
729
		for ( var findex = 0; findex < facesCount; findex ++ ) {
730 731
			newVerticeMaps = 0;

732 733 734
			for ( var vo = 0; vo < 3; vo ++ ) {
				var vid = indices[ findex * 3 + vo ];
				if ( vertexMap[ vid ] == - 1 ) {
735
					//Unmapped vertice
736 737 738 739
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
				} else if ( vertexMap[ vid ] < offset.index ) {
740
					//Reused vertices from previous block (duplicate)
741 742 743
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
744 745
				} else {
					//Reused vertice in the current block
746 747
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
748 749 750 751
				}
			}

			var faceMax = vertexPtr + newVerticeMaps;
752
			if ( faceMax > ( offset.index + size ) ) {
753
				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
754
				offsets.push( new_offset );
755 756 757
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
758 759 760 761
				for ( var v = 0; v < 6; v += 2 ) {
					var new_vid = faceVertices[ v + 1 ];
					if ( new_vid > - 1 && new_vid < offset.index )
						faceVertices[ v + 1 ] = - 1;
762 763 764 765
				}
			}

			//Reindex the face.
766 767 768
			for ( var v = 0; v < 6; v += 2 ) {
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];
769

770 771
				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;
772

773 774 775 776
				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
777 778 779 780
			}
		}

		/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
781
		this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
782 783 784 785 786 787 788 789 790 791 792 793 794
		this.offsets = offsets;

		/*
		var orderTime = Date.now();
		console.log("Reorder time: "+(orderTime-s)+"ms");
		console.log("Duplicated "+duplicatedVertices+" vertices.");
		console.log("Compute Buffers time: "+(Date.now()-s)+"ms");
		console.log("Draw offsets: "+offsets.length);
		*/

		return offsets;
	},

795 796 797 798 799 800 801 802
	merge: function () {

		console.log( 'BufferGeometry.merge(): TODO' );

	},

	normalizeNormals: function () {

803
		var normals = this.attributes[ 'normal' ].array;
804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822

		var x, y, z, n;

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

			x = normals[ i ];
			y = normals[ i + 1 ];
			z = normals[ i + 2 ];

			n = 1.0 / Math.sqrt( x * x + y * y + z * z );

			normals[ i     ] *= n;
			normals[ i + 1 ] *= n;
			normals[ i + 2 ] *= n;

		}

	},

823 824 825 826 827 828 829
	/*
		reoderBuffers:
		Reorder attributes based on a new indexBuffer and indexMap.
		indexBuffer - Uint16Array of the new ordered indices.
		indexMap - Int32Array where the position is the new vertex ID and the value the old vertex ID for each vertex.
		vertexCount - Amount of total vertices considered in this reordering (in case you want to grow the vertice stack).
	*/
830
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
831 832 833 834

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
		var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];
835 836
		for ( var attr in this.attributes ) {
			if ( attr == 'index' )
837
				continue;
838 839 840 841 842
			var sourceArray = this.attributes[ attr ].array;
			for ( var i = 0, il = types.length; i < il; i ++ ) {
				var type = types[ i ];
				if ( sourceArray instanceof type ) {
					sortedAttributes[ attr ] = new type( this.attributes[ attr ].itemSize * vertexCount );
843 844 845 846 847 848
					break;
				}
			}
		}

		/* Move attribute positions based on the new index map */
849 850
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
			var vid = indexMap[ new_vid ];
851
			for ( var attr in this.attributes ) {
852
				if ( attr == 'index' )
853
					continue;
854 855 856 857
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
858 859 860 861 862
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
			}
		}

		/* Carry the new sorted buffers locally */
863
		this.attributes[ 'index' ].array = indexBuffer;
864
		for ( var attr in this.attributes ) {
865
			if ( attr == 'index' )
866
				continue;
867 868
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
869 870 871
		}
	},

M
Mr.doob 已提交
872
	clone: function () {
O
ohmed 已提交
873 874 875

		var geometry = new THREE.BufferGeometry();

O
ohmed 已提交
876 877
		var types = [ Int8Array, Uint8Array, Uint8ClampedArray, Int16Array, Uint16Array, Int32Array, Uint32Array, Float32Array, Float64Array ];

O
ohmed 已提交
878 879
		for ( var attr in this.attributes ) {

M
Mr.doob 已提交
880 881
			var sourceAttr = this.attributes[ attr ];
			var sourceArray = sourceAttr.array;
O
ohmed 已提交
882

M
Mr.doob 已提交
883
			var attribute = {
O
ohmed 已提交
884 885

				itemSize: sourceAttr.itemSize,
O
ohmed 已提交
886
				array: null
O
ohmed 已提交
887

O
ohmed 已提交
888 889
			};

O
ohmed 已提交
890
			for ( var i = 0, il = types.length; i < il; i ++ ) {
O
ohmed 已提交
891

O
ohmed 已提交
892
				var type = types[ i ];
O
ohmed 已提交
893

O
ohmed 已提交
894
				if ( sourceArray instanceof type ) {
O
ohmed 已提交
895

M
Mr.doob 已提交
896
					attribute.array = new type( sourceArray );
O
ohmed 已提交
897
					break;
O
ohmed 已提交
898

O
ohmed 已提交
899
				}
O
ohmed 已提交
900 901 902 903 904 905 906

			}

			geometry.attributes[ attr ] = attribute;

		}

O
ohmed 已提交
907
		for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
O
ohmed 已提交
908 909 910

			var offset = this.offsets[ i ];

M
Mr.doob 已提交
911
			geometry.offsets.push( {
O
ohmed 已提交
912

O
ohmed 已提交
913 914 915
				start: offset.start,
				index: offset.index,
				count: offset.count
O
ohmed 已提交
916

M
Mr.doob 已提交
917
			} );
O
ohmed 已提交
918

O
ohmed 已提交
919
		}
O
ohmed 已提交
920 921 922 923 924

		return geometry;

	},

925
	dispose: function () {
926

927
		this.dispatchEvent( { type: 'dispose' } );
928

929
	}
930 931

};
M
Mr.doob 已提交
932 933

THREE.EventDispatcher.prototype.apply( THREE.BufferGeometry.prototype );