Преглед на файлове

[csharp] Fixed port of ConvexDecomposer, SkeletonClipping

badlogic преди 8 години
родител
ревизия
4cd5ccc5b8
променени са 2 файла, в които са добавени 283 реда и са изтрити 286 реда
  1. 3 3
      spine-csharp/src/ConvexDecomposer.cs
  2. 280 283
      spine-csharp/src/SkeletonClipping.cs

+ 3 - 3
spine-csharp/src/ConvexDecomposer.cs

@@ -42,9 +42,9 @@ namespace Spine {
 		private readonly Pool<ExposedList<float>> polygonPool = new Pool<ExposedList<float>>();
 		private readonly Pool<ExposedList<short>> polygonIndicesPool = new Pool<ExposedList<short>>();
 
-		public ExposedList<ExposedList<float>> Decompose(float[] input) {
-			var vertices = input;
-			int vertexCount = input.Length >> 1;
+		public ExposedList<ExposedList<float>> Decompose(ExposedList<float> input) {
+			var vertices = input.Items;
+			int vertexCount = input.Count >> 1;
 
 			var indicesArray = this.indicesArray;
 			indicesArray.Clear();

+ 280 - 283
spine-csharp/src/SkeletonClipping.cs

@@ -32,288 +32,285 @@ using System;
 
 namespace Spine {
 	public class SkeletonClipping {
-	//	private final ConvexDecomposer decomposer = new ConvexDecomposer();
-	//	private final FloatArray clippingPolygon = new FloatArray();
-	//	private final FloatArray clipOutput = new FloatArray(128);
-	//	private final FloatArray clippedVertices = new FloatArray(128);
-	//	private final ShortArray clippedTriangles = new ShortArray(128);
-	//	private final FloatArray scratch = new FloatArray();
-
-	//	private ClippingAttachment clipAttachment;
-	//	private Array<FloatArray> clippingPolygons;
-
-	//	public void clipStart(Slot slot, ClippingAttachment clip) {
-	//		if (clipAttachment != null) return;
-	//		clipAttachment = clip;
-
-	//		int n = clip.getWorldVerticesLength();
-	//		float[] vertices = clippingPolygon.setSize(n);
-	//		clip.computeWorldVertices(slot, 0, n, vertices, 0, 2);
-	//		makeClockwise(clippingPolygon);
-	//		clippingPolygons = decomposer.decompose(clippingPolygon);
-	//		for (FloatArray polygon : clippingPolygons) {
-	//			makeClockwise(polygon);
-	//			polygon.add(polygon.items[0]);
-	//			polygon.add(polygon.items[1]);
-	//		}
-	//	}
-
-	//	public void clipEnd(Slot slot) {
-	//		if (clipAttachment != null && clipAttachment.getEndSlot() == slot.getData()) clipEnd();
-	//	}
-
-	//	public void clipEnd() {
-	//		if (clipAttachment == null) return;
-	//		clipAttachment = null;
-	//		clippingPolygons = null;
-	//		clippedVertices.clear();
-	//		clippedTriangles.clear();
-	//		clippingPolygon.clear();
-	//	}
-
-	//	public boolean isClipping() {
-	//		return clipAttachment != null;
-	//	}
-
-	//	public void clipTriangles(float[] vertices, int verticesLength, short[] triangles, int trianglesLength, float[] uvs,
-	//		float light, float dark, boolean twoColor) {
-
-	//		FloatArray clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
-	//		ShortArray clippedTriangles = this.clippedTriangles;
-	//		Object[] polygons = clippingPolygons.items;
-	//		int polygonsCount = clippingPolygons.size;
-	//		int vertexSize = twoColor ? 6 : 5;
-
-	//		short index = 0;
-	//		clippedVertices.clear();
-	//		clippedTriangles.clear();
-	//	outer:
-	//		for (int i = 0; i < trianglesLength; i += 3) {
-	//			int vertexOffset = triangles[i] << 1;
-	//			float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
-	//			float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1];
-
-	//			vertexOffset = triangles[i + 1] << 1;
-	//			float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1];
-	//			float u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1];
-
-	//			vertexOffset = triangles[i + 2] << 1;
-	//			float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1];
-	//			float u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1];
-
-	//			for (int p = 0; p < polygonsCount; p++) {
-	//				int s = clippedVertices.size;
-	//				if (clip(x1, y1, x2, y2, x3, y3, (FloatArray)polygons[p], clipOutput)) {
-	//					int clipOutputLength = clipOutput.size;
-	//					if (clipOutputLength == 0) continue;
-	//					float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
-	//					float d = 1 / (d0 * d2 + d1 * (y1 - y3));
-
-	//					int clipOutputCount = clipOutputLength >> 1;
-	//					float[] clipOutputItems = clipOutput.items;
-	//					float[] clippedVerticesItems = clippedVertices.setSize(s + clipOutputCount * vertexSize);
-	//					for (int ii = 0; ii < clipOutputLength; ii += 2) {
-	//						float x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
-	//						clippedVerticesItems[s] = x;
-	//						clippedVerticesItems[s + 1] = y;
-	//						clippedVerticesItems[s + 2] = light;
-	//						if (twoColor) {
-	//							clippedVerticesItems[s + 3] = dark;
-	//							s += 4;
-	//						}
-	//						else
-	//							s += 3;
-	//						float c0 = x - x3, c1 = y - y3;
-	//						float a = (d0 * c0 + d1 * c1) * d;
-	//						float b = (d4 * c0 + d2 * c1) * d;
-	//						float c = 1 - a - b;
-	//						clippedVerticesItems[s] = u1 * a + u2 * b + u3 * c;
-	//						clippedVerticesItems[s + 1] = v1 * a + v2 * b + v3 * c;
-	//						s += 2;
-	//					}
-
-	//					s = clippedTriangles.size;
-	//					short[] clippedTrianglesItems = clippedTriangles.setSize(s + 3 * (clipOutputCount - 2));
-	//					clipOutputCount--;
-	//					for (int ii = 1; ii < clipOutputCount; ii++) {
-	//						clippedTrianglesItems[s] = index;
-	//						clippedTrianglesItems[s + 1] = (short)(index + ii);
-	//						clippedTrianglesItems[s + 2] = (short)(index + ii + 1);
-	//						s += 3;
-	//					}
-	//					index += clipOutputCount + 1;
-
-	//				}
-	//				else {
-	//					float[] clippedVerticesItems = clippedVertices.setSize(s + 3 * vertexSize);
-	//					clippedVerticesItems[s] = x1;
-	//					clippedVerticesItems[s + 1] = y1;
-	//					clippedVerticesItems[s + 2] = light;
-	//					if (!twoColor) {
-	//						clippedVerticesItems[s + 3] = u1;
-	//						clippedVerticesItems[s + 4] = v1;
-
-	//						clippedVerticesItems[s + 5] = x2;
-	//						clippedVerticesItems[s + 6] = y2;
-	//						clippedVerticesItems[s + 7] = light;
-	//						clippedVerticesItems[s + 8] = u2;
-	//						clippedVerticesItems[s + 9] = v2;
-
-	//						clippedVerticesItems[s + 10] = x3;
-	//						clippedVerticesItems[s + 11] = y3;
-	//						clippedVerticesItems[s + 12] = light;
-	//						clippedVerticesItems[s + 13] = u3;
-	//						clippedVerticesItems[s + 14] = v3;
-	//					}
-	//					else {
-	//						clippedVerticesItems[s + 3] = dark;
-	//						clippedVerticesItems[s + 4] = u1;
-	//						clippedVerticesItems[s + 5] = v1;
-
-	//						clippedVerticesItems[s + 6] = x2;
-	//						clippedVerticesItems[s + 7] = y2;
-	//						clippedVerticesItems[s + 8] = light;
-	//						clippedVerticesItems[s + 9] = dark;
-	//						clippedVerticesItems[s + 10] = u2;
-	//						clippedVerticesItems[s + 11] = v2;
-
-	//						clippedVerticesItems[s + 12] = x3;
-	//						clippedVerticesItems[s + 13] = y3;
-	//						clippedVerticesItems[s + 14] = light;
-	//						clippedVerticesItems[s + 15] = dark;
-	//						clippedVerticesItems[s + 16] = u3;
-	//						clippedVerticesItems[s + 17] = v3;
-	//					}
-
-	//					s = clippedTriangles.size;
-	//					short[] clippedTrianglesItems = clippedTriangles.setSize(s + 3);
-	//					clippedTrianglesItems[s] = index;
-	//					clippedTrianglesItems[s + 1] = (short)(index + 1);
-	//					clippedTrianglesItems[s + 2] = (short)(index + 2);
-	//					index += 3;
-	//					continue outer;
-	//				}
-	//			}
-	//		}
-	//	}
-
-	//	/** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping
-	//	 * area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. */
-	//	boolean clip(float x1, float y1, float x2, float y2, float x3, float y3, FloatArray clippingArea, FloatArray output) {
-	//		FloatArray originalOutput = output;
-	//		boolean clipped = false;
-
-	//		// Avoid copy at the end.
-	//		FloatArray input = null;
-	//		if (clippingArea.size % 4 >= 2) {
-	//			input = output;
-	//			output = scratch;
-	//		}
-	//		else
-	//			input = scratch;
-
-	//		input.clear();
-	//		input.add(x1);
-	//		input.add(y1);
-	//		input.add(x2);
-	//		input.add(y2);
-	//		input.add(x3);
-	//		input.add(y3);
-	//		input.add(x1);
-	//		input.add(y1);
-	//		output.clear();
-
-	//		float[] clippingVertices = clippingArea.items;
-	//		int clippingVerticesLast = clippingArea.size - 4;
-	//		for (int i = 0; ; i += 2) {
-	//			float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
-	//			float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
-	//			float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
-
-	//			float[] inputVertices = input.items;
-	//			int inputVerticesLength = input.size - 2, outputStart = output.size;
-	//			for (int ii = 0; ii < inputVerticesLength; ii += 2) {
-	//				float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
-	//				float inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3];
-	//				boolean side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0;
-	//				if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) {
-	//					if (side2) { // v1 inside, v2 inside
-	//						output.add(inputX2);
-	//						output.add(inputY2);
-	//						continue;
-	//					}
-	//					// v1 inside, v2 outside
-	//					float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
-	//					float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
-	//					output.add(edgeX + (edgeX2 - edgeX) * ua);
-	//					output.add(edgeY + (edgeY2 - edgeY) * ua);
-	//				}
-	//				else if (side2) { // v1 outside, v2 inside
-	//					float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
-	//					float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
-	//					output.add(edgeX + (edgeX2 - edgeX) * ua);
-	//					output.add(edgeY + (edgeY2 - edgeY) * ua);
-	//					output.add(inputX2);
-	//					output.add(inputY2);
-	//				}
-	//				clipped = true;
-	//			}
-
-	//			if (outputStart == output.size) { // All edges outside.
-	//				originalOutput.clear();
-	//				return true;
-	//			}
-
-	//			output.add(output.items[0]);
-	//			output.add(output.items[1]);
-
-	//			if (i == clippingVerticesLast) break;
-	//			FloatArray temp = output;
-	//			output = input;
-	//			output.clear();
-	//			input = temp;
-	//		}
-
-	//		if (originalOutput != output) {
-	//			originalOutput.clear();
-	//			originalOutput.addAll(output.items, 0, output.size - 2);
-	//		}
-	//		else
-	//			originalOutput.setSize(originalOutput.size - 2);
-
-	//		return clipped;
-	//	}
-
-	//	public FloatArray getClippedVertices() {
-	//		return clippedVertices;
-	//	}
-
-	//	public ShortArray getClippedTriangles() {
-	//		return clippedTriangles;
-	//	}
-
-	//	static void makeClockwise(FloatArray polygon) {
-	//		float[] vertices = polygon.items;
-	//		int verticeslength = polygon.size;
-
-	//		float area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x, p1y, p2x, p2y;
-	//		for (int i = 0, n = verticeslength - 3; i < n; i += 2) {
-	//			p1x = vertices[i];
-	//			p1y = vertices[i + 1];
-	//			p2x = vertices[i + 2];
-	//			p2y = vertices[i + 3];
-	//			area += p1x * p2y - p2x * p1y;
-	//		}
-	//		if (area < 0) return;
-
-	//		for (int i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) {
-	//			float x = vertices[i], y = vertices[i + 1];
-	//			int other = lastX - i;
-	//			vertices[i] = vertices[other];
-	//			vertices[i + 1] = vertices[other + 1];
-	//			vertices[other] = x;
-	//			vertices[other + 1] = y;
-	//		}
-	//	}
+		private readonly ConvexDecomposer decomposer = new ConvexDecomposer();
+		private readonly ExposedList<float> clippingPolygon = new ExposedList<float>();
+		private readonly ExposedList<float> clipOutput = new ExposedList<float>(128);
+		private readonly ExposedList<float> clippedVertices = new ExposedList<float>(128);
+		private readonly ExposedList<short> clippedTriangles = new ExposedList<short>(128);
+		private readonly ExposedList<float> scratch = new ExposedList<float>();
+
+		private ClippingAttachment clipAttachment;
+		private ExposedList<ExposedList<float>> clippingPolygons;
+
+		public ExposedList<float> ClippedVertices { get { return clippedVertices; } }
+		public ExposedList<short> ClippedTriangles { get { return clippedTriangles; } }
+
+		public void ClipStart(Slot slot, ClippingAttachment clip) {
+			if (clipAttachment != null) return;
+			clipAttachment = clip;
+
+			int n = clip.worldVerticesLength;
+			float[] vertices = clippingPolygon.Resize(n).Items;
+			clip.ComputeWorldVertices(slot, 0, n, vertices, 0, 2);
+			MakeClockwise(clippingPolygon);
+			clippingPolygons = decomposer.Decompose(clippingPolygon);
+			foreach (var polygon in clippingPolygons) {
+				MakeClockwise(polygon);
+				polygon.Add(polygon.Items[0]);
+				polygon.Add(polygon.Items[1]);
+			}
+		}
+
+		public void ClipEnd(Slot slot) {
+			if (clipAttachment != null && clipAttachment.endSlot == slot.data) ClipEnd();
+		}
+
+		public void ClipEnd() {
+			if (clipAttachment == null) return;
+			clipAttachment = null;
+			clippingPolygons = null;
+			clippedVertices.Clear();
+			clippedTriangles.Clear();
+			clippingPolygon.Clear();
+		}
+
+		public bool IsClipping() {
+			return clipAttachment != null;
+		}
+
+		public void ClipTriangles(float[] vertices, int verticesLength, short[] triangles, int trianglesLength, float[] uvs,
+			float light, float dark, bool twoColor) {
+
+			ExposedList<float> clipOutput = this.clipOutput, clippedVertices = this.clippedVertices;
+			var clippedTriangles = this.clippedTriangles;
+			var polygons = clippingPolygons.Items;
+			int polygonsCount = clippingPolygons.Count;
+			int vertexSize = twoColor ? 6 : 5;
+
+			short index = 0;
+			clippedVertices.Clear();
+			clippedTriangles.Clear();
+			outer:
+			for (int i = 0; i < trianglesLength; i += 3) {
+				int vertexOffset = triangles[i] << 1;
+				float x1 = vertices[vertexOffset], y1 = vertices[vertexOffset + 1];
+				float u1 = uvs[vertexOffset], v1 = uvs[vertexOffset + 1];
+
+				vertexOffset = triangles[i + 1] << 1;
+				float x2 = vertices[vertexOffset], y2 = vertices[vertexOffset + 1];
+				float u2 = uvs[vertexOffset], v2 = uvs[vertexOffset + 1];
+
+				vertexOffset = triangles[i + 2] << 1;
+				float x3 = vertices[vertexOffset], y3 = vertices[vertexOffset + 1];
+				float u3 = uvs[vertexOffset], v3 = uvs[vertexOffset + 1];
+
+				for (int p = 0; p < polygonsCount; p++) {
+					int s = clippedVertices.Count;
+					if (Clip(x1, y1, x2, y2, x3, y3, polygons[p], clipOutput)) {
+						int clipOutputLength = clipOutput.Count;
+						if (clipOutputLength == 0) continue;
+						float d0 = y2 - y3, d1 = x3 - x2, d2 = x1 - x3, d4 = y3 - y1;
+						float d = 1 / (d0 * d2 + d1 * (y1 - y3));
+
+						int clipOutputCount = clipOutputLength >> 1;
+						float[] clipOutputItems = clipOutput.Items;
+						float[] clippedVerticesItems = clippedVertices.Resize(s + clipOutputCount * vertexSize).Items;
+						for (int ii = 0; ii < clipOutputLength; ii += 2) {
+							float x = clipOutputItems[ii], y = clipOutputItems[ii + 1];
+							clippedVerticesItems[s] = x;
+							clippedVerticesItems[s + 1] = y;
+							clippedVerticesItems[s + 2] = light;
+							if (twoColor) {
+								clippedVerticesItems[s + 3] = dark;
+								s += 4;
+							}
+							else
+								s += 3;
+							float c0 = x - x3, c1 = y - y3;
+							float a = (d0 * c0 + d1 * c1) * d;
+							float b = (d4 * c0 + d2 * c1) * d;
+							float c = 1 - a - b;
+							clippedVerticesItems[s] = u1 * a + u2 * b + u3 * c;
+							clippedVerticesItems[s + 1] = v1 * a + v2 * b + v3 * c;
+							s += 2;
+						}
+
+						s = clippedTriangles.Count;
+						short[] clippedTrianglesItems = clippedTriangles.Resize(s + 3 * (clipOutputCount - 2)).Items;
+						clipOutputCount--;
+						for (int ii = 1; ii < clipOutputCount; ii++) {
+							clippedTrianglesItems[s] = index;
+							clippedTrianglesItems[s + 1] = (short)(index + ii);
+							clippedTrianglesItems[s + 2] = (short)(index + ii + 1);
+							s += 3;
+						}
+						index += (short)(clipOutputCount + 1);
+
+					}
+					else {
+						float[] clippedVerticesItems = clippedVertices.Resize(s + 3 * vertexSize).Items;
+						clippedVerticesItems[s] = x1;
+						clippedVerticesItems[s + 1] = y1;
+						clippedVerticesItems[s + 2] = light;
+						if (!twoColor) {
+							clippedVerticesItems[s + 3] = u1;
+							clippedVerticesItems[s + 4] = v1;
+
+							clippedVerticesItems[s + 5] = x2;
+							clippedVerticesItems[s + 6] = y2;
+							clippedVerticesItems[s + 7] = light;
+							clippedVerticesItems[s + 8] = u2;
+							clippedVerticesItems[s + 9] = v2;
+
+							clippedVerticesItems[s + 10] = x3;
+							clippedVerticesItems[s + 11] = y3;
+							clippedVerticesItems[s + 12] = light;
+							clippedVerticesItems[s + 13] = u3;
+							clippedVerticesItems[s + 14] = v3;
+						}
+						else {
+							clippedVerticesItems[s + 3] = dark;
+							clippedVerticesItems[s + 4] = u1;
+							clippedVerticesItems[s + 5] = v1;
+
+							clippedVerticesItems[s + 6] = x2;
+							clippedVerticesItems[s + 7] = y2;
+							clippedVerticesItems[s + 8] = light;
+							clippedVerticesItems[s + 9] = dark;
+							clippedVerticesItems[s + 10] = u2;
+							clippedVerticesItems[s + 11] = v2;
+
+							clippedVerticesItems[s + 12] = x3;
+							clippedVerticesItems[s + 13] = y3;
+							clippedVerticesItems[s + 14] = light;
+							clippedVerticesItems[s + 15] = dark;
+							clippedVerticesItems[s + 16] = u3;
+							clippedVerticesItems[s + 17] = v3;
+						}
+
+						s = clippedTriangles.Count;
+						short[] clippedTrianglesItems = clippedTriangles.Resize(s + 3).Items;
+						clippedTrianglesItems[s] = index;
+						clippedTrianglesItems[s + 1] = (short)(index + 1);
+						clippedTrianglesItems[s + 2] = (short)(index + 2);
+						index += 3;
+						goto outer;
+					}
+				}
+			}
+		}
+
+		/** Clips the input triangle against the convex, clockwise clipping area. If the triangle lies entirely within the clipping
+		 * area, false is returned. The clipping area must duplicate the first vertex at the end of the vertices list. */
+		internal bool Clip(float x1, float y1, float x2, float y2, float x3, float y3, ExposedList<float> clippingArea, ExposedList<float> output) {
+			var originalOutput = output;
+			var clipped = false;
+
+			// Avoid copy at the end.
+			ExposedList<float> input = null;
+			if (clippingArea.Count % 4 >= 2) {
+				input = output;
+				output = scratch;
+			}
+			else
+				input = scratch;
+
+			input.Clear();
+			input.Add(x1);
+			input.Add(y1);
+			input.Add(x2);
+			input.Add(y2);
+			input.Add(x3);
+			input.Add(y3);
+			input.Add(x1);
+			input.Add(y1);
+			output.Clear();
+
+			float[] clippingVertices = clippingArea.Items;
+			int clippingVerticesLast = clippingArea.Count - 4;
+			for (int i = 0; ; i += 2) {
+				float edgeX = clippingVertices[i], edgeY = clippingVertices[i + 1];
+				float edgeX2 = clippingVertices[i + 2], edgeY2 = clippingVertices[i + 3];
+				float deltaX = edgeX - edgeX2, deltaY = edgeY - edgeY2;
+
+				float[] inputVertices = input.Items;
+				int inputVerticesLength = input.Count - 2, outputStart = output.Count;
+				for (int ii = 0; ii < inputVerticesLength; ii += 2) {
+					float inputX = inputVertices[ii], inputY = inputVertices[ii + 1];
+					float inputX2 = inputVertices[ii + 2], inputY2 = inputVertices[ii + 3];
+					bool side2 = deltaX * (inputY2 - edgeY2) - deltaY * (inputX2 - edgeX2) > 0;
+					if (deltaX * (inputY - edgeY2) - deltaY * (inputX - edgeX2) > 0) {
+						if (side2) { // v1 inside, v2 inside
+							output.Add(inputX2);
+							output.Add(inputY2);
+							continue;
+						}
+						// v1 inside, v2 outside
+						float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
+						float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
+						output.Add(edgeX + (edgeX2 - edgeX) * ua);
+						output.Add(edgeY + (edgeY2 - edgeY) * ua);
+					}
+					else if (side2) { // v1 outside, v2 inside
+						float c0 = inputY2 - inputY, c2 = inputX2 - inputX;
+						float ua = (c2 * (edgeY - inputY) - c0 * (edgeX - inputX)) / (c0 * (edgeX2 - edgeX) - c2 * (edgeY2 - edgeY));
+						output.Add(edgeX + (edgeX2 - edgeX) * ua);
+						output.Add(edgeY + (edgeY2 - edgeY) * ua);
+						output.Add(inputX2);
+						output.Add(inputY2);
+					}
+					clipped = true;
+				}
+
+				if (outputStart == output.Count) { // All edges outside.
+					originalOutput.Clear();
+					return true;
+				}
+
+				output.Add(output.Items[0]);
+				output.Add(output.Items[1]);
+
+				if (i == clippingVerticesLast) break;
+				var temp = output;
+				output = input;
+				output.Clear();
+				input = temp;
+			}
+
+			if (originalOutput != output) {
+				originalOutput.Clear();
+				for (int i = 0, n = output.Count - 2; i < n; i++) {
+					originalOutput.Add(output.Items[i]);
+				}
+			}
+			else
+				originalOutput.Resize(originalOutput.Count - 2);
+
+			return clipped;
+		}
+
+		static void MakeClockwise(ExposedList<float> polygon) {
+			float[] vertices = polygon.Items;
+			int verticeslength = polygon.Count;
+
+			float area = vertices[verticeslength - 2] * vertices[1] - vertices[0] * vertices[verticeslength - 1], p1x, p1y, p2x, p2y;
+			for (int i = 0, n = verticeslength - 3; i < n; i += 2) {
+				p1x = vertices[i];
+				p1y = vertices[i + 1];
+				p2x = vertices[i + 2];
+				p2y = vertices[i + 3];
+				area += p1x * p2y - p2x * p1y;
+			}
+			if (area < 0) return;
+
+			for (int i = 0, lastX = verticeslength - 2, n = verticeslength >> 1; i < n; i += 2) {
+				float x = vertices[i], y = vertices[i + 1];
+				int other = lastX - i;
+				vertices[i] = vertices[other];
+				vertices[i + 1] = vertices[other + 1];
+				vertices[other] = x;
+				vertices[other + 1] = y;
+			}
+		}
 	}
 }