1 /**
  2  * @author mrdoob / http://mrdoob.com/
  3  */
  4 
  5 /**@constructor*/
  6 THREE.CanvasRenderer = function ( parameters ) {
  7 
  8 	console.log( 'THREE.CanvasRenderer', THREE.REVISION );
  9 
 10 	parameters = parameters || {};
 11 
 12 	var _this = this,
 13 	_renderData, _elements, _lights,
 14 	_projector = new THREE.Projector(),
 15 
 16 	_canvas = parameters.canvas !== undefined ? parameters.canvas : document.createElement( 'canvas' ),
 17 
 18 	_canvasWidth, _canvasHeight, _canvasWidthHalf, _canvasHeightHalf,
 19 	_context = _canvas.getContext( '2d' ),
 20 
 21 	_clearColor = new THREE.Color( 0x000000 ),
 22 	_clearOpacity = 0,
 23 
 24 	_contextGlobalAlpha = 1,
 25 	_contextGlobalCompositeOperation = 0,
 26 	_contextStrokeStyle = null,
 27 	_contextFillStyle = null,
 28 	_contextLineWidth = null,
 29 	_contextLineCap = null,
 30 	_contextLineJoin = null,
 31 
 32 	_v1, _v2, _v3, _v4,
 33 	_v5 = new THREE.RenderableVertex(),
 34 	_v6 = new THREE.RenderableVertex(),
 35 
 36 	_v1x, _v1y, _v2x, _v2y, _v3x, _v3y,
 37 	_v4x, _v4y, _v5x, _v5y, _v6x, _v6y,
 38 
 39 	_color = new THREE.Color(),
 40 	_color1 = new THREE.Color(),
 41 	_color2 = new THREE.Color(),
 42 	_color3 = new THREE.Color(),
 43 	_color4 = new THREE.Color(),
 44 
 45 	_diffuseColor = new THREE.Color(),
 46 	_emissiveColor = new THREE.Color(),
 47 
 48 	_patterns = {}, _imagedatas = {},
 49 
 50 	_near, _far,
 51 
 52 	_image, _uvs,
 53 	_uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y,
 54 
 55 	_clipRect = new THREE.Rectangle(),
 56 	_clearRect = new THREE.Rectangle(),
 57 	_bboxRect = new THREE.Rectangle(),
 58 
 59 	_enableLighting = false,
 60 	_ambientLight = new THREE.Color(),
 61 	_directionalLights = new THREE.Color(),
 62 	_pointLights = new THREE.Color(),
 63 
 64 	_pi2 = Math.PI * 2,
 65 	_vector3 = new THREE.Vector3(), // Needed for PointLight
 66 
 67 	_pixelMap, _pixelMapContext, _pixelMapImage, _pixelMapData,
 68 	_gradientMap, _gradientMapContext, _gradientMapQuality = 16;
 69 
 70 	_pixelMap = document.createElement( 'canvas' );
 71 	_pixelMap.width = _pixelMap.height = 2;
 72 
 73 	_pixelMapContext = _pixelMap.getContext( '2d' );
 74 	_pixelMapContext.fillStyle = 'rgba(0,0,0,1)';
 75 	_pixelMapContext.fillRect( 0, 0, 2, 2 );
 76 
 77 	_pixelMapImage = _pixelMapContext.getImageData( 0, 0, 2, 2 );
 78 	_pixelMapData = _pixelMapImage.data;
 79 
 80 	_gradientMap = document.createElement( 'canvas' );
 81 	_gradientMap.width = _gradientMap.height = _gradientMapQuality;
 82 
 83 	_gradientMapContext = _gradientMap.getContext( '2d' );
 84 	_gradientMapContext.translate( - _gradientMapQuality / 2, - _gradientMapQuality / 2 );
 85 	_gradientMapContext.scale( _gradientMapQuality, _gradientMapQuality );
 86 
 87 	_gradientMapQuality --; // Fix UVs
 88 
 89 	this.domElement = _canvas;
 90 
 91 	this.autoClear = true;
 92 	this.sortObjects = true;
 93 	this.sortElements = true;
 94 
 95 	this.info = {
 96 
 97 		render: {
 98 
 99 			vertices: 0,
100 			faces: 0
101 
102 		}
103 
104 	}
105 
106 	this.setSize = function ( width, height ) {
107 
108 		_canvasWidth = width;
109 		_canvasHeight = height;
110 		_canvasWidthHalf = Math.floor( _canvasWidth / 2 );
111 		_canvasHeightHalf = Math.floor( _canvasHeight / 2 );
112 
113 		_canvas.width = _canvasWidth;
114 		_canvas.height = _canvasHeight;
115 
116 		_clipRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
117 		_clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
118 
119 		_contextGlobalAlpha = 1;
120 		_contextGlobalCompositeOperation = 0;
121 		_contextStrokeStyle = null;
122 		_contextFillStyle = null;
123 		_contextLineWidth = null;
124 		_contextLineCap = null;
125 		_contextLineJoin = null;
126 
127 	};
128 
129 	this.setClearColor = function ( color, opacity ) {
130 
131 		_clearColor.copy( color );
132 		_clearOpacity = opacity !== undefined ? opacity : 1;
133 
134 		_clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
135 
136 	};
137 
138 	this.setClearColorHex = function ( hex, opacity ) {
139 
140 		_clearColor.setHex( hex );
141 		_clearOpacity = opacity !== undefined ? opacity : 1;
142 
143 		_clearRect.set( - _canvasWidthHalf, - _canvasHeightHalf, _canvasWidthHalf, _canvasHeightHalf );
144 
145 	};
146 
147 	this.getMaxAnisotropy  = function () {
148 
149 		return 0;
150 
151 	};
152 
153 	this.clear = function () {
154 
155 		_context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf );
156 
157 		if ( _clearRect.isEmpty() === false ) {
158 
159 			_clearRect.minSelf( _clipRect );
160 			_clearRect.inflate( 2 );
161 
162 			if ( _clearOpacity < 1 ) {
163 
164 				_context.clearRect( Math.floor( _clearRect.getX() ), Math.floor( _clearRect.getY() ), Math.floor( _clearRect.getWidth() ), Math.floor( _clearRect.getHeight() ) );
165 
166 			}
167 
168 			if ( _clearOpacity > 0 ) {
169 
170 				setBlending( THREE.NormalBlending );
171 				setOpacity( 1 );
172 
173 				setFillStyle( 'rgba(' + Math.floor( _clearColor.r * 255 ) + ',' + Math.floor( _clearColor.g * 255 ) + ',' + Math.floor( _clearColor.b * 255 ) + ',' + _clearOpacity + ')' );
174 
175 				_context.fillRect( Math.floor( _clearRect.getX() ), Math.floor( _clearRect.getY() ), Math.floor( _clearRect.getWidth() ), Math.floor( _clearRect.getHeight() ) );
176 
177 			}
178 
179 			_clearRect.empty();
180 
181 		}
182 
183 
184 	};
185 
186 	this.render = function ( scene, camera ) {
187 
188 		if ( camera instanceof THREE.Camera === false ) {
189 
190 			console.error( 'THREE.CanvasRenderer.render: camera is not an instance of THREE.Camera.' );
191 			return;
192 
193 		}
194 
195 		var e, el, element, material;
196 
197 		this.autoClear === true
198 			? this.clear()
199 			: _context.setTransform( 1, 0, 0, - 1, _canvasWidthHalf, _canvasHeightHalf );
200 
201 		_this.info.render.vertices = 0;
202 		_this.info.render.faces = 0;
203 
204 		_renderData = _projector.projectScene( scene, camera, this.sortObjects, this.sortElements );
205 		_elements = _renderData.elements;
206 		_lights = _renderData.lights;
207 
208 		/* DEBUG
209 		_context.fillStyle = 'rgba( 0, 255, 255, 0.5 )';
210 		_context.fillRect( _clipRect.getX(), _clipRect.getY(), _clipRect.getWidth(), _clipRect.getHeight() );
211 		*/
212 
213 		_enableLighting = _lights.length > 0;
214 
215 		if ( _enableLighting === true ) {
216 
217 			 calculateLights();
218 
219 		}
220 
221 		for ( e = 0, el = _elements.length; e < el; e++ ) {
222 
223 			element = _elements[ e ];
224 
225 			material = element.material;
226 
227 			if ( material === undefined || material.visible === false ) continue;
228 
229 			_bboxRect.empty();
230 
231 			if ( element instanceof THREE.RenderableParticle ) {
232 
233 				_v1 = element;
234 				_v1.x *= _canvasWidthHalf; _v1.y *= _canvasHeightHalf;
235 
236 				renderParticle( _v1, element, material, scene );
237 
238 			} else if ( element instanceof THREE.RenderableLine ) {
239 
240 				_v1 = element.v1; _v2 = element.v2;
241 
242 				_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
243 				_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
244 
245 				_bboxRect.addPoint( _v1.positionScreen.x, _v1.positionScreen.y );
246 				_bboxRect.addPoint( _v2.positionScreen.x, _v2.positionScreen.y );
247 
248 				if ( _clipRect.intersects( _bboxRect ) === true ) {
249 
250 					renderLine( _v1, _v2, element, material, scene );
251 
252 				}
253 
254 
255 			} else if ( element instanceof THREE.RenderableFace3 ) {
256 
257 				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3;
258 
259 				_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
260 				_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
261 				_v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
262 
263 				if ( material.overdraw === true ) {
264 
265 					expand( _v1.positionScreen, _v2.positionScreen );
266 					expand( _v2.positionScreen, _v3.positionScreen );
267 					expand( _v3.positionScreen, _v1.positionScreen );
268 
269 				}
270 
271 				_bboxRect.add3Points( _v1.positionScreen.x, _v1.positionScreen.y,
272 						      _v2.positionScreen.x, _v2.positionScreen.y,
273 						      _v3.positionScreen.x, _v3.positionScreen.y );
274 
275 				if ( _clipRect.intersects( _bboxRect ) === true ) {
276 
277 					renderFace3( _v1, _v2, _v3, 0, 1, 2, element, material, scene );
278 
279 				}
280 
281 			} else if ( element instanceof THREE.RenderableFace4 ) {
282 
283 				_v1 = element.v1; _v2 = element.v2; _v3 = element.v3; _v4 = element.v4;
284 
285 				_v1.positionScreen.x *= _canvasWidthHalf; _v1.positionScreen.y *= _canvasHeightHalf;
286 				_v2.positionScreen.x *= _canvasWidthHalf; _v2.positionScreen.y *= _canvasHeightHalf;
287 				_v3.positionScreen.x *= _canvasWidthHalf; _v3.positionScreen.y *= _canvasHeightHalf;
288 				_v4.positionScreen.x *= _canvasWidthHalf; _v4.positionScreen.y *= _canvasHeightHalf;
289 
290 				_v5.positionScreen.copy( _v2.positionScreen );
291 				_v6.positionScreen.copy( _v4.positionScreen );
292 
293 				if ( material.overdraw === true ) {
294 
295 					expand( _v1.positionScreen, _v2.positionScreen );
296 					expand( _v2.positionScreen, _v4.positionScreen );
297 					expand( _v4.positionScreen, _v1.positionScreen );
298 
299 					expand( _v3.positionScreen, _v5.positionScreen );
300 					expand( _v3.positionScreen, _v6.positionScreen );
301 
302 				}
303 
304 				_bboxRect.addPoint( _v1.positionScreen.x, _v1.positionScreen.y );
305 				_bboxRect.addPoint( _v2.positionScreen.x, _v2.positionScreen.y );
306 				_bboxRect.addPoint( _v3.positionScreen.x, _v3.positionScreen.y );
307 				_bboxRect.addPoint( _v4.positionScreen.x, _v4.positionScreen.y );
308 
309 				if ( _clipRect.intersects( _bboxRect ) === true ) {
310 
311 					renderFace4( _v1, _v2, _v3, _v4, _v5, _v6, element, material, scene );
312 
313 				}
314 
315 			}
316 
317 			/* DEBUG
318 			_context.lineWidth = 1;
319 			_context.strokeStyle = 'rgba( 0, 255, 0, 0.5 )';
320 			_context.strokeRect( _bboxRect.getX(), _bboxRect.getY(), _bboxRect.getWidth(), _bboxRect.getHeight() );
321 			*/
322 
323 			_clearRect.addRectangle( _bboxRect );
324 
325 
326 		}
327 
328 		/* DEBUG
329 		_context.lineWidth = 1;
330 		_context.strokeStyle = 'rgba( 255, 0, 0, 0.5 )';
331 		_context.strokeRect( _clearRect.getX(), _clearRect.getY(), _clearRect.getWidth(), _clearRect.getHeight() );
332 		*/
333 
334 		_context.setTransform( 1, 0, 0, 1, 0, 0 );
335 
336 		//
337 
338 		function calculateLights() {
339 
340 			_ambientLight.setRGB( 0, 0, 0 );
341 			_directionalLights.setRGB( 0, 0, 0 );
342 			_pointLights.setRGB( 0, 0, 0 );
343 
344 			for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
345 
346 				var light = _lights[ l ];
347 				var lightColor = light.color;
348 
349 				if ( light instanceof THREE.AmbientLight ) {
350 
351 					_ambientLight.r += lightColor.r;
352 					_ambientLight.g += lightColor.g;
353 					_ambientLight.b += lightColor.b;
354 
355 				} else if ( light instanceof THREE.DirectionalLight ) {
356 
357 					// for particles
358 
359 					_directionalLights.r += lightColor.r;
360 					_directionalLights.g += lightColor.g;
361 					_directionalLights.b += lightColor.b;
362 
363 				} else if ( light instanceof THREE.PointLight ) {
364 
365 					// for particles
366 
367 					_pointLights.r += lightColor.r;
368 					_pointLights.g += lightColor.g;
369 					_pointLights.b += lightColor.b;
370 
371 				}
372 
373 			}
374 
375 		}
376 
377 		function calculateLight( position, normal, color ) {
378 
379 			for ( var l = 0, ll = _lights.length; l < ll; l ++ ) {
380 
381 				var light = _lights[ l ];
382 				var lightColor = light.color;
383 
384 				if ( light instanceof THREE.DirectionalLight ) {
385 
386 					var lightPosition = light.matrixWorld.getPosition().normalize();
387 
388 					var amount = normal.dot( lightPosition );
389 
390 					if ( amount <= 0 ) continue;
391 
392 					amount *= light.intensity;
393 
394 					color.r += lightColor.r * amount;
395 					color.g += lightColor.g * amount;
396 					color.b += lightColor.b * amount;
397 
398 				} else if ( light instanceof THREE.PointLight ) {
399 
400 					var lightPosition = light.matrixWorld.getPosition();
401 
402 					var amount = normal.dot( _vector3.sub( lightPosition, position ).normalize() );
403 
404 					if ( amount <= 0 ) continue;
405 
406 					amount *= light.distance == 0 ? 1 : 1 - Math.min( position.distanceTo( lightPosition ) / light.distance, 1 );
407 
408 					if ( amount == 0 ) continue;
409 
410 					amount *= light.intensity;
411 
412 					color.r += lightColor.r * amount;
413 					color.g += lightColor.g * amount;
414 					color.b += lightColor.b * amount;
415 
416 				}
417 
418 			}
419 
420 		}
421 
422 		function renderParticle( v1, element, material, scene ) {
423 
424 			setOpacity( material.opacity );
425 			setBlending( material.blending );
426 
427 			var width, height, scaleX, scaleY,
428 			bitmap, bitmapWidth, bitmapHeight;
429 
430 			if ( material instanceof THREE.ParticleBasicMaterial ) {
431 
432 				if ( material.map === null ) {
433 
434 					scaleX = element.object.scale.x;
435 					scaleY = element.object.scale.y;
436 
437 					// TODO: Be able to disable this
438 
439 					scaleX *= element.scale.x * _canvasWidthHalf;
440 					scaleY *= element.scale.y * _canvasHeightHalf;
441 
442 					_bboxRect.set( v1.x - scaleX, v1.y - scaleY, v1.x  + scaleX, v1.y + scaleY );
443 
444 					if ( _clipRect.intersects( _bboxRect ) === false ) {
445 
446 						return;
447 
448 					}
449 
450 					setFillStyle( material.color.getContextStyle() );
451 
452 					_context.save();
453 					_context.translate( v1.x, v1.y );
454 					_context.rotate( - element.rotation );
455 					_context.scale( scaleX, scaleY );
456 					_context.fillRect( -1, -1, 2, 2 );
457 					_context.restore();
458 
459 				} else {
460 
461 					bitmap = material.map.image;
462 					bitmapWidth = bitmap.width >> 1;
463 					bitmapHeight = bitmap.height >> 1;
464 
465 					scaleX = element.scale.x * _canvasWidthHalf;
466 					scaleY = element.scale.y * _canvasHeightHalf;
467 
468 					width = scaleX * bitmapWidth;
469 					height = scaleY * bitmapHeight;
470 
471 					// TODO: Rotations break this...
472 
473 					_bboxRect.set( v1.x - width, v1.y - height, v1.x  + width, v1.y + height );
474 
475 					if ( _clipRect.intersects( _bboxRect ) === false ) {
476 
477 						return;
478 
479 					}
480 
481 					_context.save();
482 					_context.translate( v1.x, v1.y );
483 					_context.rotate( - element.rotation );
484 					_context.scale( scaleX, - scaleY );
485 
486 					_context.translate( - bitmapWidth, - bitmapHeight );
487 					_context.drawImage( bitmap, 0, 0 );
488 					_context.restore();
489 
490 				}
491 
492 				/* DEBUG
493 				setStrokeStyle( 'rgb(255,255,0)' );
494 				_context.beginPath();
495 				_context.moveTo( v1.x - 10, v1.y );
496 				_context.lineTo( v1.x + 10, v1.y );
497 				_context.moveTo( v1.x, v1.y - 10 );
498 				_context.lineTo( v1.x, v1.y + 10 );
499 				_context.stroke();
500 				*/
501 
502 			} else if ( material instanceof THREE.ParticleCanvasMaterial ) {
503 
504 				width = element.scale.x * _canvasWidthHalf;
505 				height = element.scale.y * _canvasHeightHalf;
506 
507 				_bboxRect.set( v1.x - width, v1.y - height, v1.x + width, v1.y + height );
508 
509 				if ( _clipRect.intersects( _bboxRect ) === false ) {
510 
511 					return;
512 
513 				}
514 
515 				setStrokeStyle( material.color.getContextStyle() );
516 				setFillStyle( material.color.getContextStyle() );
517 
518 				_context.save();
519 				_context.translate( v1.x, v1.y );
520 				_context.rotate( - element.rotation );
521 				_context.scale( width, height );
522 
523 				material.program( _context );
524 
525 				_context.restore();
526 
527 			}
528 
529 		}
530 
531 		function renderLine( v1, v2, element, material, scene ) {
532 
533 			setOpacity( material.opacity );
534 			setBlending( material.blending );
535 
536 			_context.beginPath();
537 			_context.moveTo( v1.positionScreen.x, v1.positionScreen.y );
538 			_context.lineTo( v2.positionScreen.x, v2.positionScreen.y );
539 
540 			if ( material instanceof THREE.LineBasicMaterial ) {
541 
542 				setLineWidth( material.linewidth );
543 				setLineCap( material.linecap );
544 				setLineJoin( material.linejoin );
545 				setStrokeStyle( material.color.getContextStyle() );
546 
547 				_context.stroke();
548 				_bboxRect.inflate( material.linewidth * 2 );
549 
550 			}
551 
552 		}
553 
554 		function renderFace3( v1, v2, v3, uv1, uv2, uv3, element, material, scene ) {
555 
556 			_this.info.render.vertices += 3;
557 			_this.info.render.faces ++;
558 
559 			setOpacity( material.opacity );
560 			setBlending( material.blending );
561 
562 			_v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
563 			_v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
564 			_v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
565 
566 			drawTriangle( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y );
567 
568 			if ( ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) && material.map === null && material.map === null ) {
569 
570 				_diffuseColor.copy( material.color );
571 				_emissiveColor.copy( material.emissive );
572 
573 				if ( material.vertexColors === THREE.FaceColors ) {
574 
575 					_diffuseColor.r *= element.color.r;
576 					_diffuseColor.g *= element.color.g;
577 					_diffuseColor.b *= element.color.b;
578 
579 				}
580 
581 				if ( _enableLighting === true ) {
582 
583 					if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 3 ) {
584 
585 						_color1.r = _color2.r = _color3.r = _ambientLight.r;
586 						_color1.g = _color2.g = _color3.g = _ambientLight.g;
587 						_color1.b = _color2.b = _color3.b = _ambientLight.b;
588 
589 						calculateLight( element.v1.positionWorld, element.vertexNormalsWorld[ 0 ], _color1 );
590 						calculateLight( element.v2.positionWorld, element.vertexNormalsWorld[ 1 ], _color2 );
591 						calculateLight( element.v3.positionWorld, element.vertexNormalsWorld[ 2 ], _color3 );
592 
593 						_color1.r = _color1.r * _diffuseColor.r + _emissiveColor.r;
594 						_color1.g = _color1.g * _diffuseColor.g + _emissiveColor.g;
595 						_color1.b = _color1.b * _diffuseColor.b + _emissiveColor.b;
596 
597 						_color2.r = _color2.r * _diffuseColor.r + _emissiveColor.r;
598 						_color2.g = _color2.g * _diffuseColor.g + _emissiveColor.g;
599 						_color2.b = _color2.b * _diffuseColor.b + _emissiveColor.b;
600 
601 						_color3.r = _color3.r * _diffuseColor.r + _emissiveColor.r;
602 						_color3.g = _color3.g * _diffuseColor.g + _emissiveColor.g;
603 						_color3.b = _color3.b * _diffuseColor.b + _emissiveColor.b;
604 
605 						_color4.r = ( _color2.r + _color3.r ) * 0.5;
606 						_color4.g = ( _color2.g + _color3.g ) * 0.5;
607 						_color4.b = ( _color2.b + _color3.b ) * 0.5;
608 
609 						_image = getGradientTexture( _color1, _color2, _color3, _color4 );
610 
611 						clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );
612 
613 					} else {
614 
615 						_color.r = _ambientLight.r;
616 						_color.g = _ambientLight.g;
617 						_color.b = _ambientLight.b;
618 
619 						calculateLight( element.centroidWorld, element.normalWorld, _color );
620 
621 						_color.r = _color.r * _diffuseColor.r + _emissiveColor.r;
622 						_color.g = _color.g * _diffuseColor.g + _emissiveColor.g;
623 						_color.b = _color.b * _diffuseColor.b + _emissiveColor.b;
624 
625 						material.wireframe === true
626 							? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
627 							: fillPath( _color );
628 
629 					}
630 
631 				} else {
632 
633 					material.wireframe === true
634 						? strokePath( material.color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
635 						: fillPath( material.color );
636 
637 				}
638 
639 			} else if ( material instanceof THREE.MeshBasicMaterial || material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
640 
641 				if ( material.map !== null ) {
642 
643 					if ( material.map.mapping instanceof THREE.UVMapping ) {
644 
645 						_uvs = element.uvs[ 0 ];
646 						patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uvs[ uv1 ].u, _uvs[ uv1 ].v, _uvs[ uv2 ].u, _uvs[ uv2 ].v, _uvs[ uv3 ].u, _uvs[ uv3 ].v, material.map );
647 
648 					}
649 
650 
651 				} else if ( material.envMap !== null ) {
652 
653 					if ( material.envMap.mapping instanceof THREE.SphericalReflectionMapping ) {
654 
655 						var cameraMatrix = camera.matrixWorldInverse;
656 
657 						_vector3.copy( element.vertexNormalsWorld[ uv1 ] );
658 						_uv1x = ( _vector3.x * cameraMatrix.elements[0] + _vector3.y * cameraMatrix.elements[4] + _vector3.z * cameraMatrix.elements[8] ) * 0.5 + 0.5;
659 						_uv1y = ( _vector3.x * cameraMatrix.elements[1] + _vector3.y * cameraMatrix.elements[5] + _vector3.z * cameraMatrix.elements[9] ) * 0.5 + 0.5;
660 
661 						_vector3.copy( element.vertexNormalsWorld[ uv2 ] );
662 						_uv2x = ( _vector3.x * cameraMatrix.elements[0] + _vector3.y * cameraMatrix.elements[4] + _vector3.z * cameraMatrix.elements[8] ) * 0.5 + 0.5;
663 						_uv2y = ( _vector3.x * cameraMatrix.elements[1] + _vector3.y * cameraMatrix.elements[5] + _vector3.z * cameraMatrix.elements[9] ) * 0.5 + 0.5;
664 
665 						_vector3.copy( element.vertexNormalsWorld[ uv3 ] );
666 						_uv3x = ( _vector3.x * cameraMatrix.elements[0] + _vector3.y * cameraMatrix.elements[4] + _vector3.z * cameraMatrix.elements[8] ) * 0.5 + 0.5;
667 						_uv3y = ( _vector3.x * cameraMatrix.elements[1] + _vector3.y * cameraMatrix.elements[5] + _vector3.z * cameraMatrix.elements[9] ) * 0.5 + 0.5;
668 
669 						patternPath( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _uv1x, _uv1y, _uv2x, _uv2y, _uv3x, _uv3y, material.envMap );
670 
671 					}/* else if ( material.envMap.mapping == THREE.SphericalRefractionMapping ) {
672 
673 
674 
675 					}*/
676 
677 
678 				} else {
679 
680 					_color.copy( material.color );
681 
682 					if ( material.vertexColors === THREE.FaceColors ) {
683 
684 						_color.r *= element.color.r;
685 						_color.g *= element.color.g;
686 						_color.b *= element.color.b;
687 
688 					}
689 
690 					material.wireframe === true
691 						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
692 						: fillPath( _color );
693 
694 				}
695 
696 			} else if ( material instanceof THREE.MeshDepthMaterial ) {
697 
698 				_near = camera.near;
699 				_far = camera.far;
700 
701 				_color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z, _near, _far );
702 				_color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z, _near, _far );
703 				_color3.r = _color3.g = _color3.b = 1 - smoothstep( v3.positionScreen.z, _near, _far );
704 
705 				_color4.r = ( _color2.r + _color3.r ) * 0.5;
706 				_color4.g = ( _color2.g + _color3.g ) * 0.5;
707 				_color4.b = ( _color2.b + _color3.b ) * 0.5;
708 
709 				_image = getGradientTexture( _color1, _color2, _color3, _color4 );
710 
711 				clipImage( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, 0, 0, 1, 0, 0, 1, _image );
712 
713 			} else if ( material instanceof THREE.MeshNormalMaterial ) {
714 
715 				_color.r = normalToComponent( element.normalWorld.x );
716 				_color.g = normalToComponent( element.normalWorld.y );
717 				_color.b = normalToComponent( element.normalWorld.z );
718 
719 				material.wireframe === true
720 					? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
721 					: fillPath( _color );
722 
723 			}
724 
725 		}
726 
727 		function renderFace4( v1, v2, v3, v4, v5, v6, element, material, scene ) {
728 
729 			_this.info.render.vertices += 4;
730 			_this.info.render.faces ++;
731 
732 			setOpacity( material.opacity );
733 			setBlending( material.blending );
734 
735 			if ( ( material.map !== undefined && material.map !== null ) || ( material.envMap !== undefined && material.envMap !== null ) ) {
736 
737 				// Let renderFace3() handle this
738 
739 				renderFace3( v1, v2, v4, 0, 1, 3, element, material, scene );
740 				renderFace3( v5, v3, v6, 1, 2, 3, element, material, scene );
741 
742 				return;
743 
744 			}
745 
746 			_v1x = v1.positionScreen.x; _v1y = v1.positionScreen.y;
747 			_v2x = v2.positionScreen.x; _v2y = v2.positionScreen.y;
748 			_v3x = v3.positionScreen.x; _v3y = v3.positionScreen.y;
749 			_v4x = v4.positionScreen.x; _v4y = v4.positionScreen.y;
750 			_v5x = v5.positionScreen.x; _v5y = v5.positionScreen.y;
751 			_v6x = v6.positionScreen.x; _v6y = v6.positionScreen.y;
752 
753 			if ( material instanceof THREE.MeshLambertMaterial || material instanceof THREE.MeshPhongMaterial ) {
754 
755 				_diffuseColor.copy( material.color );
756 				_emissiveColor.copy( material.emissive );
757 
758 				if ( material.vertexColors === THREE.FaceColors ) {
759 
760 					_diffuseColor.r *= element.color.r;
761 					_diffuseColor.g *= element.color.g;
762 					_diffuseColor.b *= element.color.b;
763 
764 				}
765 
766 				if ( _enableLighting === true ) {
767 
768 					if ( material.wireframe === false && material.shading == THREE.SmoothShading && element.vertexNormalsLength == 4 ) {
769 
770 						_color1.r = _color2.r = _color3.r = _color4.r = _ambientLight.r;
771 						_color1.g = _color2.g = _color3.g = _color4.g = _ambientLight.g;
772 						_color1.b = _color2.b = _color3.b = _color4.b = _ambientLight.b;
773 
774 						calculateLight( element.v1.positionWorld, element.vertexNormalsWorld[ 0 ], _color1 );
775 						calculateLight( element.v2.positionWorld, element.vertexNormalsWorld[ 1 ], _color2 );
776 						calculateLight( element.v4.positionWorld, element.vertexNormalsWorld[ 3 ], _color3 );
777 						calculateLight( element.v3.positionWorld, element.vertexNormalsWorld[ 2 ], _color4 );
778 
779 						_color1.r = _color1.r * _diffuseColor.r + _emissiveColor.r;
780 						_color1.g = _color1.g * _diffuseColor.g + _emissiveColor.g;
781 						_color1.b = _color1.b * _diffuseColor.b + _emissiveColor.b;
782 
783 						_color2.r = _color2.r * _diffuseColor.r + _emissiveColor.r;
784 						_color2.g = _color2.g * _diffuseColor.g + _emissiveColor.g;
785 						_color2.b = _color2.b * _diffuseColor.b + _emissiveColor.b;
786 
787 						_color3.r = _color3.r * _diffuseColor.r + _emissiveColor.r;
788 						_color3.g = _color3.g * _diffuseColor.g + _emissiveColor.g;
789 						_color3.b = _color3.b * _diffuseColor.b + _emissiveColor.b;
790 
791 						_color4.r = _color4.r * _diffuseColor.r + _emissiveColor.r;
792 						_color4.g = _color4.g * _diffuseColor.g + _emissiveColor.g;
793 						_color4.b = _color4.b * _diffuseColor.b + _emissiveColor.b;
794 
795 						_image = getGradientTexture( _color1, _color2, _color3, _color4 );
796 
797 						// TODO: UVs are incorrect, v4->v3?
798 
799 						drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
800 						clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );
801 
802 						drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
803 						clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );
804 
805 					} else {
806 
807 						_color.r = _ambientLight.r;
808 						_color.g = _ambientLight.g;
809 						_color.b = _ambientLight.b;
810 
811 						calculateLight( element.centroidWorld, element.normalWorld, _color );
812 
813 						_color.r = _color.r * _diffuseColor.r + _emissiveColor.r;
814 						_color.g = _color.g * _diffuseColor.g + _emissiveColor.g;
815 						_color.b = _color.b * _diffuseColor.b + _emissiveColor.b;
816 
817 						drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
818 
819 						material.wireframe === true
820 							? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
821 							: fillPath( _color );
822 
823 					}
824 
825 				} else {
826 
827 					_color.r = _diffuseColor.r + _emissiveColor.r;
828 					_color.g = _diffuseColor.g + _emissiveColor.g;
829 					_color.b = _diffuseColor.b + _emissiveColor.b;
830 
831 					drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
832 
833 					material.wireframe === true
834 						? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
835 						: fillPath( _color );
836 
837 				}
838 
839 			} else if ( material instanceof THREE.MeshBasicMaterial ) {
840 
841 				_color.copy( material.color );
842 
843 				if ( material.vertexColors === THREE.FaceColors ) {
844 
845 					_color.r *= element.color.r;
846 					_color.g *= element.color.g;
847 					_color.b *= element.color.b;
848 
849 				}
850 
851 				drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
852 
853 				material.wireframe === true
854 					? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
855 					: fillPath( _color );
856 
857 			} else if ( material instanceof THREE.MeshNormalMaterial ) {
858 
859 				_color.r = normalToComponent( element.normalWorld.x );
860 				_color.g = normalToComponent( element.normalWorld.y );
861 				_color.b = normalToComponent( element.normalWorld.z );
862 
863 				drawQuad( _v1x, _v1y, _v2x, _v2y, _v3x, _v3y, _v4x, _v4y );
864 
865 				material.wireframe === true
866 					? strokePath( _color, material.wireframeLinewidth, material.wireframeLinecap, material.wireframeLinejoin )
867 					: fillPath( _color );
868 
869 			} else if ( material instanceof THREE.MeshDepthMaterial ) {
870 
871 				_near = camera.near;
872 				_far = camera.far;
873 
874 				_color1.r = _color1.g = _color1.b = 1 - smoothstep( v1.positionScreen.z, _near, _far );
875 				_color2.r = _color2.g = _color2.b = 1 - smoothstep( v2.positionScreen.z, _near, _far );
876 				_color3.r = _color3.g = _color3.b = 1 - smoothstep( v4.positionScreen.z, _near, _far );
877 				_color4.r = _color4.g = _color4.b = 1 - smoothstep( v3.positionScreen.z, _near, _far );
878 
879 				_image = getGradientTexture( _color1, _color2, _color3, _color4 );
880 
881 				// TODO: UVs are incorrect, v4->v3?
882 
883 				drawTriangle( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y );
884 				clipImage( _v1x, _v1y, _v2x, _v2y, _v4x, _v4y, 0, 0, 1, 0, 0, 1, _image );
885 
886 				drawTriangle( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y );
887 				clipImage( _v5x, _v5y, _v3x, _v3y, _v6x, _v6y, 1, 0, 1, 1, 0, 1, _image );
888 
889 			}
890 
891 		}
892 
893 		//
894 
895 		function drawTriangle( x0, y0, x1, y1, x2, y2 ) {
896 
897 			_context.beginPath();
898 			_context.moveTo( x0, y0 );
899 			_context.lineTo( x1, y1 );
900 			_context.lineTo( x2, y2 );
901 			_context.closePath();
902 
903 		}
904 
905 		function drawQuad( x0, y0, x1, y1, x2, y2, x3, y3 ) {
906 
907 			_context.beginPath();
908 			_context.moveTo( x0, y0 );
909 			_context.lineTo( x1, y1 );
910 			_context.lineTo( x2, y2 );
911 			_context.lineTo( x3, y3 );
912 			_context.closePath();
913 
914 		}
915 
916 		function strokePath( color, linewidth, linecap, linejoin ) {
917 
918 			setLineWidth( linewidth );
919 			setLineCap( linecap );
920 			setLineJoin( linejoin );
921 			setStrokeStyle( color.getContextStyle() );
922 
923 			_context.stroke();
924 
925 			_bboxRect.inflate( linewidth * 2 );
926 
927 		}
928 
929 		function fillPath( color ) {
930 
931 			setFillStyle( color.getContextStyle() );
932 			_context.fill();
933 
934 		}
935 
936 		function patternPath( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, texture ) {
937 
938 			if ( texture instanceof THREE.DataTexture || texture.image === undefined || texture.image.width == 0 ) return;
939 
940 			if ( texture.needsUpdate === true ) {
941 
942 				var repeatX = texture.wrapS == THREE.RepeatWrapping;
943 				var repeatY = texture.wrapT == THREE.RepeatWrapping;
944 
945 				_patterns[ texture.id ] = _context.createPattern(
946 					texture.image, repeatX === true && repeatY === true
947 						? 'repeat'
948 						: repeatX === true && repeatY === false
949 							? 'repeat-x'
950 							: repeatX === false && repeatY === true
951 								? 'repeat-y'
952 								: 'no-repeat'
953 				);
954 
955 				texture.needsUpdate = false;
956 
957 			}
958 
959 			_patterns[ texture.id ] === undefined
960 				? setFillStyle( 'rgba(0,0,0,1)' )
961 				: setFillStyle( _patterns[ texture.id ] );
962 
963 			// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
964 
965 			var a, b, c, d, e, f, det, idet,
966 			offsetX = texture.offset.x / texture.repeat.x,
967 			offsetY = texture.offset.y / texture.repeat.y,
968 			width = texture.image.width * texture.repeat.x,
969 			height = texture.image.height * texture.repeat.y;
970 
971 			u0 = ( u0 + offsetX ) * width;
972 			v0 = ( 1.0 - v0 + offsetY ) * height;
973 
974 			u1 = ( u1 + offsetX ) * width;
975 			v1 = ( 1.0 - v1 + offsetY ) * height;
976 
977 			u2 = ( u2 + offsetX ) * width;
978 			v2 = ( 1.0 - v2 + offsetY ) * height;
979 
980 			x1 -= x0; y1 -= y0;
981 			x2 -= x0; y2 -= y0;
982 
983 			u1 -= u0; v1 -= v0;
984 			u2 -= u0; v2 -= v0;
985 
986 			det = u1 * v2 - u2 * v1;
987 
988 			if ( det === 0 ) {
989 
990 				if ( _imagedatas[ texture.id ] === undefined ) {
991 
992 					var canvas = document.createElement( 'canvas' )
993 					canvas.width = texture.image.width;
994 					canvas.height = texture.image.height;
995 
996 					var context = canvas.getContext( '2d' );
997 					context.drawImage( texture.image, 0, 0 );
998 
999 					_imagedatas[ texture.id ] = context.getImageData( 0, 0, texture.image.width, texture.image.height ).data;
1000 
1001 				}
1002 
1003 				var data = _imagedatas[ texture.id ];
1004 				var index = ( Math.floor( u0 ) + Math.floor( v0 ) * texture.image.width ) * 4;
1005 
1006 				_color.setRGB( data[ index ] / 255, data[ index + 1 ] / 255, data[ index + 2 ] / 255 );
1007 				fillPath( _color );
1008 
1009 				return;
1010 
1011 			}
1012 
1013 			idet = 1 / det;
1014 
1015 			a = ( v2 * x1 - v1 * x2 ) * idet;
1016 			b = ( v2 * y1 - v1 * y2 ) * idet;
1017 			c = ( u1 * x2 - u2 * x1 ) * idet;
1018 			d = ( u1 * y2 - u2 * y1 ) * idet;
1019 
1020 			e = x0 - a * u0 - c * v0;
1021 			f = y0 - b * u0 - d * v0;
1022 
1023 			_context.save();
1024 			_context.transform( a, b, c, d, e, f );
1025 			_context.fill();
1026 			_context.restore();
1027 
1028 		}
1029 
1030 		function clipImage( x0, y0, x1, y1, x2, y2, u0, v0, u1, v1, u2, v2, image ) {
1031 
1032 			// http://extremelysatisfactorytotalitarianism.com/blog/?p=2120
1033 
1034 			var a, b, c, d, e, f, det, idet,
1035 			width = image.width - 1,
1036 			height = image.height - 1;
1037 
1038 			u0 *= width; v0 *= height;
1039 			u1 *= width; v1 *= height;
1040 			u2 *= width; v2 *= height;
1041 
1042 			x1 -= x0; y1 -= y0;
1043 			x2 -= x0; y2 -= y0;
1044 
1045 			u1 -= u0; v1 -= v0;
1046 			u2 -= u0; v2 -= v0;
1047 
1048 			det = u1 * v2 - u2 * v1;
1049 
1050 			idet = 1 / det;
1051 
1052 			a = ( v2 * x1 - v1 * x2 ) * idet;
1053 			b = ( v2 * y1 - v1 * y2 ) * idet;
1054 			c = ( u1 * x2 - u2 * x1 ) * idet;
1055 			d = ( u1 * y2 - u2 * y1 ) * idet;
1056 
1057 			e = x0 - a * u0 - c * v0;
1058 			f = y0 - b * u0 - d * v0;
1059 
1060 			_context.save();
1061 			_context.transform( a, b, c, d, e, f );
1062 			_context.clip();
1063 			_context.drawImage( image, 0, 0 );
1064 			_context.restore();
1065 
1066 		}
1067 
1068 		function getGradientTexture( color1, color2, color3, color4 ) {
1069 
1070 			// http://mrdoob.com/blog/post/710
1071 
1072 			_pixelMapData[ 0 ] = ( color1.r * 255 ) | 0;
1073 			_pixelMapData[ 1 ] = ( color1.g * 255 ) | 0;
1074 			_pixelMapData[ 2 ] = ( color1.b * 255 ) | 0;
1075 
1076 			_pixelMapData[ 4 ] = ( color2.r * 255 ) | 0;
1077 			_pixelMapData[ 5 ] = ( color2.g * 255 ) | 0;
1078 			_pixelMapData[ 6 ] = ( color2.b * 255 ) | 0;
1079 
1080 			_pixelMapData[ 8 ] = ( color3.r * 255 ) | 0;
1081 			_pixelMapData[ 9 ] = ( color3.g * 255 ) | 0;
1082 			_pixelMapData[ 10 ] = ( color3.b * 255 ) | 0;
1083 
1084 			_pixelMapData[ 12 ] = ( color4.r * 255 ) | 0;
1085 			_pixelMapData[ 13 ] = ( color4.g * 255 ) | 0;
1086 			_pixelMapData[ 14 ] = ( color4.b * 255 ) | 0;
1087 
1088 			_pixelMapContext.putImageData( _pixelMapImage, 0, 0 );
1089 			_gradientMapContext.drawImage( _pixelMap, 0, 0 );
1090 
1091 			return _gradientMap;
1092 
1093 		}
1094 
1095 		function smoothstep( value, min, max ) {
1096 
1097 			var x = ( value - min ) / ( max - min );
1098 			return x * x * ( 3 - 2 * x );
1099 
1100 		}
1101 
1102 		function normalToComponent( normal ) {
1103 
1104 			var component = ( normal + 1 ) * 0.5;
1105 			return component < 0 ? 0 : ( component > 1 ? 1 : component );
1106 
1107 		}
1108 
1109 		// Hide anti-alias gaps
1110 
1111 		function expand( v1, v2 ) {
1112 
1113 			var x = v2.x - v1.x, y =  v2.y - v1.y,
1114 			det = x * x + y * y, idet;
1115 
1116 			if ( det === 0 ) return;
1117 
1118 			idet = 1 / Math.sqrt( det );
1119 
1120 			x *= idet; y *= idet;
1121 
1122 			v2.x += x; v2.y += y;
1123 			v1.x -= x; v1.y -= y;
1124 
1125 		}
1126 	};
1127 
1128 	// Context cached methods.
1129 
1130 	function setOpacity( value ) {
1131 
1132 		if ( _contextGlobalAlpha !== value ) {
1133 
1134 			_context.globalAlpha = value;
1135 			_contextGlobalAlpha = value;
1136 
1137 		}
1138 
1139 	}
1140 
1141 	function setBlending( value ) {
1142 
1143 		if ( _contextGlobalCompositeOperation !== value ) {
1144 
1145 			if ( value === THREE.NormalBlending ) {
1146 
1147 				_context.globalCompositeOperation = 'source-over';
1148 
1149 			} else if ( value === THREE.AdditiveBlending ) {
1150 
1151 				_context.globalCompositeOperation = 'lighter';
1152 
1153 			} else if ( value === THREE.SubtractiveBlending ) {
1154 
1155 				_context.globalCompositeOperation = 'darker';
1156 
1157 			}
1158 
1159 			_contextGlobalCompositeOperation = value;
1160 
1161 		}
1162 
1163 	}
1164 
1165 	function setLineWidth( value ) {
1166 
1167 		if ( _contextLineWidth !== value ) {
1168 
1169 			_context.lineWidth = value;
1170 			_contextLineWidth = value;
1171 
1172 		}
1173 
1174 	}
1175 
1176 	function setLineCap( value ) {
1177 
1178 		// "butt", "round", "square"
1179 
1180 		if ( _contextLineCap !== value ) {
1181 
1182 			_context.lineCap = value;
1183 			_contextLineCap = value;
1184 
1185 		}
1186 
1187 	}
1188 
1189 	function setLineJoin( value ) {
1190 
1191 		// "round", "bevel", "miter"
1192 
1193 		if ( _contextLineJoin !== value ) {
1194 
1195 			_context.lineJoin = value;
1196 			_contextLineJoin = value;
1197 
1198 		}
1199 
1200 	}
1201 
1202 	function setStrokeStyle( value ) {
1203 
1204 		if ( _contextStrokeStyle !== value ) {
1205 
1206 			_context.strokeStyle = value;
1207 			_contextStrokeStyle = value;
1208 
1209 		}
1210 
1211 	}
1212 
1213 	function setFillStyle( value ) {
1214 
1215 		if ( _contextFillStyle !== value ) {
1216 
1217 			_context.fillStyle = value;
1218 			_contextFillStyle = value;
1219 
1220 		}
1221 
1222 	}
1223 
1224 };
1225 

nike free rn new balance hombre baratas cinturones gucci ugg rebajas cinturon gucci ray ban baratas nike cortez peuterey mujer christian louboutin madrid mbt zapatos gafas ray ban baratas mbt ofertas air max blancas mbt barcelona nike air max 90 woolrich barcelona nike mujer botas ugg gafas de sol carrera aratas air max 2016 baratas oakley baratas nike air max 2016

mbt skor nike sverige louboutin skor hollister sverige polo ralph lauren skjorta woolrich jacka dam canada goose jacka woolrich jacka ray ban rea canada goose rea michael kors rea new balance skor ralph lauren skjorta new balance rea uggs sverige lacoste rea christian louboutin skor moncler jacka nike shox barbour jacka uggs rea