コード例 #1
0
ファイル: PolyMeshDetail.cs プロジェクト: MaybeMars/SharpNav
		/// <summary>
		/// Floodfill heightfield to get 2D height data, starting at vertex locations
		/// </summary>
		/// <param name="compactField">Original heightfield data</param>
		/// <param name="poly">Polygon in PolyMesh</param>
		/// <param name="polyCount">Number of vertices per polygon</param>
		/// <param name="verts">PolyMesh Vertices</param>
		/// <param name="borderSize">Heightfield border size</param>
		/// <param name="hp">HeightPatch which extracts heightfield data</param>
		/// <param name="stack">Temporary stack of CompactSpanReferences</param>
		private void GetHeightDataSeedsFromVertices(CompactHeightfield compactField, PolyMesh.Polygon poly, int polyCount, PolyVertex[] verts, int borderSize, HeightPatch hp, List<CompactSpanReference> stack)
		{
			hp.SetAll(0);

			//use poly vertices as seed points
			for (int j = 0; j < polyCount; j++)
			{
				var csr = new CompactSpanReference(0, 0, -1);
				int dmin = int.MaxValue;

				var v = verts[poly.Vertices[j]];

				for (int k = 0; k < 9; k++)
				{
					//get vertices and offset x and z coordinates depending on current drection
					int ax = v.X + VertexOffset[k * 2 + 0];
					int ay = v.Y;
					int az = v.Z + VertexOffset[k * 2 + 1];

					//skip if out of bounds
					if (ax < hp.X || ax >= hp.X + hp.Width || az < hp.Y || az >= hp.Y + hp.Length)
						continue;

					//get new cell
					CompactCell c = compactField.Cells[(az + borderSize) * compactField.Width + (ax + borderSize)];
					
					//loop through all the spans
					for (int i = c.StartIndex, end = c.StartIndex + c.Count; i < end; i++)
					{
						CompactSpan s = compactField.Spans[i];
						
						//find minimum y-distance
						int d = Math.Abs(ay - s.Minimum);
						if (d < dmin)
						{
							csr = new CompactSpanReference(ax, az, i);
							dmin = d;
						}
					}
				}

				//only add if something new found
				if (csr.Index != -1)
				{
					stack.Add(csr);
				}
			}

			//find center of polygon using flood fill
			int pcx = 0, pcz = 0;
			for (int j = 0; j < polyCount; j++)
			{
				var v = verts[poly.Vertices[j]];
				pcx += v.X;
				pcz += v.Z;
			}

			pcx /= polyCount;
			pcz /= polyCount;

			//stack groups 3 elements as one part
			foreach (var cell in stack)
			{
				int idx = (cell.Y - hp.Y) * hp.Width + (cell.X - hp.X);
				hp[idx] = 1;
			}

			//process the entire stack
			while (stack.Count > 0)
			{
				var cell = stack[stack.Count - 1];
				stack.RemoveAt(stack.Count - 1);

				//check if close to center of polygon
				if (Math.Abs(cell.X - pcx) <= 1 && Math.Abs(cell.Y - pcz) <= 1)
				{
					//clear the stack and add a new group
					stack.Clear();

					stack.Add(cell);
					break;
				}

				CompactSpan cs = compactField[cell];

				//check all four directions
				for (var dir = Direction.West; dir <= Direction.South; dir++)
				{
					//skip if disconnected
					if (!cs.IsConnected(dir))
						continue;

					//get neighbor
					int ax = cell.X + dir.GetHorizontalOffset();
					int ay = cell.Y + dir.GetVerticalOffset();

					//skip if out of bounds
					if (ax < hp.X || ax >= (hp.X + hp.Width) || ay < hp.Y || ay >= (hp.Y + hp.Length))
						continue;

					if (hp[(ay - hp.Y) * hp.Width + (ax - hp.X)] != 0)
						continue;

					//get the new index
					int ai = compactField.Cells[(ay + borderSize) * compactField.Width + (ax + borderSize)].StartIndex + CompactSpan.GetConnection(ref cs, dir);

					//save data
					int idx = (ay - hp.Y) * hp.Width + (ax - hp.X);
					hp[idx] = 1;

					//push to stack
					stack.Add(new CompactSpanReference(ax, ay, ai));
				}
			}

			//clear the heightpatch
			hp.Clear();

			//mark start locations
			for (int i = 0; i < stack.Count; i++)
			{
				var c = stack[i];

				//set new heightpatch data
				int idx = (c.Y - hp.Y) * hp.Width + (c.X - hp.X);
				CompactSpan cs = compactField.Spans[c.Index];
				hp[idx] = cs.Minimum;

				stack[i] = new CompactSpanReference(c.X + borderSize, c.Y + borderSize, c.Index);
			}
		}
コード例 #2
0
ファイル: PolyMeshDetail.cs プロジェクト: MaybeMars/SharpNav
		private void GetHeightData(CompactHeightfield compactField, PolyMesh.Polygon poly, int polyCount, PolyVertex[] verts, int borderSize, HeightPatch hp)
		{
			var stack = new List<CompactSpanReference>();
			bool empty = true;
			hp.Clear();

			for (int y = 0; y < hp.Length; y++)
			{
				int hy = hp.Y + y + borderSize;
				for (int x = 0; x < hp.Width; x++)
				{
					int hx = hp.X + x + borderSize;
					var cells = compactField.Cells[hy * compactField.Width + hx];
					for (int i = cells.StartIndex, end = cells.StartIndex + cells.Count; i < end; i++)
					{
						var span = compactField.Spans[i];

						if (span.Region == poly.RegionId)
						{
							hp[x, y] = span.Minimum;
							empty = false;

							bool border = false;
							for (var dir = Direction.West; dir <= Direction.South; dir++)
							{
								if (span.IsConnected(dir))
								{
									int ax = hx + dir.GetHorizontalOffset();
									int ay = hy + dir.GetVerticalOffset();
									int ai = compactField.Cells[ay * compactField.Width + ax].StartIndex + CompactSpan.GetConnection(ref span, dir);

									if (compactField.Spans[ai].Region != poly.RegionId)
									{
										border = true;
										break;
									}
								}
							}

							if (border)
								stack.Add(new CompactSpanReference(hx, hy, i));

							break;
						}
					}
				}
			}

			if (empty)
				GetHeightDataSeedsFromVertices(compactField, poly, polyCount, verts, borderSize, hp, stack);

			const int RetractSize = 256;
			int head = 0;

			while (head < stack.Count)
			{
				var cell = stack[head++];
				var cs = compactField[cell];

				if (head >= RetractSize)
				{
					head = 0;
					if (stack.Count > RetractSize)
					{
						for (int i = 0; i < stack.Count - RetractSize; i++)
							stack[i] = stack[i + RetractSize];
					}

					int targetSize = stack.Count % RetractSize;
					while (stack.Count > targetSize)
						stack.RemoveAt(stack.Count - 1);
				}

				//loop in all four directions
				for (var dir = Direction.West; dir <= Direction.South; dir++)
				{
					//skip
					if (!cs.IsConnected(dir))
						continue;

					int ax = cell.X + dir.GetHorizontalOffset();
					int ay = cell.Y + dir.GetVerticalOffset();
					int hx = ax - hp.X - borderSize;
					int hy = ay - hp.Y - borderSize;

					if (hx < 0 || hx >= hp.Width || hy < 0 || hy >= hp.Length)
						continue;

					//only continue if height is unset
					if (hp.IsSet(hy * hp.Width + hx))
						continue;

					//get new span
					int ai = compactField.Cells[ay * compactField.Width + ax].StartIndex + CompactSpan.GetConnection(ref cs, dir);
					CompactSpan ds = compactField.Spans[ai];

					hp[hx, hy] = ds.Minimum;

					stack.Add(new CompactSpanReference(ax, ay, ai));
				}
			}
		}