Browse Source

2d clipping on CanvasRenderer and SVGRenderer
clearRect optimisations on CanvasRenderer

Mr.doob 15 years ago
parent
commit
530f87070f
6 changed files with 298 additions and 64 deletions
  1. 8 1
      README.md
  2. 0 1
      build/three.js
  3. 124 0
      src/core/Rectangle.js
  4. 94 36
      src/renderers/CanvasRenderer.js
  5. 70 25
      src/renderers/SVGRenderer.js
  6. 2 1
      utils/deployer.py

+ 8 - 1
README.md

@@ -76,7 +76,8 @@ If you are interested on messing with the actual library, instead of importing t
 	<script type="text/javascript" src="js/three/core/Color.js"></script>
 	<script type="text/javascript" src="js/three/core/Color.js"></script>
 	<script type="text/javascript" src="js/three/core/Vector2.js"></script>
 	<script type="text/javascript" src="js/three/core/Vector2.js"></script>
 	<script type="text/javascript" src="js/three/core/Vector3.js"></script>
 	<script type="text/javascript" src="js/three/core/Vector3.js"></script>
-	<script type="text/javascript" src="js/three/core/Vector4.js"></script>		
+	<script type="text/javascript" src="js/three/core/Vector4.js"></script>
+	<script type="text/javascript" src="js/three/core/Rectangle.js"></script>	
 	<script type="text/javascript" src="js/three/core/Matrix4.js"></script>
 	<script type="text/javascript" src="js/three/core/Matrix4.js"></script>
 	<script type="text/javascript" src="js/three/core/Vertex.js"></script>
 	<script type="text/javascript" src="js/three/core/Vertex.js"></script>
 	<script type="text/javascript" src="js/three/core/Face3.js"></script>
 	<script type="text/javascript" src="js/three/core/Face3.js"></script>
@@ -101,6 +102,12 @@ If you are interested on messing with the actual library, instead of importing t
 	
 	
 ### Change Log ###
 ### Change Log ###
 
 
+2010 05 17 - **r6** (21.003 kb)
+
+* 2d clipping on CanvasRenderer and SVGRenderer
+* clearRect optimisations on CanvasRenderer
+
+
 2010 05 16 - **r5** (19.026 kb)
 2010 05 16 - **r5** (19.026 kb)
 
 
 * Removed Class.js dependency
 * Removed Class.js dependency

File diff suppressed because it is too large
+ 0 - 1
build/three.js


+ 124 - 0
src/core/Rectangle.js

@@ -0,0 +1,124 @@
+/**
+ * @author mr.doob / http://mrdoob.com/
+ */
+
+THREE.Rectangle = function (x1, y1, x2, y2) {
+
+	var _x1 = x1, _y1 = y1,
+	_x2 = x2, _y2 = y2,
+	_width = _x2 - _x1, _height = _y2 - _y1,
+	_isEmpty = false;
+
+	this.set = function (x1, y1, x2, y2) {
+	
+		_isEmpty = false;
+		
+		_x1 = x1; _y1 = y1;
+		_x2 = x2; _y2 = y2;
+
+		this.resize();
+	}
+	
+	this.resize = function () {
+	
+		_width = _x2 - _x1;
+		_height = _y2 - _y1;
+	}
+
+	this.getX = function () {
+	
+		return _x1;
+	}
+
+	this.getY = function () {
+	
+		return _y1;
+	}
+
+	this.getWidth = function () {
+	
+		return _width;
+	}
+	
+	this.getHeight = function () {
+	
+		return _height;
+	}
+	
+	this.getX1 = function() {
+	
+		return _x1;
+	}
+
+	this.getY1 = function() {
+	
+		return _y1;
+	}
+
+	this.getX2 = function() {
+	
+		return _x2;
+	}
+
+	this.getY2 = function() {
+	
+		return _y2;
+	}
+
+	this.addPoint = function (x, y) {
+	
+		if (_isEmpty) {
+			_isEmpty = false;
+			_x1 = x; _y1 = y;
+			_x2 = x; _y2 = y;
+		} else {
+			_x1 = Math.min(_x1, x);
+			_y1 = Math.min(_y1, y);
+			_x2 = Math.max(_x2, x);
+			_y2 = Math.max(_y2, y);
+		}
+		
+		this.resize();
+	}
+	
+	this.addRectangle = function (r) {
+
+		if (_isEmpty) {
+			_isEmpty = false;
+			_x1 = r.getX1(); _y1 = r.getY1();
+			_x2 = r.getX2(); _y2 = r.getY2();
+		} else {	
+			_x1 = Math.min(_x1, r.getX1());
+			_y1 = Math.min(_y1, r.getY1());
+			_x2 = Math.max(_x2, r.getX2());
+			_y2 = Math.max(_y2, r.getY2());
+		}
+		
+		this.resize();
+	}
+	/*
+	this.containsPoint = function (x, y) {
+	
+		return x > _x1 && x < _x2 && y > _y1 && y < _y2;
+	}
+	*/
+	this.instersects = function (r) {
+	
+		return Math.min(_x2, r.getX2()) - Math.max(_x1, r.getX1()) > 0 && Math.min(_y2, r.getY2()) - Math.max(_y1, r.getY1()) > 0;
+	}
+	
+	this.empty = function () {
+	
+		_isEmpty = true;	
+	
+		_x1 = 0; _y1 = 0;
+		_x2 = 0, _y2 = 0;
+
+		this.resize();
+	}
+	
+	this.toString = function () {
+	
+		return "THREE.Rectangle (x1: " + _x1 + ", y1: " + _y2 + ", x2: " + _x2 + ", y1: " + _y1 + ", width: " + _width + ", height: " + _height + ")";
+	}
+}

+ 94 - 36
src/renderers/CanvasRenderer.js

@@ -6,26 +6,39 @@ THREE.CanvasRenderer = function () {
 
 
 	THREE.Renderer.call(this);
 	THREE.Renderer.call(this);
 
 
-	var viewport = document.createElement("canvas"),
-	context = viewport.getContext("2d");
+	var _viewport = document.createElement("canvas"),
+	_context = _viewport.getContext("2d"),
+	_clipRect = new THREE.Rectangle(),
+	_clearRect = new THREE.Rectangle(),
+	_bboxRect = new THREE.Rectangle();
 	
 	
 	this.setSize = function (width, height) {
 	this.setSize = function (width, height) {
 	
 	
-		viewport.width = width;
-		viewport.height = height;
+		_viewport.width = width;
+		_viewport.height = height;
 		
 		
-		context.setTransform(1, 0, 0, 1, width / 2, height / 2);
+		_context.setTransform(1, 0, 0, 1, width / 2, height / 2);
+		
+		_clipRect.set(-width / 2, -height / 2, width / 2, height / 2);
 	}
 	}
 	
 	
-	this.domElement = viewport;
+	this.domElement = _viewport;
 
 
 	this.render = function (scene, camera) {
 	this.render = function (scene, camera) {
 	
 	
 		var i, j, element, pi2 = Math.PI * 2,
 		var i, j, element, pi2 = Math.PI * 2,
-		elementsLength, material, materialLength;
+		elementsLength, material, materialLength,
+		v1x, v1y, v2x, v2y, v3x, v3y, v4x, v4y,
+		size;
 
 
-		context.clearRect (-viewport.width / 2, -viewport.height / 2, viewport.width, viewport.height);
+		_context.clearRect(_clearRect.getX() - 1, _clearRect.getY() - 1, _clearRect.getWidth() + 2, _clearRect.getHeight() + 2);
+		_clearRect.empty();
 
 
+		/*
+		_context.fillStyle = 'rgba(255, 255, 0, 0.5)';
+		_context.fillRect(_clipRect.getX(), _clipRect.getY(), _clipRect.getWidth(), _clipRect.getHeight());
+		*/
+		
 		this.project(scene, camera);
 		this.project(scene, camera);
 
 
 		elementsLength = this.renderList.length;
 		elementsLength = this.renderList.length;
@@ -39,59 +52,104 @@ THREE.CanvasRenderer = function () {
 		
 		
 				material = element.material[j];
 				material = element.material[j];
 			
 			
-				context.beginPath();
+				_context.beginPath();
+				
+				_bboxRect.empty();
 
 
 				if (element instanceof THREE.RenderableFace3) {
 				if (element instanceof THREE.RenderableFace3) {
-			
-					context.moveTo(element.v1.x, element.v1.y);
-					context.lineTo(element.v2.x, element.v2.y);
-					context.lineTo(element.v3.x, element.v3.y);
-					context.lineTo(element.v1.x, element.v1.y);
+					
+					v1x = element.v1.x; v1y = element.v1.y;
+					v2x = element.v2.x; v2y = element.v2.y;
+					v3x = element.v3.x; v3y = element.v3.y;
+					
+					_bboxRect.addPoint(v1x, v1y);
+					_bboxRect.addPoint(v2x, v2y);
+					_bboxRect.addPoint(v3x, v3y);
+					
+					if (!_clipRect.instersects(_bboxRect)) {
+					
+						continue;
+					}
+					
+					_clearRect.addRectangle(_bboxRect);
+					
+					_context.moveTo(v1x, v1y);
+					_context.lineTo(v2x, v2y);
+					_context.lineTo(v3x, v3y);
+					_context.lineTo(v1x, v1y);			
 				
 				
 				} else if (element instanceof THREE.RenderableFace4) {
 				} else if (element instanceof THREE.RenderableFace4) {
 
 
-					context.moveTo(element.v1.x, element.v1.y);
-					context.lineTo(element.v2.x, element.v2.y);
-					context.lineTo(element.v3.x, element.v3.y);
-					context.lineTo(element.v4.x, element.v4.y);
-					context.lineTo(element.v1.x, element.v1.y);
+					v1x = element.v1.x; v1y = element.v1.y;
+					v2x = element.v2.x; v2y = element.v2.y;
+					v3x = element.v3.x; v3y = element.v3.y;
+					v4x = element.v4.x; v4y = element.v4.y;
+					
+					_bboxRect.addPoint(v1x, v1y);
+					_bboxRect.addPoint(v2x, v2y);
+					_bboxRect.addPoint(v3x, v3y);
+					_bboxRect.addPoint(v4x, v4y);
+
+					if (!_clipRect.instersects(_bboxRect)) {
+					
+						continue;
+					}
+
+					_clearRect.addRectangle(_bboxRect);
+					
+					_context.moveTo(v1x, v1y);
+					_context.lineTo(v2x, v2y);
+					_context.lineTo(v3x, v3y);
+					_context.lineTo(v4x, v4y);					
+					_context.lineTo(v1x, v1y);					
 				
 				
 				} else if (element instanceof THREE.RenderableParticle) {
 				} else if (element instanceof THREE.RenderableParticle) {
-			
-					context.arc(element.x, element.y, element.size * element.screenZ, 0, pi2, true);
+					
+					size = element.size * element.screenZ;
+					
+					_bboxRect.set(element.x - size, element.y - size, element.x + size, element.y + size);
+
+					if (!_clipRect.instersects(_bboxRect)) {
+					
+						continue;
+					}
+					
+					_clearRect.addRectangle(_bboxRect);
+					
+					_context.arc(element.x, element.y, size, 0, pi2, true);
 				}
 				}
 				
 				
 				
 				
 				if (material instanceof THREE.ColorFillMaterial) {
 				if (material instanceof THREE.ColorFillMaterial) {
 			
 			
-					context.fillStyle = material.color.styleString;
-					context.fill();
+					_context.fillStyle = material.color.styleString;
+					_context.fill();
 			
 			
 				} else if (material instanceof THREE.FaceColorFillMaterial) {
 				} else if (material instanceof THREE.FaceColorFillMaterial) {
 			
 			
-					context.fillStyle = element.color.styleString;
-					context.fill();
+					_context.fillStyle = element.color.styleString;
+					_context.fill();
 
 
 				} else if (material instanceof THREE.ColorStrokeMaterial) {
 				} else if (material instanceof THREE.ColorStrokeMaterial) {
 				
 				
-					context.lineWidth = material.lineWidth;
-					context.lineJoin = "round";
-					context.lineCap = "round";
+					_context.lineWidth = material.lineWidth;
+					_context.lineJoin = "round";
+					_context.lineCap = "round";
 
 
-					context.strokeStyle = material.color.styleString;
-					context.stroke();
+					_context.strokeStyle = material.color.styleString;
+					_context.stroke();
 				
 				
 				} else if (material instanceof THREE.FaceColorStrokeMaterial) {
 				} else if (material instanceof THREE.FaceColorStrokeMaterial) {
 				
 				
-					context.lineWidth = material.lineWidth;
-					context.lineJoin = "round";
-					context.lineCap = "round";
+					_context.lineWidth = material.lineWidth;
+					_context.lineJoin = "round";
+					_context.lineCap = "round";
 					
 					
-					context.strokeStyle = element.color.styleString;					
-					context.stroke();
+					_context.strokeStyle = element.color.styleString;					
+					_context.stroke();
 				}
 				}
 				
 				
-				context.closePath();			
+				_context.closePath();			
 			}
 			}
 		}
 		}
 	}
 	}

+ 70 - 25
src/renderers/SVGRenderer.js

@@ -6,28 +6,34 @@ THREE.SVGRenderer = function () {
 
 
 	THREE.Renderer.call(this);
 	THREE.Renderer.call(this);
 	
 	
-	var viewport = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
-	svgPathPool = [], svgCirclePool = [];
+	var _viewport = document.createElementNS('http://www.w3.org/2000/svg', 'svg'),
+	_clipRect = new THREE.Rectangle(),
+	_bboxRect = new THREE.Rectangle(),
+	_svgPathPool = [], _svgCirclePool = [];
 
 
 	this.setSize = function (width, height) {
 	this.setSize = function (width, height) {
 	
 	
-		viewport.setAttribute('viewBox', (-width / 2) + ' ' + (-height / 2) + ' ' + width + ' ' + height );
-		viewport.setAttribute('width', width);
-		viewport.setAttribute('height', height);
+		_viewport.setAttribute('viewBox', (-width / 2) + ' ' + (-height / 2) + ' ' + width + ' ' + height );
+		_viewport.setAttribute('width', width);
+		_viewport.setAttribute('height', height);
+		
+		_clipRect.set(-width / 2, -height / 2, width / 2, height / 2);
 	}
 	}
 	
 	
-	this.domElement = viewport;
+	this.domElement = _viewport;
 
 
 	this.render = function (scene, camera) {
 	this.render = function (scene, camera) {
 	
 	
 		var i, j, element, elementsLength, material, materialLength,
 		var i, j, element, elementsLength, material, materialLength,
-		pathCount = 0, circleCount = 0, svgNode;
+		pathCount = 0, circleCount = 0, svgNode,
+		v1x, v1y, v2x, v2y, v3x, v3y, v4x, v4y,
+		size;
 	
 	
 		this.project(scene, camera);
 		this.project(scene, camera);
 	
 	
-		while (viewport.childNodes.length > 0) {
+		while (_viewport.childNodes.length > 0) {
 		
 		
-			viewport.removeChild(viewport.childNodes[0]);
+			_viewport.removeChild(_viewport.childNodes[0]);
 		}
 		}
 		
 		
 		elementsLength = this.renderList.length;
 		elementsLength = this.renderList.length;
@@ -40,23 +46,62 @@ THREE.SVGRenderer = function () {
 			for (j = 0; j < materialLength; j++) {
 			for (j = 0; j < materialLength; j++) {
 			
 			
 				material = element.material[j];
 				material = element.material[j];
+				
+				_bboxRect.empty();
 
 
 				if (element instanceof THREE.RenderableFace3) {
 				if (element instanceof THREE.RenderableFace3) {
+				
+					v1x = element.v1.x; v1y = element.v1.y;
+					v2x = element.v2.x; v2y = element.v2.y;
+					v3x = element.v3.x; v3y = element.v3.y;
+					
+					_bboxRect.addPoint(v1x, v1y);
+					_bboxRect.addPoint(v2x, v2y);
+					_bboxRect.addPoint(v3x, v3y);
+					
+					if (!_clipRect.instersects(_bboxRect)) {
+					
+						continue;
+					}
 					
 					
 					svgNode = getPathNode(pathCount++);
 					svgNode = getPathNode(pathCount++);
-					svgNode.setAttribute('d', 'M ' + element.v1.x + ' ' + element.v1.y + ' L ' + element.v2.x + ' ' + element.v2.y + ' L ' + element.v3.x + ',' + element.v3.y + 'z');
+					svgNode.setAttribute('d', 'M ' + v1x + ' ' + v1y + ' L ' + v2x + ' ' + v2y + ' L ' + v3x + ',' + v3y + 'z');
 					
 					
 				} else if (element instanceof THREE.RenderableFace4) {
 				} else if (element instanceof THREE.RenderableFace4) {
-				
+					
+					v1x = element.v1.x; v1y = element.v1.y;
+					v2x = element.v2.x; v2y = element.v2.y;
+					v3x = element.v3.x; v3y = element.v3.y;
+					v4x = element.v4.x; v4y = element.v4.y;
+					
+					_bboxRect.addPoint(v1x, v1y);
+					_bboxRect.addPoint(v2x, v2y);
+					_bboxRect.addPoint(v3x, v3y);
+					_bboxRect.addPoint(v4x, v4y);
+
+					if (!_clipRect.instersects(_bboxRect)) {
+					
+						continue;
+					}
+									
 					svgNode = getPathNode(pathCount++);
 					svgNode = getPathNode(pathCount++);
-					svgNode.setAttribute('d', 'M ' + element.v1.x + ' ' + element.v1.y + ' L ' + element.v2.x + ' ' + element.v2.y + ' L ' + element.v3.x + ',' + element.v3.y + ' L ' + element.v4.x + ',' + element.v4.y + 'z');
+					svgNode.setAttribute('d', 'M ' + v1x + ' ' + v1y + ' L ' + v2x + ' ' + v2y + ' L ' + v3x + ',' + v3y + ' L ' + v4x + ',' + v4y + 'z');
 					
 					
 				} else if (element instanceof THREE.RenderableParticle) {
 				} else if (element instanceof THREE.RenderableParticle) {
 				
 				
+					size = element.size * element.screenZ;
+					
+					_bboxRect.set(element.x - size, element.y - size, element.x + size, element.y + size);
+
+					if (!_clipRect.instersects(_bboxRect)) {
+					
+						continue;
+					}
+				
 					svgNode = getCircleNode(circleCount++);
 					svgNode = getCircleNode(circleCount++);
 					svgNode.setAttribute('cx', element.x);
 					svgNode.setAttribute('cx', element.x);
 					svgNode.setAttribute('cy', element.y);
 					svgNode.setAttribute('cy', element.y);
-					svgNode.setAttribute('r', element.size * element.screenZ);
+					svgNode.setAttribute('r', size);
 				}
 				}
 
 
 				if (material instanceof THREE.ColorFillMaterial) {
 				if (material instanceof THREE.ColorFillMaterial) {
@@ -77,34 +122,34 @@ THREE.SVGRenderer = function () {
 				}
 				}
 				
 				
 
 
-				viewport.appendChild(svgNode);
+				_viewport.appendChild(svgNode);
 			}
 			}
 		}	
 		}	
 	}
 	}
 	
 	
 	function getPathNode(id) {
 	function getPathNode(id) {
 	
 	
-		if (svgPathPool[id] == null) {
+		if (_svgPathPool[id] == null) {
 		
 		
-			svgPathPool[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path');
-			// svgPathPool[id].setAttribute('shape-rendering', 'crispEdges'); //optimizeSpeed
-			return svgPathPool[id];
+			_svgPathPool[id] = document.createElementNS('http://www.w3.org/2000/svg', 'path');
+			// _svgPathPool[id].setAttribute('shape-rendering', 'crispEdges'); //optimizeSpeed
+			return _svgPathPool[id];
 		}
 		}
 		
 		
-		return svgPathPool[id];
+		return _svgPathPool[id];
 	}
 	}
 	
 	
 	function getCircleNode(id) {
 	function getCircleNode(id) {
 	
 	
-		if (svgCirclePool[id] == null) {
+		if (_svgCirclePool[id] == null) {
 		
 		
-			svgCirclePool[id] = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
-			// svgCirclePool[id].setAttribute('shape-rendering', 'crispEdges'); //optimizeSpeed
-			// svgCirclePool[id].setAttribute('fill', 'red');
-			return svgCirclePool[id];
+			_svgCirclePool[id] = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
+			// _svgCirclePool[id].setAttribute('shape-rendering', 'crispEdges'); //optimizeSpeed
+			// _svgCirclePool[id].setAttribute('fill', 'red');
+			return _svgCirclePool[id];
 		}
 		}
 		
 		
-		return svgCirclePool[id];
+		return _svgCirclePool[id];
 	}	
 	}	
 }
 }
 
 

+ 2 - 1
utils/deployer.py

@@ -3,7 +3,7 @@ import os
 
 
 # MERGER
 # MERGER
 
 
-rev = 5;
+rev = 6;
 
 
 files = [];
 files = [];
 files.append('Three.js');
 files.append('Three.js');
@@ -11,6 +11,7 @@ files.append('core/Color.js');
 files.append('core/Vector2.js');
 files.append('core/Vector2.js');
 files.append('core/Vector3.js');
 files.append('core/Vector3.js');
 files.append('core/Vector4.js');
 files.append('core/Vector4.js');
+files.append('core/Rectangle.js');
 files.append('core/Matrix4.js');
 files.append('core/Matrix4.js');
 files.append('core/Vertex.js');
 files.append('core/Vertex.js');
 files.append('core/Face3.js');
 files.append('core/Face3.js');

Some files were not shown because too many files changed in this diff