瀏覽代碼

added is3D mode (world space lines)

ncannasse 9 年之前
父節點
當前提交
8d204869f2
共有 1 個文件被更改,包括 182 次插入5 次删除
  1. 182 5
      h3d/scene/Graphics.hx

+ 182 - 5
h3d/scene/Graphics.hx

@@ -1,4 +1,24 @@
 package h3d.scene;
+import hxd.Math;
+
+private class GPoint {
+	public var x : Float;
+	public var y : Float;
+	public var z : Float;
+	public var r : Float;
+	public var g : Float;
+	public var b : Float;
+	public var a : Float;
+	public function new(x, y, z, r, g, b, a) {
+		this.x = x;
+		this.y = y;
+		this.z = z;
+		this.r = r;
+		this.g = g;
+		this.b = b;
+		this.a = a;
+	}
+}
 
 class Graphics extends Mesh {
 
@@ -11,28 +31,171 @@ class Graphics extends Mesh {
 	var curB : Float;
 	var curA : Float;
 	var lineSize = 0.;
+	var lineShader : h3d.shader.LineShader;
+	var tmpPoints : Array<GPoint>;
+
+	/**
+		Setting is3D to true will switch from a screen space line (constant size whatever the distance) to a world space line
+	**/
+	public var is3D(default, set) : Bool;
 
 	public function new(?parent) {
 		bprim = new h3d.prim.BigPrimitive(12);
 		super(bprim, null, parent);
-		material.mainPass.addShader(new h3d.shader.LineShader());
+		tmpPoints = [];
+		lineShader = new h3d.shader.LineShader();
+		material.mainPass.addShader(lineShader);
 		material.mainPass.addShader(new h3d.shader.VertexColorAlpha());
 		material.mainPass.culling = None;
 	}
 
+	function set_is3D(v) {
+		if( is3D == v )
+			return v;
+		if( v ) {
+			material.mainPass.removeShader(lineShader);
+		} else {
+			material.mainPass.addShaderAt(lineShader, 0);
+		}
+		bprim.clear();
+		tmpPoints = [];
+		return is3D = v;
+	}
+
+	function flushLine() {
+		var pts = tmpPoints;
+
+		var last = pts.length - 1;
+		var prev = pts[last];
+		var p = pts[0];
+
+		var closed = p.x == prev.x && p.y == prev.y && p.z == prev.z;
+		var count = pts.length;
+		if( !closed ) {
+			var prevLast = pts[last - 1];
+			if( prevLast == null ) prevLast = p;
+			pts.push(new GPoint(prev.x * 2 - prevLast.x, prev.y * 2 - prevLast.y, prev.z * 2 - prevLast.z, 0, 0, 0, 0));
+			var pNext = pts[1];
+			if( pNext == null ) pNext = p;
+			prev = new GPoint(p.x * 2 - pNext.x, p.y * 2 - pNext.y, p.z * 2 - pNext.z, 0, 0, 0, 0);
+		} else if( p != prev ) {
+			count--;
+			last--;
+			prev = pts[last];
+		}
+
+		var start = bprim.vertexCount();
+		var pindex = start;
+		var v = 0.;
+		for( i in 0...count ) {
+			var next = pts[(i + 1) % pts.length];
+
+			// ATM we only tesselate in the XY plane using a Z up normal !
+
+			var nx1 = prev.y - p.y;
+			var ny1 = p.x - prev.x;
+			var ns1 = Math.invSqrt(nx1 * nx1 + ny1 * ny1);
+
+			var nx2 = p.y - next.y;
+			var ny2 = next.x - p.x;
+			var ns2 = Math.invSqrt(nx2 * nx2 + ny2 * ny2);
+
+			var nx = nx1 * ns1 + nx2 * ns2;
+			var ny = ny1 * ns1 + ny2 * ns2;
+			var ns = Math.invSqrt(nx * nx + ny * ny);
+
+			nx *= ns;
+			ny *= ns;
+
+			var size = nx * nx1 * ns1 + ny * ny1 * ns1; // N.N1
+			var d = lineSize * 0.5 / size;
+			nx *= d;
+			ny *= d;
+
+			inline function add(v:Float) {
+				bprim.addVertexValue(v);
+			}
+
+			var hasIndex = i < count - 1 || closed;
+			bprim.begin(2, hasIndex ? 6 : 0);
+
+			add(p.x + nx);
+			add(p.y + ny);
+			add(p.z);
+
+			add(0);
+			add(0);
+			add(1);
+
+			add(0);
+			add(v);
+
+			add(p.r);
+			add(p.g);
+			add(p.b);
+			add(p.a);
+
+			add(p.x - nx);
+			add(p.y - ny);
+			add(p.z);
+
+			add(0);
+			add(0);
+			add(1);
+
+			add(1);
+			add(v);
+
+			add(p.r);
+			add(p.g);
+			add(p.b);
+			add(p.a);
+
+			v = 1 - v;
+
+			if( hasIndex ) {
+				var pnext = i == last ? start - pindex : 2;
+				bprim.addIndex(0);
+				bprim.addIndex(1);
+				bprim.addIndex(pnext);
+
+				bprim.addIndex(pnext);
+				bprim.addIndex(1);
+				bprim.addIndex(pnext + 1);
+			}
+
+			pindex += 2;
+
+			prev = p;
+			p = next;
+		}
+	}
+
+	function flush() {
+		if( tmpPoints.length == 0 )
+			return;
+		if( is3D ) {
+			flushLine();
+			tmpPoints = [];
+		}
+	}
+
 	override function draw( ctx : RenderContext ) {
+		flush();
 		bprim.flush();
 		super.draw(ctx);
 	}
 
 	public function clear() {
+		flush();
 		bprim.clear();
 	}
 
 	public function lineStyle( size = 0., color = 0, alpha = 1. ) {
+		flush();
 		if( size > 0 && lineSize != size ) {
 			lineSize = size;
-			material.mainPass.getShader(h3d.shader.LineShader).width = lineSize;
+			if( !is3D ) lineShader.width = lineSize;
 		}
 		setColor(color, alpha);
 	}
@@ -50,12 +213,26 @@ class Graphics extends Mesh {
 	}
 
 	public function moveTo( x : Float, y : Float, z : Float ) {
-		curX = x;
-		curY = y;
-		curZ = z;
+		if( is3D ) {
+			flush();
+			lineTo(x, y, z);
+		} else {
+			curX = x;
+			curY = y;
+			curZ = z;
+		}
+	}
+
+	inline function addVertex( x, y, z, r, g, b, a ) {
+		tmpPoints.push(new GPoint(x, y, z, r, g, b, a));
 	}
 
 	public function lineTo( x : Float, y : Float, z : Float ) {
+		if( is3D ) {
+			addVertex(x, y, z, curR, curG, curB, curA);
+			return;
+		}
+
 		bprim.begin(4,6);
 		var nx = x - curX;
 		var ny = y - curY;