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

THREE.BufferGeometry = function () {

M
Mr.doob 已提交
8 9
	Object.defineProperty( this, 'id', { value: THREE.GeometryIdCount ++ } );

10
	this.uuid = THREE.Math.generateUUID();
11

M
Mr.doob 已提交
12
	this.name = '';
13
	this.type = 'BufferGeometry';
M
Mr.doob 已提交
14

15
	this.attributes = {};
16 17
	this.attributesKeys = [];

18 19
	this.drawcalls = [];
	this.offsets = this.drawcalls; // backwards compatibility
20

21 22 23 24 25 26 27
	this.boundingBox = null;
	this.boundingSphere = null;

};

THREE.BufferGeometry.prototype = {

28
	constructor: THREE.BufferGeometry,
29

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

M
Mr.doob 已提交
32
		if ( attribute instanceof THREE.BufferAttribute === false && attribute instanceof THREE.InterleavedBufferAttribute === false ) {
33

34
			THREE.warn( 'THREE.BufferGeometry: .addAttribute() now expects ( name, attribute ).' );
35 36 37 38 39 40 41

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

			return;

		}

M
Mr.doob 已提交
42
		this.attributes[ name ] = attribute;
43
		this.attributesKeys = Object.keys( this.attributes );
44

M
Mr.doob 已提交
45 46 47 48
	},

	getAttribute: function ( name ) {

49 50
		return this.attributes[ name ];

51 52
	},

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

55
		this.drawcalls.push( {
M
Mr.doob 已提交
56 57 58

			start: start,
			count: count,
M
Mr.doob 已提交
59
			index: indexOffset !== undefined ? indexOffset : 0
M
Mr.doob 已提交
60 61 62 63 64

		} );

	},

65 66
	applyMatrix: function ( matrix ) {

M
Mr.doob 已提交
67
		var position = this.attributes.position;
68

M
Mr.doob 已提交
69
		if ( position !== undefined ) {
70

71
			matrix.applyToVector3Array( position.array );
M
Mr.doob 已提交
72
			position.needsUpdate = true;
73 74 75

		}

M
Mr.doob 已提交
76
		var normal = this.attributes.normal;
77

M
Mr.doob 已提交
78
		if ( normal !== undefined ) {
79

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

82
			normalMatrix.applyToVector3Array( normal.array );
M
Mr.doob 已提交
83
			normal.needsUpdate = true;
84 85 86

		}

M
Mr.doob 已提交
87
		if ( this.boundingBox !== null ) {
88 89 90 91 92

			this.computeBoundingBox();

		}

M
Mr.doob 已提交
93
		if ( this.boundingSphere !== null ) {
94 95 96 97 98

			this.computeBoundingSphere();

		}

99 100
	},

101 102
	center: function () {

M
Mr.doob 已提交
103 104 105 106 107 108 109
		this.computeBoundingBox();

		var offset = this.boundingBox.center().negate();

		this.applyMatrix( new THREE.Matrix4().setPosition( offset ) );

		return offset;
110 111 112

	},

113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142
	fromObject: function ( object ) {

		var geometry = object.geometry;
		var material = object.material;

		if ( object instanceof THREE.PointCloud || object instanceof THREE.Line ) {

			var positions = new Float32Array( geometry.vertices.length * 3 );
			var colors = new Float32Array( geometry.colors.length * 3 );

			this.addAttribute( 'position', new THREE.BufferAttribute( positions, 3 ).copyVector3sArray( geometry.vertices ) );
			this.addAttribute( 'color', new THREE.BufferAttribute( colors, 3 ).copyColorsArray( geometry.colors ) );
			this.computeBoundingSphere();

		} else if ( object instanceof THREE.Mesh ) {

			this.fromGeometry( geometry, material );

		}

		if ( material.attributes !== undefined ) {

			console.warn( 'THREE.BufferGeometry.fromObject(). TODO: material.attributes', material );

		}

		return this;

	},

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
	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 );
170
			this.addAttribute( 'uv', new THREE.BufferAttribute( uvs, 2 ) );
171 172 173 174 175 176 177 178 179 180 181 182 183 184

		}

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

186 187 188
			positions[ i3 + 3 ] = b.x;
			positions[ i3 + 4 ] = b.y;
			positions[ i3 + 5 ] = b.z;
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 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273
			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;
274

275 276
				uvs[ i2 + 2 ] = uvb.x;
				uvs[ i2 + 3 ] = uvb.y;
277

278 279 280 281 282 283 284
				uvs[ i2 + 4 ] = uvc.x;
				uvs[ i2 + 5 ] = uvc.y;

			}

		}

B
brason 已提交
285
		this.computeBoundingSphere();
286 287 288 289 290

		return this;

	},

291 292
	computeBoundingBox: function () {

293
		var vector = new THREE.Vector3();
294

295
		return function () {
296

297
			if ( this.boundingBox === null ) {
298

299
				this.boundingBox = new THREE.Box3();
300

301 302
			}

303
			var positions = this.attributes.position.array;
304

305
			if ( positions ) {
306

307 308
				var bb = this.boundingBox;
				bb.makeEmpty();
309

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

312 313
					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
					bb.expandByPoint( vector );
314 315 316 317 318

				}

			}

319
			if ( positions === undefined || positions.length === 0 ) {
320

321 322
				this.boundingBox.min.set( 0, 0, 0 );
				this.boundingBox.max.set( 0, 0, 0 );
323

324
			}
325

326
			if ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {
327

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

330
			}
331 332 333

		}

334
	}(),
335 336 337

	computeBoundingSphere: function () {

338 339
		var box = new THREE.Box3();
		var vector = new THREE.Vector3();
340

341
		return function () {
342

343
			if ( this.boundingSphere === null ) {
344

345
				this.boundingSphere = new THREE.Sphere();
346

347
			}
348

349
			var positions = this.attributes.position.array;
350

351
			if ( positions ) {
352

353 354
				box.makeEmpty();

355
				var center = this.boundingSphere.center;
356

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

359
					vector.set( positions[ i ], positions[ i + 1 ], positions[ i + 2 ] );
J
Jan Wrobel 已提交
360
					box.expandByPoint( vector );
361 362 363 364 365

				}

				box.center( center );

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

369 370 371 372 373 374
				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 ) );
375

376 377 378 379
				}

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

380 381
				if ( isNaN( this.boundingSphere.radius ) ) {

382
					THREE.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The "position" attribute is likely to have NaN values.' );
383 384 385

				}

386
			}
387 388 389

		}

390
	}(),
391

392 393 394 395 396 397
	computeFaceNormals: function () {

		// backwards compatibility

	},

398 399
	computeVertexNormals: function () {

400
		var attributes = this.attributes;
401

402
		if ( attributes.position ) {
403

404
			var positions = attributes.position.array;
405

406
			if ( attributes.normal === undefined ) {
407

408
				this.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( positions.length ), 3 ) );
409 410 411 412 413

			} else {

				// reset existing normals to zero

414 415 416
				var normals = attributes.normal.array;

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

418
					normals[ i ] = 0;
419 420 421 422 423

				}

			}

424
			var normals = attributes.normal.array;
425

M
Mr.doob 已提交
426
			var vA, vB, vC,
427 428 429 430 431 432 433 434

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

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

435 436
			// indexed elements

437
			if ( attributes.index ) {
438

439
				var indices = attributes.index.array;
440

441
				var offsets = ( this.offsets.length > 0 ? this.offsets : [ { start: 0, count: indices.length, index: 0 } ] );
442

443
				for ( var j = 0, jl = offsets.length; j < jl; ++ j ) {
444 445 446 447 448

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

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

M
Mr.doob 已提交
451 452 453
						vA = ( index + indices[ i     ] ) * 3;
						vB = ( index + indices[ i + 1 ] ) * 3;
						vC = ( index + indices[ i + 2 ] ) * 3;
454

M
Mr.doob 已提交
455 456 457
						pA.fromArray( positions, vA );
						pB.fromArray( positions, vB );
						pC.fromArray( positions, vC );
458

459 460 461
						cb.subVectors( pC, pB );
						ab.subVectors( pA, pB );
						cb.cross( ab );
462

M
Mr.doob 已提交
463 464 465
						normals[ vA     ] += cb.x;
						normals[ vA + 1 ] += cb.y;
						normals[ vA + 2 ] += cb.z;
466

M
Mr.doob 已提交
467 468 469
						normals[ vB     ] += cb.x;
						normals[ vB + 1 ] += cb.y;
						normals[ vB + 2 ] += cb.z;
470

M
Mr.doob 已提交
471 472 473
						normals[ vC     ] += cb.x;
						normals[ vC + 1 ] += cb.y;
						normals[ vC + 2 ] += cb.z;
474 475 476 477 478 479

					}

				}

			} else {
480

481 482 483
				// non-indexed elements (unconnected triangle soup)

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

M
Mr.doob 已提交
485 486 487
					pA.fromArray( positions, i );
					pB.fromArray( positions, i + 3 );
					pC.fromArray( positions, i + 6 );
488

489 490 491
					cb.subVectors( pC, pB );
					ab.subVectors( pA, pB );
					cb.cross( ab );
492

M
Mr.doob 已提交
493
					normals[ i     ] = cb.x;
494 495
					normals[ i + 1 ] = cb.y;
					normals[ i + 2 ] = cb.z;
496

497 498 499
					normals[ i + 3 ] = cb.x;
					normals[ i + 4 ] = cb.y;
					normals[ i + 5 ] = cb.z;
500

501 502 503
					normals[ i + 6 ] = cb.x;
					normals[ i + 7 ] = cb.y;
					normals[ i + 8 ] = cb.z;
504 505 506 507 508

				}

			}

509
			this.normalizeNormals();
510

511
			attributes.normal.needsUpdate = true;
512

513
		}
514

515
	},
516

517 518 519 520 521
	computeTangents: function () {

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

522 523 524 525
		if ( this.attributes.index === undefined ||
			 this.attributes.position === undefined ||
			 this.attributes.normal === undefined ||
			 this.attributes.uv === undefined ) {
526

527
			THREE.warn( 'THREE.BufferGeometry: Missing required attributes (index, position, normal or uv) in BufferGeometry.computeTangents()' );
528 529 530 531
			return;

		}

532 533 534 535
		var indices = this.attributes.index.array;
		var positions = this.attributes.position.array;
		var normals = this.attributes.normal.array;
		var uvs = this.attributes.uv.array;
536 537 538

		var nVertices = positions.length / 3;

539
		if ( this.attributes.tangent === undefined ) {
540

541
			this.addAttribute( 'tangent', new THREE.BufferAttribute( new Float32Array( 4 * nVertices ), 4 ) );
542 543 544

		}

545
		var tangents = this.attributes.tangent.array;
546 547 548 549 550 551 552 553 554 555

		var tan1 = [], tan2 = [];

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

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

		}

M
Mr.doob 已提交
556 557 558
		var vA = new THREE.Vector3(),
			vB = new THREE.Vector3(),
			vC = new THREE.Vector3(),
559

M
Mr.doob 已提交
560 561 562
			uvA = new THREE.Vector2(),
			uvB = new THREE.Vector2(),
			uvC = new THREE.Vector2(),
563 564 565 566 567 568 569 570

			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 ) {

M
Mr.doob 已提交
571 572 573
			vA.fromArray( positions, a * 3 );
			vB.fromArray( positions, b * 3 );
			vC.fromArray( positions, c * 3 );
574

M
Mr.doob 已提交
575 576 577
			uvA.fromArray( uvs, a * 2 );
			uvB.fromArray( uvs, b * 2 );
			uvC.fromArray( uvs, c * 2 );
578

M
Mr.doob 已提交
579 580
			x1 = vB.x - vA.x;
			x2 = vC.x - vA.x;
581

M
Mr.doob 已提交
582 583
			y1 = vB.y - vA.y;
			y2 = vC.y - vA.y;
584

M
Mr.doob 已提交
585 586
			z1 = vB.z - vA.z;
			z2 = vC.z - vA.z;
587

M
Mr.doob 已提交
588 589
			s1 = uvB.x - uvA.x;
			s2 = uvC.x - uvA.x;
590

M
Mr.doob 已提交
591 592
			t1 = uvB.y - uvA.y;
			t2 = uvC.y - uvA.y;
593 594 595

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

596 597 598 599 600 601 602 603 604 605 606
			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
			);
607

608 609 610
			tan1[ a ].add( sdir );
			tan1[ b ].add( sdir );
			tan1[ c ].add( sdir );
611

612 613 614
			tan2[ a ].add( tdir );
			tan2[ b ].add( tdir );
			tan2[ c ].add( tdir );
615 616 617 618 619 620 621

		}

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

622
		if ( this.drawcalls.length === 0 ) {
623

624
			this.addDrawCall( 0, indices.length, 0 );
625

626 627 628 629 630 631 632 633 634
		}

		var drawcalls = this.drawcalls;

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

			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653

			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 ) {

M
Mr.doob 已提交
654
			n.fromArray( normals, v * 3 );
655 656 657 658 659 660 661
			n2.copy( n );

			t = tan1[ v ];

			// Gram-Schmidt orthogonalize

			tmp.copy( t );
662
			tmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();
663 664 665

			// Calculate handedness

666
			tmp2.crossVectors( n2, t );
667
			test = tmp2.dot( tan2[ v ] );
668
			w = ( test < 0.0 ) ? - 1.0 : 1.0;
669

M
Mr.doob 已提交
670
			tangents[ v * 4     ] = tmp.x;
671 672 673 674 675 676
			tangents[ v * 4 + 1 ] = tmp.y;
			tangents[ v * 4 + 2 ] = tmp.z;
			tangents[ v * 4 + 3 ] = w;

		}

677
		for ( j = 0, jl = drawcalls.length; j < jl; ++ j ) {
678

679 680 681
			var start = drawcalls[ j ].start;
			var count = drawcalls[ j ].count;
			var index = drawcalls[ j ].index;
682 683 684 685 686 687 688 689 690 691 692 693 694 695 696

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

			}

		}

697 698
	},

699
	/*
M
Mr.doob 已提交
700 701 702 703
	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.
	size - Defaults to 65535, but allows for larger or smaller chunks.
704
	*/
M
Mr.doob 已提交
705
	computeOffsets: function ( size ) {
706

M
Mr.doob 已提交
707
		if ( size === undefined ) size = 65535; // WebGL limits type of index buffer values to 16-bit.
708

709 710
		var indices = this.attributes.index.array;
		var vertices = this.attributes.position.array;
711

712
		var facesCount = ( indices.length / 3 );
713 714

		/*
715 716 717
		THREE.log("Computing buffers in offsets of "+size+" -> indices:"+indices.length+" vertices:"+vertices.length);
		THREE.log("Faces to process: "+(indices.length/3));
		THREE.log("Reordering "+verticesCount+" vertices.");
718 719 720 721 722 723 724
		*/

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

		var offsets = [ { start:0, count:0, index:0 } ];
725
		var offset = offsets[ 0 ];
726 727 728

		var duplicatedVertices = 0;
		var newVerticeMaps = 0;
729
		var faceVertices = new Int32Array( 6 );
730 731
		var vertexMap = new Int32Array( vertices.length );
		var revVertexMap = new Int32Array( vertices.length );
732
		for ( var j = 0; j < vertices.length; j ++ ) { vertexMap[ j ] = - 1; revVertexMap[ j ] = - 1; }
733 734 735 736 737

		/*
			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.
		*/
738
		for ( var findex = 0; findex < facesCount; findex ++ ) {
739 740
			newVerticeMaps = 0;

741 742 743
			for ( var vo = 0; vo < 3; vo ++ ) {
				var vid = indices[ findex * 3 + vo ];
				if ( vertexMap[ vid ] == - 1 ) {
744
					//Unmapped vertice
745 746 747 748
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					newVerticeMaps ++;
				} else if ( vertexMap[ vid ] < offset.index ) {
749
					//Reused vertices from previous block (duplicate)
750 751 752
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = - 1;
					duplicatedVertices ++;
753 754
				} else {
					//Reused vertice in the current block
755 756
					faceVertices[ vo * 2 ] = vid;
					faceVertices[ vo * 2 + 1 ] = vertexMap[ vid ];
757 758 759 760
				}
			}

			var faceMax = vertexPtr + newVerticeMaps;
761
			if ( faceMax > ( offset.index + size ) ) {
762
				var new_offset = { start:indexPtr, count:0, index:vertexPtr };
763
				offsets.push( new_offset );
764 765 766
				offset = new_offset;

				//Re-evaluate reused vertices in light of new offset.
767 768 769 770
				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;
771 772 773 774
				}
			}

			//Reindex the face.
775 776 777
			for ( var v = 0; v < 6; v += 2 ) {
				var vid = faceVertices[ v ];
				var new_vid = faceVertices[ v + 1 ];
778

779 780
				if ( new_vid === - 1 )
					new_vid = vertexPtr ++;
781

782 783 784 785
				vertexMap[ vid ] = new_vid;
				revVertexMap[ new_vid ] = vid;
				sortedIndices[ indexPtr ++ ] = new_vid - offset.index; //XXX overflows at 16bit
				offset.count ++;
786 787 788 789
			}
		}

		/* Move all attribute values to map to the new computed indices , also expand the vertice stack to match our new vertexPtr. */
790
		this.reorderBuffers( sortedIndices, revVertexMap, vertexPtr );
791 792
		this.offsets = offsets; // TODO: Deprecate
		this.drawcalls = offsets;
793 794 795

		/*
		var orderTime = Date.now();
796 797 798 799
		THREE.log("Reorder time: "+(orderTime-s)+"ms");
		THREE.log("Duplicated "+duplicatedVertices+" vertices.");
		THREE.log("Compute Buffers time: "+(Date.now()-s)+"ms");
		THREE.log("Draw offsets: "+offsets.length);
800 801 802
		*/

		return offsets;
803

804 805
	},

806 807 808 809
	merge: function ( geometry, offset ) {

		if ( geometry instanceof THREE.BufferGeometry === false ) {

810
			THREE.error( 'THREE.BufferGeometry.merge(): geometry not an instance of THREE.BufferGeometry.', geometry );
811 812 813 814 815 816 817 818 819 820 821
			return;

		}

		if ( offset === undefined ) offset = 0;

		var attributes = this.attributes;

		for ( var key in attributes ) {

			if ( geometry.attributes[ key ] === undefined ) continue;
822

823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
			var attribute1 = attributes[ key ];
			var attributeArray1 = attribute1.array;

			var attribute2 = geometry.attributes[ key ];
			var attributeArray2 = attribute2.array;

			var attributeSize = attribute2.itemSize;

			for ( var i = 0, j = attributeSize * offset; i < attributeArray2.length; i ++, j ++ ) {

				attributeArray1[ j ] = attributeArray2[ i ];

			}

		}

		return this;
840 841 842 843 844

	},

	normalizeNormals: function () {

845
		var normals = this.attributes.normal.array;
846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864

		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;

		}

	},

865 866 867 868 869 870 871
	/*
		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).
	*/
872
	reorderBuffers: function ( indexBuffer, indexMap, vertexCount ) {
873 874 875

		/* Create a copy of all attributes for reordering. */
		var sortedAttributes = {};
876 877
		for ( var attr in this.attributes ) {
			if ( attr == 'index' )
878
				continue;
879
			var sourceArray = this.attributes[ attr ].array;
880
			sortedAttributes[ attr ] = new sourceArray.constructor( this.attributes[ attr ].itemSize * vertexCount );
881 882 883
		}

		/* Move attribute positions based on the new index map */
884 885
		for ( var new_vid = 0; new_vid < vertexCount; new_vid ++ ) {
			var vid = indexMap[ new_vid ];
886
			for ( var attr in this.attributes ) {
887
				if ( attr == 'index' )
888
					continue;
889 890 891 892
				var attrArray = this.attributes[ attr ].array;
				var attrSize = this.attributes[ attr ].itemSize;
				var sortedAttr = sortedAttributes[ attr ];
				for ( var k = 0; k < attrSize; k ++ )
893 894 895 896 897
					sortedAttr[ new_vid * attrSize + k ] = attrArray[ vid * attrSize + k ];
			}
		}

		/* Carry the new sorted buffers locally */
898
		this.attributes[ 'index' ].array = indexBuffer;
899
		for ( var attr in this.attributes ) {
900
			if ( attr == 'index' )
901
				continue;
902 903
			this.attributes[ attr ].array = sortedAttributes[ attr ];
			this.attributes[ attr ].numItems = this.attributes[ attr ].itemSize * vertexCount;
904 905 906
		}
	},

907
	toJSON: function() {
908

909 910
		// we will store all serialization data on 'data'
		var data = {};
911

912 913
		// add metadata
		data.metadata = {
914 915 916
			version: 4.4,
			type: 'BufferGeometry',
			generator: 'BufferGeometry.toJSON'
B
brason 已提交
917
		};
918

919
		// standard BufferGeometry serialization
920

921 922 923 924 925
		data.type = this.type;
		data.uuid = this.uuid;
		if ( this.name !== '' ) data.name = this.name;
		data.data = {};
		data.data.attributes = {};
926

927
		var attributes = this.attributes;
928 929 930 931 932 933 934
		var offsets = this.offsets;
		var boundingSphere = this.boundingSphere;

		for ( var key in attributes ) {

			var attribute = attributes[ key ];

M
makc 已提交
935
			var array = Array.prototype.slice.call( attribute.array );
936

937
			data.data.attributes[ key ] = {
938 939 940 941 942 943 944 945 946
				itemSize: attribute.itemSize,
				type: attribute.array.constructor.name,
				array: array
			}

		}

		if ( offsets.length > 0 ) {

947
			data.data.offsets = JSON.parse( JSON.stringify( offsets ) );
948 949 950 951 952

		}

		if ( boundingSphere !== null ) {

953
			data.data.boundingSphere = {
954 955 956 957 958 959
				center: boundingSphere.center.toArray(),
				radius: boundingSphere.radius
			}

		}

960
		return data;
961 962 963

	},

M
Mr.doob 已提交
964
	clone: function () {
O
ohmed 已提交
965 966 967 968 969

		var geometry = new THREE.BufferGeometry();

		for ( var attr in this.attributes ) {

M
Mr.doob 已提交
970
			var sourceAttr = this.attributes[ attr ];
D
dubejf 已提交
971
			geometry.addAttribute( attr, sourceAttr.clone() );
O
ohmed 已提交
972 973 974

		}

O
ohmed 已提交
975
		for ( var i = 0, il = this.offsets.length; i < il; i ++ ) {
O
ohmed 已提交
976 977 978

			var offset = this.offsets[ i ];

M
Mr.doob 已提交
979
			geometry.offsets.push( {
O
ohmed 已提交
980

O
ohmed 已提交
981 982 983
				start: offset.start,
				index: offset.index,
				count: offset.count
O
ohmed 已提交
984

M
Mr.doob 已提交
985
			} );
O
ohmed 已提交
986

O
ohmed 已提交
987
		}
O
ohmed 已提交
988 989 990 991 992

		return geometry;

	},

993
	dispose: function () {
994

995
		this.dispatchEvent( { type: 'dispose' } );
996

997
	}
998 999

};
M
Mr.doob 已提交
1000 1001

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